001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.geronimo.transaction.log;
019
020 import java.io.Serializable;
021 import java.util.Arrays;
022
023 import javax.transaction.xa.Xid;
024
025 /**
026 * Unique id for a transaction. This implementation is backed by a single byte buffer
027 * so can do less copying than one backed by several byte buffers for the different components.
028 *
029 * @version $Rev: 476049 $ $Date: 2006-11-16 23:35:17 -0500 (Thu, 16 Nov 2006) $
030 */
031 public class XidImpl2 implements Xid, Serializable {
032 private static int HEADER_SIZE = 4;
033 private static int ACTION_POS = 0;
034 private static int GLOBALID_SIZE_POS = 1;
035 private static int BRANCHID_SIZE_POS = 2;
036 //3 unused
037 private static int FORMAT_ID = 0x4765526f; // Gero
038 private static int FORMAT_SIZE = 4;
039
040 private static byte[] FORMAT_ID_BYTES = "Gero".getBytes();
041
042 private final byte[] buffer = new byte[HEADER_SIZE + FORMAT_SIZE + Xid.MAXGTRIDSIZE + Xid.MAXBQUALSIZE];
043 private int hash;
044 private Object key;
045
046 /**
047 * Constructor taking a global id (for the main transaction)
048 * @param globalId the global transaction id
049 */
050 public XidImpl2(byte[] globalId) {
051 System.arraycopy(FORMAT_ID_BYTES, 0, buffer, HEADER_SIZE, FORMAT_SIZE);
052 buffer[GLOBALID_SIZE_POS] = (byte) globalId.length;
053 System.arraycopy(globalId, 0, buffer, HEADER_SIZE + FORMAT_SIZE, Xid.MAXGTRIDSIZE);
054
055 //this.hash = hash(buffer);
056 }
057
058 /**
059 * Constructor for a branch id
060 * @param global the xid of the global transaction this branch belongs to
061 * @param branch the branch id
062 */
063 public XidImpl2(Xid global, byte[] branch) {
064 if (global instanceof XidImpl2) {
065 System.arraycopy(((XidImpl2) global).buffer, 0, buffer, 0, HEADER_SIZE + FORMAT_SIZE + Xid.MAXGTRIDSIZE);
066 } else {
067 System.arraycopy(FORMAT_ID_BYTES, 0, buffer, HEADER_SIZE, FORMAT_SIZE);
068 byte[] globalId = global.getGlobalTransactionId();
069 System.arraycopy(globalId, 0, buffer, HEADER_SIZE + FORMAT_SIZE, globalId.length);
070 }
071 buffer[BRANCHID_SIZE_POS] = (byte) branch.length;
072 System.arraycopy(branch, 0, buffer, HEADER_SIZE + FORMAT_SIZE + Xid.MAXGTRIDSIZE, Xid.MAXBQUALSIZE);
073 //hash = hash(buffer);
074 }
075
076 public XidImpl2(int formatId, byte[] globalId, byte[] branch) {
077 //todo this is wrong, it ignores formatId supplied. Maybe this is ok?
078 System.arraycopy(FORMAT_ID_BYTES, 0, buffer, HEADER_SIZE, FORMAT_SIZE);
079 System.arraycopy(globalId, 0, buffer, HEADER_SIZE + FORMAT_SIZE, globalId.length);
080 buffer[BRANCHID_SIZE_POS] = (byte) branch.length;
081 System.arraycopy(branch, 0, buffer, HEADER_SIZE + FORMAT_SIZE + Xid.MAXGTRIDSIZE, Xid.MAXBQUALSIZE);
082 //hash = hash(buffer);
083 }
084
085 private int hash(byte[] id) {
086 int hash = 0;
087 for (int i = 0; i < id.length; i++) {
088 hash = (hash * 37) + id[i];
089 }
090 return hash;
091 }
092
093 public int getFormatId() {
094 return FORMAT_ID;
095 }
096
097 public byte[] getGlobalTransactionId() {
098 byte[] globalId = new byte[buffer[GLOBALID_SIZE_POS]];
099 System.arraycopy(buffer, HEADER_SIZE + FORMAT_SIZE, globalId, 0, buffer[GLOBALID_SIZE_POS]);
100 return globalId;
101 }
102
103 public byte[] getBranchQualifier() {
104 byte[] branchId = new byte[buffer[BRANCHID_SIZE_POS]];
105 System.arraycopy(buffer, HEADER_SIZE + FORMAT_SIZE + Xid.MAXGTRIDSIZE, branchId, 0, buffer[BRANCHID_SIZE_POS]);
106 return branchId;
107 }
108
109 public boolean equals(Object obj) {
110 if (obj instanceof XidImpl2 == false) {
111 return false;
112 }
113 XidImpl2 other = (XidImpl2) obj;
114 return Arrays.equals(buffer, other.buffer);
115 }
116
117 public int hashCode() {
118 if (hash == 0) {
119 hash = hash(buffer);
120 }
121 return hash;
122 }
123
124 public String toString() {
125 StringBuffer s = new StringBuffer("[formatId=Gero,");
126 s.append("globalId=");
127 for (int i = FORMAT_SIZE; i < FORMAT_SIZE + Xid.MAXGTRIDSIZE; i++) {
128 s.append(Integer.toHexString(buffer[i]));
129 }
130 s.append(",branchId=");
131 for (int i = FORMAT_SIZE + Xid.MAXGTRIDSIZE; i < buffer.length; i++) {
132 s.append(Integer.toHexString(buffer[i]));
133 }
134 s.append("]");
135 return s.toString();
136 }
137
138 byte[] getBuffer(byte action) {
139 buffer[ACTION_POS] = action;
140 return buffer;
141 }
142
143 public void setKey(Object key) {
144 this.key = key;
145 }
146
147 public Object getKey() {
148 return key;
149 }
150 }