Preparing v1.1.0
This commit is contained in:
		
							parent
							
								
									1826fd960e
								
							
						
					
					
						commit
						c59d1c61f0
					
				
							
								
								
									
										59
									
								
								README.md
								
								
								
								
							
							
						
						
									
										59
									
								
								README.md
								
								
								
								
							| 
						 | 
				
			
			@ -1,23 +1,24 @@
 | 
			
		|||
 | 
			
		||||
# ULID Creator
 | 
			
		||||
 | 
			
		||||
A Java library for generating and handling ULIDs - _Universally Unique Lexicographically Sortable Identifiers_.
 | 
			
		||||
A Java library for generating ULIDs.
 | 
			
		||||
 | 
			
		||||
How to Use
 | 
			
		||||
------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
Create a ULID:
 | 
			
		||||
Create a ULID as GUID:
 | 
			
		||||
 | 
			
		||||
```java
 | 
			
		||||
String ulid = UlidCreator.getUlid();
 | 
			
		||||
UUID ulid = UlidCreator.getUlid();
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Create a ULID as GUID object:
 | 
			
		||||
Create a ULID string:
 | 
			
		||||
 | 
			
		||||
```java
 | 
			
		||||
UUID ulid = UlidCreator.getGuid();
 | 
			
		||||
String ulid = UlidCreator.getUlidString();
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Maven dependency
 | 
			
		||||
 | 
			
		||||
Add these lines to your `pom.xml`.
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +28,7 @@ Add these lines to your `pom.xml`.
 | 
			
		|||
<dependency>
 | 
			
		||||
  <groupId>com.github.f4b6a3</groupId>
 | 
			
		||||
  <artifactId>ulid-creator</artifactId>
 | 
			
		||||
  <version>1.0.2</version>
 | 
			
		||||
  <version>1.1.0</version>
 | 
			
		||||
</dependency>
 | 
			
		||||
```
 | 
			
		||||
See more options in [maven.org](https://search.maven.org/artifact/com.github.f4b6a3/ulid-creator) and [mvnrepository.com](https://mvnrepository.com/artifact/com.github.f4b6a3/ulid-creator).
 | 
			
		||||
| 
						 | 
				
			
			@ -35,15 +36,15 @@ See more options in [maven.org](https://search.maven.org/artifact/com.github.f4b
 | 
			
		|||
Implementation
 | 
			
		||||
------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
### ULID
 | 
			
		||||
### ULID string
 | 
			
		||||
 | 
			
		||||
The ULID is a unique and sortable 26 char sequence. See the [ULID specification](https://github.com/ulid/spec) for more information.
 | 
			
		||||
The ULID is a 26 char sequence. See the [ULID specification](https://github.com/ulid/spec) for more information.
 | 
			
		||||
 | 
			
		||||
See the section on GUIDs to know how the 128 bits are generated in this library.
 | 
			
		||||
 | 
			
		||||
```java
 | 
			
		||||
// ULIDs
 | 
			
		||||
String ulid = UlidCreator.getUlid();
 | 
			
		||||
String ulid = UlidCreator.getUlidString();
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Examples of ULIDs:
 | 
			
		||||
| 
						 | 
				
			
			@ -71,17 +72,17 @@ Examples of ULIDs:
 | 
			
		|||
   milli     randomness
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### GUID
 | 
			
		||||
### Ulid-based GUID
 | 
			
		||||
 | 
			
		||||
The GUIDs in this library are based on the [ULID specification](https://github.com/ulid/spec). The first 48 bits represent the count of milliseconds since Unix Epoch, 1 January 1970. The remaining 60 bits are generated by a secure random number generator.
 | 
			
		||||
 | 
			
		||||
Every time the timestamp changes the random part is reset to a new random value. If the current timestamp is equal to the previous one, the random bits are incremented by 1.
 | 
			
		||||
 | 
			
		||||
The default random number generator is `SecureRandom`, but it's possible to use any RNG that extends `Random`.
 | 
			
		||||
The default random number generator is `java.security.SecureRandom`, but it's possible to use any RNG that extends `java.util.Random`.
 | 
			
		||||
 | 
			
		||||
```java
 | 
			
		||||
// GUID based on ULID spec
 | 
			
		||||
UUID guid = UlidCreator.getGuid();
 | 
			
		||||
UUID ulid = UlidCreator.getUlid();
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Examples of GUIDs based on ULID spec:
 | 
			
		||||
| 
						 | 
				
			
			@ -109,38 +110,28 @@ Examples of GUIDs based on ULID spec:
 | 
			
		|||
  millisecs        randomness
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### How use the `GuidCreator` directly
 | 
			
		||||
#### How use the `UlidBasedGuidCreator` directly
 | 
			
		||||
 | 
			
		||||
These are some examples of using the `GuidCreator` to create ULIDs:
 | 
			
		||||
These are some examples of using the `UlidBasedGuidCreator` to create ULIDs strings:
 | 
			
		||||
 | 
			
		||||
```java
 | 
			
		||||
	
 | 
			
		||||
// with fixed timestamp strategy (for test cases)
 | 
			
		||||
String ulid = UlidCreator.getGuidCreator()
 | 
			
		||||
	.withTimestampStrategy(new FixedTimestampStretegy())
 | 
			
		||||
	.createUlid();
 | 
			
		||||
	
 | 
			
		||||
// with your custom timestamp strategy
 | 
			
		||||
String ulid = UlidCreator.getGuidCreator()
 | 
			
		||||
	.withTimestampStrategy(new MyCustomTimestampStrategy())
 | 
			
		||||
	.createUlid();
 | 
			
		||||
TimestampStrategy customStrategy = new CustomTimestampStrategy();
 | 
			
		||||
String ulid = UlidCreator.getUlidBasedGuidCreator()
 | 
			
		||||
	.withTimestampStrategy(customStrategy)
 | 
			
		||||
	.createString();
 | 
			
		||||
 | 
			
		||||
// with your custom random number generator
 | 
			
		||||
String ulid = UlidCreator.getGuidCreator()
 | 
			
		||||
    .withRandomGenerator(new MyCustomRandom())
 | 
			
		||||
    .createUlid();
 | 
			
		||||
 | 
			
		||||
// with fast random generator (Xorshift128Plus with salt)
 | 
			
		||||
int salt = (int) FingerprintUtil.getFingerprint();
 | 
			
		||||
Random random = new Xorshift128PlusRandom(salt);
 | 
			
		||||
String ulid = UlidCreator.getGuidCreator()
 | 
			
		||||
// with `java.util.Random` number generator
 | 
			
		||||
Random random = new Random();
 | 
			
		||||
String ulid = UlidCreator.getUlidBasedGuidCreator()
 | 
			
		||||
    .withRandomGenerator(random)
 | 
			
		||||
    .createUlid();
 | 
			
		||||
    .createString();
 | 
			
		||||
    
 | 
			
		||||
// with fast random generator (the same as above)
 | 
			
		||||
String ulid = UlidCreator.getGuidCreator()
 | 
			
		||||
String ulid = UlidCreator.getUlidBasedGuidCreator()
 | 
			
		||||
    .withFastRandomGenerator()
 | 
			
		||||
    .createUlid();
 | 
			
		||||
    .createString();
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,8 +26,8 @@ package com.github.f4b6a3.ulid;
 | 
			
		|||
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
import com.github.f4b6a3.commons.random.Xorshift128PlusRandom;
 | 
			
		||||
import com.github.f4b6a3.ulid.creator.UlidBasedGuidCreator;
 | 
			
		||||
import com.github.f4b6a3.ulid.exception.UlidCreatorException;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A factory for Universally Unique Lexicographically Sortable Identifiers.
 | 
			
		||||
| 
						 | 
				
			
			@ -40,61 +40,71 @@ public class UlidCreator {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Returns ULID as GUID object.
 | 
			
		||||
	 * Returns a ULID as GUID.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @return a GUID
 | 
			
		||||
	 * The random component is generated by a secure random number generator:
 | 
			
		||||
	 * {@link java.security.SecureRandom}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @return a UUID
 | 
			
		||||
	 */
 | 
			
		||||
	public static UUID getUlid() {
 | 
			
		||||
		return GuidCreatorLazyHolder.INSTANCE.create();
 | 
			
		||||
		return UlidBasedGuidCreatorHolder.INSTANCE.create();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Returns fast ULID as GUID object.
 | 
			
		||||
	 * Returns a ULID string.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @return a GUID
 | 
			
		||||
	 */
 | 
			
		||||
	public static UUID getFastUlid() {
 | 
			
		||||
		return FastGuidCreatorLazyHolder.INSTANCE.create();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Returns a ULID.
 | 
			
		||||
	 * The returning string is encoded to Crockford's base32.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * The random component is generated by a secure random number generator:
 | 
			
		||||
	 * {@link java.security.SecureRandom}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @return a ULID
 | 
			
		||||
	 */
 | 
			
		||||
	public static String getUlidString() {
 | 
			
		||||
		return GuidCreatorLazyHolder.INSTANCE.createString();
 | 
			
		||||
		return UlidBasedGuidCreatorHolder.INSTANCE.createString();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Returns a fast ULID.
 | 
			
		||||
	 * Returns a ULID as GUID.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * The random component is generated by a fast random number generator:
 | 
			
		||||
	 * {@link Xorshift128PlusRandom}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @return a UUID
 | 
			
		||||
	 */
 | 
			
		||||
	public static UUID getFastUlid() {
 | 
			
		||||
		return FastUlidBasedGuidCreatorHolder.INSTANCE.create();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Returns a fast ULID string.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * The returning string is encoded to Crockford's base32.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * The random component is generated by a fast random number generator:
 | 
			
		||||
	 * {@link Xorshift128PlusRandom}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @return a ULID
 | 
			
		||||
	 */
 | 
			
		||||
	public static String getFastUlidString() {
 | 
			
		||||
		return FastGuidCreatorLazyHolder.INSTANCE.createString();
 | 
			
		||||
		return FastUlidBasedGuidCreatorHolder.INSTANCE.createString();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Return a GUID creator for direct use.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * This library uses the {@link UlidBasedGuidCreator} internally to generate
 | 
			
		||||
	 * ULIDs.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * The {@link UlidBasedGuidCreator} throws a {@link UlidCreatorException} when
 | 
			
		||||
	 * too many values are requested in the same millisecond.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @return a {@link UlidBasedGuidCreator}
 | 
			
		||||
	 */
 | 
			
		||||
	public static UlidBasedGuidCreator getUlidBasedCreator() {
 | 
			
		||||
		return new UlidBasedGuidCreator();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static class GuidCreatorLazyHolder {
 | 
			
		||||
	private static class UlidBasedGuidCreatorHolder {
 | 
			
		||||
		static final UlidBasedGuidCreator INSTANCE = getUlidBasedCreator();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static class FastGuidCreatorLazyHolder {
 | 
			
		||||
	private static class FastUlidBasedGuidCreatorHolder {
 | 
			
		||||
		static final UlidBasedGuidCreator INSTANCE = getUlidBasedCreator().withFastRandomGenerator();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,13 +27,13 @@ package com.github.f4b6a3.ulid.creator;
 | 
			
		|||
import java.util.Random;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
import com.github.f4b6a3.ulid.timestamp.TimestampStrategy;
 | 
			
		||||
import com.github.f4b6a3.ulid.util.UlidUtil;
 | 
			
		||||
import com.github.f4b6a3.ulid.util.UlidConverter;
 | 
			
		||||
import com.github.f4b6a3.commons.random.Xorshift128PlusRandom;
 | 
			
		||||
import com.github.f4b6a3.commons.util.FingerprintUtil;
 | 
			
		||||
import com.github.f4b6a3.commons.util.RandomUtil;
 | 
			
		||||
import com.github.f4b6a3.ulid.exception.UlidCreatorException;
 | 
			
		||||
import com.github.f4b6a3.ulid.timestamp.DefaultTimestampStrategy;
 | 
			
		||||
import com.github.f4b6a3.ulid.strategy.TimestampStrategy;
 | 
			
		||||
import com.github.f4b6a3.ulid.strategy.timestamp.DefaultTimestampStrategy;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Factory that creates lexicographically sortable GUIDs, based on the ULID
 | 
			
		||||
| 
						 | 
				
			
			@ -69,7 +69,7 @@ public class UlidBasedGuidCreator {
 | 
			
		|||
	 * 
 | 
			
		||||
	 * Return a GUID based on the ULID specification.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * It has two parts:
 | 
			
		||||
	 * A ULID has two parts:
 | 
			
		||||
	 * 
 | 
			
		||||
	 * 1. A part of 48 bits that represent the amount of milliseconds since Unix
 | 
			
		||||
	 * Epoch, 1 January 1970.
 | 
			
		||||
| 
						 | 
				
			
			@ -85,6 +85,9 @@ public class UlidBasedGuidCreator {
 | 
			
		|||
	 * 
 | 
			
		||||
	 * The maximum GUIDs that can be generated per millisecond is 2^80.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * The random part is generated by a secure random number generator:
 | 
			
		||||
	 * {@link java.security.SecureRandom}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * ### Specification of Universally Unique Lexicographically Sortable ID
 | 
			
		||||
	 * 
 | 
			
		||||
	 * #### Components
 | 
			
		||||
| 
						 | 
				
			
			@ -116,7 +119,7 @@ public class UlidBasedGuidCreator {
 | 
			
		|||
	 * 2^80 ULIDs within the same millisecond, or cause the random component to
 | 
			
		||||
	 * overflow with less, the generation will fail.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @return {@link UUID} a UUID value
 | 
			
		||||
	 * @return {@link UUID} a GUID value
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @throws UlidCreatorException an overrun exception if too many requests are
 | 
			
		||||
	 *                              made within the same millisecond.
 | 
			
		||||
| 
						 | 
				
			
			@ -135,13 +138,14 @@ public class UlidBasedGuidCreator {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Return a ULID.
 | 
			
		||||
	 * Returns a ULID string.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * The returning string is encoded to Crockford's base32.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @return a ULID string
 | 
			
		||||
	 */
 | 
			
		||||
	public synchronized String createString() {
 | 
			
		||||
		UUID guid = create();
 | 
			
		||||
		return UlidUtil.fromUuidToUlid(guid);
 | 
			
		||||
		return UlidConverter.toString(create());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -185,7 +189,8 @@ public class UlidBasedGuidCreator {
 | 
			
		|||
	/**
 | 
			
		||||
	 * Increment the random part of the GUID.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * An exception is thrown when more than 2^80 increment operations are made.
 | 
			
		||||
	 * An exception is thrown when more than 2^80 increment operations are made,
 | 
			
		||||
	 * although it's extremely unlikely to occur.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @throws UlidCreatorException if an overrun happens.
 | 
			
		||||
	 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
/*
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 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.exception;
 | 
			
		||||
 | 
			
		||||
public class InvalidUlidException extends RuntimeException {
 | 
			
		||||
 | 
			
		||||
	private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
	public InvalidUlidException(String message) {
 | 
			
		||||
		super(message);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -26,7 +26,7 @@ package com.github.f4b6a3.ulid.exception;
 | 
			
		|||
 | 
			
		||||
public class UlidCreatorException extends RuntimeException {
 | 
			
		||||
 | 
			
		||||
	private static final long serialVersionUID = 6755381080404981234L;
 | 
			
		||||
	private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
	public UlidCreatorException(String message) {
 | 
			
		||||
		super(message);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,7 +22,7 @@
 | 
			
		|||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package com.github.f4b6a3.ulid.timestamp;
 | 
			
		||||
package com.github.f4b6a3.ulid.strategy;
 | 
			
		||||
 | 
			
		||||
public interface TimestampStrategy {
 | 
			
		||||
	long getTimestamp();
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +22,9 @@
 | 
			
		|||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package com.github.f4b6a3.ulid.timestamp;
 | 
			
		||||
package com.github.f4b6a3.ulid.strategy.timestamp;
 | 
			
		||||
 | 
			
		||||
import com.github.f4b6a3.ulid.strategy.TimestampStrategy;
 | 
			
		||||
 | 
			
		||||
public class DefaultTimestampStrategy implements TimestampStrategy {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +22,9 @@
 | 
			
		|||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package com.github.f4b6a3.ulid.timestamp;
 | 
			
		||||
package com.github.f4b6a3.ulid.strategy.timestamp;
 | 
			
		||||
 | 
			
		||||
import com.github.f4b6a3.ulid.strategy.TimestampStrategy;
 | 
			
		||||
 | 
			
		||||
public class FixedTimestampStretegy implements TimestampStrategy {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,103 @@
 | 
			
		|||
/*
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 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.util;
 | 
			
		||||
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
import com.github.f4b6a3.commons.util.Base32Util;
 | 
			
		||||
import com.github.f4b6a3.commons.util.ByteUtil;
 | 
			
		||||
 | 
			
		||||
public class UlidConverter {
 | 
			
		||||
 | 
			
		||||
	private UlidConverter() {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Convert a UUID to ULID string
 | 
			
		||||
	 * 
 | 
			
		||||
	 * The returning string is encoded to Crockford's base32.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * The timestamp and random components are encoded separated.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param uuid a UUID
 | 
			
		||||
	 * @return a ULID
 | 
			
		||||
	 */
 | 
			
		||||
	public static String toString(UUID uuid) {
 | 
			
		||||
 | 
			
		||||
		final long msb = uuid.getMostSignificantBits();
 | 
			
		||||
		final long lsb = uuid.getLeastSignificantBits();
 | 
			
		||||
 | 
			
		||||
		// Extract timestamp component
 | 
			
		||||
		final long timeNumber = (msb >>> 16);
 | 
			
		||||
		String timestampComponent = leftPad(Base32Util.toBase32Crockford(timeNumber));
 | 
			
		||||
 | 
			
		||||
		// Extract randomness component
 | 
			
		||||
		byte[] randBytes = new byte[10];
 | 
			
		||||
		randBytes[0] = (byte) (msb >>> 8);
 | 
			
		||||
		randBytes[1] = (byte) (msb);
 | 
			
		||||
		byte[] lsbBytes = ByteUtil.toBytes(lsb);
 | 
			
		||||
		System.arraycopy(lsbBytes, 0, randBytes, 2, 8);
 | 
			
		||||
		String randomnessComponent = Base32Util.toBase32Crockford(randBytes);
 | 
			
		||||
 | 
			
		||||
		return timestampComponent + randomnessComponent;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Converts a ULID string to a UUID.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * The input string must be encoded to Crockford's base32, following the ULID
 | 
			
		||||
	 * specification.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * The timestamp and random components are decoded separated.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * An exception is thrown if the ULID string is invalid.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param ulid a ULID
 | 
			
		||||
	 * @return a UUID if valid
 | 
			
		||||
	 */
 | 
			
		||||
	public static UUID fromString(final String ulid) {
 | 
			
		||||
 | 
			
		||||
		UlidValidator.validate(ulid);
 | 
			
		||||
 | 
			
		||||
		// Extract timestamp component
 | 
			
		||||
		final String timestampComponent = ulid.substring(0, 10);
 | 
			
		||||
		final long timeNumber = Base32Util.fromBase32CrockfordAsLong(timestampComponent);
 | 
			
		||||
 | 
			
		||||
		// Extract randomness component
 | 
			
		||||
		final String randomnessComponent = ulid.substring(10, 26);
 | 
			
		||||
		byte[] randBytes = Base32Util.fromBase32Crockford(randomnessComponent);
 | 
			
		||||
		byte[] lsbBytes = new byte[8];
 | 
			
		||||
		System.arraycopy(randBytes, 2, lsbBytes, 0, 8);
 | 
			
		||||
 | 
			
		||||
		final long msb = (timeNumber << 16) | ((randBytes[0] << 8) & 0x0000ff00L) | ((randBytes[1]) & 0x000000ffL);
 | 
			
		||||
		final long lsb = ByteUtil.toNumber(lsbBytes);
 | 
			
		||||
 | 
			
		||||
		return new UUID(msb, lsb);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static String leftPad(String unpadded) {
 | 
			
		||||
		return "0000000000".substring(unpadded.length()) + unpadded;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -25,237 +25,16 @@
 | 
			
		|||
package com.github.f4b6a3.ulid.util;
 | 
			
		||||
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
import com.github.f4b6a3.commons.util.Base32Util;
 | 
			
		||||
import com.github.f4b6a3.commons.util.ByteUtil;
 | 
			
		||||
 | 
			
		||||
public class UlidUtil {
 | 
			
		||||
 | 
			
		||||
	// Date: 10889-08-02T05:31:50.655Z
 | 
			
		||||
	protected static final long TIMESTAMP_MAX = (long) Math.pow(2, 48) - 1;
 | 
			
		||||
 | 
			
		||||
	protected static final String ULID_PATTERN_STRICT = "^[0-9a-hjkmnp-tv-zA-HJKMNP-TV-Z]{26}$";
 | 
			
		||||
	protected static final String ULID_PATTERN_LOOSE = "^[0-9a-tv-zA-TV-Z]{26}$";
 | 
			
		||||
 | 
			
		||||
	private UlidUtil() {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Convert a UUID to ULID string
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param uuid
 | 
			
		||||
	 *            a UUID
 | 
			
		||||
	 * @return a ULID
 | 
			
		||||
	 */
 | 
			
		||||
	public static String fromUuidToUlid(UUID uuid) {
 | 
			
		||||
 | 
			
		||||
		final long msb = uuid.getMostSignificantBits();
 | 
			
		||||
		final long lsb = uuid.getLeastSignificantBits();
 | 
			
		||||
 | 
			
		||||
		// Extract timestamp component
 | 
			
		||||
		final long timeNumber = (msb >>> 16);
 | 
			
		||||
		String timestampComponent = leftPad(Base32Util.toBase32Crockford(timeNumber));
 | 
			
		||||
 | 
			
		||||
		// Extract randomness component
 | 
			
		||||
		byte[] randBytes = new byte[10];
 | 
			
		||||
		randBytes[0] = (byte) (msb >>> 8);
 | 
			
		||||
		randBytes[1] = (byte) (msb);
 | 
			
		||||
		byte[] lsbBytes = ByteUtil.toBytes(lsb);
 | 
			
		||||
		System.arraycopy(lsbBytes, 0, randBytes, 2, 8);
 | 
			
		||||
		String randomnessComponent = Base32Util.toBase32Crockford(randBytes);
 | 
			
		||||
 | 
			
		||||
		return timestampComponent + randomnessComponent;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Converts a ULID string to a UUID.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * An exception is thrown if the ULID string is invalid.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param ulid
 | 
			
		||||
	 *            a ULID
 | 
			
		||||
	 * @return a UUID if valid
 | 
			
		||||
	 */
 | 
			
		||||
	public static UUID fromUlidToUuid(final String ulid) {
 | 
			
		||||
 | 
			
		||||
		UlidUtil.validate(ulid);
 | 
			
		||||
 | 
			
		||||
		// Extract timestamp component
 | 
			
		||||
		final String timestampComponent = ulid.substring(0, 10);
 | 
			
		||||
		final long timeNumber = Base32Util.fromBase32CrockfordAsLong(timestampComponent);
 | 
			
		||||
 | 
			
		||||
		// Extract randomness component
 | 
			
		||||
		final String randomnessComponent = ulid.substring(10, 26);
 | 
			
		||||
		byte[] randBytes = Base32Util.fromBase32Crockford(randomnessComponent);
 | 
			
		||||
		byte[] lsbBytes = new byte[8];
 | 
			
		||||
		System.arraycopy(randBytes, 2, lsbBytes, 0, 8);
 | 
			
		||||
 | 
			
		||||
		final long msb = (timeNumber << 16) | ((randBytes[0] << 8) & 0x0000ff00L) | ((randBytes[1]) & 0x000000ffL);
 | 
			
		||||
		final long lsb = ByteUtil.toNumber(lsbBytes);
 | 
			
		||||
 | 
			
		||||
		return new UUID(msb, lsb);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Get the array of bytes from a UUID.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param uuid
 | 
			
		||||
	 *            a UUID
 | 
			
		||||
	 * @return an array of bytes
 | 
			
		||||
	 */
 | 
			
		||||
	public static byte[] fromUuidToBytes(final UUID uuid) {
 | 
			
		||||
		final long msb = uuid.getMostSignificantBits();
 | 
			
		||||
		final long lsb = uuid.getLeastSignificantBits();
 | 
			
		||||
		final byte[] msbBytes = ByteUtil.toBytes(msb);
 | 
			
		||||
		final byte[] lsbBytes = ByteUtil.toBytes(lsb);
 | 
			
		||||
		return ByteUtil.concat(msbBytes, lsbBytes);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Get a UUID from an array of bytes;
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param bytes
 | 
			
		||||
	 *            an array of bytes
 | 
			
		||||
	 * @return a UUID
 | 
			
		||||
	 */
 | 
			
		||||
	public static UUID fromBytesToUuid(byte[] bytes) {
 | 
			
		||||
		byte[] msbBytes = new byte[8];
 | 
			
		||||
		System.arraycopy(bytes, 0, msbBytes, 0, 8);
 | 
			
		||||
		byte[] lsbBytes = new byte[8];
 | 
			
		||||
		System.arraycopy(bytes, 8, lsbBytes, 0, 8);
 | 
			
		||||
		final long msb = ByteUtil.toNumber(msbBytes);
 | 
			
		||||
		final long lsb = ByteUtil.toNumber(lsbBytes);
 | 
			
		||||
		return new UUID(msb, lsb);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Convert an array of bytes to a ULID string.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param bytes
 | 
			
		||||
	 *            a byte array
 | 
			
		||||
	 * @return a ULID string
 | 
			
		||||
	 */
 | 
			
		||||
	public static String fromBytesToUlid(byte[] bytes) {
 | 
			
		||||
 | 
			
		||||
		byte[] timeBytes = new byte[6];
 | 
			
		||||
		System.arraycopy(bytes, 0, timeBytes, 0, 6);
 | 
			
		||||
		final long timeNumber = ByteUtil.toNumber(timeBytes);
 | 
			
		||||
		final String timestampComponent = leftPad(Base32Util.toBase32Crockford(timeNumber));
 | 
			
		||||
 | 
			
		||||
		byte[] randBytes = new byte[10];
 | 
			
		||||
		System.arraycopy(bytes, 6, randBytes, 0, 10);
 | 
			
		||||
		final String randomnessComponent = Base32Util.toBase32Crockford(randBytes);
 | 
			
		||||
 | 
			
		||||
		return timestampComponent + randomnessComponent;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Convert a ULID string to an array of bytes.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param ulid
 | 
			
		||||
	 *            a ULID string
 | 
			
		||||
	 * @return an array of bytes
 | 
			
		||||
	 */
 | 
			
		||||
	public static byte[] fromUlidToBytes(final String ulid) {
 | 
			
		||||
		UlidUtil.validate(ulid);
 | 
			
		||||
		byte[] bytes = new byte[16];
 | 
			
		||||
 | 
			
		||||
		final String timestampComponent = ulid.substring(0, 10);
 | 
			
		||||
		final long timeNumber = Base32Util.fromBase32CrockfordAsLong(timestampComponent);
 | 
			
		||||
		byte[] timeBytes = ByteUtil.toBytes(timeNumber);
 | 
			
		||||
		System.arraycopy(timeBytes, 2, bytes, 0, 6);
 | 
			
		||||
 | 
			
		||||
		final String randomnessComponent = ulid.substring(10, 26);
 | 
			
		||||
		byte[] randBytes = Base32Util.fromBase32Crockford(randomnessComponent);
 | 
			
		||||
		System.arraycopy(randBytes, 0, bytes, 6, 10);
 | 
			
		||||
 | 
			
		||||
		return bytes;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Checks if the ULID string is a valid.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * The validation mode is not strict.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * See {@link UlidUtil#validate(String, boolean)}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param ulid
 | 
			
		||||
	 *            a ULID
 | 
			
		||||
	 */
 | 
			
		||||
	protected static void validate(String ulid) {
 | 
			
		||||
		validate(ulid, false);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Checks if the ULID string is a valid.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * See {@link UlidUtil#validate(String, boolean)}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param ulid
 | 
			
		||||
	 *            a ULID
 | 
			
		||||
	 */
 | 
			
		||||
	protected static void validate(String ulid, boolean strict) {
 | 
			
		||||
		if (!isValid(ulid, strict)) {
 | 
			
		||||
			throw new UlidUtilException(String.format("Invalid ULID: %s.", ulid));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Checks if the string is a valid ULID.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * The validation mode is not strict.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * See {@link UlidUtil#validate(String, boolean)}.
 | 
			
		||||
	 */
 | 
			
		||||
	public static boolean isValid(String ulid) {
 | 
			
		||||
		return isValid(ulid, false);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Checks if the string is a valid ULID.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * <pre>
 | 
			
		||||
	 * Strict validation: checks if the string is in the ULID specification format:
 | 
			
		||||
	 * 
 | 
			
		||||
	 * - 0123456789ABCDEFGHJKMNPKRS (26 alphanumeric, case insensitive, except iI, lL, oO and uU)
 | 
			
		||||
	 * 
 | 
			
		||||
	 * Loose validation: checks if the string is in one of these formats:
 | 
			
		||||
	 *
 | 
			
		||||
	 * - 0123456789ABCDEFGHIJKLMNOP (26 alphanumeric, case insensitive, except uU)
 | 
			
		||||
	 * </pre>
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param ulid
 | 
			
		||||
	 *            a ULID
 | 
			
		||||
	 * @param strict
 | 
			
		||||
	 *            true for strict validation, false for loose validation
 | 
			
		||||
	 * @return boolean true if valid
 | 
			
		||||
	 */
 | 
			
		||||
	public static boolean isValid(String ulid, boolean strict) {
 | 
			
		||||
 | 
			
		||||
		if (ulid == null || ulid.isEmpty()) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		boolean matches = false;
 | 
			
		||||
 | 
			
		||||
		if (strict) {
 | 
			
		||||
			matches = ulid.matches(ULID_PATTERN_STRICT);
 | 
			
		||||
		} else {
 | 
			
		||||
			String u = ulid.replaceAll("-", "");
 | 
			
		||||
			matches = u.matches(ULID_PATTERN_LOOSE);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!matches) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		long timestamp = extractUnixMilliseconds(ulid);
 | 
			
		||||
		return timestamp >= 0 && timestamp <= TIMESTAMP_MAX;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static long extractTimestamp(String ulid) {
 | 
			
		||||
		UlidUtil.validate(ulid);
 | 
			
		||||
		UlidValidator.validate(ulid);
 | 
			
		||||
		return extractUnixMilliseconds(ulid);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -265,12 +44,12 @@ public class UlidUtil {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	public static String extractTimestampComponent(String ulid) {
 | 
			
		||||
		UlidUtil.validate(ulid);
 | 
			
		||||
		UlidValidator.validate(ulid);
 | 
			
		||||
		return ulid.substring(0, 10);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static String extractRandomnessComponent(String ulid) {
 | 
			
		||||
		UlidUtil.validate(ulid);
 | 
			
		||||
		UlidValidator.validate(ulid);
 | 
			
		||||
		return ulid.substring(10, 26);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -278,16 +57,4 @@ public class UlidUtil {
 | 
			
		|||
		String milliseconds = ulid.substring(0, 10);
 | 
			
		||||
		return Base32Util.fromBase32CrockfordAsLong(milliseconds);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static String leftPad(String unpadded) {
 | 
			
		||||
		return "0000000000".substring(unpadded.length()) + unpadded;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static class UlidUtilException extends RuntimeException {
 | 
			
		||||
		private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
		public UlidUtilException(String message) {
 | 
			
		||||
			super(message);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,87 @@
 | 
			
		|||
/*
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 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.util;
 | 
			
		||||
 | 
			
		||||
import com.github.f4b6a3.ulid.exception.InvalidUlidException;
 | 
			
		||||
 | 
			
		||||
public class UlidValidator {
 | 
			
		||||
 | 
			
		||||
	protected static final String ULID_PATTERN = "^[0-9a-tv-zA-TV-Z]{26}$";
 | 
			
		||||
 | 
			
		||||
	// Date: 10889-08-02T05:31:50.655Z
 | 
			
		||||
	protected static final long TIMESTAMP_MAX = (long) Math.pow(2, 48) - 1;
 | 
			
		||||
 | 
			
		||||
	private UlidValidator() {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Checks if the string is a valid ULID.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * A valid ULID string is a sequence of 26 characters from Crockford's base 32
 | 
			
		||||
	 * alphabet.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * Dashes are ignored by this validator.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * <pre>
 | 
			
		||||
	 * Examples of valid ULID strings:
 | 
			
		||||
	 * - 0123456789ABCDEFGHJKMNPKRS (26 alphanumeric, case insensitive, except iI, lL, oO and uU)
 | 
			
		||||
	 * - 0123456789ABCDEFGHIJKLMNOP (26 alphanumeric, case insensitive, except uU)
 | 
			
		||||
	 * - 0123456789-ABCDEFGHJK-MNPKRS (26 alphanumeric, case insensitive, except iI, lL, oO and uU)
 | 
			
		||||
	 * - 0123456789-ABCDEFGHIJ-KLMNOP (26 alphanumeric, case insensitive, except uU, with dashes)
 | 
			
		||||
	 * </pre>
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param ulid a ULID
 | 
			
		||||
	 * @return boolean true if valid
 | 
			
		||||
	 */
 | 
			
		||||
	public static boolean isValid(String ulid) {
 | 
			
		||||
 | 
			
		||||
		if (ulid == null || ulid.isEmpty()) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		String u = ulid.replaceAll("-", "");
 | 
			
		||||
		if (!u.matches(ULID_PATTERN)) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		long timestamp = UlidUtil.extractUnixMilliseconds(ulid);
 | 
			
		||||
		return timestamp >= 0 && timestamp <= TIMESTAMP_MAX;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Checks if the ULID string is a valid.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * See {@link TsidValidator#isValid(String)}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param ulid a ULID string
 | 
			
		||||
	 * @throws InvalidUlidException if invalid
 | 
			
		||||
	 */
 | 
			
		||||
	protected static void validate(String ulid) {
 | 
			
		||||
		if (!isValid(ulid)) {
 | 
			
		||||
			throw new InvalidUlidException(String.format("Invalid ULID: %s.", ulid));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,19 +1,21 @@
 | 
			
		|||
package com.github.f4b6a3;
 | 
			
		||||
package com.github.f4b6a3.ulid;
 | 
			
		||||
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.junit.runners.Suite;
 | 
			
		||||
 | 
			
		||||
import com.github.f4b6a3.ulid.UlidCreatorTest;
 | 
			
		||||
import com.github.f4b6a3.ulid.creator.UlidBasedGuidCreatorTest;
 | 
			
		||||
import com.github.f4b6a3.ulid.timestamp.DefaultTimestampStrategyTest;
 | 
			
		||||
import com.github.f4b6a3.ulid.ulid.UlidCreatorTest;
 | 
			
		||||
import com.github.f4b6a3.ulid.util.UlidConverterTest;
 | 
			
		||||
import com.github.f4b6a3.ulid.util.UlidUtilTest;
 | 
			
		||||
import com.github.f4b6a3.ulid.util.UlidValidatorTest;
 | 
			
		||||
 | 
			
		||||
@RunWith(Suite.class)
 | 
			
		||||
@Suite.SuiteClasses({
 | 
			
		||||
   DefaultTimestampStrategyTest.class,
 | 
			
		||||
   UlidBasedGuidCreatorTest.class,
 | 
			
		||||
   UlidUtilTest.class,
 | 
			
		||||
   UlidCreatorTest.class,
 | 
			
		||||
   UlidBasedGuidCreatorTest.class,
 | 
			
		||||
   UlidConverterTest.class,
 | 
			
		||||
   UlidUtilTest.class,
 | 
			
		||||
   UlidValidatorTest.class,
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
package com.github.f4b6a3;
 | 
			
		||||
package com.github.f4b6a3.ulid;
 | 
			
		||||
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
| 
						 | 
				
			
			@ -6,7 +6,7 @@ import java.util.UUID;
 | 
			
		|||
import com.github.f4b6a3.ulid.UlidCreator;
 | 
			
		||||
import com.github.f4b6a3.ulid.creator.UlidBasedGuidCreator;
 | 
			
		||||
import com.github.f4b6a3.ulid.exception.UlidCreatorException;
 | 
			
		||||
import com.github.f4b6a3.ulid.timestamp.FixedTimestampStretegy;
 | 
			
		||||
import com.github.f4b6a3.ulid.strategy.timestamp.FixedTimestampStretegy;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
package com.github.f4b6a3;
 | 
			
		||||
package com.github.f4b6a3.ulid.bench;
 | 
			
		||||
 | 
			
		||||
// Add theese dependencies to pom.xml:
 | 
			
		||||
//
 | 
			
		||||
| 
						 | 
				
			
			@ -7,7 +7,7 @@ import org.junit.Test;
 | 
			
		|||
 | 
			
		||||
import com.github.f4b6a3.commons.random.Xorshift128PlusRandom;
 | 
			
		||||
import com.github.f4b6a3.ulid.exception.UlidCreatorException;
 | 
			
		||||
import com.github.f4b6a3.ulid.timestamp.FixedTimestampStretegy;
 | 
			
		||||
import com.github.f4b6a3.ulid.strategy.timestamp.FixedTimestampStretegy;
 | 
			
		||||
 | 
			
		||||
import static org.junit.Assert.*;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
package com.github.f4b6a3.demo;
 | 
			
		||||
package com.github.f4b6a3.ulid.demo;
 | 
			
		||||
 | 
			
		||||
import com.github.f4b6a3.ulid.UlidCreator;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -10,7 +10,7 @@ public class DemoTest {
 | 
			
		|||
		int max = 100;
 | 
			
		||||
 | 
			
		||||
		System.out.println(HORIZONTAL_LINE);
 | 
			
		||||
		System.out.println("### ULID");
 | 
			
		||||
		System.out.println("### ULID string");
 | 
			
		||||
		System.out.println(HORIZONTAL_LINE);
 | 
			
		||||
 | 
			
		||||
		for (int i = 0; i < max; i++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ public class DemoTest {
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		System.out.println(HORIZONTAL_LINE);
 | 
			
		||||
		System.out.println("### GUID");
 | 
			
		||||
		System.out.println("### ULID-based GUID");
 | 
			
		||||
		System.out.println(HORIZONTAL_LINE);
 | 
			
		||||
 | 
			
		||||
		for (int i = 0; i < max; i++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1,12 +0,0 @@
 | 
			
		|||
package com.github.f4b6a3.ulid.timestamp;
 | 
			
		||||
 | 
			
		||||
import static org.junit.Assert.assertTrue;
 | 
			
		||||
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
public class DefaultTimestampStrategyTest {
 | 
			
		||||
	@Test
 | 
			
		||||
	public void testVoid() {
 | 
			
		||||
		assertTrue("void test", true);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
package com.github.f4b6a3.ulid;
 | 
			
		||||
package com.github.f4b6a3.ulid.ulid;
 | 
			
		||||
 | 
			
		||||
import org.junit.BeforeClass;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
| 
						 | 
				
			
			@ -6,6 +6,7 @@ import org.junit.Test;
 | 
			
		|||
import com.github.f4b6a3.ulid.UlidCreator;
 | 
			
		||||
import com.github.f4b6a3.ulid.creator.UlidBasedGuidCreator;
 | 
			
		||||
import com.github.f4b6a3.ulid.util.UlidUtil;
 | 
			
		||||
import com.github.f4b6a3.ulid.util.UlidValidator;
 | 
			
		||||
 | 
			
		||||
import static org.junit.Assert.*;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
| 
						 | 
				
			
			@ -54,7 +55,7 @@ public class UlidCreatorTest {
 | 
			
		|||
			assertTrue("ULID is null", ulid != null);
 | 
			
		||||
			assertTrue("ULID is empty", !ulid.isEmpty());
 | 
			
		||||
			assertTrue("ULID length is wrong ", ulid.length() == ULID_LENGTH);
 | 
			
		||||
			assertTrue("ULID is not valid", UlidUtil.isValid(ulid, /* strict */ true));
 | 
			
		||||
			assertTrue("ULID is not valid", UlidValidator.isValid(ulid));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,35 @@
 | 
			
		|||
package com.github.f4b6a3.ulid.util;
 | 
			
		||||
 | 
			
		||||
import static org.junit.Assert.*;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import com.github.f4b6a3.ulid.UlidCreator;
 | 
			
		||||
import com.github.f4b6a3.ulid.util.UlidConverter;
 | 
			
		||||
import com.github.f4b6a3.ulid.util.UlidValidator;
 | 
			
		||||
 | 
			
		||||
public class UlidConverterTest {
 | 
			
		||||
 | 
			
		||||
	private static final int ULID_LENGTH = 26;
 | 
			
		||||
	private static final int DEFAULT_LOOP_MAX = 100_000;
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void testToAndFromUlid() {
 | 
			
		||||
 | 
			
		||||
		for (int i = 0; i < DEFAULT_LOOP_MAX; i++) {
 | 
			
		||||
 | 
			
		||||
			UUID uuid1 = UlidCreator.getUlid();
 | 
			
		||||
			String ulid = UlidConverter.toString(uuid1);
 | 
			
		||||
 | 
			
		||||
			assertTrue("ULID is null", ulid != null);
 | 
			
		||||
			assertTrue("ULID is empty", !ulid.isEmpty());
 | 
			
		||||
			assertTrue("ULID length is wrong ", ulid.length() == ULID_LENGTH);
 | 
			
		||||
			assertTrue("ULID is not valid", UlidValidator.isValid(ulid));
 | 
			
		||||
 | 
			
		||||
			UUID uuid2 = UlidConverter.fromString(ulid);
 | 
			
		||||
			assertEquals("Result ULID is different from original ULID", uuid1, uuid2);
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2,14 +2,13 @@ package com.github.f4b6a3.ulid.util;
 | 
			
		|||
 | 
			
		||||
import static org.junit.Assert.*;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import com.github.f4b6a3.ulid.util.UlidUtil.UlidUtilException;
 | 
			
		||||
import com.github.f4b6a3.commons.util.Base32Util;
 | 
			
		||||
import com.github.f4b6a3.commons.util.ByteUtil;
 | 
			
		||||
import com.github.f4b6a3.ulid.UlidCreator;
 | 
			
		||||
import com.github.f4b6a3.ulid.exception.InvalidUlidException;
 | 
			
		||||
import com.github.f4b6a3.ulid.util.UlidUtil;
 | 
			
		||||
 | 
			
		||||
public class UlidUtilTest {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -19,13 +18,10 @@ public class UlidUtilTest {
 | 
			
		|||
 | 
			
		||||
	private static final long TIMESTAMP_MAX = 281474976710655l; // 2^48 - 1
 | 
			
		||||
 | 
			
		||||
	private static final int ULID_LENGTH = 26;
 | 
			
		||||
	private static final int DEFAULT_LOOP_MAX = 100_000;
 | 
			
		||||
 | 
			
		||||
	private static final String[] EXAMPLE_DATES = { "1970-01-01T00:00:00.000Z", "1985-10-26T01:16:00.123Z",
 | 
			
		||||
			"2001-09-09T01:46:40.456Z", "2020-01-15T14:30:33.789Z", "2038-01-19T03:14:07.321Z" };
 | 
			
		||||
 | 
			
		||||
	@Test(expected = UlidUtilException.class)
 | 
			
		||||
	@Test(expected = InvalidUlidException.class)
 | 
			
		||||
	public void testExtractTimestamp() {
 | 
			
		||||
 | 
			
		||||
		String ulid = "0000000000" + EXAMPLE_RANDOMNESS;
 | 
			
		||||
| 
						 | 
				
			
			@ -95,155 +91,6 @@ public class UlidUtilTest {
 | 
			
		|||
		assertEquals(expected, result);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void testIsValidLoose() {
 | 
			
		||||
 | 
			
		||||
		String ulid = null; // Null
 | 
			
		||||
		assertFalse("Null ULID should be invalid.", UlidUtil.isValid(ulid));
 | 
			
		||||
 | 
			
		||||
		ulid = ""; // length: 0
 | 
			
		||||
		assertFalse("ULID with empty string should be invalid.", UlidUtil.isValid(ulid));
 | 
			
		||||
 | 
			
		||||
		ulid = EXAMPLE_ULID; // All upper case
 | 
			
		||||
		assertTrue("Ulid in upper case should valid.", UlidUtil.isValid(ulid));
 | 
			
		||||
 | 
			
		||||
		ulid = "0123456789abcdefghjklmnpqr"; // All lower case
 | 
			
		||||
		assertTrue("ULID in lower case should be valid.", UlidUtil.isValid(ulid));
 | 
			
		||||
 | 
			
		||||
		ulid = "0123456789AbCdEfGhJkMnPqRs"; // Mixed case
 | 
			
		||||
		assertTrue("Ulid in upper and lower case should valid.", UlidUtil.isValid(ulid));
 | 
			
		||||
 | 
			
		||||
		ulid = "0123456789ABCDEFGHJKLMNPQ"; // length: 25
 | 
			
		||||
		assertFalse("ULID length lower than 26 should be invalid.", UlidUtil.isValid(ulid));
 | 
			
		||||
 | 
			
		||||
		ulid = "0123456789ABCDEFGHJKMNPQZZZ"; // length: 27
 | 
			
		||||
		assertFalse("ULID length greater than 26 should be invalid.", UlidUtil.isValid(ulid));
 | 
			
		||||
 | 
			
		||||
		ulid = "u123456789ABCDEFGHJKMNPQRS"; // Letter u
 | 
			
		||||
		assertFalse("ULID with 'u' or 'U' should be invalid.", UlidUtil.isValid(ulid));
 | 
			
		||||
 | 
			
		||||
		ulid = "#123456789ABCDEFGHJKMNPQRS"; // Special char
 | 
			
		||||
		assertFalse("ULID with special chars should be invalid.", UlidUtil.isValid(ulid));
 | 
			
		||||
 | 
			
		||||
		ulid = "01234-56789-ABCDEFGHJKMNPQRS"; // Hiphens
 | 
			
		||||
		assertTrue("ULID with hiphens should be valid.", UlidUtil.isValid(ulid));
 | 
			
		||||
 | 
			
		||||
		ulid = "8ZZZZZZZZZABCDEFGHJKMNPQRS"; // timestamp > (2^48)-1
 | 
			
		||||
		assertFalse("ULID with timestamp greater than (2^48)-1 should be invalid.", UlidUtil.isValid(ulid));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void testIsValidStrict() {
 | 
			
		||||
		boolean strict = true;
 | 
			
		||||
 | 
			
		||||
		String ulid = null; // Null
 | 
			
		||||
		assertFalse("Null ULID should be invalid in strict mode.", UlidUtil.isValid(ulid, strict));
 | 
			
		||||
 | 
			
		||||
		ulid = ""; // length: 0
 | 
			
		||||
		assertFalse("ULID with empty string should be invalid  in strict mode.", UlidUtil.isValid(ulid, strict));
 | 
			
		||||
 | 
			
		||||
		ulid = EXAMPLE_ULID; // All upper case
 | 
			
		||||
		assertTrue("ULID in upper case should valid in strict mode.", UlidUtil.isValid(ulid, strict));
 | 
			
		||||
 | 
			
		||||
		ulid = "0123456789abcdefghjkmnpqrs"; // All lower case
 | 
			
		||||
		assertTrue("ULID in lower case should be valid in strict mode.", UlidUtil.isValid(ulid, strict));
 | 
			
		||||
 | 
			
		||||
		ulid = "0123456789AbCdEfGhJkMnPqRs"; // Mixed case
 | 
			
		||||
		assertTrue("ULID in upper and lower case should valid in strict mode.", UlidUtil.isValid(ulid, strict));
 | 
			
		||||
 | 
			
		||||
		ulid = "0123456789ABCDEFGHJKLMNPQ"; // length: 25
 | 
			
		||||
		assertFalse("ULID length lower than 26 should be invalid in strict mode.", UlidUtil.isValid(ulid, strict));
 | 
			
		||||
 | 
			
		||||
		ulid = "0123456789ABCDEFGHJKMNPQZZZ"; // length: 27
 | 
			
		||||
		assertFalse("ULID length greater than 26 should be invalid in strict mode.", UlidUtil.isValid(ulid, strict));
 | 
			
		||||
 | 
			
		||||
		ulid = "i123456789ABCDEFGHJKMNPQRS"; // Letter i
 | 
			
		||||
		assertFalse("ULID with 'i' or 'I' should be invalid in strict mode.", UlidUtil.isValid(ulid, strict));
 | 
			
		||||
 | 
			
		||||
		ulid = "L123456789ABCDEFGHJKMNPQRS"; // letter L
 | 
			
		||||
		assertFalse("ULID with 'l' or 'L' should be invalid in strict mode.", UlidUtil.isValid(ulid, strict));
 | 
			
		||||
 | 
			
		||||
		ulid = "o123456789ABCDEFGHJKMNPQRS"; // letter o
 | 
			
		||||
		assertFalse("ULID with 'o' or 'O' should be invalid in strict mode.", UlidUtil.isValid(ulid, strict));
 | 
			
		||||
 | 
			
		||||
		ulid = "u123456789ABCDEFGHJKMNPQRS"; // letter u
 | 
			
		||||
		assertFalse("ULID with 'u' or 'U' should be invalid in strict mode.", UlidUtil.isValid(ulid, strict));
 | 
			
		||||
 | 
			
		||||
		ulid = "#123456789ABCDEFGHJKMNPQRS"; // Special char
 | 
			
		||||
		assertFalse("ULID with special chars should be invalid in strict mode.", UlidUtil.isValid(ulid, strict));
 | 
			
		||||
 | 
			
		||||
		ulid = "01234-56789-ABCDEFGHJKMNPQRS"; // Hyphens
 | 
			
		||||
		assertFalse("ULID with hiphens should be invalid in strict mode.", UlidUtil.isValid(ulid, strict));
 | 
			
		||||
 | 
			
		||||
		ulid = "8ZZZZZZZZZABCDEFGHJKMNPQRS"; // timestamp > (2^48)-1
 | 
			
		||||
		assertFalse("ULID with timestamp greater than (2^48)-1 should be invalid.", UlidUtil.isValid(ulid));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void testToAndFromUlid() {
 | 
			
		||||
 | 
			
		||||
		for (int i = 0; i < DEFAULT_LOOP_MAX; i++) {
 | 
			
		||||
 | 
			
		||||
			UUID uuid1 = UlidCreator.getUlid();
 | 
			
		||||
			String ulid = UlidUtil.fromUuidToUlid(uuid1);
 | 
			
		||||
 | 
			
		||||
			assertTrue("ULID is null", ulid != null);
 | 
			
		||||
			assertTrue("ULID is empty", !ulid.isEmpty());
 | 
			
		||||
			assertTrue("ULID length is wrong ", ulid.length() == ULID_LENGTH);
 | 
			
		||||
			assertTrue("ULID is not valid", UlidUtil.isValid(ulid, /* strict */
 | 
			
		||||
					true));
 | 
			
		||||
 | 
			
		||||
			UUID uuid2 = UlidUtil.fromUlidToUuid(ulid);
 | 
			
		||||
			assertEquals("Result ULID is different from original ULID", uuid1, uuid2);
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void testToAndFromBytes() {
 | 
			
		||||
		for (int i = 0; i < DEFAULT_LOOP_MAX; i++) {
 | 
			
		||||
			String ulid1 = UlidCreator.getUlidString();
 | 
			
		||||
			byte[] bytes = UlidUtil.fromUlidToBytes(ulid1);
 | 
			
		||||
			String ulid2 = UlidUtil.fromBytesToUlid(bytes);
 | 
			
		||||
 | 
			
		||||
			// Check ULID 1
 | 
			
		||||
			assertTrue(ulid1 != null);
 | 
			
		||||
			assertTrue(!ulid1.isEmpty());
 | 
			
		||||
			assertTrue(ulid1.length() == ULID_LENGTH);
 | 
			
		||||
			assertTrue(UlidUtil.isValid(ulid1, /* strict */ true));
 | 
			
		||||
 | 
			
		||||
			// Check ULID 2
 | 
			
		||||
			assertTrue(ulid2 != null);
 | 
			
		||||
			assertTrue(!ulid2.isEmpty());
 | 
			
		||||
			assertTrue(ulid2.length() == ULID_LENGTH);
 | 
			
		||||
			assertTrue(UlidUtil.isValid(ulid2, /* strict */ true));
 | 
			
		||||
 | 
			
		||||
			assertEquals(ulid1, ulid2);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void testFromUuidToBytes() {
 | 
			
		||||
		for (int i = 0; i < DEFAULT_LOOP_MAX; i++) {
 | 
			
		||||
			UUID uuid1 = UlidCreator.getUlid();
 | 
			
		||||
			byte[] bytes = UlidUtil.fromUuidToBytes(uuid1);
 | 
			
		||||
			long msb = ByteUtil.toNumber(ByteUtil.copy(bytes, 0, 8));
 | 
			
		||||
			long lsb = ByteUtil.toNumber(ByteUtil.copy(bytes, 8, 16));
 | 
			
		||||
			UUID uuid2 = new UUID(msb, lsb);
 | 
			
		||||
			assertEquals(uuid1, uuid2);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void testFromBytesToUuid() {
 | 
			
		||||
		for (int i = 0; i < DEFAULT_LOOP_MAX; i++) {
 | 
			
		||||
			UUID uuid1 = UlidCreator.getUlid();
 | 
			
		||||
			byte[] bytes = UlidUtil.fromUuidToBytes(uuid1);
 | 
			
		||||
			UUID uuid2 = UlidUtil.fromBytesToUuid(bytes);
 | 
			
		||||
			assertEquals(uuid1, uuid2);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private String leftPad(String unpadded) {
 | 
			
		||||
		return "0000000000".substring(unpadded.length()) + unpadded;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,47 @@
 | 
			
		|||
package com.github.f4b6a3.ulid.util;
 | 
			
		||||
 | 
			
		||||
import static org.junit.Assert.*;
 | 
			
		||||
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import com.github.f4b6a3.ulid.util.UlidValidator;
 | 
			
		||||
 | 
			
		||||
public class UlidValidatorTest {
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void testIsValidStrict() {
 | 
			
		||||
 | 
			
		||||
		String ulid = null; // Null
 | 
			
		||||
		assertFalse("Null ULID should be invalid.", UlidValidator.isValid(ulid));
 | 
			
		||||
 | 
			
		||||
		ulid = ""; // length: 0
 | 
			
		||||
		assertFalse("ULID with empty string should be invalid .", UlidValidator.isValid(ulid));
 | 
			
		||||
 | 
			
		||||
		ulid = "0123456789ABCDEFGHJKMNPQRS"; // All upper case
 | 
			
		||||
		assertTrue("ULID in upper case should valid.", UlidValidator.isValid(ulid));
 | 
			
		||||
 | 
			
		||||
		ulid = "0123456789abcdefghjklmnpqr"; // All lower case
 | 
			
		||||
		assertTrue("ULID in lower case should be valid.", UlidValidator.isValid(ulid));
 | 
			
		||||
 | 
			
		||||
		ulid = "0123456789AbCdEfGhJkMnPqRs"; // Mixed case
 | 
			
		||||
		assertTrue("Ulid in upper and lower case should valid.", UlidValidator.isValid(ulid));
 | 
			
		||||
 | 
			
		||||
		ulid = "0123456789ABCDEFGHJKLMNPQ"; // length: 25
 | 
			
		||||
		assertFalse("ULID length lower than 26 should be invalid.", UlidValidator.isValid(ulid));
 | 
			
		||||
 | 
			
		||||
		ulid = "0123456789ABCDEFGHJKMNPQZZZ"; // length: 27
 | 
			
		||||
		assertFalse("ULID length greater than 26 should be invalid.", UlidValidator.isValid(ulid));
 | 
			
		||||
 | 
			
		||||
		ulid = "u123456789ABCDEFGHJKMNPQRS"; // Letter u
 | 
			
		||||
		assertFalse("ULID with 'u' or 'U' should be invalid.", UlidValidator.isValid(ulid));
 | 
			
		||||
 | 
			
		||||
		ulid = "#123456789ABCDEFGHJKMNPQRS"; // Special char
 | 
			
		||||
		assertFalse("ULID with special chars should be invalid.", UlidValidator.isValid(ulid));
 | 
			
		||||
 | 
			
		||||
		ulid = "01234-56789-ABCDEFGHJKMNPQRS"; // Hyphens
 | 
			
		||||
		assertTrue("ULID with hiphens should be valid.", UlidValidator.isValid(ulid));
 | 
			
		||||
 | 
			
		||||
		ulid = "8ZZZZZZZZZABCDEFGHJKMNPQRS"; // timestamp > (2^48)-1
 | 
			
		||||
		assertFalse("ULID with timestamp greater than (2^48)-1 should be invalid.", UlidValidator.isValid(ulid));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue