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.manager;
019    
020    import java.util.Random;
021    import javax.transaction.xa.Xid;
022    import java.net.InetAddress;
023    import java.net.UnknownHostException;
024    
025    /**
026     * Factory for transaction ids.
027     * The Xid is constructed of three parts:
028     * <ol><li>8 byte count (LSB first)</li>
029     * <li>4 byte system id</li>
030     * <li>2 byte entropy</li>
031     * <li>4 or 16 byte IP address of host</li>
032     * <ol>
033     * @version $Rev: 740842 $ $Date: 2009-02-04 14:51:48 -0500 (Wed, 04 Feb 2009) $
034     * todo Should have a way of setting baseId
035     */
036    public class XidFactoryImpl implements XidFactory {
037        private final byte[] baseId = new byte[Xid.MAXGTRIDSIZE];
038        private long count = 1;
039    
040        public XidFactoryImpl(byte[] tmId) {
041           System.arraycopy(tmId, 0, baseId, 8, tmId.length);
042        }
043    
044        public XidFactoryImpl() {
045            byte[] hostid;
046            try {
047                hostid = InetAddress.getLocalHost().getAddress();
048            } catch (UnknownHostException e) {
049                hostid = new byte[]{127, 0, 0, 1};
050            }
051            int uid = System.identityHashCode(this);
052            baseId[8] = (byte) uid;
053            baseId[9] = (byte) (uid >>> 8);
054            baseId[10] = (byte) (uid >>> 16);
055            baseId[11] = (byte) (uid >>> 24);
056    
057            byte[] entropy = new byte[2];
058            new Random().nextBytes(entropy);
059            baseId[12] = entropy[0];
060            baseId[13] = entropy[1];
061    
062            System.arraycopy(hostid, 0, baseId, 14, hostid.length);
063        }
064    
065        public Xid createXid() {
066            byte[] globalId = (byte[]) baseId.clone();
067            long id;
068            synchronized (this) {
069                id = count++;
070            }
071            globalId[0] = (byte) id;
072            globalId[1] = (byte) (id >>> 8);
073            globalId[2] = (byte) (id >>> 16);
074            globalId[3] = (byte) (id >>> 24);
075            globalId[4] = (byte) (id >>> 32);
076            globalId[5] = (byte) (id >>> 40);
077            globalId[6] = (byte) (id >>> 48);
078            globalId[7] = (byte) (id >>> 56);
079            return new XidImpl(globalId);
080        }
081    
082        public Xid createBranch(Xid globalId, int branch) {
083            byte[] branchId = (byte[]) baseId.clone();
084            branchId[0] = (byte) branch;
085            branchId[1] = (byte) (branch >>> 8);
086            branchId[2] = (byte) (branch >>> 16);
087            branchId[3] = (byte) (branch >>> 24);
088            return new XidImpl(globalId, branchId);
089        }
090    
091        public boolean matchesGlobalId(byte[] globalTransactionId) {
092            if (globalTransactionId.length != Xid.MAXGTRIDSIZE) {
093                return false;
094            }
095            for (int i = 8; i < globalTransactionId.length; i++) {
096                if (globalTransactionId[i] != baseId[i]) {
097                    return false;
098                }
099            }
100            return true;
101        }
102    
103        public boolean matchesBranchId(byte[] branchQualifier) {
104            if (branchQualifier.length != Xid.MAXBQUALSIZE) {
105                return false;
106            }
107            for (int i = 8; i < branchQualifier.length; i++) {
108                if (branchQualifier[i] != baseId[i]) {
109                    return false;
110                }
111            }
112            return true;
113        }
114    
115        public Xid recover(int formatId, byte[] globalTransactionid, byte[] branchQualifier) {
116            return new XidImpl(formatId, globalTransactionid, branchQualifier);
117        }
118    
119    }