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    package org.apache.activemq.command;
018    
019    import java.util.ArrayList;
020    import java.util.Arrays;
021    import javax.transaction.xa.Xid;
022    import org.apache.activemq.util.HexSupport;
023    
024    /**
025     * @openwire:marshaller code="112"
026     * 
027     */
028    public 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    }