KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > distributedtx > J2EETransaction


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23 package com.sun.enterprise.distributedtx;
24
25 import java.util.*;
26 import javax.transaction.*;
27 import com.sun.enterprise.*;
28 import com.sun.enterprise.resource.*;
29 import com.sun.enterprise.log.Log;
30 import com.sun.enterprise.util.Utility;
31 import com.sun.enterprise.util.i18n.StringManager;
32
33 import javax.transaction.xa.*;
34
35 import javax.persistence.EntityManagerFactory;
36 import javax.persistence.EntityManager;
37
38 import com.sun.jts.jta.TransactionManagerImpl;
39 import com.sun.jts.jta.TransactionImpl;
40
41 //START OF IASRI 4660742
42
import java.util.logging.*;
43 import com.sun.logging.*;
44 //END OF IASRI 4660742
45

46 /**
47  * This class implements the JTA Transaction API for the J2EE RI.
48  * It is a wrapper over the JTS Transaction object that provides optimized local
49  * transaction support when a transaction uses zero/one non-XA resource,
50  * and delegates to JTS otherwise.
51  * This object can be in two states: local tx (jtsTx==null) or global (JTS) tx.
52  * If jtsTx!=null, all calls are delegated to jtsTx.
53  *
54
55  * Time out capability is added to the local transactions. This class extends the TimerTask.
56  * When the transaction needs to be timedout, this schedules with the timer. At the commit
57  * and rollback time, task will be cancelled. If the transaction is timedout, run() method
58  * will be called and transaction will be marked for rollback.
59  */

60 public final class J2EETransaction extends TimerTask implements Transaction {
61
62     // START OF IASRI 4660742
63
static Logger _logger=LogDomains.getLogger(LogDomains.JTA_LOGGER);
64     // END OF IASRI 4660742
65
// Sting Manager for Localization
66
private static StringManager sm = StringManager.getManager(J2EETransaction.class);
67
68
69
70     // Local Tx ids are just numbers: they dont need to be unique across
71
// processes or across multiple activations of this server process.
72
private static long txIdCounter = 1;
73
74     private long txId;
75     private J2EEXid xid;
76     static J2EETransactionManagerOpt j2eeTM;
77     private Transaction jtsTx;
78     private ResourceHandle nonXAResource;
79     private ResourceHandle laoResource;
80     private int localTxStatus;
81     private Vector syncs = new Vector();
82     private Vector interposedSyncs = new Vector();
83     private boolean commitStarted = false;
84     // START 4662745
85
private long startTime;
86     // END 4662745
87

88     // START: local transaction timeout
89
private boolean isTimedOut = false;
90     private boolean isTimerTask = false;
91     private int timeout;
92     // END: local transaction timeout
93
private boolean imported = false;
94
95     private HashMap resourceTable;
96     private HashMap<Object JavaDoc, Object JavaDoc> userResourceMap;
97
98     //This cache contains the EntityContexts in this Tx
99
private Object JavaDoc activeTxCache;
100
101     // EntityManager mapping for EMs with TX persistent context type
102
private Map<EntityManagerFactory, EntityManager> txEntityManagerMap;
103
104     // EntityManager mapping for EMs with EXTENDED persistence context type
105
private Map<EntityManagerFactory, EntityManager> extendedEntityManagerMap;
106     private String JavaDoc componentName = null;
107     private ArrayList<String JavaDoc> resourceNames = null;
108
109     static private boolean isTimerInitialized = false;
110     static private Timer timer = null;
111
112     static synchronized private void initializeTimer() {
113         if (isTimerInitialized)
114             return;
115         timer = new Timer(true); // daemon
116
isTimerInitialized = true;
117     }
118
119     // J2EETransaction(J2EETransactionManagerOpt j2eeTM)
120
J2EETransaction()
121     {
122         this.txId = getNewTxId();
123         this.xid = new J2EEXid(txId);
124         this.resourceTable = new HashMap();
125         localTxStatus = Status.STATUS_ACTIVE;
126         startTime=System.currentTimeMillis();
127         if (_logger.isLoggable(Level.FINE)) {
128             _logger.log(Level.FINE,"--Created new J2EETransaction, txId = "+txId);
129         }
130     }
131
132     
133     // START: local transaction timeout
134
J2EETransaction(int timeout)
135     {
136         this();
137         if (!isTimerInitialized)
138             initializeTimer();
139         timer.schedule(this,timeout * 1000);
140         isTimerTask = true;
141         this.timeout = timeout;
142     }
143     // END: local transaction timeout
144

145
146
147     J2EETransaction(Transaction jtsTx)
148     {
149     this();
150     this.jtsTx = jtsTx;
151     }
152
153     // START: local transaction timeout
154
// TimerTask run() method implementation
155
public void run() {
156         isTimedOut = true;
157         try {
158         setRollbackOnly();
159     } catch (Exception JavaDoc e) {
160         e.printStackTrace();
161     }
162     }
163
164     boolean isAssociatedTimeout() {
165         return isTimerTask;
166     }
167
168     // Cancels the timertask and returns the timeout
169
int cancelTimerTask() {
170         cancel();
171         return timeout;
172     }
173
174     boolean isTimedout() {
175         return isTimedOut;
176     }
177     // END: local transaction timeout
178

179
180
181     private static synchronized long getNewTxId() {
182     long newTxId = txIdCounter++;
183     return newTxId;
184     }
185
186     public boolean equals(Object JavaDoc other)
187     {
188     if ( other == this )
189         return true;
190     if ( other instanceof J2EETransaction ) {
191         J2EETransaction othertx = (J2EETransaction)other;
192         return ( txId == othertx.txId );
193     }
194     return false;
195     }
196
197     public int hashCode()
198     {
199     return (int)txId;
200     }
201
202
203     Xid getLocalXid()
204     {
205     return xid;
206     }
207
208     public ResourceHandle getNonXAResource()
209     {
210     return nonXAResource;
211     }
212
213     void setNonXAResource(ResourceHandle h)
214     {
215     nonXAResource = h;
216     }
217
218     ResourceHandle getLAOResource()
219     {
220         return laoResource;
221     }
222
223     void setLAOResource(ResourceHandle h)
224     {
225         laoResource = h;
226     }
227
228     void setImportedTransaction() {
229         imported = true;
230     }
231
232     boolean isImportedTransaction() {
233         return imported;
234     }
235
236     synchronized void putUserResource(Object JavaDoc key, Object JavaDoc value) {
237         if (userResourceMap == null)
238             userResourceMap = new HashMap<Object JavaDoc, Object JavaDoc>();
239         userResourceMap.put(key, value);
240     }
241
242     synchronized Object JavaDoc getUserResource(Object JavaDoc key) {
243         if (userResourceMap == null)
244             return null;
245         return userResourceMap.get(key);
246     }
247
248     void registerInterposedSynchronization(Synchronization sync) {
249         interposedSyncs.add(sync);
250     }
251
252     void setComponentName(String JavaDoc componentName) {
253         this.componentName = componentName;
254     }
255     
256     String JavaDoc getComponentName() {
257         return componentName;
258     }
259  
260     synchronized void addResourceName(String JavaDoc resourceName) {
261         if (resourceNames == null)
262             resourceNames = new ArrayList<String JavaDoc>();
263         resourceNames.add(resourceName);
264     }
265
266     synchronized ArrayList<String JavaDoc> getResourceNames() {
267         return resourceNames;
268     }
269
270
271     public void addTxEntityManagerMapping(EntityManagerFactory emf,
272                                           EntityManager em) {
273         getTxEntityManagerMap().put(emf, em);
274     }
275
276     public EntityManager getTxEntityManager(EntityManagerFactory emf) {
277         return getTxEntityManagerMap().get(emf);
278     }
279
280     private Map<EntityManagerFactory, EntityManager>
281         getTxEntityManagerMap() {
282         if( txEntityManagerMap == null ) {
283             txEntityManagerMap =
284                 new HashMap<EntityManagerFactory, EntityManager>();
285         }
286         return txEntityManagerMap;
287     }
288     
289     private void onTxCompletion(boolean status) {
290         for (Map.Entry<EntityManagerFactory, EntityManager> entry :
291             getTxEntityManagerMap().entrySet()) {
292             
293             EntityManager em = entry.getValue();
294             if (em.isOpen()) {
295                 try {
296                     em.close();
297                 } catch (Throwable JavaDoc th) {
298                     if (_logger.isLoggable(Level.FINE)) {
299                         _logger.log(Level.FINE, "Exception while closing em.", th);
300                     }
301                 }
302             }
303         }
304     }
305
306     public void addExtendedEntityManagerMapping(EntityManagerFactory emf,
307                                                 EntityManager em) {
308         getExtendedEntityManagerMap().put(emf, em);
309     }
310
311     public void removeExtendedEntityManagerMapping(EntityManagerFactory emf) {
312         getExtendedEntityManagerMap().remove(emf);
313     }
314
315     public EntityManager getExtendedEntityManager(EntityManagerFactory emf) {
316         return getExtendedEntityManagerMap().get(emf);
317     }
318
319     private Map<EntityManagerFactory, EntityManager>
320         getExtendedEntityManagerMap() {
321         if( extendedEntityManagerMap == null ) {
322             extendedEntityManagerMap =
323                 new HashMap<EntityManagerFactory, EntityManager>();
324         }
325         return extendedEntityManagerMap;
326     }
327
328     boolean isLocalTx()
329     {
330     return (jtsTx==null);
331     }
332
333     void setJTSTx(Transaction jtsTx) throws RollbackException, SystemException
334     {
335     this.jtsTx = jtsTx;
336
337     if ( !commitStarted ) {
338         // register syncs
339
for ( int i=0; i<syncs.size(); i++ )
340         jtsTx.registerSynchronization((Synchronization)syncs.elementAt(i));
341         for ( int i=0; i<interposedSyncs.size(); i++ )
342         ((TransactionImpl)jtsTx).registerInterposedSynchronization((Synchronization)interposedSyncs.elementAt(i));
343     }
344     }
345
346     Transaction getJTSTx()
347     {
348     return jtsTx;
349     }
350
351
352     public void commit() throws RollbackException,
353                 HeuristicMixedException, HeuristicRollbackException,
354                 SecurityException JavaDoc, IllegalStateException JavaDoc, SystemException
355     {
356     // START local transaction timeout
357
// If this transaction is set for timeout, cancel it as it is in the commit state
358
if (isTimerTask)
359         cancel();
360     // END local transaction timeout
361
if (_logger.isLoggable(Level.FINE)) {
362             _logger.log(Level.FINE,"--In J2EETransaction.commit, jtsTx="+jtsTx
363                 +" nonXAResource="+ nonXAResource);
364         }
365     commitStarted = true;
366
367     if ( jtsTx != null ) {
368         try {
369         jtsTx.commit();
370         } finally {
371         j2eeTM.clearThreadTx();
372                 onTxCompletion(true);
373         }
374     }
375     else { // local tx
376
try {
377         if ( isTimedOut ) {
378             // rollback nonXA resource
379
if ( nonXAResource != null )
380             nonXAResource.getXAResource().rollback(xid);
381             localTxStatus = Status.STATUS_ROLLEDBACK;
382             throw new RollbackException(sm.getString("enterprise_distributedtx.rollback_timeout"));
383         }
384         if ( isRollbackOnly() ) {
385             // rollback nonXA resource
386
if ( nonXAResource != null )
387             nonXAResource.getXAResource().rollback(xid);
388             localTxStatus = Status.STATUS_ROLLEDBACK;
389             throw new RollbackException(sm.getString("enterprise_distributedtx.mark_rollback"));
390         }
391         // call beforeCompletion
392
for ( int i=0; i<syncs.size(); i++ ) {
393             try {
394             Synchronization sync = (Synchronization)syncs.elementAt(i);
395             sync.beforeCompletion();
396             } catch ( RuntimeException JavaDoc ex ) {
397                         setRollbackOnly();
398                     } catch (Exception JavaDoc ex) { }
399         }
400         for ( int i=0; i<interposedSyncs.size(); i++ ) {
401             try {
402             Synchronization sync = (Synchronization)interposedSyncs.elementAt(i);
403             sync.beforeCompletion();
404             } catch ( RuntimeException JavaDoc ex ) {
405                         setRollbackOnly();
406                     } catch (Exception JavaDoc ex) { }
407                 }
408         // check rollbackonly again, in case any of the beforeCompletion
409
// calls marked it for rollback.
410
if ( isRollbackOnly()) {
411             //Check if it is a Local Transaction
412
if(jtsTx == null) {
413                 if ( nonXAResource != null )
414                 nonXAResource.getXAResource().rollback(xid);
415                 localTxStatus = Status.STATUS_ROLLEDBACK;
416                 throw new RollbackException(sm.getString("enterprise_distributedtx.mark_rollback"));
417             // else it is a global transaction
418
} else {
419                 jtsTx.rollback();
420                 localTxStatus = Status.STATUS_ROLLEDBACK;
421                 throw new RollbackException(sm.getString("enterprise_distributedtx.mark_rollback"));
422             }
423         }
424         // check if there is a jtsTx active, in case any of the
425
// beforeCompletions registered the first XA resource.
426
if ( jtsTx != null ) {
427             jtsTx.commit();
428             //IASRI START 4731186
429
localTxStatus = Status.STATUS_COMMITTED;
430             //IASRI END 4731186
431
// Note: JTS will not call afterCompletions in this case,
432
// because no syncs have been registered with JTS.
433
// So afterCompletions are called in finally block below.
434
}
435         else {
436             // do single-phase commit on nonXA resource
437
if ( nonXAResource != null )
438             nonXAResource.getXAResource().commit(xid, true);
439
440             // XXX should this be STATUS_NO_TRANSACTION ?
441
localTxStatus = Status.STATUS_COMMITTED;
442         }
443         } catch ( RollbackException ex ) {
444         localTxStatus = Status.STATUS_ROLLEDBACK; // XXX is this correct ?
445
throw ex;
446         } catch ( SystemException ex ) {
447         // localTxStatus = Status.STATUS_ROLLEDBACK; // XXX is this correct ?
448
localTxStatus = Status.STATUS_COMMITTING;
449         throw ex;
450         } catch ( Exception JavaDoc ex ) {
451         localTxStatus = Status.STATUS_ROLLEDBACK; // XXX is this correct ?
452
SystemException exc = new SystemException();
453                 exc.initCause(ex);
454                 throw exc;
455         } finally {
456         j2eeTM.clearThreadTx();
457         for ( int i=0; i<interposedSyncs.size(); i++ ) {
458             try {
459             Synchronization sync = (Synchronization)interposedSyncs.elementAt(i);
460             sync.afterCompletion(localTxStatus);
461             } catch ( Exception JavaDoc ex ) {}
462         }
463         // call afterCompletions
464
for ( int i=0; i<syncs.size(); i++ ) {
465             try {
466             Synchronization sync = (Synchronization)syncs.elementAt(i);
467             sync.afterCompletion(localTxStatus);
468             } catch ( Exception JavaDoc ex ) {}
469         }
470                 onTxCompletion(true);
471         }
472     }
473     }
474
475     public void rollback() throws IllegalStateException JavaDoc, SystemException
476     {
477         // START local transaction timeout
478
// If this transaction is set for timeout, cancel it as it is in the rollback state
479
if (isTimerTask)
480             cancel();
481         // END local transaction timeout
482
if (_logger.isLoggable(Level.FINE)) {
483         _logger.log(Level.FINE,"--In J2EETransaction.rollback, jtsTx="+jtsTx
484             +" nonXAResource="+nonXAResource);
485         }
486     try {
487         if ( jtsTx != null )
488         jtsTx.rollback();
489         else { // rollback nonXA resource
490
if ( nonXAResource != null )
491             nonXAResource.getXAResource().rollback(xid);
492
493         // XXX should this be STATUS_NO_TRANSACTION ?
494
localTxStatus = Status.STATUS_ROLLEDBACK;
495         }
496     } catch ( Exception JavaDoc ex ) {
497         localTxStatus = Status.STATUS_ROLLEDBACK; // XXX is this correct ?
498
} finally {
499         j2eeTM.clearThreadTx();
500         if ( jtsTx == null ) {
501         // call afterCompletions
502
for ( int i=0; i<syncs.size(); i++ ) {
503             try {
504             Synchronization sync = (Synchronization)syncs.elementAt(i);
505             sync.afterCompletion(Status.STATUS_ROLLEDBACK);
506             } catch ( Exception JavaDoc ex ) {}
507         }
508         }
509             onTxCompletion(false);
510     }
511     }
512
513     public boolean delistResource(XAResource xaRes, int flag)
514         throws IllegalStateException JavaDoc, SystemException
515     {
516         // START OF IASRI 4660742
517
if (_logger.isLoggable(Level.FINE)) {
518             _logger.log(Level.FINE,"--In J2EETransaction.delistResource, jtsTx="
519           +jtsTx +" nonXAResource="+nonXAResource);
520        }
521         // END OF IASRI 4660742
522

523     if ( jtsTx != null )
524         return jtsTx.delistResource(xaRes, flag);
525     else
526         throw new IllegalStateException JavaDoc(sm.getString("enterprise_distributedtx.deleteresource_for_localtx"));
527     }
528
529     public boolean enlistResource(XAResource xaRes)
530         throws RollbackException, IllegalStateException JavaDoc,
531         SystemException
532     {
533       if (_logger.isLoggable(Level.FINE)) {
534             _logger.log(Level.FINE,"--In J2EETransaction.enlistResource, jtsTx="
535                 +jtsTx+" nonXAResource="+nonXAResource);
536        }
537     if ( jtsTx != null )
538         return jtsTx.enlistResource(xaRes);
539     else if ( nonXAResource != null )
540         throw new IllegalStateException JavaDoc(sm.getString("enterprise_distributedtx.already_has_nonxa"));
541     // IASRI END 4723068
542
/***
543     else // XXX what to do ? Start a new JTS tx ?
544         throw new IllegalStateException("J2EETransaction.enlistResource called for local tx");
545     ***/

546     else { // Start a new JTS tx
547
j2eeTM.startJTSTx(this);
548         return jtsTx.enlistResource(xaRes);
549     }
550     // IASRI END 4723068
551
}
552
553     public int getStatus() throws SystemException
554     {
555     if ( jtsTx != null )
556         return jtsTx.getStatus();
557     else
558         return localTxStatus;
559     }
560
561     public void registerSynchronization(Synchronization sync)
562                 throws RollbackException, IllegalStateException JavaDoc,
563                 SystemException
564     {
565         // START OF IASRI 4660742
566
if (_logger.isLoggable(Level.FINE)) {
567             _logger.log(Level.FINE,"--In J2EETransaction.registerSynchronization, jtsTx=" +jtsTx+" nonXAResource="+nonXAResource);
568       }
569         // END OF IASRI 4660742
570

571     if ( jtsTx != null )
572         jtsTx.registerSynchronization(sync);
573     else
574         syncs.add(sync);
575     }
576
577     public void setRollbackOnly() throws IllegalStateException JavaDoc,
578         SystemException
579     {
580     if ( jtsTx != null )
581         jtsTx.setRollbackOnly();
582     else
583         localTxStatus = Status.STATUS_MARKED_ROLLBACK;
584     }
585
586     private boolean isRollbackOnly() throws IllegalStateException JavaDoc,
587         SystemException
588     {
589     int status;
590     if ( jtsTx != null )
591         status = jtsTx.getStatus();
592     else
593         status = localTxStatus;
594
595     return (status == Status.STATUS_MARKED_ROLLBACK);
596     }
597
598
599
600     public String JavaDoc toString()
601     {
602     return "J2EETransaction: txId="+txId+" nonXAResource="+nonXAResource
603         +" jtsTx="+jtsTx+" localTxStatus="+localTxStatus
604         +" syncs="+syncs;
605     }
606
607     // START IASRI 4662745
608
/*
609      * This method is used for the Admin Framework displaying
610      * of Transactions Ids
611      */

612     public String JavaDoc getTransactionId(){
613         return xid.toString();
614     }
615
616     /*
617      * This method returns the time this transaction was started
618      */

619     public long getStartTime(){
620         return startTime;
621     }
622     // END IASRI 4662745
623

624     public void setResources(Set resources, String JavaDoc poolName) {
625         resourceTable.put(poolName, resources);
626     }
627
628     public Set getResources(String JavaDoc poolName) {
629         return (Set) resourceTable.get(poolName);
630     }
631
632     /**
633      * Return all pools registered in the resourceTable. This
634      * will cut down the scope of pools on which transactionComplted
635      * is called by the PoolManagerImpl. This method will return
636      * only those pools that have ever participated in a tx
637      */

638     public Set getAllParticipatingPools() {
639         return (Set) resourceTable.keySet();
640     }
641
642     // somehow javac wont allow this declaration within J2EEXid
643
private static final byte[] bqual = new byte[]{0};
644
645     // Assume that there is only one instance of this class per local tx.
646
private class J2EEXid implements javax.transaction.xa.Xid JavaDoc {
647     private static final int formatId = 987654321;
648     private byte[] gtrId;
649         // START IASRI 4662745
650
private String JavaDoc stringForm=null;
651         // END IASRI 4662745
652
J2EEXid(long txId) {
653         gtrId = new byte[8];
654         Utility.longToBytes(txId, gtrId, 0);
655     }
656     public int getFormatId() {
657         return formatId;
658     }
659     public byte[] getGlobalTransactionId() {
660         return gtrId;
661     }
662     public byte[] getBranchQualifier() {
663         return bqual; // XXX check if its ok to always have same bqual
664
}
665
666         // START IASRI 4662745
667
/*
668          * returens the Transaction id of this transaction
669          */

670         public String JavaDoc toString(){
671
672             // If we have a cached copy of the string form of the global identifier, return
673
// it now.
674
if( stringForm != null ) return stringForm;
675
676             // Otherwise format the global identifier.
677
//char[] buff = new char[gtrId.length*2 + 2/*'[' and ']'*/ + 3/*bqual and ':'*/];
678
char[] buff = new char[gtrId.length*2 + 3/*bqual and ':'*/];
679             int pos = 0;
680             //buff[pos++] = '[';
681

682             // Convert the global transaction identifier into a string of hex digits.
683

684             int globalLen = gtrId.length ;
685             for( int i = 0; i < globalLen; i++ ) {
686                 int currCharHigh = (gtrId[i]&0xf0) >> 4;
687                 int currCharLow = gtrId[i]&0x0f;
688                 buff[pos++] = (char)(currCharHigh + (currCharHigh > 9 ? 'A'-10 : '0'));
689                 buff[pos++] = (char)(currCharLow + (currCharLow > 9 ? 'A'-10 : '0'));
690             }
691
692             //buff[pos++] = ':';
693
buff[pos++] = '_';
694             int currCharHigh = (0&0xf0) >> 4;
695             int currCharLow = 0&0x0f;
696             buff[pos++] = (char)(currCharHigh + (currCharHigh > 9 ? 'A'-10 : '0'));
697             buff[pos++] = (char)(currCharLow + (currCharLow > 9 ? 'A'-10 : '0'));
698             //buff[pos] = ']';
699

700             // Cache the string form of the global identifier.
701
stringForm = new String JavaDoc(buff);
702
703             return stringForm;
704         }
705         // END IASRI 4662745
706
}
707
708     public void setActiveTxCache(Object JavaDoc cache) {
709     this.activeTxCache = cache;
710     }
711
712     public Object JavaDoc getActiveTxCache() {
713     return this.activeTxCache;
714     }
715
716 }
717
Popular Tags