| /** |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.geronimo.transaction.log; |
| |
| import java.io.Serializable; |
| import java.util.Arrays; |
| |
| import javax.transaction.xa.Xid; |
| |
| /** |
| * Unique id for a transaction. This implementation is backed by a single byte buffer |
| * so can do less copying than one backed by several byte buffers for the different components. |
| * |
| * @version $Rev$ $Date$ |
| */ |
| public class XidImpl2 implements Xid, Serializable { |
| private static int HEADER_SIZE = 4; |
| private static int ACTION_POS = 0; |
| private static int GLOBALID_SIZE_POS = 1; |
| private static int BRANCHID_SIZE_POS = 2; |
| //3 unused |
| private static int FORMAT_ID = 0x4765526f; // Gero |
| private static int FORMAT_SIZE = 4; |
| |
| private static byte[] FORMAT_ID_BYTES = "Gero".getBytes(); |
| |
| private final byte[] buffer = new byte[HEADER_SIZE + FORMAT_SIZE + Xid.MAXGTRIDSIZE + Xid.MAXBQUALSIZE]; |
| private int hash; |
| private Object key; |
| |
| /** |
| * Constructor taking a global id (for the main transaction) |
| * @param globalId the global transaction id |
| */ |
| public XidImpl2(byte[] globalId) { |
| System.arraycopy(FORMAT_ID_BYTES, 0, buffer, HEADER_SIZE, FORMAT_SIZE); |
| buffer[GLOBALID_SIZE_POS] = (byte) globalId.length; |
| System.arraycopy(globalId, 0, buffer, HEADER_SIZE + FORMAT_SIZE, Xid.MAXGTRIDSIZE); |
| |
| //this.hash = hash(buffer); |
| check(); |
| } |
| |
| private void check() { |
| if (buffer[GLOBALID_SIZE_POS] > Xid.MAXGTRIDSIZE) { |
| throw new IllegalStateException("Global ID too large: " + buffer[GLOBALID_SIZE_POS]); |
| } |
| if (buffer[BRANCHID_SIZE_POS] > Xid.MAXBQUALSIZE) { |
| throw new IllegalStateException("Branch ID too large: " + buffer[GLOBALID_SIZE_POS]); |
| } |
| } |
| |
| /** |
| * Constructor for a branch id |
| * @param global the xid of the global transaction this branch belongs to |
| * @param branch the branch id |
| */ |
| public XidImpl2(Xid global, byte[] branch) { |
| if (global instanceof XidImpl2) { |
| System.arraycopy(((XidImpl2) global).buffer, 0, buffer, 0, HEADER_SIZE + FORMAT_SIZE + Xid.MAXGTRIDSIZE); |
| } else { |
| System.arraycopy(FORMAT_ID_BYTES, 0, buffer, HEADER_SIZE, FORMAT_SIZE); |
| byte[] globalId = global.getGlobalTransactionId(); |
| System.arraycopy(globalId, 0, buffer, HEADER_SIZE + FORMAT_SIZE, globalId.length); |
| } |
| buffer[BRANCHID_SIZE_POS] = (byte) branch.length; |
| System.arraycopy(branch, 0, buffer, HEADER_SIZE + FORMAT_SIZE + Xid.MAXGTRIDSIZE, Xid.MAXBQUALSIZE); |
| //hash = hash(buffer); |
| check(); |
| } |
| |
| public XidImpl2(int formatId, byte[] globalId, byte[] branch) { |
| //todo this is wrong, it ignores formatId supplied. Maybe this is ok? |
| System.arraycopy(FORMAT_ID_BYTES, 0, buffer, HEADER_SIZE, FORMAT_SIZE); |
| System.arraycopy(globalId, 0, buffer, HEADER_SIZE + FORMAT_SIZE, globalId.length); |
| buffer[BRANCHID_SIZE_POS] = (byte) branch.length; |
| System.arraycopy(branch, 0, buffer, HEADER_SIZE + FORMAT_SIZE + Xid.MAXGTRIDSIZE, Xid.MAXBQUALSIZE); |
| //hash = hash(buffer); |
| check(); |
| } |
| |
| private int hash(byte[] id) { |
| int hash = 0; |
| for (int i = 0; i < id.length; i++) { |
| hash = (hash * 37) + id[i]; |
| } |
| return hash; |
| } |
| |
| public int getFormatId() { |
| return FORMAT_ID; |
| } |
| |
| public byte[] getGlobalTransactionId() { |
| byte[] globalId = new byte[buffer[GLOBALID_SIZE_POS]]; |
| System.arraycopy(buffer, HEADER_SIZE + FORMAT_SIZE, globalId, 0, buffer[GLOBALID_SIZE_POS]); |
| return globalId; |
| } |
| |
| public byte[] getBranchQualifier() { |
| byte[] branchId = new byte[buffer[BRANCHID_SIZE_POS]]; |
| System.arraycopy(buffer, HEADER_SIZE + FORMAT_SIZE + Xid.MAXGTRIDSIZE, branchId, 0, buffer[BRANCHID_SIZE_POS]); |
| return branchId; |
| } |
| |
| public boolean equals(Object obj) { |
| if (obj instanceof XidImpl2 == false) { |
| return false; |
| } |
| XidImpl2 other = (XidImpl2) obj; |
| return Arrays.equals(buffer, other.buffer); |
| } |
| |
| public int hashCode() { |
| if (hash == 0) { |
| hash = hash(buffer); |
| } |
| return hash; |
| } |
| |
| public String toString() { |
| StringBuffer s = new StringBuffer("[XidImpl2:formatId=Gero,"); |
| s.append("globalId="); |
| for (int i = FORMAT_SIZE; i < FORMAT_SIZE + Xid.MAXGTRIDSIZE; i++) { |
| s.append(Integer.toHexString(buffer[i])); |
| } |
| s.append(",branchId="); |
| for (int i = FORMAT_SIZE + Xid.MAXGTRIDSIZE; i < buffer.length; i++) { |
| s.append(Integer.toHexString(buffer[i])); |
| } |
| s.append("]"); |
| return s.toString(); |
| } |
| |
| byte[] getBuffer(byte action) { |
| buffer[ACTION_POS] = action; |
| return buffer; |
| } |
| |
| public void setKey(Object key) { |
| this.key = key; |
| } |
| |
| public Object getKey() { |
| return key; |
| } |
| } |