UniqueId.java

package org.microspace.util;

import java.io.Serializable;
import java.util.concurrent.atomic.AtomicLong;

/**
 * A UniqueId that is ideal for a primary key Index.
 * <ol>
 *  <li>It does not need to be seeded. Works with MAC address. </li>
 *  <li>It works across virtual machines, even when started at the same time.</li>
 *  <li>It uses a long start up time allowing 1ms server restarts.</li>
 *  <li>It uses a long sequence part allowing for more unique ids to be generated.</li>
 * </ol>
 * <p>
 * You can only fool this unique id if two classloaders in one jvm load 
 * this class at the same millisecond.
 * @author gaspar.sinai at microspace.org
 * @version 2016-06-20
 *
 */
public final class UniqueId implements Comparable<UniqueId>, Serializable {

	private static final long serialVersionUID = -2399508564638750854L;

	String value;
	
	private static AtomicLong sequencePart = new AtomicLong();

	private static UniqueIdSeed seed;
	private static String macAddressString;
	
	static {
		seed = new UniqueIdSeed();
		StringBuffer sb = new StringBuffer();
		for (byte b : seed.getMacAddress()) {
			sb.append(String.format("%02x", b));
		}
		macAddressString = sb.toString();
	}
	
	public UniqueId () {
		long sequence = sequencePart.incrementAndGet();
		value = String.format("%s-%x-%x-%x", macAddressString, seed.getProcessId(), seed.getTime(), sequence);
	}
	
	public static String getSeedPart () {
		return String.format("%s-%x-%x", macAddressString, seed.getProcessId(), seed.getTime());
	}
	
	public UniqueId (String value) {
		if (value == null) {
			throw new NullPointerException ("String value null");
		}
		this.value = value;
	}
	
	public static String newString () {
		UniqueId id = new UniqueId();
		return id.toString();
	}
	
	
	public UniqueIdSeed getUniqueIdSeed() {
		new UniqueId();
		return seed;
	}
	
	@Override
	public String toString () {
		return value;
	}
	
	public String getValue() {
		return value;
	}

	@Override
	public int hashCode() {
		return toString().hashCode();
	}
	@Override
	public boolean equals (Object o) {
		if (o==null) return false;
		if (!(o instanceof UniqueId)) return false;
		return toString().equals(((UniqueId)o).toString());
	}
	@Override
	public int compareTo(UniqueId o) {
		if (o==null) return Integer.MAX_VALUE;
		return toString().compareTo (o.toString());
	}
}