001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.tm;
023:
024: import java.io.IOException;
025: import javax.transaction.xa.Xid;
026:
027: /**
028: * This object encapsulates the global transaction ID of a transaction.
029: * It is similar to an Xid, but holds only the GlobalId part.
030: * This implementation is immutable and always serializable at runtime.
031: *
032: * @see XidImpl
033: * @author <a href="mailto:osh@sparre.dk">Ole Husgaard</a>
034: * @author <a href="mailto:reverbel@ime.usp.br">Francisco Reverbel</a>
035: * @version $Revision: 57208 $
036: */
037: public class GlobalId implements java.io.Externalizable {
038: static final long serialVersionUID = 6879509375433435464L;
039: /**
040: * Format id of this instance.
041: */
042: private int formatId;
043:
044: /**
045: * Global transaction id of this instance.
046: * The coding of this class depends on the fact that this variable is
047: * initialized in the constructor and never modified. References to
048: * this array are never given away, instead a clone is delivered.
049: */
050: private byte[] globalId;
051:
052: /**
053: * Hash code of this instance. For a native GlobalId (one whose formatId
054: * is XidImpl.JBOSS_FORMAT_ID), this is really a sequence number.
055: */
056: private int hash;
057:
058: // Constructors --------------------------------------------------
059:
060: public GlobalId() {
061: // Used for Externalizable support
062: }
063:
064: /**
065: * Create a new instance. This constructor is package-private, as it
066: * trusts the hash parameter to be good.
067: */
068: GlobalId(int formatId, byte[] globalId, int hash) {
069: this .formatId = formatId;
070: this .globalId = globalId;
071: this .hash = hash;
072: }
073:
074: /**
075: * Create a new instance. This constructor is public <em>only</em>
076: * to get around a class loader problem; it should be package-private.
077: */
078: public GlobalId(int formatId, byte[] globalId) {
079: this .formatId = formatId;
080: this .globalId = globalId;
081: hash = computeHash();
082: }
083:
084: public GlobalId(Xid xid) {
085: formatId = xid.getFormatId();
086: globalId = xid.getGlobalTransactionId();
087: if (xid instanceof XidImpl
088: && formatId == XidImpl.JBOSS_FORMAT_ID) {
089: // native GlobalId: use its hash code (a sequence number)
090: hash = xid.hashCode();
091: } else {
092: // foreign GlobalId: do the hash computation
093: hash = computeHash();
094: }
095: }
096:
097: public GlobalId(int formatId, int bqual_length, byte[] tid) {
098: this .formatId = formatId;
099: if (bqual_length == 0)
100: globalId = tid;
101: else {
102: int len = tid.length - bqual_length;
103: globalId = new byte[len];
104: System.arraycopy(tid, 0, globalId, 0, len);
105: }
106: hash = computeHash();
107: }
108:
109: // Public --------------------------------------------------------
110:
111: /**
112: * Compare for equality.
113: *
114: * Instances are considered equal if they both refer to the same
115: * global transaction id.
116: */
117: public boolean equals(Object obj) {
118: if (obj instanceof GlobalId) {
119: GlobalId other = (GlobalId) obj;
120:
121: if (formatId != other.formatId)
122: return false;
123:
124: if (globalId == other.globalId)
125: return true;
126:
127: if (globalId.length != other.globalId.length)
128: return false;
129:
130: int len = globalId.length;
131: for (int i = 0; i < len; ++i)
132: if (globalId[i] != other.globalId[i])
133: return false;
134:
135: return true;
136: }
137: return false;
138: }
139:
140: public int hashCode() {
141: return hash;
142: }
143:
144: public String toString() {
145: return getClass().getName() + "[formatId=" + formatId
146: + ", globalId=" + new String(globalId).trim()
147: + ", hash=" + hash + "]";
148: }
149:
150: // Externalizable implementation ---------------------------------
151:
152: public void writeExternal(java.io.ObjectOutput out)
153: throws IOException {
154: out.writeInt(formatId);
155: out.writeObject(globalId);
156: }
157:
158: public void readExternal(java.io.ObjectInput in)
159: throws IOException, ClassNotFoundException {
160: formatId = in.readInt();
161: globalId = (byte[]) in.readObject();
162: hash = computeHash();
163: }
164:
165: // Private -------------------------------------------------------
166:
167: private int computeHash() {
168: if (formatId == XidImpl.JBOSS_FORMAT_ID) {
169: return (int) TransactionImpl.xidFactory
170: .extractLocalIdFrom(globalId);
171: } else {
172: int len = globalId.length;
173: int hashval = 0;
174:
175: // TODO: use a better hash function
176: for (int i = 0; i < len; ++i)
177: hashval = 3 * globalId[i] + hashval;
178: hashval += formatId;
179: return hashval;
180: }
181: }
182:
183: }
|