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 */
017package org.apache.activemq.command;
018
019import java.util.ArrayList;
020import java.util.Arrays;
021import javax.transaction.xa.Xid;
022import org.apache.activemq.util.HexSupport;
023
024/**
025 * @openwire:marshaller code="112"
026 * 
027 */
028public class XATransactionId extends TransactionId implements Xid, Comparable {
029
030    public static final byte DATA_STRUCTURE_TYPE = CommandTypes.ACTIVEMQ_XA_TRANSACTION_ID;
031
032    private int formatId;
033    private byte[] branchQualifier;
034    private byte[] globalTransactionId;
035
036    private transient int hash;
037    private transient String transactionKey;
038    private transient ArrayList<MessageAck> preparedAcks;
039
040    public XATransactionId() {
041    }
042
043    public XATransactionId(Xid xid) {
044        this.formatId = xid.getFormatId();
045        this.globalTransactionId = xid.getGlobalTransactionId();
046        this.branchQualifier = xid.getBranchQualifier();
047    }
048
049    public byte getDataStructureType() {
050        return DATA_STRUCTURE_TYPE;
051    }
052
053    public synchronized String getTransactionKey() {
054        if (transactionKey == null) {
055            StringBuffer s = new StringBuffer();
056            s.append("XID:[globalId=");
057            for (int i = 0; i < globalTransactionId.length; i++) {
058                s.append(Integer.toHexString(globalTransactionId[i]));
059            }
060            s.append(",branchId=");
061            for (int i = 0; i < branchQualifier.length; i++) {
062                s.append(Integer.toHexString(branchQualifier[i]));
063            }
064            s.append("]");
065            transactionKey = s.toString();
066        }
067        return transactionKey;
068    }
069
070    public String toString() {
071        return getTransactionKey();
072    }
073
074    public boolean isXATransaction() {
075        return true;
076    }
077
078    public boolean isLocalTransaction() {
079        return false;
080    }
081
082    /**
083     * @openwire:property version=1
084     */
085    public int getFormatId() {
086        return formatId;
087    }
088
089    /**
090     * @openwire:property version=1
091     */
092    public byte[] getGlobalTransactionId() {
093        return globalTransactionId;
094    }
095
096    /**
097     * @openwire:property version=1
098     */
099    public byte[] getBranchQualifier() {
100        return branchQualifier;
101    }
102
103    public void setBranchQualifier(byte[] branchQualifier) {
104        this.branchQualifier = branchQualifier;
105        this.hash = 0;
106    }
107
108    public void setFormatId(int formatId) {
109        this.formatId = formatId;
110        this.hash = 0;
111    }
112
113    public void setGlobalTransactionId(byte[] globalTransactionId) {
114        this.globalTransactionId = globalTransactionId;
115        this.hash = 0;
116    }
117
118    public int hashCode() {
119        if (hash == 0) {
120            hash = formatId;
121            hash = hash(globalTransactionId, hash);
122            hash = hash(branchQualifier, hash);
123            if (hash == 0) {
124                hash = 0xaceace;
125            }
126        }
127        return hash;
128    }
129
130    private static int hash(byte[] bytes, int hash) {
131        int size = bytes.length;
132        for (int i = 0; i < size; i++) {
133            hash ^= bytes[i] << ((i % 4) * 8);
134        }
135        return hash;
136    }
137
138    public boolean equals(Object o) {
139        if (o == null || o.getClass() != XATransactionId.class) {
140            return false;
141        }
142        XATransactionId xid = (XATransactionId)o;
143        return xid.formatId == formatId && Arrays.equals(xid.globalTransactionId, globalTransactionId)
144               && Arrays.equals(xid.branchQualifier, branchQualifier);
145    }
146
147    public int compareTo(Object o) {
148        if (o == null || o.getClass() != XATransactionId.class) {
149            return -1;
150        }
151        XATransactionId xid = (XATransactionId)o;
152        return getTransactionKey().compareTo(xid.getTransactionKey());
153    }
154
155    public void setPreparedAcks(ArrayList<MessageAck> preparedAcks) {
156        this.preparedAcks = preparedAcks;
157    }
158
159    public ArrayList<MessageAck> getPreparedAcks() {
160        return preparedAcks;
161    }
162}