[chore] regular maintenance

This commit is contained in:
Fabio Lima 2023-07-23 22:32:11 -03:00
parent 7e7e3c496c
commit dfff0557c9
2 changed files with 135 additions and 78 deletions

View File

@ -59,7 +59,8 @@ public final class UlidCreator {
* <p> * <p>
* The random component is reset for each new ULID generated. * The random component is reset for each new ULID generated.
* *
* @param time a number of milliseconds since 1970-01-01 (Unix epoch). * @param time the current time in milliseconds, measured from the UNIX epoch of
* 1970-01-01T00:00Z (UTC)
* @return a ULID * @return a ULID
*/ */
public static Ulid getUlid(final long time) { public static Ulid getUlid(final long time) {
@ -84,7 +85,8 @@ public final class UlidCreator {
* The random component is incremented for each new ULID generated in the same * The random component is incremented for each new ULID generated in the same
* millisecond. * millisecond.
* *
* @param time a number of milliseconds since 1970-01-01 (Unix epoch). * @param time the current time in milliseconds, measured from the UNIX epoch of
* 1970-01-01T00:00Z (UTC)
* @return a ULID * @return a ULID
*/ */
public static Ulid getMonotonicUlid(final long time) { public static Ulid getMonotonicUlid(final long time) {
@ -107,7 +109,8 @@ public final class UlidCreator {
* Ulid ulid = UlidCreator.getHashUlid(time, name); * Ulid ulid = UlidCreator.getHashUlid(time, name);
* }</pre> * }</pre>
* *
* @param time a number of milliseconds since 1970-01-01 (Unix epoch). * @param time the time in milliseconds, measured from the UNIX epoch of
* 1970-01-01T00:00Z (UTC)
* @param string a string to be hashed using SHA-256 algorithm. * @param string a string to be hashed using SHA-256 algorithm.
* @return a ULID * @return a ULID
* @since 5.2.0 * @since 5.2.0
@ -133,7 +136,8 @@ public final class UlidCreator {
* Ulid ulid = UlidCreator.getHashUlid(time, bytes); * Ulid ulid = UlidCreator.getHashUlid(time, bytes);
* }</pre> * }</pre>
* *
* @param time a number of milliseconds since 1970-01-01 (Unix epoch). * @param time the time in milliseconds, measured from the UNIX epoch of
* 1970-01-01T00:00Z (UTC)
* @param bytes a byte array to be hashed using SHA-256 algorithm. * @param bytes a byte array to be hashed using SHA-256 algorithm.
* @return a ULID * @return a ULID
* @since 5.2.0 * @since 5.2.0

View File

@ -26,6 +26,7 @@ package com.github.f4b6a3.ulid;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.time.Clock; import java.time.Clock;
import java.util.Objects;
import java.util.Random; import java.util.Random;
import java.util.function.IntFunction; import java.util.function.IntFunction;
import java.util.function.LongFunction; import java.util.function.LongFunction;
@ -42,14 +43,14 @@ import java.util.function.LongSupplier;
* Instances of this class can behave in one of two ways: monotonic or * Instances of this class can behave in one of two ways: monotonic or
* non-monotonic (default). * non-monotonic (default).
* <p> * <p>
* If the factory is monotonic, the random component is incremented by 1 If more * If the factory is monotonic, the random component is incremented by 1 if more
* than one ULID is generated within the same millisecond. * than one ULID is generated within the same millisecond.
* <p> * <p>
* The maximum ULIDs that can be generated per millisecond is 2^80. * The maximum ULIDs that can be generated per millisecond is 2^80.
*/ */
public final class UlidFactory { public final class UlidFactory {
private final LongSupplier timeMillisNow; // for tests private final LongSupplier timeFunction;
private final LongFunction<Ulid> ulidFunction; private final LongFunction<Ulid> ulidFunction;
// ****************************** // ******************************
@ -60,31 +61,36 @@ public final class UlidFactory {
* Default constructor. * Default constructor.
*/ */
public UlidFactory() { public UlidFactory() {
this(new UlidFunction(IRandom.newInstance())); this(new UlidFunction());
} }
private UlidFactory(LongFunction<Ulid> ulidFunction) { private UlidFactory(LongFunction<Ulid> ulidFunction) {
this(ulidFunction, (LongSupplier) null); this(ulidFunction, System::currentTimeMillis);
} }
private UlidFactory(LongFunction<Ulid> ulidFunction, Clock clock) { private UlidFactory(LongFunction<Ulid> ulidFunction, LongSupplier timeFunction) {
this(ulidFunction, clock != null ? clock::millis : null);
} Objects.requireNonNull(ulidFunction, "ULID function must not be null");
Objects.requireNonNull(timeFunction, "Time function must not be null");
private UlidFactory(LongFunction<Ulid> ulidFunction, LongSupplier timeMillisNow) {
this.ulidFunction = ulidFunction; this.ulidFunction = ulidFunction;
this.timeMillisNow = timeMillisNow != null ? timeMillisNow : Clock.systemUTC()::millis; this.timeFunction = timeFunction;
if (this.ulidFunction instanceof MonotonicFunction) {
// initialize the internal state of the monotonic function
((MonotonicFunction) this.ulidFunction).initialize(this.timeFunction);
}
} }
/** /**
* Returns a new factory. * Returns a new factory.
* <p> * <p>
* It is equivalent to {@code new UlidFactory()}. * It is equivalent to the default constructor {@code new UlidFactory()}.
* *
* @return {@link UlidFactory} * @return {@link UlidFactory}
*/ */
public static UlidFactory newInstance() { public static UlidFactory newInstance() {
return new UlidFactory(new UlidFunction(IRandom.newInstance())); return new UlidFactory(new UlidFunction());
} }
/** /**
@ -94,7 +100,7 @@ public final class UlidFactory {
* @return {@link UlidFactory} * @return {@link UlidFactory}
*/ */
public static UlidFactory newInstance(Random random) { public static UlidFactory newInstance(Random random) {
return new UlidFactory(new UlidFunction(IRandom.newInstance(random))); return new UlidFactory(new UlidFunction(random));
} }
/** /**
@ -106,7 +112,7 @@ public final class UlidFactory {
* @return {@link UlidFactory} * @return {@link UlidFactory}
*/ */
public static UlidFactory newInstance(LongSupplier randomFunction) { public static UlidFactory newInstance(LongSupplier randomFunction) {
return new UlidFactory(new UlidFunction(IRandom.newInstance(randomFunction))); return new UlidFactory(new UlidFunction(randomFunction));
} }
/** /**
@ -118,7 +124,7 @@ public final class UlidFactory {
* @return {@link UlidFactory} * @return {@link UlidFactory}
*/ */
public static UlidFactory newInstance(IntFunction<byte[]> randomFunction) { public static UlidFactory newInstance(IntFunction<byte[]> randomFunction) {
return new UlidFactory(new UlidFunction(IRandom.newInstance(randomFunction))); return new UlidFactory(new UlidFunction(randomFunction));
} }
/** /**
@ -127,7 +133,7 @@ public final class UlidFactory {
* @return {@link UlidFactory} * @return {@link UlidFactory}
*/ */
public static UlidFactory newMonotonicInstance() { public static UlidFactory newMonotonicInstance() {
return new UlidFactory(new MonotonicFunction(IRandom.newInstance())); return new UlidFactory(new MonotonicFunction());
} }
/** /**
@ -137,19 +143,7 @@ public final class UlidFactory {
* @return {@link UlidFactory} * @return {@link UlidFactory}
*/ */
public static UlidFactory newMonotonicInstance(Random random) { public static UlidFactory newMonotonicInstance(Random random) {
return new UlidFactory(new MonotonicFunction(IRandom.newInstance(random))); return new UlidFactory(new MonotonicFunction(random));
}
/**
* Returns a new monotonic factory.
*
* @param random a {@link Random} generator
* @param timeMillisNow a function that returns the current time as milliseconds
* from epoch
* @return {@link UlidFactory}
*/
public static UlidFactory newMonotonicInstance(Random random, LongSupplier timeMillisNow) {
return new UlidFactory(new MonotonicFunction(IRandom.newInstance(random), timeMillisNow), timeMillisNow);
} }
/** /**
@ -161,7 +155,7 @@ public final class UlidFactory {
* @return {@link UlidFactory} * @return {@link UlidFactory}
*/ */
public static UlidFactory newMonotonicInstance(LongSupplier randomFunction) { public static UlidFactory newMonotonicInstance(LongSupplier randomFunction) {
return new UlidFactory(new MonotonicFunction(IRandom.newInstance(randomFunction))); return new UlidFactory(new MonotonicFunction(randomFunction));
} }
/** /**
@ -173,22 +167,21 @@ public final class UlidFactory {
* @return {@link UlidFactory} * @return {@link UlidFactory}
*/ */
public static UlidFactory newMonotonicInstance(IntFunction<byte[]> randomFunction) { public static UlidFactory newMonotonicInstance(IntFunction<byte[]> randomFunction) {
return new UlidFactory(new MonotonicFunction(IRandom.newInstance(randomFunction))); return new UlidFactory(new MonotonicFunction(randomFunction));
} }
/** /**
* Returns a new monotonic factory. * Returns a new monotonic factory.
* <p>
* The given random function must return a long value.
* *
* @param randomFunction a random function that returns a long value * @param random a {@link Random} generator
* @param timeMillisNow a function that returns the current time as * @param clock a clock instance that provides the current time in
* milliseconds from epoch * milliseconds, measured from the UNIX epoch of 1970-01-01T00:00Z
* (UTC)
* @return {@link UlidFactory} * @return {@link UlidFactory}
*/ */
public static UlidFactory newMonotonicInstance(LongSupplier randomFunction, LongSupplier timeMillisNow) { static UlidFactory newMonotonicInstance(Random random, Clock clock) {
return new UlidFactory(new MonotonicFunction(IRandom.newInstance(randomFunction), timeMillisNow), Objects.requireNonNull(clock, "Clock instant must not be null");
timeMillisNow); return new UlidFactory(new MonotonicFunction(random), clock::millis);
} }
/** /**
@ -197,11 +190,14 @@ public final class UlidFactory {
* The given random function must return a long value. * The given random function must return a long value.
* *
* @param randomFunction a random function that returns a long value * @param randomFunction a random function that returns a long value
* @param clock a custom clock instance for tests * @param clock a clock instance that provides the current time in
* milliseconds, measured from the UNIX epoch of
* 1970-01-01T00:00Z (UTC)
* @return {@link UlidFactory} * @return {@link UlidFactory}
*/ */
static UlidFactory newMonotonicInstance(LongSupplier randomFunction, Clock clock) { static UlidFactory newMonotonicInstance(LongSupplier randomFunction, Clock clock) {
return UlidFactory.newMonotonicInstance(randomFunction, clock::millis); Objects.requireNonNull(clock, "Clock instant must not be null");
return new UlidFactory(new MonotonicFunction(randomFunction), clock::millis);
} }
/** /**
@ -210,26 +206,56 @@ public final class UlidFactory {
* The given random function must return a byte array. * The given random function must return a byte array.
* *
* @param randomFunction a random function that returns a byte array * @param randomFunction a random function that returns a byte array
* @param timeMillisNow a function that returns the current time as * @param clock a clock instance that provides the current time in
* milliseconds from epoch * milliseconds, measured from the UNIX epoch of
* @return {@link UlidFactory} * 1970-01-01T00:00Z (UTC)
*/
public static UlidFactory newMonotonicInstance(IntFunction<byte[]> randomFunction, LongSupplier timeMillisNow) {
return new UlidFactory(new MonotonicFunction(IRandom.newInstance(randomFunction), timeMillisNow),
timeMillisNow);
}
/**
* Returns a new monotonic factory.
* <p>
* The given random function must return a byte array.
*
* @param randomFunction a random function that returns a byte array
* @param clock a custom clock instance for tests
* @return {@link UlidFactory} * @return {@link UlidFactory}
*/ */
static UlidFactory newMonotonicInstance(IntFunction<byte[]> randomFunction, Clock clock) { static UlidFactory newMonotonicInstance(IntFunction<byte[]> randomFunction, Clock clock) {
return UlidFactory.newMonotonicInstance(randomFunction, clock::millis); Objects.requireNonNull(clock, "Clock instant must not be null");
return new UlidFactory(new MonotonicFunction(randomFunction), clock::millis);
}
/**
* Returns a new monotonic factory.
*
* @param random a {@link Random} generator
* @param timeFunction a function that returns the current time in milliseconds,
* measured from the UNIX epoch of 1970-01-01T00:00Z (UTC)
* @return {@link UlidFactory}
*/
public static UlidFactory newMonotonicInstance(Random random, LongSupplier timeFunction) {
return new UlidFactory(new MonotonicFunction(random), timeFunction);
}
/**
* Returns a new monotonic factory.
* <p>
* The given random function must return a long value.
*
* @param randomFunction a random function that returns a long value
* @param timeFunction a function that returns the current time in
* milliseconds, measured from the UNIX epoch of
* 1970-01-01T00:00Z (UTC)
* @return {@link UlidFactory}
*/
public static UlidFactory newMonotonicInstance(LongSupplier randomFunction, LongSupplier timeFunction) {
return new UlidFactory(new MonotonicFunction(randomFunction), timeFunction);
}
/**
* Returns a new monotonic factory.
* <p>
* The given random function must return a byte array.
*
* @param randomFunction a random function that returns a byte array
* @param timeFunction a function that returns the current time in
* milliseconds, measured from the UNIX epoch of
* 1970-01-01T00:00Z (UTC)
* @return {@link UlidFactory}
*/
public static UlidFactory newMonotonicInstance(IntFunction<byte[]> randomFunction, LongSupplier timeFunction) {
return new UlidFactory(new MonotonicFunction(randomFunction), timeFunction);
} }
// ****************************** // ******************************
@ -237,18 +263,19 @@ public final class UlidFactory {
// ****************************** // ******************************
/** /**
* Returns a UUID. * Returns a new ULID.
* *
* @return a ULID * @return a ULID
*/ */
public synchronized Ulid create() { public synchronized Ulid create() {
return this.ulidFunction.apply(timeMillisNow.getAsLong()); return this.ulidFunction.apply(timeFunction.getAsLong());
} }
/** /**
* Returns a UUID with a specific time. * Returns a new ULID.
* *
* @param time a number of milliseconds since 1970-01-01 (Unix epoch). * @param time the current time in milliseconds, measured from the UNIX epoch of
* 1970-01-01T00:00Z (UTC)
* @return a ULID * @return a ULID
*/ */
public synchronized Ulid create(final long time) { public synchronized Ulid create(final long time) {
@ -266,10 +293,26 @@ public final class UlidFactory {
private final IRandom random; private final IRandom random;
public UlidFunction(IRandom random) { private UlidFunction(IRandom random) {
this.random = random; this.random = random;
} }
public UlidFunction() {
this(IRandom.newInstance());
}
public UlidFunction(Random random) {
this(IRandom.newInstance(random));
}
public UlidFunction(LongSupplier randomFunction) {
this(IRandom.newInstance(randomFunction));
}
public UlidFunction(IntFunction<byte[]> randomFunction) {
this(IRandom.newInstance(randomFunction));
}
@Override @Override
public Ulid apply(final long time) { public Ulid apply(final long time) {
if (this.random instanceof ByteRandom) { if (this.random instanceof ByteRandom) {
@ -294,20 +337,30 @@ public final class UlidFactory {
// Used to preserve monotonicity when the system clock is // Used to preserve monotonicity when the system clock is
// adjusted by NTP after a small clock drift or when the // adjusted by NTP after a small clock drift or when the
// system clock jumps back by 1 second due to leap second. // system clock jumps back by 1 second due to leap second.
protected static final int CLOCK_DRIFT_TOLERANCE = 10_000; static final int CLOCK_DRIFT_TOLERANCE = 10_000;
public MonotonicFunction(IRandom random) { private MonotonicFunction(IRandom random) {
this(random, Clock.systemUTC());
}
public MonotonicFunction(IRandom random, Clock clock) {
this(random, clock::millis);
}
public MonotonicFunction(IRandom random, LongSupplier timeMillisNow) {
this.random = random; this.random = random;
// initialize internal state }
this.lastUlid = new Ulid(timeMillisNow.getAsLong(), this.random.nextBytes(Ulid.RANDOM_BYTES));
public MonotonicFunction() {
this(IRandom.newInstance());
}
public MonotonicFunction(Random random) {
this(IRandom.newInstance(random));
}
public MonotonicFunction(LongSupplier randomFunction) {
this(IRandom.newInstance(randomFunction));
}
public MonotonicFunction(IntFunction<byte[]> randomFunction) {
this(IRandom.newInstance(randomFunction));
}
void initialize(LongSupplier timeFunction) {
this.lastUlid = new Ulid(timeFunction.getAsLong(), this.random.nextBytes(Ulid.RANDOM_BYTES));
} }
@Override @Override