KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > tm > XidFactoryImpl


1 /*
2   * JBoss, Home of Professional Open Source
3   * Copyright 2005, JBoss Inc., and individual contributors as indicated
4   * by the @authors tag. See the copyright.txt in the distribution for a
5   * full listing of individual contributors.
6   *
7   * This is free software; you can redistribute it and/or modify it
8   * under the terms of the GNU Lesser General Public License as
9   * published by the Free Software Foundation; either version 2.1 of
10   * the License, or (at your option) any later version.
11   *
12   * This software is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this software; if not, write to the Free
19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21   */

22 package org.jboss.tm;
23
24 import javax.transaction.xa.Xid JavaDoc;
25
26 import org.jboss.system.server.ServerConfigUtil;
27
28 /**
29  * XidFactory.java
30  * <p/>
31  * <p/>
32  * Created: Sat Jun 15 19:01:18 2002
33  *
34  * @author <a HREF="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
35  * @jmx.mbean
36  */

37 public class XidFactoryImpl
38       implements XidFactoryBase
39 {
40    
41    /**
42     * The default value of baseGlobalId is the host name, followed by a
43     * colon (":"), the server's JNDI port, and a slash. It the server's JNDI
44     * port cannot be obtained, then the startService time is used instead.
45     * <p/>
46     * This is used for building globally unique transaction identifiers.
47     * It would be safer to use the IP address, but a host name is better
48     * for humans to read and will do for now.
49     */

50    private String JavaDoc baseGlobalId;
51
52    /**
53     * The next transaction id to use on this host.
54     */

55    private long globalIdNumber = 0;
56
57    /**
58     * The variable <code>pad</code> says whether the byte[] should be their
59     * maximum 64 byte length or the minimum.
60     * The max length is required for Oracle..
61     */

62    private boolean pad = false;
63
64    /**
65     * The <code>branchQualifier</code> is the host name, followed by a
66     * colon (":") and the server's JNDI port. It the server's JNDI
67     * port cannot be obtained, then the startService time is used instead.
68     */

69    private String JavaDoc branchQualifier;
70
71    /**
72     * This field stores the byte reprsentation of baseGlobalId
73     * to avoid the expensive getBytes() call on that String object
74     * when we create a new Xid, which we do VERY often!
75     */

76    private byte[] baseGlobalIdBytes;
77
78    /**
79     * This field stores the byte reprsentation of branchQualifier
80     * to avoid the expensive getBytes() call on that String object.
81     */

82    private byte[] branchQualifierBytes;
83
84    /**
85     * This field stores the byte reprsentation of base branchQualifier
86     * to avoid the expensive getBytes() call on that String object.
87     */

88    private byte[] baseBranchQualifierBytes;
89
90    private long uniqueInstanceId = System.currentTimeMillis();
91
92    public void start()
93    {
94       String JavaDoc hostName = ServerConfigUtil.getSpecificBindAddress();
95
96       baseGlobalId = hostName + ":" + uniqueInstanceId;
97       // Ensure room for 14 digits of serial no and timestamp
98
if (baseGlobalId.length() > Xid.MAXGTRIDSIZE - 15)
99          baseGlobalId = baseGlobalId.substring(0, Xid.MAXGTRIDSIZE - 15);
100       baseGlobalId = baseGlobalId + "/";
101       baseGlobalIdBytes = baseGlobalId.getBytes();
102
103       branchQualifier = hostName + ":" + uniqueInstanceId;
104       int len = pad ? Xid.MAXBQUALSIZE : branchQualifier.length();
105       branchQualifierBytes = new byte[len];
106       // this method is deprecated, but does exactly what we need in a very fast
107
// way the default conversion from String.getBytes() is way too expensive
108
branchQualifier.getBytes(0, branchQualifier.length(),
109                                branchQualifierBytes, 0);
110       
111       String JavaDoc baseBranchQualifier = branchQualifier + "/";
112       baseBranchQualifierBytes = new byte[baseBranchQualifier.length()];
113       // use deprecated method again
114
baseBranchQualifier.getBytes(0, baseBranchQualifier.length(),
115                                    baseBranchQualifierBytes, 0);
116
117    }
118
119    public long getUniqueInstanceId()
120    {
121       return uniqueInstanceId;
122    }
123
124    public void setUniqueInstanceId(long uniqueInstanceId)
125    {
126       this.uniqueInstanceId = uniqueInstanceId;
127    }
128
129    /**
130     * mbean get-set pair for field BaseGlobalId
131     * Get the value of BaseGlobalId
132     *
133     * @return value of BaseGlobalId
134     * @jmx:managed-attribute
135     */

136    public String JavaDoc getBaseGlobalId()
137    {
138       return baseGlobalId;
139    }
140
141    /**
142     * Set the value of BaseGlobalId
143     *
144     * @param BaseGlobalId Value to assign to BaseGlobalId
145     * @jmx:managed-attribute
146     */

147    public void setBaseGlobalId(final String JavaDoc baseGlobalId)
148    {
149       this.baseGlobalId = baseGlobalId;
150       baseGlobalIdBytes = baseGlobalId.getBytes();
151    }
152
153    /**
154     * mbean get-set pair for field globalIdNumber
155     * Get the value of globalIdNumber
156     *
157     * @return value of globalIdNumber
158     * @jmx:managed-attribute
159     */

160    public synchronized long getGlobalIdNumber()
161    {
162       return globalIdNumber;
163    }
164
165    /**
166     * Set the value of globalIdNumber
167     *
168     * @param globalIdNumber Value to assign to globalIdNumber
169     * @jmx:managed-attribute
170     */

171    public synchronized void setGlobalIdNumber(final long globalIdNumber)
172    {
173       this.globalIdNumber = globalIdNumber;
174    }
175
176    /**
177     * mbean get-set pair for field BranchQualifier
178     * Get the value of BranchQualifier
179     *
180     * @return value of BranchQualifier
181     * @jmx:managed-attribute
182     */

183    public String JavaDoc getBranchQualifier()
184    {
185       return branchQualifier;
186    }
187
188    /**
189     * Set the value of BranchQualifier
190     *
191     * @param branchQualifier Value to assign to BranchQualifier
192     * @jmx:managed-attribute
193     */

194    public void setBranchQualifier(final String JavaDoc branchQualifier)
195    {
196       this.branchQualifier = branchQualifier;
197       
198       int len = pad ? Xid.MAXBQUALSIZE : branchQualifier.length();
199       branchQualifierBytes = new byte[len];
200       // This method is deprecated, but does exactly what we need in a
201
// very fast way. The default conversion from String.getBytes()
202
// is way too expensive.
203
branchQualifier.getBytes(0, branchQualifier.length(),
204                                branchQualifierBytes, 0);
205
206       String JavaDoc baseBranchQualifier = branchQualifier + "/";
207       baseBranchQualifierBytes = new byte[baseBranchQualifier.length()];
208       // use deprecated method again
209
baseBranchQualifier.getBytes(0, baseBranchQualifier.length(),
210                                    baseBranchQualifierBytes, 0);
211    }
212
213    /**
214     * mbean get-set pair for field pad
215     * Get the value of pad
216     *
217     * @return value of pad
218     * @jmx:managed-attribute
219     */

220    public boolean isPad()
221    {
222       return pad;
223    }
224
225    /**
226     * Set the value of pad
227     *
228     * @param pad Value to assign to pad
229     * @jmx:managed-attribute
230     */

231    public void setPad(boolean pad)
232    {
233       if (this.pad != pad)
234       {
235          this.pad = pad;
236          if (branchQualifier != null)
237          {
238             // update branchQualifierBytes according to the new value of pad
239
int len = pad ? Xid.MAXBQUALSIZE : branchQualifier.length();
240             branchQualifierBytes = new byte[len];
241             // This method is deprecated, but does exactly what we need in a
242
// very fast way. The default conversion from String.getBytes()
243
// is way too expensive.
244
branchQualifier.getBytes(0, branchQualifier.length(),
245                                      branchQualifierBytes, 0);
246          }
247       }
248             
249    }
250
251    /**
252     * Creates a <code>XidImpl</code> for a new transaction.
253     *
254     * @return a <code>XidImpl</code> value
255     * @jmx.managed-operation
256     */

257    public XidImpl newXid()
258    {
259       long localId = getNextId();
260       return new XidImpl(localIdToGlobalId(localId),
261                          branchQualifierBytes,
262                          (int) localId,
263                          localId);
264    }
265
266    /**
267     * Creates a <code>XidImpl</code> for a branch of an existing transaction.
268     *
269     * @param globalId the code>GlobalId</code> of the existing transaction
270     * @return a <code>XidImpl</code> tor the new transaction branch.
271     * @jmx.managed-operation
272     */

273    public XidImpl newBranch(GlobalId globalId)
274    {
275       long localId = getNextId();
276       return new XidImpl(globalId, branchQualifierBytes, localId);
277    }
278
279    /**
280     * Creates a <code>XidImpl</code> for a "fake branch" of an existing
281     * transaction. This method exists for a single reason: some
282     * <code>XAResource</code> implementations return false on all calls to
283     * <code>isSameRM</code>. If <code>isSameRM</code> worked properly, then
284     * there would be no need to generate a "fake branch" Xid for each
285     * <code>XAResource</code> that may or may not represent a new RM. A same
286     * <code>Xid</code> (the real <code>Xid</code> for the transaction branch)
287     * could (and should) be used for all <code>XAResource</code>s that
288     * represent different RMs. If <code>isSameRM</code> may return false
289     * negatives, however, the real branch Xid may be passed more than once
290     * to a same RM in calls to <code>XAResource.start</code>. This would result
291     * in <code>XAException</code>s with error code <code>XAER_DUPID</code>.
292     * We avoid this problem by generating a "fake branch" <code>Xid</code>
293     * for each <code>XAResource</code> that corresponds to a "new" RM according
294     * to <code>isSameRM</code>, but might actually not represent a new one.
295     *
296     * @param xid a <code>XidImpl</code> for the existing transaction
297     * @param branchNum a branch number to be included in the branch qualifier.
298     * @return a <code>XidImpl</code> for the new transaction branch.
299     * @jmx.managed-operation
300     */

301    public XidImpl newBranch(XidImpl xid, long branchNum)
302    {
303       String JavaDoc id = Long.toString(branchNum);
304       int len = pad ? Xid.MAXBQUALSIZE
305                     : baseBranchQualifierBytes.length + id.length();
306       byte[] branchQualifier = new byte[len];
307       System.arraycopy(baseBranchQualifierBytes, 0,
308                        branchQualifier, 0,
309                        baseBranchQualifierBytes.length);
310       // This method is deprecated, but does exactly what we need in a very
311
// fast way. The conversion via String.getBytes() is way too expensive.
312
id.getBytes(0, id.length(), branchQualifier,
313                   baseBranchQualifierBytes.length);
314       return new XidImpl(xid, branchQualifier);
315    }
316
317    public XidImpl recreateXid(long localId)
318    {
319       return new XidImpl(localIdToGlobalId(localId),
320             branchQualifierBytes,
321             (int) localId,
322             localId);
323    }
324    
325    public XidImpl recreateXid(long localId, GlobalId globalId)
326    {
327       return new XidImpl(globalId, branchQualifierBytes, localId);
328    }
329
330    /**
331     * Converts a local id into a global transaction id.
332     *
333     * @param localId the local transaction id
334     * @return the global transaction id
335     */

336    public byte[] localIdToGlobalId(long localId)
337    {
338       String JavaDoc id = Long.toString(localId);
339       int len = pad ? Xid.MAXGTRIDSIZE : id.length() + baseGlobalIdBytes.length;
340       byte[] globalId = new byte[len];
341       System.arraycopy(baseGlobalIdBytes, 0, globalId, 0, baseGlobalIdBytes.length);
342       // this method is deprecated, but does exactly what we need in a very fast way
343
// the default conversion from String.getBytes() is way too expensive
344
id.getBytes(0, id.length(), globalId, baseGlobalIdBytes.length);
345       return globalId;
346    }
347
348    /**
349     * Extracts the local id contained in a global id.
350     *
351     * @param globalId a global id
352     * @return the local id extracted from the global id
353     * @jmx:managed-operation
354     */

355    public long extractLocalIdFrom(byte[] globalId)
356    {
357       int i, start;
358       int len = globalId.length;
359
360       for (i = 0; globalId[i++] != (byte) '/';)
361          ;
362       start = i;
363       while (i < len && globalId[i] != 0)
364          i++;
365       String JavaDoc globalIdNumber = new String JavaDoc(globalId, 0, start, i - start);
366       return Long.parseLong(globalIdNumber);
367    }
368
369    /**
370     * @param branchQualifier
371     * @return
372     * @jmx:managed-operation
373     */

374    public String JavaDoc getBaseBranchQualifier(byte[] branchQualifier)
375    {
376       int len = branchQualifier.length;
377       int i = 0;
378       
379       while (branchQualifier[i] != (byte) '/'
380                && branchQualifier[i] != (byte) 0
381                && i < len)
382          i++;
383
384       String JavaDoc base = new String JavaDoc(branchQualifier, 0, 0, i);
385       return base;
386    }
387
388    /**
389     * Describe <code>toString</code> method here.
390     *
391     * @param xid a <code>Xid</code> value
392     * @return a <code>String</code> value
393     * @jmx.managed-operation
394     */

395    public String JavaDoc toString(Xid JavaDoc xid)
396    {
397       return XidImpl.toString(xid);
398    }
399
400    private synchronized long getNextId()
401    {
402       return ++globalIdNumber;
403    }
404
405 }
406
Popular Tags