package org.opensource.clearpool.jta.xa; import java.nio.ByteBuffer; import java.security.SecureRandom; import java.util.Arrays; import java.util.Calendar; import java.util.UUID; import java.util.concurrent.atomic.AtomicLong; import javax.transaction.xa.Xid; /** * XidImpl used to represent a global unique transaction. * * @author xionghui * @date 16.08.2014 * @version 1.0 */ public final class XidImpl implements Xid { private static final int FORMAT_ID = 0xffff; private static final AtomicLong UNIQUE_LONG = new AtomicLong(); private static final SecureRandom SECURE_RANDOM = new SecureRandom(); // cache the hash code for Xid private int hash; byte[] bqual; int formatId; byte[] gtrid; public XidImpl() { this.bqual = this.buildUnique(); this.gtrid = this.buildUnique(); this.formatId = FORMAT_ID; } public XidImpl(Xid xid) { byte[] anoBqual = xid.getBranchQualifier(); byte[] anoGtrid = xid.getGlobalTransactionId(); this.bqual = Arrays.copyOf(anoBqual, anoBqual.length); this.gtrid = Arrays.copyOf(anoGtrid, anoGtrid.length); this.formatId = xid.getFormatId(); } public XidImpl(byte[] bqual, int formatId, byte[] gtrid) { this.bqual = Arrays.copyOf(bqual, bqual.length); this.gtrid = Arrays.copyOf(gtrid, gtrid.length); this.formatId = formatId; } /** * Build a unique bytes:year+UUID+unique_long. */ private byte[] buildUnique() { ByteBuffer uuidBys = ByteBuffer.allocate(24); int year = Calendar.getInstance().get(Calendar.YEAR); uuidBys.putLong(year); long ul = UNIQUE_LONG.getAndIncrement(); uuidBys.putLong(ul); uuidBys.putLong(SECURE_RANDOM.nextLong()); return uuidBys.array(); } public static void main(String[] args) { String str = UUID.randomUUID().toString(); char[] chs = UUID.randomUUID().toString().toCharArray(); System.out.print(str + " " + chs.length); } @Override public byte[] getBranchQualifier() { return this.bqual; } @Override public int getFormatId() { return this.formatId; } @Override public byte[] getGlobalTransactionId() { return this.gtrid; } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof XidImpl) { XidImpl anoXid = (XidImpl) obj; if (this.formatId == anoXid.formatId) { if (this.checkBytesEquals(this.bqual, anoXid.bqual)) { if (this.checkBytesEquals(this.gtrid, anoXid.gtrid)) { return true; } } } } return false; } /** * Check if byte[] is equaled */ private boolean checkBytesEquals(byte[] b1, byte[] b2) { int len = b1.length; if (len == b2.length) { for (int i = 0; i < len; i++) { if (b1[i] != b2[i]) { return false; } } return true; } return false; } @Override public int hashCode() { if (this.hash == 0) { int h = this.formatId; for (int i = 0, len = this.bqual.length; i < len; i++) { h = 31 * h + this.bqual[i]; } for (int i = 0, len = this.gtrid.length; i < len; i++) { h = 31 * h + this.gtrid[i]; } this.hash = h; } return this.hash; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("{formatId:"); builder.append(this.formatId); builder.append("\n"); builder.append("bqual:"); this.formatBytes(this.bqual, builder); builder.append("\n"); builder.append("gtrid:"); this.formatBytes(this.gtrid, builder); builder.append("}"); return builder.toString(); } /** * Format the byte array. */ private void formatBytes(byte[] bytes, StringBuilder builder) { builder.append("["); for (byte b : bytes) { builder.append(b); builder.append(","); } builder.deleteCharAt(builder.length() - 1); builder.append("]"); } }