Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ UUID uuid = Generators.nameBasedgenerator().generate("string to hash"); // Versi
// With JUG 4.1+: support for https://github.com/uuid6/uuid6-ietf-draft versions 6 and 7:
UUID uuid = Generators.timeBasedReorderedGenerator().generate(); // Version 6
UUID uuid = Generators.timeBasedEpochGenerator().generate(); // Version 7
UUID uuid = Generators.timeBasedEpochRandomGenerator().generate(); // Version 7 with random values
```

If you want customize generators, you may also just want to hold on to generator instance:
Expand Down
37 changes: 35 additions & 2 deletions src/main/java/com/fasterxml/uuid/Generators.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.fasterxml.uuid.impl.NameBasedGenerator;
import com.fasterxml.uuid.impl.RandomBasedGenerator;
import com.fasterxml.uuid.impl.TimeBasedEpochGenerator;
import com.fasterxml.uuid.impl.TimeBasedEpochRandomGenerator;
import com.fasterxml.uuid.impl.TimeBasedReorderedGenerator;
import com.fasterxml.uuid.impl.TimeBasedGenerator;

Expand Down Expand Up @@ -135,6 +136,8 @@ public static TimeBasedEpochGenerator timeBasedEpochGenerator()
* Factory method for constructing UUID generator that generates UUID using
* version 7 (Unix Epoch time+random based), using specified {@link Random}
* number generator.
* Calls within same millisecond produce very similar values what may be
* unsafe in some environments.
* No additional external synchronization is used.
*/
public static TimeBasedEpochGenerator timeBasedEpochGenerator(Random random)
Expand All @@ -145,9 +148,10 @@ public static TimeBasedEpochGenerator timeBasedEpochGenerator(Random random)
/**
* Factory method for constructing UUID generator that generates UUID using
* version 7 (Unix Epoch time+random based), using specified {@link Random}
* number generato.
* number generator.
* Timestamp to use is accessed using specified {@link UUIDClock}
*
* Calls within same millisecond produce very similar values what may be
* unsafe in some environments.
* No additional external synchronization is used.
*
* @since 4.3
Expand All @@ -158,6 +162,35 @@ public static TimeBasedEpochGenerator timeBasedEpochGenerator(Random random,
return new TimeBasedEpochGenerator(random, clock);
}

/**
* Factory method for constructing UUID generator that generates UUID using
* version 7 (Unix Epoch time+random based), using specified {@link Random}
* number generator.
* Calls within same millisecond produce as random as possible values.
* No additional external synchronization is used.
*/
public static TimeBasedEpochRandomGenerator timeBasedEpochRandomGenerator(Random random)
{
return new TimeBasedEpochRandomGenerator(random);
}

/**
* Factory method for constructing UUID generator that generates UUID using
* version 7 (Unix Epoch time+random based), using specified {@link Random}
* number generato.
* Timestamp to use is accessed using specified {@link UUIDClock}
* Calls within same millisecond produce as random as possible values.
*
* No additional external synchronization is used.
*
* @since 4.3
*/
public static TimeBasedEpochRandomGenerator timeBasedEpochRandomGenerator(Random random,
UUIDClock clock)
{
return new TimeBasedEpochRandomGenerator(random, clock);
}

// // Time+location-based generation

/**
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/com/fasterxml/uuid/Jug.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public class Jug
TYPES.put("name-based", "n");
TYPES.put("reordered-time-based", "o"); // Version 6
TYPES.put("epoch-time-based", "e"); // Version 7
TYPES.put("random-epoch-time-based", "m"); // Version 7 but more random
}

protected final static HashMap<String,String> OPTIONS = new HashMap<String,String>();
Expand Down Expand Up @@ -266,6 +267,16 @@ public static void main(String[] args)
noArgGenerator = Generators.timeBasedEpochGenerator(r);
}
break;
case 'm': // random-epoch-time-based
usesRnd = true;
{
SecureRandom r = new SecureRandom();
if (verbose) {
System.out.print("(using secure random generator, info = '"+r.getProvider().getInfo()+"')");
}
noArgGenerator = Generators.timeBasedEpochRandomGenerator(r);
}
break;
case 'n': // name-based
if (nameSpace == null) {
System.err.println("--name-space (-s) - argument missing when using method that requires it, exiting.");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package com.fasterxml.uuid.impl;

import com.fasterxml.uuid.NoArgGenerator;
import com.fasterxml.uuid.UUIDClock;
import com.fasterxml.uuid.UUIDType;

import java.security.SecureRandom;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
* Implementation of UUID generator that uses time/location based generation
* method field from the Unix Epoch timestamp source - the number of
* milliseconds seconds since midnight 1 Jan 1970 UTC, leap seconds excluded.
* This is usually referred to as "Version 7".
* In addition to that random part is regenerated for every new UUID.
* This removes possibilities to have almost similar UUID, when calls
* to generate are made within same millisecond.
* <p>
* As all JUG provided implementations, this generator is fully thread-safe.
* Additionally it can also be made externally synchronized with other instances
* (even ones running on other JVMs); to do this, use
* {@link com.fasterxml.uuid.ext.FileBasedTimestampSynchronizer} (or
* equivalent).
*
* @since 4.1
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5.0

*/
public class TimeBasedEpochRandomGenerator extends NoArgGenerator
{
private static final int ENTROPY_BYTE_LENGTH = 10;

/*
/**********************************************************************
/* Configuration
/**********************************************************************
*/

/**
* Random number generator that this generator uses.
*/
protected final Random _random;

/**
* Underlying {@link UUIDClock} used for accessing current time, to use for
* generation.
*
* @since 4.3
*/
protected final UUIDClock _clock;

private final byte[] _lastEntropy = new byte[ENTROPY_BYTE_LENGTH];
private final Lock lock = new ReentrantLock();

/*
/**********************************************************************
/* Construction
/**********************************************************************
*/

/**
* @param rnd Random number generator to use for generating UUIDs; if null,
* shared default generator is used. Note that it is strongly recommend to
* use a <b>good</b> (pseudo) random number generator; for example, JDK's
* {@link SecureRandom}.
*/
public TimeBasedEpochRandomGenerator(Random rnd) {
this(rnd, UUIDClock.systemTimeClock());
}

/**
* @param rnd Random number generator to use for generating UUIDs; if null,
* shared default generator is used. Note that it is strongly recommend to
* use a <b>good</b> (pseudo) random number generator; for example, JDK's
* {@link SecureRandom}.
* @param clock clock Object used for accessing current time to use for generation
*/
public TimeBasedEpochRandomGenerator(Random rnd, UUIDClock clock)
{
if (rnd == null) {
rnd = LazyRandom.sharedSecureRandom();
}
_random = rnd;
_clock = clock;
}

/*
/**********************************************************************
/* Access to config
/**********************************************************************
*/

@Override
public UUIDType getType() { return UUIDType.TIME_BASED_EPOCH; }

/*
/**********************************************************************
/* UUID generation
/**********************************************************************
*/

@Override
public UUID generate()
{
return construct(_clock.currentTimeMillis());
}

/**
* Method that will construct actual {@link UUID} instance for given
* unix epoch timestamp: called by {@link #generate()} but may alternatively be
* called directly to construct an instance with known timestamp.
* NOTE: calling this method directly produces somewhat distinct UUIDs as
* "entropy" value is still generated as necessary to avoid producing same
* {@link UUID} even if same timestamp is being passed.
*
* @param rawTimestamp unix epoch millis
*
* @return unix epoch time based UUID
*
* @since 4.3
*/
public UUID construct(long rawTimestamp)
{
lock.lock();
try {
_random.nextBytes(_lastEntropy);
return UUIDUtil.constructUUID(UUIDType.TIME_BASED_EPOCH, (rawTimestamp << 16) | _toShort(_lastEntropy, 0), _toLong(_lastEntropy, 2));
} finally {
lock.unlock();
}
}

/*
/**********************************************************************
/* Internal methods
/**********************************************************************
*/

protected final static long _toLong(byte[] buffer, int offset)
{
long l1 = _toInt(buffer, offset);
long l2 = _toInt(buffer, offset+4);
long l = (l1 << 32) + ((l2 << 32) >>> 32);
return l;
}

private final static long _toInt(byte[] buffer, int offset)
{
return (buffer[offset] << 24)
+ ((buffer[++offset] & 0xFF) << 16)
+ ((buffer[++offset] & 0xFF) << 8)
+ (buffer[++offset] & 0xFF);
}

private final static long _toShort(byte[] buffer, int offset)
{
return ((buffer[offset] & 0xFF) << 8)
+ (buffer[++offset] & 0xFF);
}
}
1 change: 1 addition & 0 deletions src/test/java/com/fasterxml/uuid/UUIDComparatorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import com.fasterxml.uuid.impl.TimeBasedEpochGenerator;

import com.fasterxml.uuid.impl.TimeBasedEpochRandomGenerator;
import junit.framework.TestCase;

public class UUIDComparatorTest
Expand Down
Loading