001 /** 002 * 003 * Copyright 2003-2004 The Apache Software Foundation 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * 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: 355877 $ $Date: 2005-12-10 18:48:27 -0800 (Sat, 10 Dec 2005) $ 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 }