/*
* Copyright (c) 2014 tabletoptool.com team.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*
* Contributors:
* rptools.com team - initial implementation
* tabletoptool.com team - further development
*/
package com.t3.guid;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import com.t3.xstreamversioned.version.SerializationVersion;
/**
* Global unique identificator object.
*/
@SerializationVersion(0)
public class GUID extends Object implements Serializable, Comparable<GUID> {
/** Serial version unique identifier. */
private static final long serialVersionUID = 6361057925697403643L;
/** GUIDs always have 16 bytes. */
public static final int GUID_LENGTH = 16;
// NOTE: THIS CAN NEVER BE CHANGED, OR IT WILL AFFECT ALL THINGS THAT PREVIOUSLY USED IT
public static final int GUID_BUCKETS = 100;
// NOTE: THIS CAN NEVER BE CHANGED, OR IT WILL AFFECT ALL THINGS THAT PREVIOUSLY USED IT
private byte[] baGUID;
static byte[] ip;
static {
try {
InetAddress id = InetAddress.getLocalHost();
ip = id.getAddress(); // 192.168.0.14
} catch (UnknownHostException e) {
// Default to something known
ip = new byte[]{127, 0, 0, 1};
}
}
// Cache of the hashCode for a GUID
private transient int hash;
public GUID() {
this.baGUID = generateGUID();
validateGUID();
}
/** Creates a new GUID based on the specified GUID value. */
public GUID(byte[] baGUID) throws InvalidGUIDException {
this.baGUID = baGUID;
validateGUID();
}
/** Creates a new GUID based on the specified hexadecimal-code string. */
public GUID(String strGUID) {
if (strGUID == null) throw new InvalidGUIDException("GUID is null");
try {
this.baGUID = Hex.decodeHex(strGUID.toCharArray());
} catch (DecoderException e) {
throw new Error(e);
}
validateGUID();
}
/** Ensures the GUID is legal. */
private void validateGUID() throws InvalidGUIDException {
if (baGUID == null) throw new InvalidGUIDException("GUID is null");
if (baGUID.length != GUID_LENGTH) throw new InvalidGUIDException("GUID length is invalid");
}
/** Returns the GUID representation of the {@link byte} array argument. */
public static GUID valueOf(byte[] bits) {
if (bits == null) return null;
return new GUID(bits);
}
/** Returns the GUID representation of the {@link String} argument. */
public static GUID valueOf(String s) {
if (s == null) return null;
return new GUID(s);
}
/** Determines whether two GUIDs are equal. */
@Override
public boolean equals(Object object) {
if (object == null) {
return this == null;
}
Class<?> objClass = object.getClass();
GUID guid;
try {
if (objClass == String.class) { // string
guid = new GUID((String)object);
} else { // try to cast to a GUID
guid = (GUID)object;
}
} catch (ClassCastException e) { // not a GUID
return false;
}
// Compare bytes.
for (int i = 0; i < GUID_LENGTH; i++) {
if (this.baGUID[i] != guid.baGUID[i])
return false;
}
// All tests pass.
return true;
}
public byte[] getBytes() { return baGUID; }
/** Returns a string for the GUID. */
@Override
public String toString() {
return Hex.encodeHexString(baGUID);
}
/**
* Returns a hashcode for this GUID. This function is based on the algorithm that JDK 1.3 uses for a String.
* @return a hash code value for this object.
*/
@Override
public int hashCode() {
int h = hash;
if (h == 0) {
byte val[] = baGUID;
int len = GUID_LENGTH;
for (int i = 0; i < len; i++)
h = 31*h + val[i];
hash = h;
}
return h;
}
private static long guidGenerationCounter = 0;
public static byte[] generateGUID() throws InvalidGUIDException{
byte[] guid = new byte[16];
System.currentTimeMillis();
long time = System.currentTimeMillis();
guidGenerationCounter++;
int n = 0;
guid[n++] = ip[0];
guid[n++] = ip[1];
guid[n++] = ip[2];
guid[n++] = ip[3];
guid[n++] = (byte) (time & 0xFF);
guid[n++] = (byte) (time >> 8 & 0xFF);
guid[n++] = (byte) (time >> 16 & 0xFF);
guid[n++] = (byte) (time >> 24 & 0xFF);
guid[n++] = (byte) (guidGenerationCounter & 0xFF);
guid[n++] = (byte) (guidGenerationCounter >> 8 & 0xFF);
guid[n++] = (byte) (guidGenerationCounter >> 16 & 0xFF);
guid[n++] = (byte) (guidGenerationCounter >> 24 & 0xFF);
guid[n++] = (byte) ((time >> 24 & 0xFF) & ip[0]);
guid[n++] = (byte) ((time >> 16 & 0xFF) & ip[1]);
guid[n++] = (byte) ((time >> 8 & 0xFF) & ip[2]);
guid[n++] = (byte) ((time >> 0 & 0xFF) & ip[3]);
return guid;
}
public static void main(String[] args) throws Exception {
for (int i = 0; i < 10; i++) {
GUID guid = new GUID();
//System.out.println("insert into sys_guids values ('" + guid.toString() + "');");
System.out.println(guid.toString());
}
}
@Override
public int compareTo(GUID o) {
if (o != this) {
for (int i = 0; i < GUID_LENGTH; i++) {
if (this.baGUID[i] != o.baGUID[i])
return this.baGUID[i] - o.baGUID[i];
}
}
return 0;
}
}