/** * Alipay.com Inc. * Copyright (c) 2004-2012 All Rights Reserved. */ package com.alipay.zdal.datasource.tm; import java.io.IOException; import javax.transaction.xa.Xid; /** * This object encapsulates the global transaction ID of a transaction. * It is similar to an Xid, but holds only the GlobalId part. * This implementation is immutable and always serializable at runtime. * * @author ���� * @version $Id: GlobalId.java, v 0.1 2014-1-6 ����05:46:36 Exp $ */ public class GlobalId implements java.io.Externalizable { static final long serialVersionUID = 6879509375433435464L; /** * Format id of this instance. */ private int formatId; /** * Global transaction id of this instance. * The coding of this class depends on the fact that this variable is * initialized in the constructor and never modified. References to * this array are never given away, instead a clone is delivered. */ private byte[] globalId; /** * Hash code of this instance. For a native GlobalId (one whose formatId * is XidImpl.JBOSS_FORMAT_ID), this is really a sequence number. */ private int hash; // Constructors -------------------------------------------------- public GlobalId() { // Used for Externalizable support } /** * Create a new instance. This constructor is package-private, as it * trusts the hash parameter to be good. */ GlobalId(int formatId, byte[] globalId, int hash) { this.formatId = formatId; this.globalId = globalId; this.hash = hash; } /** * Create a new instance. This constructor is public <em>only</em> * to get around a class loader problem; it should be package-private. */ public GlobalId(int formatId, byte[] globalId) { this.formatId = formatId; this.globalId = globalId; hash = computeHash(); } public GlobalId(Xid xid) { formatId = xid.getFormatId(); globalId = xid.getGlobalTransactionId(); if (xid instanceof XidImpl && formatId == XidImpl.JBOSS_FORMAT_ID) { // native GlobalId: use its hash code (a sequence number) hash = xid.hashCode(); } else { // foreign GlobalId: do the hash computation hash = computeHash(); } } public GlobalId(int formatId, int bqual_length, byte[] tid) { this.formatId = formatId; if (bqual_length == 0) globalId = tid; else { int len = tid.length - bqual_length; globalId = new byte[len]; System.arraycopy(tid, 0, globalId, 0, len); } hash = computeHash(); } // Public -------------------------------------------------------- /** * Compare for equality. * * Instances are considered equal if they both refer to the same * global transaction id. */ public boolean equals(Object obj) { if (obj instanceof GlobalId) { GlobalId other = (GlobalId) obj; if (formatId != other.formatId) return false; if (globalId == other.globalId) return true; if (globalId.length != other.globalId.length) return false; int len = globalId.length; for (int i = 0; i < len; ++i) if (globalId[i] != other.globalId[i]) return false; return true; } return false; } public int hashCode() { return hash; } public String toString() { return getClass().getName() + "[formatId=" + formatId + ", globalId=" + new String(globalId).trim() + ", hash=" + hash + "]"; } // Externalizable implementation --------------------------------- public void writeExternal(java.io.ObjectOutput out) throws IOException { out.writeInt(formatId); out.writeObject(globalId); } public void readExternal(java.io.ObjectInput in) throws IOException, ClassNotFoundException { formatId = in.readInt(); globalId = (byte[]) in.readObject(); hash = computeHash(); } // Private ------------------------------------------------------- private int computeHash() { if (formatId == XidImpl.JBOSS_FORMAT_ID) { return (int) TransactionImpl.xidFactory.extractLocalIdFrom(globalId); } else { int len = globalId.length; int hashval = 0; // TODO: use a better hash function for (int i = 0; i < len; ++i) hashval = 3 * globalId[i] + hashval; hashval += formatId; return hashval; } } }