Commit 82a586a0 authored by ZWT's avatar ZWT

feat(吉林演示): 松原

1.修改风电站运行状态接口,增加模拟实际发电功率处理逻辑,完成接口冒烟测试;
2.修改天气数据处理定时任务,解决晚上十一点半天气预报数据处理异常问题,修改风资源预测数据和光伏资源预测数据时间处理逻辑,完成接口冒烟测试;
3.修改风机预测数据模块相关功能接口,增加判断当前部署环境逻辑,解决查询全量数据问题;
4.修改风机预测数据生成模块第三方风力发电数据生成功能,增加数据拆分逻辑,区分15分数据层级,完成功能冒烟测试;
5.修改风机预测监控页面历史风速统计接口,统计数据不显示问题及小数位过多问题;

BREAKING CHANGE: 无

Closes 无

[skip ci]
parent c1b0031e
/* JUG Java Uuid Generator
*
* Copyright (c) 2002- Tatu Saloranta, tatu.saloranta@iki.fi
*
* Licensed under the License specified in the file LICENSE which is
* included with the source code.
* You may not use this file except in compliance with the License.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fasterxml.uuid;
import java.io.IOException;
/**
* This is the API for utility classes optionally used by {@link UUIDTimer} to
* ensure that timestamp values used for generating time/location-based UUIDs
* are monotonically increasing, as well as that only one such generator
* is ever used on a single system, even in presence of multiple JVMs.
* <p>
* The default implementation used by JUG is
* {@link com.fasterxml.uuid.ext.FileBasedTimestampSynchronizer}.
*/
public abstract class TimestampSynchronizer {
protected TimestampSynchronizer() {
}
/**
* Initialization method is will be called on an instance by
* {@link UUIDTimer} right after it's been configured with one.
* At this point the implementation instance should have been properly
* configured, and should be able to determine the first legal timestamp
* value (return value). Method should also initialize any locking that
* it does (if any), such as locking files it needs.
* <p>
* Return value thus indicates the lowest initial time value that can
* be used by the caller that can not have been used by previous
* incarnations of the UUID generator (assuming instance was able to
* find properly persisted data to figure that out).
* However, caller also needs to make sure that it will
* call {@link #update} when it actually needs the time stamp for the
* first time,
* since this method can not allocate timestamps beyond this initial
* value at this point.
*
* @return First (and last) legal timestamp to use; <code>0L</code> if it
* can not
* determine it and caller can use whatever value (current timestamp)
* it has access to.
*/
protected abstract long initialize()
throws IOException;
/**
* Method {@link UUIDTimer} will call if this synchronizer object is
* being replaced by another synchronizer (or removed, that is, no
* more synchronization is to be done). It will not be called if JVM
* terminates.
*/
protected abstract void deactivate()
throws IOException;
/**
* Method called by {@link UUIDTimer} to indicate that it has generated
* a timestamp value that is beyond last legal timestamp value.
* The method should only return once it has "locked" specified timestamp
* value (and possible additional ones).
*
* @param now Timestamp value caller wants to use, and that the
* synchronizer is asked to protect.
* @return First timestamp value that can NOT be used by the caller;
* has to be higher than the input timestamp value
*/
protected abstract long update(long now)
throws IOException;
}
\ No newline at end of file
/* JUG Java Uuid Generator
*
* Copyright (c) 2002 Tatu Saloranta, tatu.saloranta@iki.fi
*
* Licensed under the License specified in the file LICENSE which is
* included with the source code.
* You may not use this file except in compliance with the License.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fasterxml.uuid;
/**
* UUIDClock is used by UUIDTimer to get the current time. The default
* implementation returns the time from the system clock, but this class can
* be overriden to return any number. This is useful when UUIDs with past or
* future timestamps should be generated, or when UUIDs must be generated in
* a reproducible manner.
*
* @since 3.3
*/
public class UUIDClock {
/**
* Returns the current time in milliseconds.
*/
public long currentTimeMillis() {
return System.currentTimeMillis();
}
}
\ No newline at end of file
/* JUG Java Uuid Generator
*
* Copyright (c) 2002 Tatu Saloranta, tatu.saloranta@iki.fi
*
* Licensed under the License specified in the file LICENSE which is
* included with the source code.
* You may not use this file except in compliance with the License.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fasterxml.uuid;
import com.fasterxml.uuid.impl.LoggerFacade;
import com.fasterxml.uuid.impl.UUIDUtil;
import java.io.IOException;
import java.util.Random;
/**
* UUIDTimer produces the time stamps required for time-based UUIDs.
* It works as outlined in the UUID specification, with following
* implementation:
* <ul>
* <li>Java classes can only product time stamps with maximum resolution
* of one millisecond (at least before JDK 1.5).
* To compensate, an additional counter is used,
* so that more than one UUID can be generated between java clock
* updates. Counter may be used to generate up to 10000 UUIDs for
* each distinct java clock value.
* <li>Due to even lower clock resolution on some platforms (older
* Windows versions use 55 msec resolution), timestamp value can
* also advanced ahead of physical value within limits (by default,
* up 100 millisecond ahead of reported), if necessary (ie. 10000
* instances created before clock time advances).
* <li>As an additional precaution, counter is initialized not to 0
* but to a random 8-bit number, and each time clock changes, lowest
* 8-bits of counter are preserved. The purpose it to make likelyhood
* of multi-JVM multi-instance generators to collide, without significantly
* reducing max. UUID generation speed. Note though that using more than
* one generator (from separate JVMs) is strongly discouraged, so
* hopefully this enhancement isn't needed.
* This 8-bit offset has to be reduced from total max. UUID count to
* preserve ordering property of UUIDs (ie. one can see which UUID
* was generated first for given UUID generator); the resulting
* 9500 UUIDs isn't much different from the optimal choice.
* <li>Finally, as of version 2.0 and onwards, optional external timestamp
* synchronization can be done. This is done similar to the way UUID
* specification suggests; except that since there is no way to
* lock the whole system, file-based locking is used. This works
* between multiple JVMs and Jug instances.
* </ul>
* <p>
* Some additional assumptions about calculating the timestamp:
* <ul>
* <li>System.currentTimeMillis() is assumed to give time offset in UTC,
* or at least close enough thing to get correct timestamps. The
* alternate route would have to go through calendar object, use
* TimeZone offset to get to UTC, and then modify. Using currentTimeMillis
* should be much faster to allow rapid UUID creation.
* <li>Similarly, the constant used for time offset between 1.1.1970 and
* start of Gregorian calendar is assumed to be correct (which seems
* to be the case when testing with Java calendars).
* </ul>
* <p>
* Note about synchronization: main synchronization point (as of version
* 3.1.1 and above) is {@link #getTimestamp}, so caller need not
* synchronize access explicitly.
*/
public class UUIDTimer {
/**
* Since System.longTimeMillis() returns time from january 1st 1970,
* and UUIDs need time from the beginning of gregorian calendar
* (15-oct-1582), need to apply the offset:
*/
private final static long kClockOffset = 0x01b21dd213814000L;
// // // Constants
/**
* Also, instead of getting time in units of 100nsecs, we get something
* with max resolution of 1 msec... and need the multiplier as well
*/
private final static int kClockMultiplier = 10000;
private final static long kClockMultiplierL = 10000L;
/**
* Let's allow "virtual" system time to advance at most 100 milliseconds
* beyond actual physical system time, before adding delays.
*/
private final static long kMaxClockAdvance = 100L;
private final static int MAX_WAIT_COUNT = 50;
// // // Configuration
/**
* Object used to reliably ensure that no multiple JVMs
* generate UUIDs, and also that the time stamp value used for
* generating time-based UUIDs is monotonically increasing
* even if system clock moves backwards over a reboot (usually
* due to some system level problem).
* <p>
* See {@link TimestampSynchronizer} for details.
*/
protected final TimestampSynchronizer _syncer;
/**
* Random number generator used to generate additional information
* to further reduce probability of collisions.
*/
protected final Random _random;
/**
* Clock used to get the time when a timestamp is requested.
*
* @since 3.3
*/
protected final UUIDClock _clock;
// // // Clock state:
private final LoggerFacade _logger = LoggerFacade.getLogger(getClass());
/**
* Additional state information used to protect against anomalous
* cases (clock time going backwards, node id getting mixed up).
* Third byte is actually used for seeding counter on counter
* overflow.
* Note that only lowermost 16 bits are actually used as sequence
*/
private int _clockSequence;
/**
* Last physical timestamp value <code>System.currentTimeMillis()</code>
* returned: used to catch (and report) cases where system clock
* goes backwards. Is also used to limit "drifting", that is, amount
* timestamps used can differ from the system time value. This value
* is not guaranteed to be monotonically increasing.
*/
private long _lastSystemTimestamp = 0L;
/**
* Timestamp value last used for generating a UUID (along with
* {@link #_clockCounter}. Usually the same as
* {@link #_lastSystemTimestamp}, but not always (system clock
* moved backwards). Note that this value is guaranteed to be
* monotonically increasing; that is, at given absolute time points
* t1 and t2 (where t2 is after t1), t1 <= t2 will always hold true.
*/
private long _lastUsedTimestamp = 0L;
/**
* First timestamp that can NOT be used without synchronizing
* using synchronization object ({@link #_syncer}). Only used when
* external timestamp synchronization (and persistence) is used,
* ie. when {@link #_syncer} is not null.
*/
private long _firstUnsafeTimestamp = Long.MAX_VALUE;
/**
* Counter used to compensate inadequate resolution of JDK system
* timer.
*/
private int _clockCounter = 0;
public UUIDTimer(Random rnd, TimestampSynchronizer sync) throws IOException {
this(rnd, sync, new UUIDClock());
}
/**
* @param rnd Random-number generator to use
* @param sync Synchronizer needed for multi-threaded timestamp access
* @param clock Provider for milli-second resolution timestamp
* @throws IOException if initialization of {@code sync} fails due to problem related
* to reading of persisted last-used timestamp
* @since 3.3
*/
public UUIDTimer(Random rnd, TimestampSynchronizer sync, UUIDClock clock) throws IOException {
_random = rnd;
_syncer = sync;
_clock = clock;
initCounters(rnd);
_lastSystemTimestamp = 0L;
// This may get overwritten by the synchronizer
_lastUsedTimestamp = 0L;
/* Ok, now; synchronizer can tell us what is the first timestamp
* value that definitely was NOT used by the previous incarnation.
* This can serve as the last used time stamp, assuming it is not
* less than value we are using now.
*/
if (sync != null) {
long lastSaved = sync.initialize();
if (lastSaved > _lastUsedTimestamp) {
_lastUsedTimestamp = lastSaved;
}
}
/* Also, we need to make sure there are now no safe values (since
* synchronizer is not yet requested to allocate any):
*/
_firstUnsafeTimestamp = 0L; // ie. will always trigger sync.update()
}
private void initCounters(Random rnd) {
/* Let's generate the clock sequence field now; as with counter,
* this reduces likelihood of collisions (as explained in UUID specs)
*/
_clockSequence = rnd.nextInt();
/* Ok, let's also initialize the counter...
* Counter is used to make it slightly less likely that
* two instances of UUIDGenerator (from separate JVMs as no more
* than one can be created in one JVM) would produce colliding
* time-based UUIDs. The practice of using multiple generators,
* is strongly discouraged, of course, but just in case...
*/
_clockCounter = (_clockSequence >> 16) & 0xFF;
}
public int getClockSequence() {
return (_clockSequence & 0xFFFF);
}
/*
/**********************************************************************
/* Test-support methods
/**********************************************************************
*/
/**
* Method that constructs unique timestamp suitable for use for
* constructing UUIDs. Default implementation is fully synchronized;
* sub-classes may choose to implemented alternate strategies
*
* @return 64-bit timestamp to use for constructing UUID
*/
public synchronized long getTimestamp() {
long systime = _clock.currentTimeMillis();
/* Let's first verify that the system time is not going backwards;
* independent of whether we can use it:
*/
if (systime < _lastSystemTimestamp) {
_logger.warn("System time going backwards! (got value %d, last %d)",
systime, _lastSystemTimestamp);
// Let's write it down, still
_lastSystemTimestamp = systime;
}
/* But even without it going backwards, it may be less than the
* last one used (when generating UUIDs fast with coarse clock
* resolution; or if clock has gone backwards over reboot etc).
*/
if (systime <= _lastUsedTimestamp) {
/* Can we just use the last time stamp (ok if the counter
* hasn't hit max yet)
*/
if (_clockCounter < kClockMultiplier) { // yup, still have room
systime = _lastUsedTimestamp;
} else { // nope, have to roll over to next value and maybe wait
long actDiff = _lastUsedTimestamp - systime;
long origTime = systime;
systime = _lastUsedTimestamp + 1L;
_logger.warn("Timestamp over-run: need to reinitialize random sequence");
/* Clock counter is now at exactly the multiplier; no use
* just anding its value. So, we better get some random
* numbers instead...
*/
initCounters(_random);
/* But do we also need to slow down? (to try to keep virtual
* time close to physical time; i.e. either catch up when
* system clock has been moved backwards, or when coarse
* clock resolution has forced us to advance virtual timer
* too far)
*/
if (actDiff >= kMaxClockAdvance) {
slowDown(origTime, actDiff);
}
}
} else {
/* Clock has advanced normally; just need to make sure counter is
* reset to a low value (need not be 0; good to leave a small
* residual to further decrease collisions)
*/
_clockCounter &= 0xFF;
}
_lastUsedTimestamp = systime;
/* Ok, we have consistent clock (virtual or physical) value that
* we can and should use.
* But do we need to check external syncing now?
*/
if (_syncer != null && systime >= _firstUnsafeTimestamp) {
try {
_firstUnsafeTimestamp = _syncer.update(systime);
} catch (IOException ioe) {
throw new RuntimeException("Failed to synchronize timestamp: " + ioe);
}
}
/* Now, let's translate the timestamp to one UUID needs, 100ns
* unit offset from the beginning of Gregorian calendar...
*/
systime *= kClockMultiplierL;
systime += kClockOffset;
// Plus add the clock counter:
systime += _clockCounter;
// and then increase
++_clockCounter;
return systime;
}
/*
/**********************************************************************
/* Private methods
/**********************************************************************
*/
/* Method for accessing timestamp to use for creating UUIDs.
* Used ONLY by unit tests, hence protected.
*/
protected final void getAndSetTimestamp(byte[] uuidBytes) {
long timestamp = getTimestamp();
uuidBytes[UUIDUtil.BYTE_OFFSET_CLOCK_SEQUENCE] = (byte) _clockSequence;
uuidBytes[UUIDUtil.BYTE_OFFSET_CLOCK_SEQUENCE + 1] = (byte) (_clockSequence >> 8);
// Time fields aren't nicely split across the UUID, so can't just
// linearly dump the stamp:
int clockHi = (int) (timestamp >>> 32);
int clockLo = (int) timestamp;
uuidBytes[UUIDUtil.BYTE_OFFSET_CLOCK_HI] = (byte) (clockHi >>> 24);
uuidBytes[UUIDUtil.BYTE_OFFSET_CLOCK_HI + 1] = (byte) (clockHi >>> 16);
uuidBytes[UUIDUtil.BYTE_OFFSET_CLOCK_MID] = (byte) (clockHi >>> 8);
uuidBytes[UUIDUtil.BYTE_OFFSET_CLOCK_MID + 1] = (byte) clockHi;
uuidBytes[UUIDUtil.BYTE_OFFSET_CLOCK_LO] = (byte) (clockLo >>> 24);
uuidBytes[UUIDUtil.BYTE_OFFSET_CLOCK_LO + 1] = (byte) (clockLo >>> 16);
uuidBytes[UUIDUtil.BYTE_OFFSET_CLOCK_LO + 2] = (byte) (clockLo >>> 8);
uuidBytes[UUIDUtil.BYTE_OFFSET_CLOCK_LO + 3] = (byte) clockLo;
}
/**
* Simple utility method to use to wait for couple of milliseconds,
* to let system clock hopefully advance closer to the virtual
* timestamps used. Delay is kept to just a millisecond or two,
* to prevent excessive blocking; but that should be enough to
* eventually synchronize physical clock with virtual clock values
* used for UUIDs.
*
* @param actDiff Number of milliseconds to wait for from current
* time point, to catch up
*/
protected void slowDown(long startTime, long actDiff) {
/* First, let's determine how long we'd like to wait.
* This is based on how far ahead are we as of now.
*/
long ratio = actDiff / kMaxClockAdvance;
long delay;
if (ratio < 2L) { // 200 msecs or less
delay = 1L;
} else if (ratio < 10L) { // 1 second or less
delay = 2L;
} else if (ratio < 600L) { // 1 minute or less
delay = 3L;
} else {
delay = 5L;
}
_logger.warn("Need to wait for %d milliseconds; virtual clock advanced too far in the future", delay);
long waitUntil = startTime + delay;
int counter = 0;
do {
try {
Thread.sleep(delay);
} catch (InterruptedException ignored) {
}
delay = 1L;
/* This is just a sanity check: don't want an "infinite"
* loop if clock happened to be moved backwards by, say,
* an hour...
*/
if (++counter > MAX_WAIT_COUNT) {
break;
}
} while (System.currentTimeMillis() < waitUntil);
}
}
\ No newline at end of file
package com.fasterxml.uuid;
/**
* Enumeration of different flavors of UUIDs: 5 specified by specs
* (<a href="http://tools.ietf.org/html/rfc4122">RFC-4122</a>)
* and one
* virtual entry ("UNKNOWN") to represent invalid one that consists of
* all zero bites
*/
public enum UUIDType {
TIME_BASED(1),
DCE(2),
NAME_BASED_MD5(3),
RANDOM_BASED(4),
NAME_BASED_SHA1(5),
TIME_BASED_REORDERED(6),
TIME_BASED_EPOCH(7),
FREE_FORM(8),
UNKNOWN(0);
private final int _raw;
UUIDType(int raw) {
_raw = raw;
}
/**
* Returns "raw" type constants, embedded within UUID bytes.
*/
public int raw() {
return _raw;
}
}
/* JUG Java Uuid Generator
*
* Copyright (c) 2002- Tatu Saloranta, tatu.saloranta@iki.fi
*
* Licensed under the License specified in the file LICENSE which is
* included with the source code.
* You may not use this file except in compliance with the License.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fasterxml.uuid.ext;
import com.fasterxml.uuid.TimestampSynchronizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
/**
* Implementation of {@link TimestampSynchronizer}, which uses file system
* as the storage and locking mechanism.
* <p>
* Synchronization is achieved by obtaining an exclusive file locks on two
* specified lock files, and by using the files to store first "safe" timestamp
* value that the generator can use; alternating between one to use to ensure
* one of them always contains a valid timestamp. Latter is needed to guard
* against system clock moving backwards after UUID generator restart.
* <p>
* Note: this class will only work on JDK 1.4 and above, since it requires
* NIO package to do proper file locking (as well as new opening mode for
* {@link RandomAccessFile}).
* <p>
* Also note that it is assumed that the caller has taken care to synchronize
* access to method to be single-threaded. As such, none of the methods
* is explicitly synchronized here.
*/
public final class FileBasedTimestampSynchronizer
extends TimestampSynchronizer {
protected final static String DEFAULT_LOCK_FILE_NAME1 = "uuid1.lck";
// // // Constants:
protected final static String DEFAULT_LOCK_FILE_NAME2 = "uuid2.lck";
/**
* The default update interval is 10 seconds, meaning that the
* synchronizer "reserves" next 10 seconds for generation. This
* also means that the lock files need to be accessed at most
* once every ten second.
*/
final static long DEFAULT_UPDATE_INTERVAL = 10L * 1000L;
private static final Logger logger = LoggerFactory.getLogger(FileBasedTimestampSynchronizer.class);
// // // Configuration:
protected final LockedFile mLocked1, mLocked2;
protected long mInterval = DEFAULT_UPDATE_INTERVAL;
// // // State:
/**
* Flag used to indicate which of timestamp files has the most
* recently succesfully updated timestamp value. True means that
* <code>mFile1</code> is more recent; false that <code>mFile2</code>
* is.
*/
boolean mFirstActive = false;
/**
* Constructor that uses default values for names of files to use
* (files will get created in the current working directory), as
* well as for the update frequency value (10 seconds).
*/
public FileBasedTimestampSynchronizer()
throws IOException {
this(new File(DEFAULT_LOCK_FILE_NAME1), new File(DEFAULT_LOCK_FILE_NAME2));
}
public FileBasedTimestampSynchronizer(File lockFile1, File lockFile2)
throws IOException {
this(lockFile1, lockFile2, DEFAULT_UPDATE_INTERVAL);
}
public FileBasedTimestampSynchronizer(File lockFile1, File lockFile2, long interval)
throws IOException {
mInterval = interval;
mLocked1 = new LockedFile(lockFile1);
boolean ok = false;
try {
mLocked2 = new LockedFile(lockFile2);
ok = true;
} finally {
if (!ok) {
mLocked1.deactivate();
}
}
// But let's leave reading up to initialization
}
/*
//////////////////////////////////////////////////////////////
// Configuration
//////////////////////////////////////////////////////////////
*/
protected static void doDeactivate(LockedFile lf1, LockedFile lf2) {
if (lf1 != null) {
lf1.deactivate();
}
if (lf2 != null) {
lf2.deactivate();
}
}
/*
//////////////////////////////////////////////////////////////
// Implementation of the API
//////////////////////////////////////////////////////////////
*/
public void setUpdateInterval(long interval) {
if (interval < 1L) {
throw new IllegalArgumentException("Illegal value (" + interval + "); has to be a positive integer value");
}
mInterval = interval;
}
/**
* This method is to be called only once by
* {@link com.fasterxml.uuid.UUIDTimer}. It
* should fetch the persisted timestamp value, which indicates
* first timestamp value that is guaranteed NOT to have used by
* a previous incarnation. If it can not determine such value, it
* is to return 0L as a marker.
*
* @return First timestamp value that was NOT locked by lock files;
* 0L to indicate that no information was read.
*/
@Override
protected long initialize() {
long ts1 = mLocked1.readStamp();
long ts2 = mLocked2.readStamp();
long result;
if (ts1 > ts2) {
mFirstActive = true;
result = ts1;
} else {
mFirstActive = false;
result = ts2;
}
/* Hmmh. If we didn't get a time stamp (-> 0), or if written time is
* ahead of current time, let's log something:
*/
if (result <= 0L) {
logger.warn("Could not determine safe timer starting point: assuming current system time is acceptable");
} else {
long now = System.currentTimeMillis();
//long diff = now - result;
/* It's more suspicious if old time was ahead... although with
* longer iteration values, it can be ahead without errors. So
* let's base check on current iteration value:
*/
if ((now + mInterval) < result) {
logger.warn("Safe timestamp read is {} milliseconds in future, and is greater than the inteval ({})", (result - now), mInterval);
}
/* Hmmh. Is there any way a suspiciously old timestamp could be
* harmful? It can obviously be useless but...
*/
}
return result;
}
@Override
public void deactivate() {
doDeactivate(mLocked1, mLocked2);
}
/*
//////////////////////////////////////////////////////////////
// Internal methods
//////////////////////////////////////////////////////////////
*/
/**
* @return Timestamp value that the caller can NOT use. That is, all
* timestamp values prior to (less than) this value can be used
* ok, but this value and ones after can only be used by first
* calling update.
*/
@Override
public long update(long now)
throws IOException {
long nextAllowed = now + mInterval;
/* We have to make sure to (over)write the one that is NOT
* actively used, to ensure that we always have fully persisted
* timestamp value, even if the write process gets interruped
* half-way through.
*/
if (mFirstActive) {
mLocked2.writeStamp(nextAllowed);
} else {
mLocked1.writeStamp(nextAllowed);
}
mFirstActive = !mFirstActive;
return nextAllowed;
}
}
/* JUG Java Uuid Generator
*
* Copyright (c) 2002- Tatu Saloranta, tatu.saloranta@iki.fi
*
* Licensed under the License specified in the file LICENSE which is
* included with the source code.
* You may not use this file except in compliance with the License.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fasterxml.uuid.ext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
/**
* Utility class used by {@link FileBasedTimestampSynchronizer} to do
* actual file access and locking.
* <p>
* Class stores simple timestamp values based on system time accessed
* using <code>System.currentTimeMillis()</code>. A single timestamp
* is stored into a file using {@link RandomAccessFile} in fully
* synchronized mode. Value is written in ISO-Latin (ISO-8859-1)
* encoding (superset of Ascii, 1 byte per char) as 16-digit hexadecimal
* number, surrounded by brackets. As such, file produced should
* always have exact size of 18 bytes. For extra robustness, slight
* variations in number of digits are accepeted, as are white space
* chars before and after bracketed value.
*/
class LockedFile {
/**
* Expected file length comes from hex-timestamp (16 digits),
* preamble "[0x",(3 chars) and trailer "]\r\n" (2 chars, linefeed
* to help debugging -- in some environments, missing trailing linefeed
* causes problems: also, 2-char linefeed to be compatible with all
* standard linefeeds on MacOS, Unix and Windows).
*/
final static int DEFAULT_LENGTH = 22;
final static long READ_ERROR = 0L;
final static String HEX_DIGITS = "0123456789abcdef";
// // // Configuration:
private static final Logger logger = LoggerFactory.getLogger(LockedFile.class);
// // // File state
final File mFile;
RandomAccessFile mRAFile;
FileChannel mChannel;
FileLock mLock;
ByteBuffer mWriteBuffer = null;
/**
* Flag set if the original file (created before this instance was
* created) had size other than default size and needs to be
* truncated
*/
boolean mWeirdSize;
/**
* Marker used to ensure that the timestamps stored are monotonously
* increasing. Shouldn't really be needed, since caller should take
* care of it, but let's be bit paranoid here.
*/
long mLastTimestamp = 0L;
LockedFile(File f)
throws IOException {
mFile = f;
RandomAccessFile raf = null;
FileChannel channel;
FileLock lock = null;
boolean ok = false;
try { // let's just use a single block to share cleanup code
raf = new RandomAccessFile(f, "rwd");
// Then lock them, if possible; if not, let's err out
channel = raf.getChannel();
if (channel == null) {
throw new IOException("Failed to access channel for '" + f + "'");
}
lock = channel.tryLock();
if (lock == null) {
throw new IOException("Failed to lock '" + f + "' (another JVM running UUIDGenerator?)");
}
ok = true;
} finally {
if (!ok) {
doDeactivate(f, raf, lock);
}
}
mRAFile = raf;
mChannel = channel;
mLock = lock;
}
protected static void doDeactivate(File f, RandomAccessFile raf,
FileLock lock) {
if (lock != null) {
try {
lock.release();
} catch (Throwable t) {
logger.error("Failed to release lock (for file '{}')", f, t);
}
}
if (raf != null) {
try {
raf.close();
} catch (Throwable t) {
logger.error("Failed to close file '{}'", f, t);
}
}
}
public void deactivate() {
RandomAccessFile raf = mRAFile;
mRAFile = null;
FileLock lock = mLock;
mLock = null;
doDeactivate(mFile, raf, lock);
}
public long readStamp() {
int size;
try {
size = (int) mChannel.size();
} catch (IOException ioe) {
logger.error("Failed to read file size", ioe);
return READ_ERROR;
}
mWeirdSize = (size != DEFAULT_LENGTH);
// Let's check specifically empty files though
if (size == 0) {
logger.warn("Missing or empty file, can not read timestamp value");
return READ_ERROR;
}
// Let's also allow some slack... but just a bit
if (size > 100) {
size = 100;
}
byte[] data = new byte[size];
try {
mRAFile.readFully(data);
} catch (IOException ie) {
logger.error("(file '{}') Failed to read {} bytes", mFile, size, ie);
return READ_ERROR;
}
/* Ok, got data. Now, we could just directly parse the bytes (since
* it is single-byte encoding)... but for convenience, let's create
* the String (this is only called once per JVM session)
*/
char[] cdata = new char[size];
for (int i = 0; i < size; ++i) {
cdata[i] = (char) (data[i] & 0xFF);
}
String dataStr = new String(cdata);
// And let's trim leading (and trailing, who cares)
dataStr = dataStr.trim();
long result = -1;
String err = null;
if (!dataStr.startsWith("[0")
|| dataStr.length() < 3
|| Character.toLowerCase(dataStr.charAt(2)) != 'x') {
err = "does not start with '[0x' prefix";
} else {
int ix = dataStr.indexOf(']', 3);
if (ix <= 0) {
err = "does not end with ']' marker";
} else {
String hex = dataStr.substring(3, ix);
if (hex.length() > 16) {
err = "length of the (hex) timestamp too long; expected 16, had " + hex.length() + " ('" + hex + "')";
} else {
try {
result = Long.parseLong(hex, 16);
} catch (NumberFormatException nex) {
err = "does not contain a valid hex timestamp; got '"
+ hex + "' (parse error: " + nex + ")";
}
}
}
}
// Unsuccesful?
if (result < 0L) {
logger.error("(file '{}') Malformed timestamp file contents: {}", mFile, err);
return READ_ERROR;
}
mLastTimestamp = result;
return result;
}
/*
//////////////////////////////////////////////////////////////
// Internal methods
//////////////////////////////////////////////////////////////
*/
public void writeStamp(long stamp)
throws IOException {
// Let's do sanity check first:
if (stamp <= mLastTimestamp) {
/* same stamp is not dangerous, but pointless... so warning,
* not an error:
*/
if (stamp == mLastTimestamp) {
logger.warn("(file '{}') Trying to re-write existing timestamp ({})", mFile, stamp);
return;
}
throw new IOException("" + mFile + " trying to overwrite existing value (" + mLastTimestamp + ") with an earlier timestamp (" + stamp + ")");
}
//System.err.println("!!!! Syncing ["+mFile+"] with "+stamp+" !!!");
// Need to initialize the buffer?
if (mWriteBuffer == null) {
mWriteBuffer = ByteBuffer.allocate(DEFAULT_LENGTH);
mWriteBuffer.put(0, (byte) '[');
mWriteBuffer.put(1, (byte) '0');
mWriteBuffer.put(2, (byte) 'x');
mWriteBuffer.put(19, (byte) ']');
mWriteBuffer.put(20, (byte) '\r');
mWriteBuffer.put(21, (byte) '\n');
}
// Converting to hex is simple
for (int i = 18; i >= 3; --i) {
int val = (((int) stamp) & 0x0F);
mWriteBuffer.put(i, (byte) HEX_DIGITS.charAt(val));
stamp = (stamp >> 4);
}
// and off we go:
mWriteBuffer.position(0); // to make sure we always write it all
mChannel.write(mWriteBuffer, 0L);
if (mWeirdSize) {
mRAFile.setLength(DEFAULT_LENGTH);
mWeirdSize = false;
}
// This is probably not needed (as the random access file is supposedly synced)... but let's be safe:
mChannel.force(false);
// And that's it!
}
}
package com.fasterxml.uuid.impl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LoggerFacade {
private final Class<?> _forClass;
private WrappedLogger _logger;
private LoggerFacade(Class<?> forClass) {
_forClass = forClass;
}
public static LoggerFacade getLogger(Class<?> forClass) {
return new LoggerFacade(forClass);
}
public void warn(String msg) {
_warn(msg);
}
public void warn(String msg, Object arg) {
_warn(String.format(msg, arg));
}
public void warn(String msg, Object arg, Object arg2) {
_warn(String.format(msg, arg, arg2));
}
private synchronized void _warn(String message) {
if (_logger == null) {
_logger = WrappedLogger.logger(_forClass);
}
_logger.warn(message);
}
private static class WrappedLogger {
private final Logger _logger;
private WrappedLogger(Logger l) {
_logger = l;
}
public static WrappedLogger logger(Class<?> forClass) {
// Why all these contortions? To support case where Slf4j API missing
// (or, if it ever fails for not having impl) to just print to STDERR
try {
return new WrappedLogger(LoggerFactory.getLogger(forClass));
} catch (Throwable t) {
return new WrappedLogger(null);
}
}
public void warn(String message) {
if (_logger != null) {
_logger.warn(message);
} else {
System.err.println("WARN: " + message);
}
}
}
}
\ No newline at end of file
package com.fasterxml.uuid.impl;
import com.fasterxml.uuid.UUIDType;
import java.util.UUID;
public class UUIDUtil {
public final static int BYTE_OFFSET_CLOCK_LO = 0;
public final static int BYTE_OFFSET_CLOCK_MID = 4;
public final static int BYTE_OFFSET_CLOCK_HI = 6;
// note: clock-hi and type occupy same byte (different bits)
public final static int BYTE_OFFSET_TYPE = 6;
// similarly, clock sequence and variant are multiplexed
public final static int BYTE_OFFSET_CLOCK_SEQUENCE = 8;
public final static int BYTE_OFFSET_VARIATION = 8;
/*
/**********************************************************************
/* Construction (can instantiate, although usually not necessary)
/**********************************************************************
*/
// note: left public just for convenience; all functionality available
// via static methods
public UUIDUtil() {
}
/*
/**********************************************************************
/* Factory methods
/**********************************************************************
*/
/**
* Factory method for creating UUIDs from the canonical string
* representation.
*
* @param id String that contains the canonical representation of
* the UUID to build; 36-char string (see UUID specs for details).
* Hex-chars may be in upper-case too; UUID class will always output
* them in lowercase.
*/
public static UUID uuid(String id) {
if (id == null) {
throw new NullPointerException();
}
if (id.length() != 36) {
throw new NumberFormatException("UUID has to be represented by the standard 36-char representation");
}
long lo, hi;
lo = hi = 0;
for (int i = 0, j = 0; i < 36; ++j) {
// Need to bypass hyphens:
switch (i) {
case 8:
case 13:
case 18:
case 23:
if (id.charAt(i) != '-') {
throw new NumberFormatException("UUID has to be represented by the standard 36-char representation");
}
++i;
}
int curr;
char c = id.charAt(i);
if (c >= '0' && c <= '9') {
curr = (c - '0');
} else if (c >= 'a' && c <= 'f') {
curr = (c - 'a' + 10);
} else if (c >= 'A' && c <= 'F') {
curr = (c - 'A' + 10);
} else {
throw new NumberFormatException("Non-hex character at #" + i + ": '" + c
+ "' (value 0x" + Integer.toHexString(c) + ")");
}
curr = (curr << 4);
c = id.charAt(++i);
if (c >= '0' && c <= '9') {
curr |= (c - '0');
} else if (c >= 'a' && c <= 'f') {
curr |= (c - 'a' + 10);
} else if (c >= 'A' && c <= 'F') {
curr |= (c - 'A' + 10);
} else {
throw new NumberFormatException("Non-hex character at #" + i + ": '" + c
+ "' (value 0x" + Integer.toHexString(c) + ")");
}
if (j < 8) {
hi = (hi << 8) | curr;
} else {
lo = (lo << 8) | curr;
}
++i;
}
return new UUID(hi, lo);
}
/**
* Factory method for constructing {@link java.util.UUID} instance from given
* 16 bytes.
* NOTE: since absolutely no validation is done for contents, this method should
* only be used if contents are known to be valid.
*/
public static UUID uuid(byte[] bytes) {
_checkUUIDByteArray(bytes, 0);
long l1 = gatherLong(bytes, 0);
long l2 = gatherLong(bytes, 8);
return new UUID(l1, l2);
}
/**
* Factory method for constructing {@link java.util.UUID} instance from given
* 16 bytes.
* NOTE: since absolutely no validation is done for contents, this method should
* only be used if contents are known to be valid.
*
* @param bytes Array that contains sequence of 16 bytes that contain a valid UUID
* @param offset Offset of the first of 16 bytes
*/
public static UUID uuid(byte[] bytes, int offset) {
_checkUUIDByteArray(bytes, offset);
return new UUID(gatherLong(bytes, offset), gatherLong(bytes, offset + 8));
}
/**
* Helper method for constructing UUID instances with appropriate type
*/
public static UUID constructUUID(UUIDType type, byte[] uuidBytes) {
// first, ensure type is ok
int b = uuidBytes[BYTE_OFFSET_TYPE] & 0xF; // clear out high nibble
b |= type.raw() << 4;
uuidBytes[BYTE_OFFSET_TYPE] = (byte) b;
// second, ensure variant is properly set too
b = uuidBytes[UUIDUtil.BYTE_OFFSET_VARIATION] & 0x3F; // remove 2 MSB
b |= 0x80; // set as '10'
uuidBytes[BYTE_OFFSET_VARIATION] = (byte) b;
return uuid(uuidBytes);
}
public static UUID constructUUID(UUIDType type, long l1, long l2) {
// first, ensure type is ok
l1 &= ~0xF000L; // remove high nibble of 6th byte
l1 |= (long) type.raw() << 12;
// second, ensure variant is properly set too (8th byte; most-sig byte of second long)
l2 = ((l2 << 2) >>> 2); // remove 2 MSB
l2 |= (2L << 62); // set 2 MSB to '10'
return new UUID(l1, l2);
}
public static long initUUIDFirstLong(long l1, UUIDType type) {
return initUUIDFirstLong(l1, type.raw());
}
public static long initUUIDFirstLong(long l1, int rawType) {
l1 &= ~0xF000L; // remove high nibble of 6th byte
l1 |= (long) rawType << 12;
return l1;
}
public static long initUUIDSecondLong(long l2) {
l2 = ((l2 << 2) >>> 2); // remove 2 MSB
l2 |= (2L << 62); // set 2 MSB to '10'
return l2;
}
/*
/***********************************************************************
/* Type introspection
/***********************************************************************
*/
/**
* Method for determining which type of UUID given UUID is.
* Returns null if type can not be determined.
*
* @param uuid UUID to check
* @return Null if UUID is null or type can not be determined (== invalid UUID);
* otherwise type
*/
public static UUIDType typeOf(UUID uuid) {
if (uuid == null) {
return null;
}
// Ok: so 4 MSB of byte at offset 6...
long l = uuid.getMostSignificantBits();
int typeNibble = (((int) l) >> 12) & 0xF;
switch (typeNibble) {
case 0:
// possibly null?
if (l == 0L && uuid.getLeastSignificantBits() == l) {
return UUIDType.UNKNOWN;
}
break;
case 1:
return UUIDType.TIME_BASED;
case 2:
return UUIDType.DCE;
case 3:
return UUIDType.NAME_BASED_MD5;
case 4:
return UUIDType.RANDOM_BASED;
case 5:
return UUIDType.NAME_BASED_SHA1;
case 6:
return UUIDType.TIME_BASED_REORDERED;
case 7:
return UUIDType.TIME_BASED_EPOCH;
case 8:
return UUIDType.FREE_FORM;
}
// not recognized: return null
return null;
}
/*
/***********************************************************************
/* Conversions to other types
/***********************************************************************
*/
public static byte[] asByteArray(UUID uuid) {
long hi = uuid.getMostSignificantBits();
long lo = uuid.getLeastSignificantBits();
byte[] result = new byte[16];
_appendInt((int) (hi >> 32), result, 0);
_appendInt((int) hi, result, 4);
_appendInt((int) (lo >> 32), result, 8);
_appendInt((int) lo, result, 12);
return result;
}
public static void toByteArray(UUID uuid, byte[] buffer) {
toByteArray(uuid, buffer, 0);
}
public static void toByteArray(UUID uuid, byte[] buffer, int offset) {
_checkUUIDByteArray(buffer, offset);
long hi = uuid.getMostSignificantBits();
long lo = uuid.getLeastSignificantBits();
_appendInt((int) (hi >> 32), buffer, offset);
_appendInt((int) hi, buffer, offset + 4);
_appendInt((int) (lo >> 32), buffer, offset + 8);
_appendInt((int) lo, buffer, offset + 12);
}
/*
/********************************************************************************
/* Package helper methods
/********************************************************************************
*/
//private final static long MASK_LOW_INT = 0x0FFFFFFFF;
protected static long gatherLong(byte[] buffer, int offset) {
long hi = ((long) _gatherInt(buffer, offset)) << 32;
//long lo = ((long) _gatherInt(buffer, offset+4)) & MASK_LOW_INT;
long lo = (((long) _gatherInt(buffer, offset + 4)) << 32) >>> 32;
return hi | lo;
}
/*
/********************************************************************************
/* Internal helper methods
/********************************************************************************
*/
private static void _appendInt(int value, byte[] buffer, int offset) {
buffer[offset++] = (byte) (value >> 24);
buffer[offset++] = (byte) (value >> 16);
buffer[offset++] = (byte) (value >> 8);
buffer[offset] = (byte) value;
}
private static int _gatherInt(byte[] buffer, int offset) {
return (buffer[offset] << 24) | ((buffer[offset + 1] & 0xFF) << 16)
| ((buffer[offset + 2] & 0xFF) << 8) | (buffer[offset + 3] & 0xFF);
}
private static void _checkUUIDByteArray(byte[] bytes, int offset) {
if (bytes == null) {
throw new IllegalArgumentException("Invalid byte[] passed: can not be null");
}
if (offset < 0) {
throw new IllegalArgumentException("Invalid offset (" + offset + ") passed: can not be negative");
}
if ((offset + 16) > bytes.length) {
throw new IllegalArgumentException("Invalid offset (" + offset + ") passed: not enough room in byte array (need 16 bytes)");
}
}
}
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment