|
| 1 | +package com.fasterxml.uuid.impl; |
| 2 | + |
| 3 | +import com.fasterxml.uuid.NoArgGenerator; |
| 4 | +import com.fasterxml.uuid.UUIDClock; |
| 5 | +import com.fasterxml.uuid.UUIDType; |
| 6 | + |
| 7 | +import java.security.SecureRandom; |
| 8 | +import java.util.Random; |
| 9 | +import java.util.UUID; |
| 10 | +import java.util.concurrent.locks.Lock; |
| 11 | +import java.util.concurrent.locks.ReentrantLock; |
| 12 | + |
| 13 | +/** |
| 14 | + * Implementation of UUID generator that uses time/location based generation |
| 15 | + * method field from the Unix Epoch timestamp source - the number of |
| 16 | + * milliseconds seconds since midnight 1 Jan 1970 UTC, leap seconds excluded. |
| 17 | + * This is usually referred to as "Version 7". |
| 18 | + * In addition to that random part is regenerated for every new UUID. |
| 19 | + * This removes possibilities to have almost similar UUID, when calls |
| 20 | + * to generate are made within same millisecond. |
| 21 | + * <p> |
| 22 | + * As all JUG provided implementations, this generator is fully thread-safe. |
| 23 | + * Additionally it can also be made externally synchronized with other instances |
| 24 | + * (even ones running on other JVMs); to do this, use |
| 25 | + * {@link com.fasterxml.uuid.ext.FileBasedTimestampSynchronizer} (or |
| 26 | + * equivalent). |
| 27 | + * |
| 28 | + * @since 5.0 |
| 29 | + */ |
| 30 | +public class TimeBasedEpochRandomGenerator extends NoArgGenerator |
| 31 | +{ |
| 32 | + private static final int ENTROPY_BYTE_LENGTH = 10; |
| 33 | + |
| 34 | + /* |
| 35 | + /********************************************************************** |
| 36 | + /* Configuration |
| 37 | + /********************************************************************** |
| 38 | + */ |
| 39 | + |
| 40 | + /** |
| 41 | + * Random number generator that this generator uses. |
| 42 | + */ |
| 43 | + protected final Random _random; |
| 44 | + |
| 45 | + /** |
| 46 | + * Underlying {@link UUIDClock} used for accessing current time, to use for |
| 47 | + * generation. |
| 48 | + */ |
| 49 | + protected final UUIDClock _clock; |
| 50 | + |
| 51 | + private final byte[] _lastEntropy = new byte[ENTROPY_BYTE_LENGTH]; |
| 52 | + private final Lock lock = new ReentrantLock(); |
| 53 | + |
| 54 | + /* |
| 55 | + /********************************************************************** |
| 56 | + /* Construction |
| 57 | + /********************************************************************** |
| 58 | + */ |
| 59 | + |
| 60 | + /** |
| 61 | + * @param rnd Random number generator to use for generating UUIDs; if null, |
| 62 | + * shared default generator is used. Note that it is strongly recommend to |
| 63 | + * use a <b>good</b> (pseudo) random number generator; for example, JDK's |
| 64 | + * {@link SecureRandom}. |
| 65 | + */ |
| 66 | + public TimeBasedEpochRandomGenerator(Random rnd) { |
| 67 | + this(rnd, UUIDClock.systemTimeClock()); |
| 68 | + } |
| 69 | + |
| 70 | + /** |
| 71 | + * @param rnd Random number generator to use for generating UUIDs; if null, |
| 72 | + * shared default generator is used. Note that it is strongly recommend to |
| 73 | + * use a <b>good</b> (pseudo) random number generator; for example, JDK's |
| 74 | + * {@link SecureRandom}. |
| 75 | + * @param clock clock Object used for accessing current time to use for generation |
| 76 | + */ |
| 77 | + public TimeBasedEpochRandomGenerator(Random rnd, UUIDClock clock) |
| 78 | + { |
| 79 | + if (rnd == null) { |
| 80 | + rnd = LazyRandom.sharedSecureRandom(); |
| 81 | + } |
| 82 | + _random = rnd; |
| 83 | + _clock = clock; |
| 84 | + } |
| 85 | + |
| 86 | + /* |
| 87 | + /********************************************************************** |
| 88 | + /* Access to config |
| 89 | + /********************************************************************** |
| 90 | + */ |
| 91 | + |
| 92 | + @Override |
| 93 | + public UUIDType getType() { return UUIDType.TIME_BASED_EPOCH; } |
| 94 | + |
| 95 | + /* |
| 96 | + /********************************************************************** |
| 97 | + /* UUID generation |
| 98 | + /********************************************************************** |
| 99 | + */ |
| 100 | + |
| 101 | + @Override |
| 102 | + public UUID generate() |
| 103 | + { |
| 104 | + return construct(_clock.currentTimeMillis()); |
| 105 | + } |
| 106 | + |
| 107 | + /** |
| 108 | + * Method that will construct actual {@link UUID} instance for given |
| 109 | + * unix epoch timestamp: called by {@link #generate()} but may alternatively be |
| 110 | + * called directly to construct an instance with known timestamp. |
| 111 | + * NOTE: calling this method directly produces somewhat distinct UUIDs as |
| 112 | + * "entropy" value is still generated as necessary to avoid producing same |
| 113 | + * {@link UUID} even if same timestamp is being passed. |
| 114 | + * |
| 115 | + * @param rawTimestamp unix epoch millis |
| 116 | + * |
| 117 | + * @return unix epoch time based UUID |
| 118 | + */ |
| 119 | + public UUID construct(long rawTimestamp) |
| 120 | + { |
| 121 | + lock.lock(); |
| 122 | + try { |
| 123 | + _random.nextBytes(_lastEntropy); |
| 124 | + return UUIDUtil.constructUUID(UUIDType.TIME_BASED_EPOCH, (rawTimestamp << 16) | _toShort(_lastEntropy, 0), _toLong(_lastEntropy, 2)); |
| 125 | + } finally { |
| 126 | + lock.unlock(); |
| 127 | + } |
| 128 | + } |
| 129 | +} |
0 commit comments