package com.yihu.hos.common; import java.io.Serializable; import java.security.SecureRandom; import java.util.Date; import java.util.concurrent.atomic.AtomicInteger; /** * @author HZY * @vsrsion 1.0 * Created at 2016/8/8. */ public final class ObjectVersion implements Comparable, Serializable { private static final long serialVersionUID = 789056789654456072L; private static final int BYTE_ARRAY_LENGTH = 6; private static final AtomicInteger NEXT_COUNTER = new AtomicInteger((new SecureRandom()).nextInt()); private static final char[] HEX_CHARS = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; private final int timestamp; private final short counter; public static boolean isValid(String hexString) { if(hexString == null) { throw new IllegalArgumentException(); } else { int len = hexString.length(); if(len != 12) { return false; } else { for(int i = 0; i < len; ++i) { char c = hexString.charAt(i); if((c < 48 || c > 57) && (c < 97 || c > 102) && (c < 65 || c > 70)) { return false; } } return true; } } } public static int getCurrentCounter() { return NEXT_COUNTER.get(); } public ObjectVersion() { this(new Date()); } public ObjectVersion(Date date) { this(dateToTimestampSeconds(date), (short)NEXT_COUNTER.getAndIncrement()); } public ObjectVersion(Date date, short counter) { this(dateToTimestampSeconds(date), counter); } public ObjectVersion(int timestamp, short counter) { this.timestamp = timestamp; this.counter = counter; } public ObjectVersion(String hexString) { this(parseHexString(hexString)); } public ObjectVersion(byte[] bytes) { if(bytes == null) { throw new IllegalArgumentException(); } else if(bytes.length != 6) { throw new IllegalArgumentException("need 6 bytes"); } else { this.timestamp = makeInt(bytes[0], bytes[1], bytes[2], bytes[3]); this.counter = (short)makeInt((byte)0, (byte)0, bytes[4], bytes[5]); } } public byte[] toByteArray() { byte[] bytes = new byte[]{int3(this.timestamp), int2(this.timestamp), int1(this.timestamp), int0(this.timestamp), int1(this.counter), int0(this.counter)}; return bytes; } public Date getDate() { return new Date((long)this.timestamp * 1000L); } public int getTimestamp() { return this.timestamp; } public short getCounter() { return this.counter; } public String toHexString() { char[] chars = new char[12]; int i = 0; byte[] var3 = this.toByteArray(); int var4 = var3.length; for(int var5 = 0; var5 < var4; ++var5) { byte b = var3[var5]; chars[i++] = HEX_CHARS[b >> 4 & 15]; chars[i++] = HEX_CHARS[b & 15]; } return new String(chars); } public boolean equals(Object o) { if(this == o) { return true; } else if(o != null && this.getClass() == o.getClass()) { ObjectVersion objectId = (ObjectVersion)o; return this.counter != objectId.counter?false:this.timestamp == objectId.timestamp; } else { return false; } } public int hashCode() { int result = this.timestamp; result = 31 * result + this.counter; return result; } public int compareTo(ObjectVersion other) { if(other == null) { throw new NullPointerException(); } else { byte[] byteArray = this.toByteArray(); byte[] otherByteArray = other.toByteArray(); for(int i = 0; i < 6; ++i) { if(byteArray[i] != otherByteArray[i]) { return (byteArray[i] & 255) < (otherByteArray[i] & 255)?-1:1; } } return 0; } } public String toString() { return this.toHexString(); } private static byte[] parseHexString(String s) { if(!isValid(s)) { throw new IllegalArgumentException("invalid hexadecimal representation of an ObjectId: [" + s + "]"); } else { byte[] b = new byte[6]; for(int i = 0; i < b.length; ++i) { b[i] = (byte)Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16); } return b; } } private static int dateToTimestampSeconds(Date time) { return (int)(time.getTime() / 1000L); } private static int makeInt(byte b3, byte b2, byte b1, byte b0) { return b3 << 24 | (b2 & 255) << 16 | (b1 & 255) << 8 | b0 & 255; } private static byte int3(int x) { return (byte)(x >> 24); } private static byte int2(int x) { return (byte)(x >> 16); } private static byte int1(int x) { return (byte)(x >> 8); } private static byte int0(int x) { return (byte)x; } }