001: /*
002: * @(#) JavaXidImpl.java
003: *
004: * JOTM: Java Open Transaction Manager
005: *
006: *
007: * This module was originally developed by
008: *
009: * - Bull S.A. as part of the JOnAS application server code released in
010: * July 1999 (www.bull.com)
011: *
012: * --------------------------------------------------------------------------
013: * The original code and portions created by Bull SA are
014: * Copyright (c) 1999 BULL SA
015: * All rights reserved.
016: *
017: * Redistribution and use in source and binary forms, with or without
018: * modification, are permitted provided that the following conditions are met:
019: *
020: * -Redistributions of source code must retain the above copyright notice, this
021: * list of conditions and the following disclaimer.
022: *
023: * -Redistributions in binary form must reproduce the above copyright notice,
024: * this list of conditions and the following disclaimer in the documentation
025: * and/or other materials provided with the distribution.
026: *
027: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
028: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
029: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
030: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
031: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
032: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
033: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
034: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
035: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
036: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
037: * POSSIBILITY OF SUCH DAMAGE.
038: *
039: * --------------------------------------------------------------------------
040: * $Id: JavaXidImpl.java,v 1.2 2005/04/22 17:49:37 tonyortiz Exp $
041: * --------------------------------------------------------------------------
042: */
043: package org.objectweb.jotm;
044:
045: import java.io.Serializable;
046: import java.nio.ByteBuffer;
047: import java.security.SecureRandom;
048: import javax.transaction.xa.Xid;
049:
050: /**
051: * Xid implementation for JTA
052: *
053: * XID has the following format as defined by X/Open Specification:
054: *
055: * XID
056: * long formatId format identifier
057: * long gtrid_length value 1-64
058: * long bqual_length value 1-64
059: * byte data [XIDDATASIZE] where XIDDATASIZE = 128
060: *
061: * The data field comprises at most two contiguous components:
062: * a global transaction identifier (gtrid) and a branch qualifier (bqual)
063: * which are defined as:
064: *
065: * byte gtrid [1-64] global transaction identfier
066: * byte bqual [1-64] branch qualifier
067: *
068: */
069: public class JavaXidImpl implements Xid, Serializable {
070:
071: public static final int JOTM_FORMAT_ID = 0xBB14;
072:
073: // these cells are gated by this.getClass()
074: private static SecureRandom rand = null; // (also used as first-time flag)
075: private final byte internalVersId = 1;
076: private static int count = 1;
077: private static long uuid0;
078: private static long uuid1;
079: private static boolean uuidsRecovered = false;
080: private static byte[] gtrid_base = null; // created by makeGtridBase()
081: private static String host, server;
082:
083: private String fullString = "";
084: private String shortString = "";
085:
086: private boolean hashcodevalid = false;
087: private int myhashcode;
088:
089: static String HexDigits[] = { "00", "01", "02", "03", "04", "05",
090: "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
091: "10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
092: "1a", "1b", "1c", "1d", "1e", "1f", "20", "21", "22", "23",
093: "24", "25", "26", "27", "28", "29", "2a", "2b", "2c", "2d",
094: "2e", "2f", "30", "31", "32", "33", "34", "35", "36", "37",
095: "38", "39", "3a", "3b", "3c", "3d", "3e", "3f", "40", "41",
096: "42", "43", "44", "45", "46", "47", "48", "49", "4a", "4b",
097: "4c", "4d", "4e", "4f", "50", "51", "52", "53", "54", "55",
098: "56", "57", "58", "59", "5a", "5b", "5c", "5d", "5e", "5f",
099: "60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
100: "6a", "6b", "6c", "6d", "6e", "6f", "70", "71", "72", "73",
101: "74", "75", "76", "77", "78", "79", "7a", "7b", "7c", "7d",
102: "7e", "7f", "80", "81", "82", "83", "84", "85", "86", "87",
103: "88", "89", "8a", "8b", "8c", "8d", "8e", "8f", "90", "91",
104: "92", "93", "94", "95", "96", "97", "98", "99", "9a", "9b",
105: "9c", "9d", "9e", "9f", "a0", "a1", "a2", "a3", "a4", "a5",
106: "a6", "a7", "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af",
107: "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9",
108: "ba", "bb", "bc", "bd", "be", "bf", "c0", "c1", "c2", "c3",
109: "c4", "c5", "c6", "c7", "c8", "c9", "ca", "cb", "cc", "cd",
110: "ce", "cf", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
111: "d8", "d9", "da", "db", "dc", "dd", "de", "df", "e0", "e1",
112: "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9", "ea", "eb",
113: "ec", "ed", "ee", "ef", "f0", "f1", "f2", "f3", "f4", "f5",
114: "f6", "f7", "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff" };
115:
116: /**
117: * format id
118: * @serial
119: */
120: private int formatId;
121:
122: /**
123: * gtrid length
124: * @serial
125: */
126: private int gtrid_length;
127:
128: /**
129: * bqual length
130: * @serial
131: */
132: private int bqual_length;
133:
134: /**
135: * global transaction id
136: * @serial
137: */
138: private byte[] gtrid;
139:
140: /**
141: * branch qualifier
142: * @serial
143: */
144: private byte[] bqual;
145:
146: // -------------------------------------------------------------------
147: // Constructors
148: // -------------------------------------------------------------------
149:
150: /**
151: * Build an javax.transaction.xa.Xid from the org.objectweb.jotm.Xid
152: */
153: public JavaXidImpl(org.objectweb.jotm.Xid jotmXid) {
154: if (TraceTm.jotm.isDebugEnabled()) {
155: TraceTm.jotm.debug("jotmXID= " + jotmXid);
156: }
157:
158: formatId = jotmXid.getFormatId();
159: gtrid = jotmXid.getGlobalTransactionId();
160: gtrid_length = gtrid.length;
161: bqual = jotmXid.getBranchQualifier();
162: bqual_length = bqual.length;
163: }
164:
165: // -------------------------------------------------------------------
166: // Xid implementation
167: // -------------------------------------------------------------------
168:
169: /**
170: * Get the format id for that Xid
171: */
172: public int getFormatId() {
173: return formatId;
174: }
175:
176: /**
177: * Get the Global Id for that Xid
178: */
179: public byte[] getGlobalTransactionId() {
180: return gtrid;
181: }
182:
183: /**
184: * Get the Branch Qualifier for that Xid
185: */
186: public byte[] getBranchQualifier() {
187: return bqual;
188: }
189:
190: // -------------------------------------------------------------------
191: // other methods
192: // -------------------------------------------------------------------
193:
194: /**
195: * Hex Dump of byte
196: */
197: static final void byteToHex(byte inbyte, StringBuffer str_buff) {
198:
199: int myByte = 0xFF & inbyte;
200:
201: str_buff.append(HexDigits[myByte]);
202: return;
203: }
204:
205: /**
206: * String form
207: * default toString() compresses Xid's
208: */
209: public String toString() {
210: return this .toString(false);
211: }
212:
213: public String toString(boolean Full) {
214:
215: byte[] gtrid_local = null;
216: byte[] bqual_local = null;
217:
218: if (Full && (fullString.length() != 0)) {
219: return fullString;
220: } else if (!Full && (shortString.length() != 0)) {
221: return shortString;
222: }
223:
224: // Buffers need two hex characters per byte
225: StringBuffer str_buff_gtrid = new StringBuffer(MAXGTRIDSIZE * 2);
226: StringBuffer str_buff_bqual = new StringBuffer(MAXBQUALSIZE * 2);
227:
228: gtrid_local = new byte[MAXGTRIDSIZE];
229: ByteBuffer aa = ByteBuffer.wrap(gtrid_local);
230:
231: System.arraycopy(gtrid, 0, gtrid_local, 0, gtrid_length);
232:
233: for (int i = 0; i < gtrid_length; i++) {
234: byteToHex(aa.get(), str_buff_gtrid);
235: }
236:
237: bqual_local = new byte[MAXBQUALSIZE];
238: ByteBuffer bb = ByteBuffer.wrap(bqual_local);
239:
240: if (bqual != null) {
241: System.arraycopy(bqual, 0, bqual_local, 0, bqual_length);
242:
243: for (int i = 0; i < bqual_length; i++) {
244: byteToHex(bb.get(), str_buff_bqual);
245: }
246: }
247:
248: if ((gtrid_length > 30) && !Full) { // be prepared to reduce output string
249: int strlen = str_buff_gtrid.length();
250: str_buff_gtrid.replace((strlen / 6), (strlen / 6) + 2,
251: "...");
252: str_buff_gtrid.delete((strlen / 6) + 3, strlen - 5);
253: }
254:
255: if ((bqual_length > 30) && !Full) { // be prepared to reduce output string
256: int strlen = str_buff_bqual.length();
257: str_buff_bqual.replace((strlen / 6), (strlen / 6) + 2,
258: "...");
259: str_buff_bqual.delete((strlen / 6) + 3, strlen - 5);
260: }
261:
262: if (Full) {
263: fullString = Long.toHexString(formatId) + ":"
264: + Long.toHexString(gtrid_length) + ":"
265: + Long.toHexString(bqual_length) + ":"
266: + str_buff_gtrid.toString() + ":"
267: + str_buff_bqual.toString();
268: return fullString;
269: }
270:
271: shortString = Long.toHexString(formatId) + ":"
272: + Long.toHexString(gtrid_length) + ":"
273: + Long.toHexString(bqual_length) + ":"
274: + str_buff_gtrid.toString() + ":"
275: + str_buff_bqual.toString();
276: return shortString;
277: }
278:
279: /*
280: * make a unique but recognizable gtrid.
281: *
282: * format:
283: * 1. internal version identifier - 1 byte
284: * 2. uuid - 16 bytes
285: * 3. host name - 16 bytes
286: * 4. server name - 15 bytes
287: * 5. timestamp - 8 bytes
288: * 6. [reserved for use by bqual - 8 bytes]
289: *
290: * Items 1 thru 4 are generated by makeGtridBase and comprise the recognizable
291: * portion of a gtrid or bqual. Together, these serve to make Xids generated on
292: * this system unique from those generated on other systems.
293: * Item 5 is generated by this routine and serves to make gtrids unique.
294: * Item 6 serves to distinguish different bquals belonging
295: * to the same Xid, and is generated elsewhere.
296: *
297: * Items 1 thru 4 are used to determine if we (JOTM) generated this gtrid/bqual.
298: */
299:
300: private byte[] makeGtrid() {
301: makeGtridBase();
302: long uniqueTimeStamp;
303:
304: synchronized (getClass()) {
305: uniqueTimeStamp = System.currentTimeMillis() * 1024 + count;
306: count++;
307: }
308:
309: ByteBuffer bb = ByteBuffer.allocate(gtrid_base.length + 8);
310: bb.put(gtrid_base);
311: bb.putLong(uniqueTimeStamp);
312: return bb.array();
313: }
314:
315: private void makeGtridBase() {
316: // acquire the configured uuid, host and server name.
317: // fabricate a uuid if one does not yet exist.
318: // and append a unique timestamp.
319:
320: synchronized (getClass()) {
321: if (rand == null) {
322: rand = new SecureRandom();
323:
324: if (uuidsRecovered == false) { // first time or no journal
325: //uuid0 = Long.parseLong(System.getProperty("jotm.uuid.part1"),16);
326: //uuid1 = Long.parseLong(System.getProperty("jotm.uuid.part2"),16);
327: uuid0 = rand.nextLong();
328: uuid1 = rand.nextLong();
329:
330: // We build the Inique ID Record in makeGtridBase
331: // Store the Unique ID Record using HOWL so it can manage for us.
332: // It will never have a DONE record written.
333: //
334: // The Unique ID record consists of two fields:
335: // 1. uuid0
336: // 2. uuid1
337: //
338: // The XA Unique ID record format:
339: // Unique ID record type1 (byte[3]) - 'RU1'
340: // Unique ID record stored uuido (long) - 8 bytes
341: // Unique ID record stored uuid1 (long) - 8 bytes
342: //
343:
344: byte[] UniqueID = new byte[3 + 8 + 8];
345: byte[][] UniqueIDRecord = new byte[1][3 + 8 + 8];
346:
347: String rt1 = "RU1";
348:
349: ByteBuffer rr1 = ByteBuffer.wrap(UniqueID);
350: rr1.put(rt1.getBytes());
351: rr1.putLong(uuid0);
352: rr1.putLong(uuid1);
353:
354: UniqueIDRecord[0] = UniqueID;
355: }
356:
357: host = "";
358: server = "";
359: // make host & server names fixed length, as defined above
360: host = (host + " ").substring(0, 15);
361: server = (server + " ").substring(0, 14);
362: gtrid_base = new byte[1 + 8 + 8 + 16 + 15];
363: ByteBuffer bb = ByteBuffer.wrap(gtrid_base);
364: bb.put(internalVersId);
365: bb.putLong(uuid0);
366: bb.putLong(uuid1);
367: bb.put(host.getBytes());
368: bb.put(server.getBytes());
369: }
370: }
371: }
372:
373: // -------------------------------------------------------------------
374: // equals and hashCode
375: // -------------------------------------------------------------------
376:
377: /**
378: * return true if objects are identical
379: */
380: public boolean equals(Object obj2) {
381:
382: JavaXidImpl xid2 = (JavaXidImpl) obj2;
383:
384: if (formatId == xid2.getFormatId()
385: && java.util.Arrays.equals(bqual, xid2
386: .getBranchQualifier())
387: && java.util.Arrays.equals(gtrid, xid2
388: .getGlobalTransactionId())) {
389: return true;
390: } else {
391: return false;
392: }
393: }
394:
395: /**
396: * return a hashcode value for this object
397: */
398: public int hashCode() {
399:
400: int hc = 0;
401:
402: if (hashcodevalid == false) {
403:
404: for (int i = 0; i < gtrid.length; i++) {
405: hc = hc * 37 + gtrid[i];
406: }
407:
408: for (int i = 0; i < bqual.length; i++) {
409: hc = hc * 37 + bqual[i];
410: }
411:
412: myhashcode = hc;
413: hashcodevalid = true;
414: }
415: return myhashcode;
416: }
417: }
|