KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > slide > common > AbstractService


1 /*
2  * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/common/AbstractService.java,v 1.9 2004/07/28 09:38:24 ib Exp $
3  * $Revision: 1.9 $
4  * $Date: 2004/07/28 09:38:24 $
5  *
6  * ====================================================================
7  *
8  * Copyright 1999-2002 The Apache Software Foundation
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  * http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  */

23
24 package org.apache.slide.common;
25
26 import java.util.Hashtable JavaDoc;
27 import java.util.Vector JavaDoc;
28
29 import javax.transaction.xa.XAException JavaDoc;
30 import javax.transaction.xa.XAResource JavaDoc;
31 import javax.transaction.xa.Xid JavaDoc;
32
33 import org.apache.slide.transaction.SlideTransactionManager;
34
35 /**
36  * Slide Service abstract implementation with support for multiple
37  * simultaneous transaction context.
38  *
39  * @version $Revision: 1.9 $
40  */

41 public abstract class AbstractService extends AbstractServiceBase
42     implements Service {
43     
44     
45     // -------------------------------------------------------------- Constants
46

47     
48     public static final int TX_IDLE = 0;
49     public static final int TX_PREPARED = 1;
50     public static final int TX_SUSPENDED = 2;
51     
52     
53     // ----------------------------------------------------- Instance Variables
54

55     
56     /**
57      * Current transaction context.
58      */

59     protected Hashtable JavaDoc currentContexts = new Hashtable JavaDoc();
60     
61     
62     // ----------------------------------------------------- XAResource Mathods
63

64     
65     /**
66      * Commit the global transaction specified by xid.
67      *
68      * @param xid A global transaction identifier
69      * @param onePhase If true, the resource manager should use a one-phase
70      * commit protocol to commit the work done on behalf of xid.
71      * @exception XAException An error has occurred. Possible XAExceptions
72      * are XA_HEURHAZ, XA_HEURCOM, XA_HEURRB, XA_HEURMIX, XAER_RMERR,
73      * XAER_RMFAIL, XAER_NOTA, XAER_INVAL, or XAER_PROTO. If the resource
74      * manager did not commit the transaction and the paramether onePhase is
75      * set to true, the resource manager may throw one of the XA_RB*
76      * exceptions. Upon return, the resource manager has rolled back the
77      * branch's work and has released all held resources.
78      */

79     public void commit(Xid JavaDoc xid, boolean onePhase)
80         throws XAException JavaDoc {
81         
82         ContextTuple currentContextTuple =
83             (ContextTuple) currentContexts.get(Thread.currentThread());
84         Xid JavaDoc currentContext =
85             currentContextTuple!=null?currentContextTuple.getXid():null;
86         
87         if (currentContext == null)
88             throw new XAException JavaDoc(XAException.XAER_NOTA);
89         if (xid == null)
90             throw new XAException JavaDoc(XAException.XAER_INVAL);
91         if (currentContext.getGlobalTransactionId()
92             != xid.getGlobalTransactionId())
93             throw new XAException JavaDoc(XAException.XAER_PROTO);
94         
95         if (!onePhase && currentContextTuple.getStatus() != TX_PREPARED)
96             throw new XAException JavaDoc(XAException.XAER_PROTO);
97         if (onePhase &&
98             (!((currentContextTuple.getStatus() == TX_IDLE) ||
99                (currentContextTuple.getStatus() == TX_SUSPENDED))))
100             throw new XAException JavaDoc(XAException.XAER_PROTO);
101         
102         if (((ContextTuple) currentContexts.get(Thread.currentThread()))
103             .getRollbackOnly()) {
104             rollback(xid);
105             throw new XAException JavaDoc(XAException.XA_RBROLLBACK);
106         }
107         
108         currentContexts.remove(Thread.currentThread());
109         
110     }
111     
112     
113     /**
114      * Ends the work performed on behalf of a transaction branch. The
115      * resource manager disassociates the XA resource from the transaction
116      * branch specified and let the transaction be completed.
117      * If TMSUSPEND is specified in flags, the transaction branch is
118      * temporarily suspended in incomplete state. The transaction context is
119      * in suspened state and must be resumed via start with TMRESUME specified.
120      * If TMFAIL is specified, the portion of work has failed. The resource
121      * manager may mark the transaction as rollback-only.
122      * If TMSUCCESS is specified, the portion of work has completed
123      * successfully.
124      *
125      * @param xid A global transaction identifier that is the same as what
126      * was used previously in the start method.
127      * @param flags One of TMSUCCESS, TMFAIL, or TMSUSPEND
128      * @exception XAException An error has occurred. Possible XAException
129      * values are XAER_RMERR, XAER_RMFAILED, XAER_NOTA, XAER_INVAL,
130      * XAER_PROTO, or XA_RB*.
131      */

132     public void end(Xid JavaDoc xid, int flags)
133         throws XAException JavaDoc {
134         
135         ContextTuple currentContextTuple =
136             (ContextTuple) currentContexts.get(Thread.currentThread());
137         Xid JavaDoc currentContext =
138             currentContextTuple!=null?currentContextTuple.getXid():null;
139         
140         if (currentContext == null)
141             throw new XAException JavaDoc(XAException.XAER_NOTA);
142         if (xid == null)
143             throw new XAException JavaDoc(XAException.XAER_INVAL);
144         if (currentContext.getGlobalTransactionId()
145             != xid.getGlobalTransactionId())
146             throw new XAException JavaDoc(XAException.XAER_PROTO);
147         
148         if (flags == XAResource.TMSUSPEND)
149             currentContextTuple.setStatus(TX_SUSPENDED);
150         
151         if (flags == XAResource.TMFAIL)
152             ((ContextTuple) currentContexts.get(Thread.currentThread()))
153                 .setRollbackOnly(true);
154         
155     }
156     
157     
158     /**
159      * Tell the resource manager to forget about a heuristically completed
160      * transaction branch.
161      *
162      * @param xid A global transaction identifier
163      * @exception XAException An error has occurred. Possible exception values
164      * are XAER_RMERR, XAER_RMFAIL, XAER_NOTA, XAER_INVAL, or XAER_PROTO.
165      */

166     public void forget(Xid JavaDoc xid)
167         throws XAException JavaDoc {
168         
169         ContextTuple currentContextTuple =
170             (ContextTuple) currentContexts.get(Thread.currentThread());
171         Xid JavaDoc currentContext =
172             currentContextTuple!=null?currentContextTuple.getXid():null;
173         
174         if (currentContext == null)
175             throw new XAException JavaDoc(XAException.XAER_NOTA);
176         if (xid == null)
177             throw new XAException JavaDoc(XAException.XAER_INVAL);
178         if (currentContext.getGlobalTransactionId()
179             != xid.getGlobalTransactionId())
180             throw new XAException JavaDoc(XAException.XAER_PROTO);
181         
182         currentContexts.remove(Thread.currentThread());
183         
184     }
185     
186     
187     /**
188      * Obtain the current transaction timeout value set for this XAResource
189      * instance. If XAResource.setTransactionTimeout was not use prior to
190      * invoking this method, the return value is the default timeout set for
191      * the resource manager; otherwise, the value used in the previous
192      * setTransactionTimeout call is returned.
193      *
194      * @return the transaction timeout value in seconds.
195      * @exception XAException An error has occurred. Possible exception
196      * values are XAER_RMERR, XAER_RMFAIL.
197      */

198     public int getTransactionTimeout()
199         throws XAException JavaDoc {
200         
201         return ((ContextTuple) currentContexts.get(Thread.currentThread()))
202             .getTransactionTimeout();
203         
204     }
205     
206     
207     /**
208      * This method is called to determine if the resource manager instance
209      * represented by the target object is the same as the resouce manager
210      * instance represented by the parameter xares.
211      *
212      * @param xares An XAResource object whose resource manager instance is
213      * to be compared with the resource manager instance of the target object.
214      * @return true if it's the same RM instance; otherwise false.
215      * @exception XAException An error has occurred. Possible exception values
216      * are XAER_RMERR, XAER_RMFAIL.
217      */

218     public boolean isSameRM(XAResource JavaDoc xares)
219         throws XAException JavaDoc {
220         
221         if (xares == null)
222             return false;
223         
224         return (this == xares);
225         
226     }
227     
228     
229     /**
230      * Ask the resource manager to prepare for a transaction commit of the
231      * transaction specified in xid.
232      *
233      * @param xid A global transaction identifier
234      * @return A value indicating the resource manager's vote on the outcome
235      * of the transaction. The possible values are: XA_RDONLY or XA_OK. If
236      * the resource manager wants to roll back the transaction, it should do
237      * so by raising an appropriate XAException in the prepare method.
238      * @exception XAException An error has occurred. Possible exception
239      * values are: XA_RB*, XAER_RMERR, XAER_RMFAIL, XAER_NOTA, XAER_INVAL,
240      * or XAER_PROTO.
241      */

242     public int prepare(Xid JavaDoc xid)
243         throws XAException JavaDoc {
244         
245         ContextTuple currentContextTuple =
246             (ContextTuple) currentContexts.get(Thread.currentThread());
247         Xid JavaDoc currentContext =
248             currentContextTuple!=null?currentContextTuple.getXid():null;
249         
250         if (currentContext == null)
251             throw new XAException JavaDoc(XAException.XAER_NOTA);
252         if (xid == null)
253             throw new XAException JavaDoc(XAException.XAER_INVAL);
254         if (currentContext.getGlobalTransactionId()
255             != xid.getGlobalTransactionId())
256             throw new XAException JavaDoc(XAException.XAER_PROTO);
257         
258         if (!((currentContextTuple.getStatus() == TX_IDLE) ||
259               (currentContextTuple.getStatus() == TX_SUSPENDED)))
260             throw new XAException JavaDoc(XAException.XAER_PROTO);
261         
262         if (((ContextTuple) currentContexts.get(Thread.currentThread()))
263             .getRollbackOnly()) {
264             // FIXME: Don't know if should be automatically rollbacked in that
265
// case
266
throw new XAException JavaDoc(XAException.XA_RBROLLBACK);
267         }
268         
269         currentContextTuple.setStatus(TX_PREPARED);
270         
271         return XAResource.XA_OK;
272         
273     }
274     
275     
276     /**
277      * Obtain a list of prepared transaction branches from a resource manager.
278      * The transaction manager calls this method during recovery to obtain the
279      * list of transaction branches that are currently in prepared or
280      * heuristically completed states.
281      *
282      * @param flag One of TMSTARTRSCAN, TMENDRSCAN, TMNOFLAGS. TMNOFLAGS must
283      * be used when no other flags are set in flags.
284      * @return The resource manager returns zero or more XIDs for the
285      * transaction branches that are currently in a prepared or heuristically
286      * completed state. If an error occurs during the operation, the resource
287      * manager should throw the appropriate XAException.
288      * @exception XAException An error has occurred. Possible values are
289      * XAER_RMERR, XAER_RMFAIL, XAER_INVAL, and XAER_PROTO.
290      */

291     public Xid JavaDoc[] recover(int flag)
292         throws XAException JavaDoc {
293         
294         ContextTuple currentContextTuple =
295            (ContextTuple) currentContexts.get(Thread.currentThread());
296         Xid JavaDoc currentContext =
297            currentContextTuple!=null?currentContextTuple.getXid():null;
298         
299         Vector JavaDoc list = new Vector JavaDoc();
300         
301         if ((currentContextTuple.getStatus() == TX_PREPARED) &&
302             (currentContext != null))
303            list.addElement(currentContext);
304         
305         return (Xid JavaDoc[]) list.toArray(new Xid JavaDoc[list.size()]);
306         
307     }
308     
309     
310     /**
311      * Inform the resource manager to roll back work done on behalf of a
312      * transaction branch.
313      *
314      * @param xid A global transaction identifier
315      * @exception XAException An error has occurred
316      */

317     public void rollback(Xid JavaDoc xid)
318         throws XAException JavaDoc {
319         
320         ContextTuple currentContextTuple =
321             (ContextTuple) currentContexts.get(Thread.currentThread());
322         Xid JavaDoc currentContext =
323             currentContextTuple!=null?currentContextTuple.getXid():null;
324         
325         if (currentContext == null)
326             throw new XAException JavaDoc(XAException.XAER_NOTA);
327         if (xid == null)
328             throw new XAException JavaDoc(XAException.XAER_INVAL);
329         if (currentContext.getGlobalTransactionId()
330             != xid.getGlobalTransactionId())
331             throw new XAException JavaDoc(XAException.XAER_PROTO);
332         
333         currentContexts.remove(Thread.currentThread());
334         
335     }
336     
337     
338     /**
339      * Set the current transaction timeout value for this XAResource instance.
340      *
341      * @param seconds the transaction timeout value in seconds.
342      * @return true if transaction timeout value is set successfully;
343      * otherwise false.
344      * @exception XAException An error has occurred. Possible exception
345      * values are XAER_RMERR, XAER_RMFAIL, or XAER_INVAL.
346      */

347     public boolean setTransactionTimeout(int seconds)
348         throws XAException JavaDoc {
349             
350         ((ContextTuple) currentContexts.get(Thread.currentThread()))
351             .setTransactionTimeout(seconds);
352         return true;
353         
354     }
355     
356     
357     /**
358      * Start work on behalf of a transaction branch specified in xid If
359      * TMJOIN is specified, the start is for joining a transaction previously
360      * seen by the resource manager. If TMRESUME is specified, the start is
361      * to resume a suspended transaction specified in the parameter xid. If
362      * neither TMJOIN nor TMRESUME is specified and the transaction specified
363      * by xid has previously been seen by the resource manager, the resource
364      * manager throws the XAException exception with XAER_DUPID error code.
365      *
366      * @param xid A global transaction identifier to be associated with the
367      * resource
368      * @param flags One of TMNOFLAGS, TMJOIN, or TMRESUME
369      * @exception XAException An error has occurred. Possible exceptions are
370      * XA_RB*, XAER_RMERR, XAER_RMFAIL, XAER_DUPID, XAER_OUTSIDE, XAER_NOTA,
371      * XAER_INVAL, or XAER_PROTO.
372      */

373     public void start(Xid JavaDoc xid, int flags)
374         throws XAException JavaDoc {
375         
376         ContextTuple currentContextTuple =
377             (ContextTuple) currentContexts.get(Thread.currentThread());
378         Xid JavaDoc currentContext =
379             currentContextTuple!=null?currentContextTuple.getXid():null;
380         
381         if (xid == null)
382             throw new XAException JavaDoc(XAException.XAER_INVAL);
383         if ( (currentContext != null) &&
384              (currentContext.getGlobalTransactionId()
385               != xid.getGlobalTransactionId()) )
386             throw new XAException JavaDoc(XAException.XAER_OUTSIDE);
387         
388         switch (flags) {
389         case XAResource.TMNOFLAGS:
390             if (currentContext != null)
391                 throw new XAException JavaDoc(XAException.XAER_INVAL);
392             currentContext = xid;
393             // is the idle status really ok ???
394
currentContexts.put
395                 (Thread.currentThread(),new ContextTuple
396                     (xid, TX_IDLE,
397                      SlideTransactionManager.DEFAULT_TRANSACTION_TIMEOUT,
398                      false));
399             break;
400         case XAResource.TMJOIN:
401             if (currentContext == null)
402                 throw new XAException JavaDoc(XAException.XAER_NOTA);
403             if (currentContext.getGlobalTransactionId()
404                 != xid.getGlobalTransactionId())
405                 throw new XAException JavaDoc(XAException.XAER_INVAL);
406             break;
407         case XAResource.TMRESUME:
408             if (currentContext == null)
409                 throw new XAException JavaDoc(XAException.XAER_NOTA);
410             if (currentContextTuple.getStatus() != TX_SUSPENDED)
411                 throw new XAException JavaDoc(XAException.XAER_INVAL);
412             currentContextTuple.setStatus(TX_IDLE);
413             break;
414         }
415         
416     }
417     
418     
419     // ------------------------------------------------ ContextTuple InnerClass
420

421     
422     /**
423      * inner class to pack both the xid and the status
424      **/

425     private class ContextTuple {
426         private Xid JavaDoc xid;
427         private int status;
428         private int transactionTimeout;
429         private boolean rollbackOnly;
430         public ContextTuple(Xid JavaDoc xid, int status, int transactionTimeout,
431                             boolean rollbackOnly) {
432             this.xid = xid;
433             setStatus(status);
434             setTransactionTimeout(transactionTimeout);
435             setRollbackOnly(rollbackOnly);
436         }
437         public Xid JavaDoc getXid() {
438             return xid;
439         }
440         public int getStatus() {
441             return status;
442         }
443         public void setStatus(int status) {
444             this.status = status;
445         }
446         public int getTransactionTimeout() {
447             return transactionTimeout;
448         }
449         public void setTransactionTimeout(int transactionTimeout) {
450             this.transactionTimeout = transactionTimeout;
451         }
452         public boolean getRollbackOnly() {
453             return rollbackOnly;
454         }
455         public void setRollbackOnly(boolean rollbackOnly) {
456             this.rollbackOnly = rollbackOnly;
457         }
458         
459     }
460     
461     
462 }
463
464
465
Popular Tags