Add constructors in UlidFactory for random generators #12

New constructors:

- public UlidFactory(Random random) { }
- public UlidFactory(RandomGenerator randomGenerator) { }
This commit is contained in:
Fabio Lima 2021-07-18 01:21:41 -03:00
parent 0e1fe3f162
commit 0f431d01b1
13 changed files with 121 additions and 117 deletions

View File

@ -4,12 +4,18 @@ All notable changes to this project will be documented in this file.
## [Unreleased] ## [Unreleased]
### Fixed ## [3.2.0] - 2021-07-17
- Fixed typos in `CHANGELOG.md` Simplified the use of `UlidFactory` with other random generators.
### Added
- Added constructors in `UlidFactory` for random generators.
## [3.1.1] - 2021-07-17 ## [3.1.1] - 2021-07-17
Creates a module name be used in Java 9+.
### Added ### Added
- Added module name for Java 9+ - Added module name for Java 9+
@ -233,7 +239,8 @@ Project created as an alternative Java implementation of [ULID spec](https://git
- Added `LICENSE` - Added `LICENSE`
- Added test cases - Added test cases
[unreleased]: https://github.com/f4b6a3/ulid-creator/compare/ulid-creator-3.1.1...HEAD [unreleased]: https://github.com/f4b6a3/ulid-creator/compare/ulid-creator-3.2.0...HEAD
[3.1.0]: https://github.com/f4b6a3/ulid-creator/compare/ulid-creator-3.1.1...ulid-creator-3.2.0
[3.1.0]: https://github.com/f4b6a3/ulid-creator/compare/ulid-creator-3.1.0...ulid-creator-3.1.1 [3.1.0]: https://github.com/f4b6a3/ulid-creator/compare/ulid-creator-3.1.0...ulid-creator-3.1.1
[3.1.0]: https://github.com/f4b6a3/ulid-creator/compare/ulid-creator-3.0.1...ulid-creator-3.1.0 [3.1.0]: https://github.com/f4b6a3/ulid-creator/compare/ulid-creator-3.0.1...ulid-creator-3.1.0
[3.0.1]: https://github.com/f4b6a3/ulid-creator/compare/ulid-creator-3.0.0...ulid-creator-3.0.1 [3.0.1]: https://github.com/f4b6a3/ulid-creator/compare/ulid-creator-3.0.0...ulid-creator-3.0.1

View File

@ -35,7 +35,7 @@ Add these lines to your `pom.xml`.
<dependency> <dependency>
<groupId>com.github.f4b6a3</groupId> <groupId>com.github.f4b6a3</groupId>
<artifactId>ulid-creator</artifactId> <artifactId>ulid-creator</artifactId>
<version>3.1.1</version> <version>3.2.0</version>
</dependency> </dependency>
``` ```
See more options in [maven.org](https://search.maven.org/artifact/com.github.f4b6a3/ulid-creator). See more options in [maven.org](https://search.maven.org/artifact/com.github.f4b6a3/ulid-creator).
@ -194,22 +194,20 @@ byte[] random = ulid.getRandom(); // 10 bytes (80 bits)
byte[] random = Ulid.getRandom("0123456789ABCDEFGHJKMNPQRS"); // 10 bytes (80 bits) byte[] random = Ulid.getRandom("0123456789ABCDEFGHJKMNPQRS"); // 10 bytes (80 bits)
``` ```
Use a `UlidFactory` instance with `java.util.Random` to generate ULIDs: Use a `UlidFactory` with `java.util.Random`:
```java ```java
Random random = new Random(); // use a `Random` instance
UlidFactory factory = UlidCreator.getDefaultFactory().withRandomGenerator(random::nextBytes); UlidFactory factory = new DefaultFactory(new Random());
Ulid ulid = factory.create(); Ulid ulid = factory.create();
``` ```
Use a `UlidFactory` instance with any random generator you like(*) to generate ULIDs: Use a `UlidFactory` with a random generator of your choice:
```java ```java
// use a method of any RNG with this signature: `void nextBytes(byte[])`
import com.github.niceguy.random.AwesomeRandom; // a hypothetical RNG import com.github.niceguy.random.AwesomeRandom; // a hypothetical RNG
AwesomeRandom awesomeRandom = new AwesomeRandom(); UlidFactory factory = new DefaultFactory(new AwesomeRandom()::nextBytes);
UlidFactory factory = UlidCreator.getDefaultFactory().withRandomGenerator(awesomeRandom::nextBytes);
Ulid ulid = factory.create(); Ulid ulid = factory.create();
``` ```
@ -244,5 +242,6 @@ See: [uuid-creator-benchmark](https://github.com/fabiolimace/uuid-creator-benchm
Other generators Other generators
------------------------------------------- -------------------------------------------
* [UUID Creator](https://github.com/f4b6a3/uuid-creator): for generating UUIDs * [UUID Creator](https://github.com/f4b6a3/uuid-creator): for generating UUIDs
* [TSID Creator](https://github.com/f4b6a3/tsid-creator): for generating Time Sortable IDs * [TSID Creator](https://github.com/f4b6a3/tsid-creator): for generating TSIDs
* [KSUID Creator](https://github.com/f4b6a3/ksuid-creator): for generating KSUIDs

View File

@ -365,7 +365,8 @@ public final class Ulid implements Serializable, Comparable<Ulid> {
* The output string is 26 characters long and contains only characters from * The output string is 26 characters long and contains only characters from
* Crockford's base 32 alphabet. * Crockford's base 32 alphabet.
* *
* It is at least twice as fast as {@code Ulid.toString().toLowerCase()}. * It is a shorthand at least twice as fast as
* {@code Ulid.toString().toLowerCase()}.
* *
* See: https://www.crockford.com/base32.html * See: https://www.crockford.com/base32.html
* *
@ -542,7 +543,7 @@ public final class Ulid implements Serializable, Comparable<Ulid> {
bytes[0x2] = (byte) (random0 >>> 16); bytes[0x2] = (byte) (random0 >>> 16);
bytes[0x3] = (byte) (random0 >>> 8); bytes[0x3] = (byte) (random0 >>> 8);
bytes[0x4] = (byte) (random0); bytes[0x4] = (byte) (random0);
bytes[0x5] = (byte) (random1 >>> 32); bytes[0x5] = (byte) (random1 >>> 32);
bytes[0x6] = (byte) (random1 >>> 24); bytes[0x6] = (byte) (random1 >>> 24);
bytes[0x7] = (byte) (random1 >>> 16); bytes[0x7] = (byte) (random1 >>> 16);
@ -619,7 +620,13 @@ public final class Ulid implements Serializable, Comparable<Ulid> {
/** /**
* Converts the ULID into a canonical string in upper case. * Converts the ULID into a canonical string in upper case.
* *
* It is the same as {@code Ulid.toUpperCase()}. * The output string is 26 characters long and contains only characters from
* Crockford's base 32 alphabet.
*
* For lower case string, use the shorthand {@code Ulid#toLowerCase()}, instead
* of {@code Ulid#toString()#toLowerCase()}.
*
* See: https://www.crockford.com/base32.html
* *
* @return a ULID string * @return a ULID string
*/ */

View File

@ -24,8 +24,8 @@
package com.github.f4b6a3.ulid; package com.github.f4b6a3.ulid;
import com.github.f4b6a3.ulid.factory.DefaultUlidFactory; import com.github.f4b6a3.ulid.factory.DefaultFactory;
import com.github.f4b6a3.ulid.factory.MonotonicUlidFactory; import com.github.f4b6a3.ulid.factory.MonotonicFactory;
import com.github.f4b6a3.ulid.factory.UlidFactory; import com.github.f4b6a3.ulid.factory.UlidFactory;
/** /**
@ -92,29 +92,11 @@ public final class UlidCreator {
return MonotonicFactoryHolder.INSTANCE.create(time); return MonotonicFactoryHolder.INSTANCE.create(time);
} }
/**
* Returns an instance of the Default ULID factory.
*
* @return a ULID factory
*/
public static UlidFactory getDefaultFactory() {
return new DefaultUlidFactory();
}
/**
* Returns an instance of the Monotonic ULID factory.
*
* @return a ULID factory
*/
public static UlidFactory getMonotonicFactory() {
return new MonotonicUlidFactory();
}
private static class DefaultFactoryHolder { private static class DefaultFactoryHolder {
static final UlidFactory INSTANCE = getDefaultFactory(); static final UlidFactory INSTANCE = new DefaultFactory();
} }
private static class MonotonicFactoryHolder { private static class MonotonicFactoryHolder {
static final UlidFactory INSTANCE = getMonotonicFactory(); static final UlidFactory INSTANCE = new MonotonicFactory();
} }
} }

View File

@ -24,16 +24,44 @@
package com.github.f4b6a3.ulid.factory; package com.github.f4b6a3.ulid.factory;
import java.util.Random;
import com.github.f4b6a3.ulid.Ulid; import com.github.f4b6a3.ulid.Ulid;
import com.github.f4b6a3.ulid.random.RandomGenerator;
/** /**
* Factory that generates default ULIDs. * Factory that generates ULIDs.
* *
* The random component is always reset to a new random value. * The random component is always reset to a new random value.
* *
* 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 class DefaultUlidFactory extends UlidFactory { public class DefaultFactory extends UlidFactory {
/**
* Use the default {@link java.security.SecureRandom}.
*/
public DefaultFactory() {
super();
}
/**
* Use a random generator that inherits from {@link Random}.
*
* @param random a {@link Random} instance
*/
public DefaultFactory(Random random) {
this(random::nextBytes);
}
/**
* Use a random generator that inherits from {@link RandomGenerator}.
*
* @param randomGenerator a {@link RandomGenerator} instance
*/
public DefaultFactory(RandomGenerator randomGenerator) {
super(randomGenerator);
}
/** /**
* Returns a ULID. * Returns a ULID.

View File

@ -24,23 +24,52 @@
package com.github.f4b6a3.ulid.factory; package com.github.f4b6a3.ulid.factory;
import java.util.Random;
import com.github.f4b6a3.ulid.Ulid; import com.github.f4b6a3.ulid.Ulid;
import com.github.f4b6a3.ulid.random.RandomGenerator;
/** /**
* Factory that generates Monotonic ULIDs. * Factory that generates Monotonic ULIDs.
* *
* The random component is reset to a new value every time the millisecond changes. * The random component is reset to a new value every time the millisecond
* changes.
* *
* If more than one ULID is generated within the same millisecond, the random * If more than one ULID is generated within the same millisecond, the random
* component is incremented by one. * component is incremented by one.
* *
* 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 MonotonicUlidFactory extends UlidFactory { public final class MonotonicFactory extends UlidFactory {
private long lastTime = -1; private long lastTime = -1;
private Ulid lastUlid = null; private Ulid lastUlid = null;
/**
* Use the default {@link java.security.SecureRandom}.
*/
public MonotonicFactory() {
super();
}
/**
* Use a random generator that inherits from {@link Random}.
*
* @param random a {@link Random} instance
*/
public MonotonicFactory(Random random) {
this(random::nextBytes);
}
/**
* Use a random generator that inherits from {@link RandomGenerator}.
*
* @param randomGenerator a {@link RandomGenerator} instance
*/
public MonotonicFactory(RandomGenerator randomGenerator) {
super(randomGenerator);
}
/** /**
* Returns a ULID. * Returns a ULID.
* *

View File

@ -24,10 +24,9 @@
package com.github.f4b6a3.ulid.factory; package com.github.f4b6a3.ulid.factory;
import java.util.Random; import java.security.SecureRandom;
import com.github.f4b6a3.ulid.Ulid; import com.github.f4b6a3.ulid.Ulid;
import com.github.f4b6a3.ulid.random.DefaultRandomGenerator;
import com.github.f4b6a3.ulid.random.RandomGenerator; import com.github.f4b6a3.ulid.random.RandomGenerator;
/** /**
@ -39,8 +38,20 @@ public abstract class UlidFactory {
protected RandomGenerator randomGenerator; protected RandomGenerator randomGenerator;
/**
* Use the default {@link java.security.SecureRandom}.
*/
public UlidFactory() { public UlidFactory() {
this.randomGenerator = new DefaultRandomGenerator(); this(new SecureRandom()::nextBytes);
}
/**
* Use a random generator that inherits from {@link RandomGenerator}.
*
* @param randomGenerator a {@link RandomGenerator} instance
*/
public UlidFactory(RandomGenerator randomGenerator) {
this.randomGenerator = randomGenerator;
} }
/** /**
@ -61,21 +72,4 @@ public abstract class UlidFactory {
* @return a ULID * @return a ULID
*/ */
public abstract Ulid create(final long time); public abstract Ulid create(final long time);
/**
* Replaces the default random generator with another.
*
* The default random generator uses {@link java.security.SecureRandom}.
*
* See {@link Random}.
*
* @param <T> the type parameter
* @param randomGenerator a random generator
* @return {@link UlidFactory}
*/
@SuppressWarnings("unchecked")
public synchronized <T extends UlidFactory> T withRandomGenerator(RandomGenerator randomGenerator) {
this.randomGenerator = randomGenerator;
return (T) this;
}
} }

View File

@ -1,41 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2018-2020 Fabio Lima
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.github.f4b6a3.ulid.random;
import java.security.SecureRandom;
import java.util.Random;
/**
* It uses an instance of {@link java.security.SecureRandom}.
*/
public final class DefaultRandomGenerator implements RandomGenerator {
private static final Random SECURE_RANDOM = new SecureRandom();
@Override
public void nextBytes(byte[] bytes) {
SECURE_RANDOM.nextBytes(bytes);
}
}

View File

@ -3,13 +3,13 @@ package com.github.f4b6a3.ulid;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Suite; import org.junit.runners.Suite;
import com.github.f4b6a3.ulid.factory.DefaultUlidFactoryTest; import com.github.f4b6a3.ulid.factory.DefaultFactoryTest;
import com.github.f4b6a3.ulid.factory.MonotonicUlidFactoryTest; import com.github.f4b6a3.ulid.factory.MonotonicFactoryTest;
@RunWith(Suite.class) @RunWith(Suite.class)
@Suite.SuiteClasses({ @Suite.SuiteClasses({
MonotonicUlidFactoryTest.class, MonotonicFactoryTest.class,
DefaultUlidFactoryTest.class, DefaultFactoryTest.class,
UlidTest.class, UlidTest.class,
}) })

View File

@ -71,7 +71,7 @@ public class UlidTest {
} }
try { try {
long time = 0x1000000000000000L; // negative number long time = 0x8000000000000000L; // negative number
byte[] bytes = new byte[Ulid.RANDOM_BYTES_LENGTH]; byte[] bytes = new byte[Ulid.RANDOM_BYTES_LENGTH];
new Ulid(time, bytes); new Ulid(time, bytes);
fail("Should throw an exception"); fail("Should throw an exception");

View File

@ -1,7 +1,9 @@
package com.github.f4b6a3.ulid; package com.github.f4b6a3.ulid;
import java.util.HashSet; import java.util.HashSet;
import com.github.f4b6a3.ulid.UlidCreator; import java.util.Random;
import com.github.f4b6a3.ulid.factory.MonotonicFactory;
import com.github.f4b6a3.ulid.factory.UlidFactory; import com.github.f4b6a3.ulid.factory.UlidFactory;
/** /**
@ -117,8 +119,7 @@ public class UniquenessTest {
} }
public static void execute(boolean verbose, int threadCount, int requestCount) { public static void execute(boolean verbose, int threadCount, int requestCount) {
UlidFactory factory = UlidCreator.getMonotonicFactory(); UlidFactory factory = new MonotonicFactory(new Random());
UniquenessTest test = new UniquenessTest(threadCount, requestCount, factory, verbose); UniquenessTest test = new UniquenessTest(threadCount, requestCount, factory, verbose);
test.start(); test.start();
} }

View File

@ -11,7 +11,7 @@ import static org.junit.Assert.*;
import java.util.HashSet; import java.util.HashSet;
import java.util.Random; import java.util.Random;
public class DefaultUlidFactoryTest extends UlidFactoryTest { public class DefaultFactoryTest extends UlidFactoryTest {
@Test @Test
public void testGetUlid() { public void testGetUlid() {
@ -67,8 +67,7 @@ public class DefaultUlidFactoryTest extends UlidFactoryTest {
// Instantiate and start many threads // Instantiate and start many threads
for (int i = 0; i < THREAD_TOTAL; i++) { for (int i = 0; i < THREAD_TOTAL; i++) {
Random random = new Random(); UlidFactory factory = new DefaultFactory(new Random());
UlidFactory factory = UlidCreator.getDefaultFactory().withRandomGenerator(random::nextBytes);
threads[i] = new TestThread(factory, DEFAULT_LOOP_MAX); threads[i] = new TestThread(factory, DEFAULT_LOOP_MAX);
threads[i].start(); threads[i].start();
} }

View File

@ -12,7 +12,7 @@ import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Random; import java.util.Random;
public class MonotonicUlidFactoryTest extends UlidFactoryTest { public class MonotonicFactoryTest extends UlidFactoryTest {
@Test @Test
public void testGetUlid() { public void testGetUlid() {
@ -78,8 +78,7 @@ public class MonotonicUlidFactoryTest extends UlidFactoryTest {
// Instantiate and start many threads // Instantiate and start many threads
for (int i = 0; i < THREAD_TOTAL; i++) { for (int i = 0; i < THREAD_TOTAL; i++) {
Random random = new Random(); UlidFactory factory = new MonotonicFactory(new Random());
UlidFactory factory = UlidCreator.getMonotonicFactory().withRandomGenerator(random::nextBytes);
threads[i] = new TestThread(factory, DEFAULT_LOOP_MAX); threads[i] = new TestThread(factory, DEFAULT_LOOP_MAX);
threads[i].start(); threads[i].start();
} }