KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jdo > spi > persistence > support > sqlstore > impl > TransactionImpl


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
24 /*
25  * TransactionImpl.java
26  *
27  * Create on March 3, 2000
28  */

29
30 package com.sun.jdo.spi.persistence.support.sqlstore.impl;
31
32 import javax.transaction.*;
33
34 import java.util.Hashtable JavaDoc;
35 import java.util.ArrayList JavaDoc;
36 import java.sql.Connection JavaDoc;
37 import javax.sql.DataSource JavaDoc;
38 import java.util.Locale JavaDoc;
39 import java.util.ResourceBundle JavaDoc;
40
41 import com.sun.jdo.api.persistence.support.ConnectionFactory;
42 import com.sun.jdo.api.persistence.support.JDOException;
43 import com.sun.jdo.api.persistence.support.JDOUnsupportedOptionException;
44 import com.sun.jdo.api.persistence.support.JDOFatalInternalException;
45 import com.sun.jdo.api.persistence.support.JDOUserException;
46 import com.sun.jdo.api.persistence.support.JDODataStoreException;
47
48 import com.sun.jdo.spi.persistence.support.sqlstore.PersistenceManager;
49 import com.sun.jdo.spi.persistence.support.sqlstore.PersistenceManagerFactory;
50 import com.sun.jdo.spi.persistence.utility.I18NHelper;
51
52 import com.sun.jdo.spi.persistence.support.sqlstore.connection.ConnectionImpl;
53
54 import com.sun.jdo.spi.persistence.support.sqlstore.utility.*;
55 import com.sun.jdo.spi.persistence.support.sqlstore.ejb.EJBHelper;
56 import com.sun.jdo.spi.persistence.utility.logging.Logger;
57 import com.sun.jdo.spi.persistence.support.sqlstore.LogHelperTransaction;
58
59 /**
60  *
61  * The Transaction interface allows operations to be performed against
62  * the transaction in the target Transaction object. A Transaction
63  * object is created corresponding to each global transaction creation.
64  * The Transaction object can be used for resource enlistment,
65  * synchronization registration, transaction completion and status
66  * query operations.
67  *
68  * This implementation is completely internal.
69  * All externally documented methods are on the Transaction interface.
70  *
71  * Note on synchronized(this):
72  * There are a number of places that calls are made outside the
73  * transaction system. For example, Synchronization.beforeCompletion()
74  * and XAResource.start(). It is important that no locks are held
75  * when these callbacks are made. This requires more state checking
76  * up return from these calls, and the methods are careful to check
77  * state transitions after release the lock and reacquiring it.
78  *
79  * Also be careful NOT to call into a lower method with the lock, if that
80  * method may call out of the transaction system.
81  *
82  * Take care if you make methods "synchronized" because:
83  * synchronized methodName()
84  * is not the same lock as a more localized:
85  * synchronized(this)
86  *
87  * This is tested in the regression tests (see "Lock Test")
88  */

89 public class TransactionImpl
90     implements com.sun.jdo.spi.persistence.support.sqlstore.Transaction {
91     /**
92      * Trace level for sh:6.
93      *
94      * This is public to this transaction package and referenced:
95      * if (TransactionImpl.tracing)
96      * This is reset by calling TransactionImpl.setTrace().
97      */

98     static boolean tracing;
99     private static final int TRACE_THREADS = 0x01;
100     private static final int TRACE_RESOURCES = 0x02;
101     private static final int TRACE_SYNCHRONIZATIONS = 0x04;
102     private static final int TRACE_ONE_PHASE = 0x08;
103
104     /**
105      * Package-visible lock for static attributes.
106      *
107      * Note that globalLock can be a higher-level lock, in that it may be
108      * locked before other lower-level objects are locked (i.e. the
109      * transaction object). It may NOT be locked the other way round.
110      */

111     static String JavaDoc globalLock = "TranGlobalLock"; // NOI18N
112

113     /**
114      * Transaction status (from javax.transaction.Status).
115      */

116     private int status;
117
118     /**
119      * Timeout for this transaction
120      */

121     private int timeout;
122     public static final int TRAN_DEFAULT_TIMEOUT = 0; // No timeout
123

124     /**
125      * Query and Update Statement timeouts for the datastore associated
126      * with this transaction
127      */

128     private int queryTimeout = 0; // No limit
129
private int updateTimeout = 0; // No limit
130

131     /**
132      * Number of threads participating in this transaction.
133      */

134     private int threads;
135     public static final int TRAN_MAX_THREADS = 50; // Public for test
136

137     /**
138      * The commit process has already begun (even though the status is still
139      * STATUS_ACTIVE). This is set during before-commit notification.
140      */

141     private boolean startedCommit;
142
143     /**
144      * During prepare-processing we determine if we can commit this transaction
145      * in one-phase. See check in commitPrepare().
146      */

147     private boolean onePhase;
148
149     /**
150      * Array of registered Synchronization interfaces.
151      */

152     private Synchronization synchronization = null;
153
154     /**
155      * Array of registered Resource interfaces.
156      */

157     private ArrayList JavaDoc resources;
158     private static final int RESOURCE_START = 0;
159     private static final int RESOURCE_END = 1;
160
161     /**
162      * PersistenceManagerFactory associated with this transaction
163      */

164     private PersistenceManagerFactory pmFactory = null;
165
166     /**
167      * PersistenceManager associated with this transaction (1-1)
168      */

169     private PersistenceManager persistenceManager = null;
170
171     /**
172      * Connection Factory from which this transaction gets Connections
173      */

174     private Object JavaDoc connectionFactory = null;
175
176     private javax.transaction.Transaction JavaDoc jta = null;
177
178     /**
179      * Type of the datasource. True if it javax.sql.DataSource
180      */

181     private boolean isDataSource = false;
182
183     /** values for the datasource user and user password to access
184      * security connections
185      */

186     private String JavaDoc username = null;
187     private String JavaDoc password = null;
188
189     /**
190      * Associated Connection
191      */

192     private Connection JavaDoc _connection = null;
193
194     /**
195      * Number of users (or threads) currently using this connection.
196      */

197     private int _connectionReferenceCount = 0;
198
199     /**
200      * Flag that indicates how to handle objects after commit.
201      * If true, at commit instances retain their values and the instances
202      */

203     private boolean retainValues = true;
204     
205     /**
206      * Flag that indicates how to handle objects after roolback.
207      * If true, at rollback instances restore their values and the instances
208      */

209     private boolean restoreValues = false;
210
211     /**
212      * Flag that indicates type of the transaction.
213      * Optimistic transactions do not hold data store locks until commit time.
214      */

215     private boolean optimistic = true;
216
217     /**
218      * Flag that indicates if queries and navigation are allowed
219      * without an active transaction
220      */

221     private boolean nontransactionalRead = true;
222
223     /**
224      * Possible values of txType
225      */

226     public static final int NON_MGD = 0;
227     public static final int CMT = 1;
228     public static final int BMT_UT = 2;
229     public static final int BMT_JDO = 3;
230
231     /**
232      * Flag to indicate usage mode (non-managed vs. managed, etc.)
233      */

234     private int txType = -1;
235
236     /**
237      * The logger
238      */

239     private static Logger logger = LogHelperTransaction.getLogger();
240
241
242     /**
243      * I18N message handler
244      */

245     private final static ResourceBundle JavaDoc messages = I18NHelper.loadBundle(
246             TransactionImpl.class);
247
248     /**
249      * Constructor
250      */

251     public TransactionImpl(PersistenceManager pm, String JavaDoc username, String JavaDoc password, int seconds) {
252         this.status = Status.STATUS_NO_TRANSACTION;
253         this.timeout = seconds;
254         this.startedCommit = false;
255         this.onePhase = false;
256         this.resources = new ArrayList JavaDoc();
257
258         persistenceManager = pm;
259         this.username = username;
260         this.password = password;
261
262         pmFactory = (PersistenceManagerFactory)pm.getPersistenceManagerFactory();
263         connectionFactory = pmFactory.getConnectionFactory();
264         if (!(connectionFactory instanceof ConnectionFactory)) {
265             isDataSource = true;
266         }
267
268         optimistic = pmFactory.getOptimistic();
269         retainValues = pmFactory.getRetainValues();
270         nontransactionalRead = pmFactory.getNontransactionalRead();
271         queryTimeout = pmFactory.getQueryTimeout();
272         updateTimeout = pmFactory.getUpdateTimeout();
273
274     }
275
276     /**
277      * Set PersistenceManager
278      */

279     public void setPersistenceManager(PersistenceManager pm) {
280     }
281
282     /**
283      * Returns PersistenceManager associated with this transaction
284      */

285     public com.sun.jdo.api.persistence.support.PersistenceManager getPersistenceManager() {
286         return persistenceManager.getCurrentWrapper();
287     }
288
289     public boolean isActive() {
290         return (this.status == Status.STATUS_ACTIVE ||
291             this.status == Status.STATUS_MARKED_ROLLBACK);
292     }
293
294     public void setRetainValues(boolean flag) {
295         //
296
// First do a quick check to make sure the transaction is active.
297
// This allows us to throw an exception immediately.
298
// Cannot change flag to true inside an active pessimistic tx
299
//
300
if (isActive() && !optimistic && flag)
301             throw new JDOUnsupportedOptionException(I18NHelper.getMessage(messages,
302                 "transaction.transactionimpl.setoptimistic.notallowed")); // NOI18N
303

304         //
305
// Now get an exclusive lock so we can modify the retainValues flag.
306
//
307
persistenceManager.acquireExclusiveLock();
308
309         try {
310             // Cannot change flag to true inside an active pessimistic tx
311
if (isActive() && !optimistic && flag)
312                 throw new JDOUnsupportedOptionException(I18NHelper.getMessage(messages,
313                     "transaction.transactionimpl.setoptimistic.notallowed")); // NOI18N
314

315             this.retainValues = flag;
316
317             // Adjust depending flags
318
if (flag) {
319                 nontransactionalRead = flag;
320                 persistenceManager.notifyNontransactionalRead(flag);
321             }
322         } finally {
323             persistenceManager.releaseExclusiveLock();
324         }
325     }
326
327     public boolean getRetainValues() {
328         return retainValues;
329     }
330     
331     public void setRestoreValues(boolean flag) {
332         //
333
// First do a quick check to make sure the transaction is active.
334
// This allows us to throw an exception immediately.
335
// Cannot change flag to true inside an active tx
336
//
337
if (isActive())
338             throw new JDOUnsupportedOptionException(I18NHelper.getMessage(messages,
339                 "transaction.transactionimpl.setoptimistic.notallowed")); // NOI18N
340

341         //
342
// Now get an exclusive lock so we can modify the restoreValues flag.
343
//
344
persistenceManager.acquireExclusiveLock();
345
346         try {
347             // Cannot change flag to true inside an active tx
348
if (isActive())
349                 throw new JDOUnsupportedOptionException(I18NHelper.getMessage(messages,
350                     "transaction.transactionimpl.setoptimistic.notallowed")); // NOI18N
351

352             this.restoreValues = flag;
353
354         } finally {
355             persistenceManager.releaseExclusiveLock();
356         }
357     }
358
359     public boolean getRestoreValues() {
360         return restoreValues;
361     }
362     
363
364     public void setNontransactionalRead (boolean flag) {
365         //
366
// First do a quick check to make sure the transaction is active.
367
// This allows us to throw an exception immediately.
368
// Cannot change flag to false inside an active optimistic tx
369
//
370
if (isActive() && optimistic && !flag)
371             throw new JDOUnsupportedOptionException(I18NHelper.getMessage(messages,
372                 "transaction.transactionimpl.setoptimistic.notallowed")); // NOI18N
373

374         //
375
// Now get an exclusive lock so we can modify the nontransactionalRead flag.
376
//
377
persistenceManager.acquireExclusiveLock();
378
379         try {
380             // Cannot change flag to false inside an active optimistic tx
381
if (isActive() && optimistic && !flag)
382                 throw new JDOUnsupportedOptionException(I18NHelper.getMessage(messages,
383                     "transaction.transactionimpl.setoptimistic.notallowed")); // NOI18N
384

385             this.nontransactionalRead = flag;
386             persistenceManager.notifyNontransactionalRead(flag);
387
388             // Adjust depending flags
389
if (flag == false) {
390                 retainValues = flag;
391                 optimistic = flag;
392
393                 // Notify PM about Tx type change
394
persistenceManager.notifyOptimistic(flag);
395             }
396         } finally {
397             persistenceManager.releaseExclusiveLock();
398         }
399     }
400
401     public boolean getNontransactionalRead() {
402         return nontransactionalRead;
403     }
404
405     /**
406      * Sets the number of seconds to wait for a query statement
407      * to execute in the datastore associated with this Transaction instance
408      * @param timeout new timout value in seconds; zero means unlimited
409      */

410     public void setQueryTimeout(int timeout) {
411         queryTimeout = timeout;
412     }
413
414     /**
415      * Gets the number of seconds to wait for a query statement
416      * to execute in the datastore associated with this Transaction instance
417      * @return timout value in seconds; zero means unlimited
418      */

419     public int getQueryTimeout() {
420         return queryTimeout;
421     }
422
423     /**
424      * Sets the number of seconds to wait for an update statement
425      * to execute in the datastore associated with this Transaction instance
426      * @param timeout new timout value in seconds; zero means unlimited
427      */

428     public void setUpdateTimeout(int timeout) {
429         updateTimeout = timeout;
430     }
431
432     /**
433      * Gets the number of seconds to wait for an update statement
434      * to execute in the datastore associated with this Transaction instance
435      * @return timout value in seconds; zero means unlimited
436      */

437     public int getUpdateTimeout() {
438         return updateTimeout;
439     }
440
441     public void setOptimistic(boolean flag) {
442         //
443
// First do a quick check to make sure the transaction is active.
444
// This allows us to throw an exception immediately.
445
//
446
if (!isTerminated()) {
447             throw new JDOUnsupportedOptionException(I18NHelper.getMessage(messages,
448                   "transaction.transactionimpl.setoptimistic.notallowed")); // NOI18N
449
}
450
451         //
452
// Now, get an exclusive lock in order to actually modify the optimistic flag.
453
//
454
persistenceManager.acquireExclusiveLock();
455
456         try {
457             if (isTerminated()) {
458                 this.optimistic = flag;
459
460                 // Adjust depending flags
461
if (flag) {
462                     nontransactionalRead = flag;
463                     persistenceManager.notifyNontransactionalRead(flag);
464                 }
465             } else {
466                 throw new JDOUnsupportedOptionException(I18NHelper.getMessage(messages,
467                       "transaction.transactionimpl.setoptimistic.notallowed")); // NOI18N
468
}
469
470             // Notify PM about Tx type change
471
persistenceManager.notifyOptimistic(flag);
472         } finally {
473             persistenceManager.releaseExclusiveLock();
474         }
475     }
476
477     public boolean getOptimistic() {
478         return optimistic;
479     }
480
481     public void setSynchronization(Synchronization sync) {
482         if (this.tracing)
483         this.traceCall("setSynchronization"); // NOI18N
484

485         persistenceManager.acquireExclusiveLock();
486
487         try {
488             synchronization = sync;
489
490             if (this.tracing) {
491                 this.traceCallInfo("setSynchronization", // NOI18N
492
TRACE_SYNCHRONIZATIONS, null);
493             }
494
495         } finally {
496             persistenceManager.releaseExclusiveLock();
497         }
498     }
499
500     public Synchronization getSynchronization() {
501         persistenceManager.acquireShareLock();
502
503         try {
504             return synchronization;
505         } finally {
506             persistenceManager.releaseShareLock();
507         }
508     }
509
510     public int getTransactionType() {
511         return txType;
512     }
513
514     /** Verify that username and password are equal to ones stored before
515      *
516      * @param username as String
517      * @param password as String
518      * @return true if they are equal
519      */

520     public boolean verify(String JavaDoc username, String JavaDoc password)
521     {
522         if ((this.username != null && !this.username.equals(username)) ||
523             (this.username == null && username != null) ||
524             (this.password != null && !this.password.equals(password)) ||
525             (this.password == null && password != null)) {
526             return false;
527         }
528         return true;
529     }
530
531     //
532
// ----- Methods from javax.transaction.Transaction interface ------
533
//
534

535     /**
536      * Begin a transaction.
537      */

538     public void begin() {
539
540         persistenceManager.acquireExclusiveLock();
541
542         try {
543
544             // Check and set status...
545
beginInternal();
546
547             // BMT with JDO Transaction
548
if (EJBHelper.isManaged()) {
549                 txType = BMT_JDO;
550                 try {
551                     TransactionManager tm = EJBHelper.getLocalTransactionManager();
552
553                     tm.begin();
554                     jta = tm.getTransaction();
555                     EJBHelper.registerSynchronization(jta, this);
556                     pmFactory.registerPersistenceManager(persistenceManager, jta);
557
558                 } catch (JDOException e) {
559                     throw e; // re-throw it.
560

561                 } catch (Exception JavaDoc e) {
562                     throw new JDOFatalInternalException(I18NHelper.getMessage(
563                         messages, "transaction.transactionimpl.begin.failedlocaltx"), e); // NOI18N
564
}
565             } else {
566                 txType = NON_MGD;
567             }
568         } finally {
569             persistenceManager.releaseExclusiveLock();
570         }
571     }
572
573     /**
574      * Status change and validation
575      */

576     private void beginInternal() {
577         this.setTrace();
578
579         if (this.tracing)
580             this.traceCall("begin"); // NOI18N
581

582         // RESOLVE: need to reset to NO_TX
583
if (this.isActive()) {
584             throw new JDOUserException(I18NHelper.getMessage(messages,
585                 "transaction.transactionimpl.begin.notnew", // NOI18N
586
this.statusString(this.status)));
587
588         }
589         this.setStatus(Status.STATUS_ACTIVE);
590         this.threads = 1;
591     }
592
593     /**
594      * Begin a transaction in managed environment
595      */

596     public void begin(javax.transaction.Transaction JavaDoc t) {
597
598         persistenceManager.acquireExclusiveLock();
599
600         try {
601             beginInternal();
602             try {
603                 jta = t;
604                 EJBHelper.registerSynchronization(jta, this);
605             } catch (Exception JavaDoc e) {
606                 throw new JDOFatalInternalException(I18NHelper.getMessage(
607                     messages, "transaction.transactionimpl.begin.registersynchfailed"), e); // NOI18N
608
}
609
610             txType = CMT;
611         } finally {
612             persistenceManager.releaseExclusiveLock();
613         }
614     }
615
616     /**
617      * Commit the transaction represented by this Transaction object
618      *
619      */

620     public void commit() {
621
622         persistenceManager.acquireExclusiveLock();
623
624         try {
625             if (txType == CMT || txType == BMT_UT) {
626                 // Error - should not be called
627
throw new JDOUserException(I18NHelper.getMessage(messages,
628                      "transaction.transactionimpl.mgd", "commit")); //NOI18N
629
} else if (txType == BMT_JDO) {
630                 // Send request to the container:
631
try {
632                     EJBHelper.getLocalTransactionManager().commit();
633                     return;
634                 } catch (Exception JavaDoc e) {
635                     throw new JDOException("", e); // NOI18N
636
}
637             }
638
639             this.setTrace();
640
641             if (this.tracing)
642                 this.traceCall("commit"); // NOI18N
643

644             this.commitBefore();
645             this.commitPrepare();
646             this.commitComplete();
647             this.notifyAfterCompletion();
648         } finally {
649             persistenceManager.releaseExclusiveLock();
650         }
651     }
652
653     /**
654      * Called in the managed environment only for transaction completion
655      */

656     public void beforeCompletion() {
657
658         if (txType == NON_MGD) {
659             // Error - should not be called
660
throw new JDOUserException(I18NHelper.getMessage(messages,
661                 "transaction.transactionimpl.nonmgd", "beforeCompletion")); //NOI18N
662
}
663
664         Object JavaDoc o = null;
665
666         try {
667             o = EJBHelper.preInvoke(new Object JavaDoc[] {this, persistenceManager, jta});
668             this.commitBefore(); // do actual beforeComplition
669
this.commitPrepare(); // check internal status
670
this.commitComplete();
671         } finally {
672             this.closeConnection();
673             EJBHelper.postInvoke(o);
674         }
675     }
676
677     /**
678      * Called in the managed environment only for transaction completion
679      */

680     public void afterCompletion(int st) {
681
682         if (txType == NON_MGD) {
683             throw new JDOUserException(I18NHelper.getMessage(messages,
684                         "transaction.transactionimpl.nonmgd", "afterCompletion")); //NOI18N
685
}
686         st = EJBHelper.translateStatus(st); // translate Status
687

688         if (this.tracing) {
689             this.traceCallInfo("afterCompletion", TRACE_SYNCHRONIZATIONS, //NOI18N
690
this.statusString(st));
691         }
692
693         if (st == Status.STATUS_ROLLEDBACK) {
694             this.setStatus(Status.STATUS_ROLLING_BACK);
695             this.internalRollback();
696         }
697
698         if (st != this.status) {
699             if (synchronization != null) {
700                 // Allow user to do any cleanup.
701
try {
702                     synchronization.afterCompletion(st);
703                 } catch (Exception JavaDoc ex) {
704                     logger.log(Logger.WARNING, I18NHelper.getMessage(
705                            messages,
706                            "transaction.transactionimpl.syncmanager.aftercompletion", // NOI18N
707
ex.getMessage()));
708                 }
709             }
710
711             // Force to close the persistence manager.
712
persistenceManager.forceClose();
713
714             throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
715                 "transaction.transactionimpl.commitprepare.wrongstatus", // NOI18N
716
"afterCompletion", this.statusString(this.status), // NOI18N
717
this.statusString(st)));
718         }
719
720         this.notifyAfterCompletion();
721     }
722
723     /**
724      * Lower-level before-commit method - phase 0.
725      *
726      * This is called before commit processing actually begins.
727      * State transition:
728      * STATUS_ACTIVE starting state
729      * startedCommit set to avoid concurrent commits
730      * beforeCompletion() called while still active
731      * STATUS_PREPARING no longer active, about to "really" commit
732      *
733      * The startedCommit status is an "internal state" which is still active
734      * but prevents concurrent commits and some other operations.
735      *
736      * For exceptions see commit() method.
737      */

738     private void commitBefore() {
739         boolean rollbackOnly = false; //marked for rollback
740
boolean notified = false;
741
742         if (this.tracing)
743             this.traceCall("commitBefore"); // NOI18N
744
//
745
// Validate transaction state before we commit
746
//
747

748         if ((this.status == Status.STATUS_ROLLING_BACK)
749             || (this.status == Status.STATUS_ROLLEDBACK)) {
750             throw new JDOUserException(I18NHelper.getMessage(messages,
751                 "transaction.transactionimpl.rolledback", // NOI18N
752
"commit", // NOI18N
753
this.statusString(this.status)));
754         }
755
756         if (this.status == Status.STATUS_MARKED_ROLLBACK) {
757             rollbackOnly = true;
758         } else if (this.status != Status.STATUS_ACTIVE) {
759             throw new JDOUserException(I18NHelper.getMessage(messages,
760                 "transaction.transactionimpl.commit_rollback.notactive", // NOI18N
761
"commit", // NOI18N
762
this.statusString(this.status)));
763         }
764
765         if (this.startedCommit) {
766             throw new JDOUserException(I18NHelper.getMessage(messages,
767                 "transaction.transactionimpl.commitbefore.incommit", // NOI18N
768
"commit")); // NOI18N
769
}
770         this.startedCommit = true;
771
772         //
773
// User notifications done outside of lock - check for concurrent
774
// rollback or setRollbackOnly during notification.
775
//
776
if (!rollbackOnly) {
777             this.notifyBeforeCompletion();
778             notified = true;
779
780             if (this.status == Status.STATUS_ACTIVE) { // All ok
781
this.setStatus(Status.STATUS_PREPARING);
782             } else if (this.status == Status.STATUS_MARKED_ROLLBACK) {
783                 rollbackOnly = true;
784             } else { // Must have been concurrently rolled back
785
throw new JDOUserException(I18NHelper.getMessage(messages,
786                     "transaction.transactionimpl.commitbefore.rolledback")); // NOI18N
787
}
788         }
789         if (rollbackOnly && txType == NON_MGD) {
790             this.rollback();
791
792             throw new JDOUserException(I18NHelper.getMessage(messages,
793                 notified ?
794                    "transaction.transactionimpl.commitbefore.rollbackonly_insync" : // NOI18N
795
"transaction.transactionimpl.commitbefore.rollbackonly")); // NOI18N
796
}
797     }
798
799     /**
800      * Lower-level prepare-commit method - phase 1.
801      *
802      * This is called once we've started "real commit" processing.
803      * State transition:
804      * STATUS_PREPARING starting state
805      * prepareResources() if not one-phase
806      * STATUS_PREPARED
807      *
808      * For exceptions see commit() method.
809      */

810     private void commitPrepare() {
811         if (this.tracing)
812             this.traceCall("commitPrepare"); // NOI18N
813
//
814
// Once we've reached the Status.STATUS_PREPARING state we do not need
815
// to check for concurrent state changes. All user-level methods
816
// (rollback, setRollbackOnly, register, enlist, etc) are no longer
817
// allowed.
818
//
819

820         //
821
// Validate initial state
822
//
823
if (this.status != Status.STATUS_PREPARING) {
824             throw new JDOUserException(I18NHelper.getMessage(messages,
825                "transaction.transactionimpl.commitprepare.wrongstatus", // NOI18N
826
"commitPrepare", // NOI18N
827
"STATUS_PREPARING", // NOI18N
828
this.statusString(this.status)));
829         }
830
831         //
832
// If there is at most one resource then we can do this in 1-phase.
833
//
834
if (this.resources.size() <= 1)
835             this.onePhase = true;
836
837         /*
838         //
839         // Prepare resources if not one-phase
840         //
841         if (!this.onePhase) {
842             int error = this.prepareResources();
843             if (error != XAResource.XA_OK) {
844                 this.forceRollback();
845
846                 throw (RollbackException)ErrorManager.createFormatAdd(
847                         RollbackException.class,
848                         ErrorManager.USER,
849                         TransactionMsgCat.SH_ERR_TX_TR_CMT_RB_IN_PREP_XA,
850                         this.XAErrorString(error));
851             }
852         }
853         */

854
855         this.setStatus(Status.STATUS_PREPARED);
856     }
857
858     /**
859      * Lower-level complete-commit method - phase 2.
860      *
861      * State transition:
862      * STATUS_PREPARED starting state
863      * STATUS_COMMITTING starting to do final phase
864      * commitResources() maybe one-phase
865      * STATUS_COMMITTED
866      * afterCompletion() no longer active
867      *
868      * For exceptions see commit() method.
869      */

870     private void commitComplete() {
871         if (this.tracing)
872             this.traceCallInfo("commitComplete", TRACE_ONE_PHASE, null); // NOI18N
873

874         //
875
// Validate initial state
876
//
877
if (this.status == Status.STATUS_ROLLING_BACK) {
878             this.setStatus(Status.STATUS_ROLLING_BACK); //st);
879
internalRollback();
880         } else if (this.status == Status.STATUS_PREPARED) {
881             this.setStatus(Status.STATUS_COMMITTING);
882             internalCommit();
883         } else {
884             throw new JDOUserException(I18NHelper.getMessage(messages,
885                 "transaction.transactionimpl.commitprepare.wrongstatus", // NOI18N
886
"commitComplete", // NOI18N
887
"STATUS_PREPARED", // NOI18N
888
this.statusString(this.status)));
889         }
890     }
891
892     /**
893      * Internal method to process commit operation
894      */

895     private void internalCommit() {
896         /*
897          * CODE FOR XAResource support
898         //
899         // Commit resources. If onePhase then we can expect a rollback
900         // indication so be prepared to deal with that.
901         //
902         int error = this.commitResources();
903         if (error != XAResource.XA_OK) {
904             this.forceRollback();
905
906             throw (RollbackException)ErrorManager.createFormatAdd(
907                     RollbackException.class,
908                     ErrorManager.USER,
909                     TransactionMsgCat.SH_ERR_TX_TR_CMT_RB_IN_CMT_COMP_XA,
910                     this.XAErrorString(error));
911         }
912          * END CODE FOR XAResource support
913          */

914
915         if (txType == NON_MGD) {
916             int error = this.commitConnection();
917             if (error != INTERNAL_OK) {
918                 this.forceRollback();
919                 throw new JDOUserException(I18NHelper.getMessage(messages,
920                     "transaction.transactionimpl.commitcomplete.error", // NOI18N
921
"Connection Error")); // NOI18N
922
}
923             this.closeConnection();
924         }
925         this.setStatus(Status.STATUS_COMMITTED);
926     }
927
928     /**
929      * Rollback the transaction represented by this transaction object.
930      *
931      */

932     public void rollback() {
933
934         persistenceManager.acquireExclusiveLock();
935
936         try {
937             if (txType == CMT || txType == BMT_UT) {
938                 // Error - should not be called
939
throw new JDOUserException(I18NHelper.getMessage(messages,
940                      "transaction.transactionimpl.mgd", "rollback")); //NOI18N
941
}
942
943             this.setTrace();
944
945             if (this.tracing)
946                 this.traceCall("rollback"); // NOI18N
947

948             if ((this.status != Status.STATUS_ACTIVE)
949                 && (this.status != Status.STATUS_MARKED_ROLLBACK)) {
950                 //
951
// Once commit processing has started (PREPARING, COMMITTING
952
// or COMITTED) the only way to rollback a transaction is
953
// via the registered resource interface throwing an
954
// XAException, which will use a lower-level rollback.
955
//
956

957                 throw new JDOUserException(I18NHelper.getMessage(messages,
958                     "transaction.transactionimpl.commit_rollback.notactive", // NOI18N
959
"rollback", // NOI18N
960
this.statusString(this.status)));
961             }
962
963             this.setStatus(Status.STATUS_ROLLING_BACK);
964
965             this.internalRollback();
966             this.closeConnection();
967
968             if (txType == BMT_JDO) {
969                 // Send request to the container:
970
try {
971                     EJBHelper.getLocalTransactionManager().rollback();
972                 } catch (Exception JavaDoc e) {
973                     throw new JDOException("", e); // NOI18N
974
}
975             } else { //NON_MGD
976
//This has effect of rolling back changes also
977
//which would not happen in case of BMT_JDO
978
//Is this the desired behavior ?
979
//TransactionImpl.notifyAfterCompletion()
980
//PersistenceManagerImp.afterCompletion()
981
//SQLStateManager.rollback()
982
this.notifyAfterCompletion();
983             }
984         } finally {
985             persistenceManager.releaseExclusiveLock();
986         }
987     }
988
989     /**
990      * Lower-level rollback method. This is expected to be called once
991      * the caller has confirmed that itself has set the status to
992      * STATUS_ROLLING_BACK. This is to avoid concurrent rollbacks.
993      *
994      */

995     private void internalRollback() {
996         if (this.tracing)
997             this.traceCall("internalRollback"); // NOI18N
998

999         if (this.status == Status.STATUS_ROLLEDBACK) {
1000            return;
1001        }
1002
1003        if (this.status != Status.STATUS_ROLLING_BACK) {
1004            throw new JDOUserException(I18NHelper.getMessage(messages,
1005                "transaction.transactionimpl.commitprepare.wrongstatus", // NOI18N
1006
"internalRollback", // NOI18N
1007
"STATUS_ROLLING_BACK", // NOI18N
1008
this.statusString(this.status)));
1009        }
1010
1011        if (txType == NON_MGD) {
1012            this.rollbackConnection();
1013        }
1014
1015        this.setStatus(Status.STATUS_ROLLEDBACK);
1016    }
1017
1018    /**
1019     * [package-visible]
1020     *
1021     * Force rollback. This is called when something goes wrong during
1022     * a late state check (i.e. some failure occurred during the prepare
1023     * stage). Unless we're not already rolling back (or rolled back) this
1024     * will blindly change the state of the transaction and complete the
1025     * latter stage of rollback.
1026     *
1027     * @return the final status of the transaction.
1028     *
1029     * See internalRollback() for exceptions
1030     */

1031    int forceRollback() {
1032        if (this.tracing)
1033            this.traceCall("forceRollback"); // NOI18N
1034

1035        if ((this.status == Status.STATUS_ROLLING_BACK) // Already
1036
|| (this.status == Status.STATUS_ROLLEDBACK) // Done
1037
|| (this.status == Status.STATUS_COMMITTED) // Too late
1038
|| (this.status == Status.STATUS_NO_TRANSACTION) // Never was
1039
) {
1040            return this.status;
1041        }
1042        this.internalRollback();
1043        this.notifyAfterCompletion();
1044
1045        return this.status;
1046    }
1047
1048    /**
1049     * Modify the transaction object such that the only possible outcome of
1050     * the transaction is to roll back.
1051     *
1052     */

1053    public void setRollbackOnly() {
1054        if (this.tracing)
1055            this.traceCall("setRollbackOnly"); // NOI18N
1056

1057        if ((this.status == Status.STATUS_ROLLING_BACK)
1058                || (this.status == Status.STATUS_ROLLEDBACK)
1059                || (this.status == Status.STATUS_MARKED_ROLLBACK)) {
1060            //
1061
// Already rolled back, rollback in progress or already marked.
1062
//
1063
return;
1064        }
1065
1066        if (txType != NON_MGD) {
1067            try {
1068                jta.setRollbackOnly();
1069            } catch (Exception JavaDoc e) {
1070                throw new JDOException("", e); // NOI18N
1071
}
1072        } else {
1073            this.setStatus(Status.STATUS_MARKED_ROLLBACK);
1074        }
1075
1076    }
1077
1078    /**
1079     * Obtain the status of this transaction object.
1080     *
1081     * @return The transaction status.
1082     *
1083     */

1084    public int getStatus() {
1085        //
1086
// Leave this as "synchronized" as I want to test that from callbacks
1087
// (i.e. beforeCompletion, xaRes.prepare) the lock is released, and
1088
// that other threads can access this object. See note at top of file.
1089
//
1090
synchronized (this.globalLock) {
1091            return this.status;
1092        }
1093    }
1094
1095    //
1096
// ----- Methods introduced in com.forte.transaction.ForteTran ------
1097
//
1098

1099
1100    /**
1101     * Confirm that transaction is terminated.
1102     *
1103     * @return True if transaction is completed.
1104     */

1105    boolean isTerminated() {
1106        synchronized (this.globalLock) {
1107            return ((this.status == Status.STATUS_COMMITTED)
1108                || (this.status == Status.STATUS_ROLLEDBACK)
1109                || (this.status == Status.STATUS_NO_TRANSACTION));
1110        }
1111    }
1112
1113    /**
1114     * Check if two transactions are equal. Implemented per suggestion
1115     * in "Java Transaction API" 0.92, p. 12.
1116     *
1117     * @return true if equal.
1118     */

1119    public boolean equals(Object JavaDoc o) {
1120        return (this == o);
1121    }
1122
1123    //
1124
// ----- Private methods ------
1125
//
1126

1127    /**
1128     * Notify registered Synchronization interfaces with beforeCompletion().
1129     * This method is only called before a commit so we stop iterating if
1130     * we encounter an invalid status. Which could have been set by a
1131     * rollback during (or concurrent with) the notification.
1132     */

1133    //
1134
// CHANGES
1135
// 18-jan-1999
1136
// written (ncg)
1137
//
1138
private void notifyBeforeCompletion() {
1139        if (synchronization != null) {
1140            try {
1141                synchronization.beforeCompletion();
1142            } catch (Exception JavaDoc ex) {
1143                //
1144
// RESOLVE: ignored ?
1145
//
1146
}
1147        }
1148        persistenceManager.beforeCompletion();
1149    }
1150
1151    /**
1152     * Notify registered Synchronization interfaces with afterCompletion().
1153     * We assume that no status changes occur while executing this method.
1154     */

1155    private void notifyAfterCompletion() {
1156        try {
1157            persistenceManager.afterCompletion(this.status);
1158
1159        } finally {
1160            if (synchronization != null) {
1161                try {
1162                    synchronization.afterCompletion(this.status);
1163                } catch (Exception JavaDoc ex) {
1164                    logger.log(Logger.WARNING, I18NHelper.getMessage(
1165                         messages,
1166                         "transaction.transactionimpl.syncmanager.aftercompletion", // NOI18N
1167
ex.getMessage()));
1168                }
1169            }
1170        }
1171
1172        this.forget();
1173    }
1174
1175
1176
1177    /**
1178     * Set status under lock (may be a nested lock which is ok)
1179     */

1180    //
1181
// CHANGES
1182
// 27-jan-1999
1183
// created (ncg)
1184
//
1185
private void setStatus(int status) {
1186        synchronized(this.globalLock) {
1187            if (this.tracing) {
1188                Object JavaDoc[] items= new Object JavaDoc[] {Thread.currentThread(),this.toString(),
1189                    this.statusString(this.status), this.statusString(status), persistenceManager};
1190                logger.finest("sqlstore.transactionimpl.status",items); // NOI18N
1191
}
1192            this.status = status;
1193            persistenceManager.notifyStatusChange(isActive());
1194        }
1195    }
1196
1197    /**
1198     * Forget this transaction
1199     */

1200    private void forget() {
1201        if (this.tracing)
1202            this.traceCall("forget"); // NOI18N
1203

1204        //
1205
// Do not clear:
1206
//
1207
// .tid -- users can still browse transaction id
1208
// .status -- users can still check status
1209
// .timeout -- users can still check timeout
1210
// .onePhase -- remember if was committed 1-phase
1211
//
1212
this.threads = 0;
1213        this.startedCommit = false;
1214
1215        // SHOULD BE CLOSED: closeConnection();
1216
if (_connection != null) {
1217            try {
1218                if (!_connection.isClosed()) {
1219                    closeConnection();
1220                    throw new JDOFatalInternalException(I18NHelper.getMessage(
1221                        messages,
1222                        "transaction.transactionimpl.forget.connectionnotclosed")); // NOI18N
1223
}
1224            } catch (Exception JavaDoc e) {
1225            }
1226            _connection = null;
1227        }
1228        _connectionReferenceCount = 0;
1229
1230        //
1231
// Do we need to invoke forget on the resource?
1232
//
1233
this.resources.clear();
1234            if (txType != NON_MGD) {
1235            persistenceManager.close();
1236        }
1237
1238        jta = null;
1239        txType = NON_MGD; // Restore the flag
1240

1241        this.setTrace();
1242    }
1243
1244    //
1245
// ----- Debugging utilities -----
1246
//
1247

1248    /**
1249     * Set the global transaction tracing.
1250     */

1251    static void setTrace() {
1252        TransactionImpl.tracing = logger.isLoggable(Logger.FINEST);
1253    }
1254
1255    /**
1256     * Trace method call.
1257     */

1258    private void traceCall(String JavaDoc call) {
1259        Object JavaDoc[] items = new Object JavaDoc[]{Thread.currentThread(),this.toString(),call,
1260             this.statusString(this.status),txTypeString(), persistenceManager};
1261        logger.finest("sqlstore.transactionimpl.call",items); // NOI18N
1262
}
1263
1264    /**
1265     * Trace method call with extra info.
1266     */

1267    //
1268
// CHANGES
1269
// 11-jan-1999
1270
// created (ncg)
1271
//
1272
private void traceCallInfo(String JavaDoc call, int info, String JavaDoc s) {
1273
1274        //TODO : Optimize this when converting to resource budles
1275
StringBuffer JavaDoc logMessage = new StringBuffer JavaDoc();
1276        logMessage.append("Thread.currentThread()").append("Tran[") // NOI18N
1277
.append(this.toString()).append("].").append(call) // NOI18N
1278
.append(": status = ").append(this.statusString(this.status)); // NOI18N
1279

1280        if ((info & TRACE_THREADS) != 0)
1281            logMessage.append(", threads = " + this.threads); // NOI18N
1282
if ((info & TRACE_SYNCHRONIZATIONS) != 0)
1283            logMessage.append(", sync = " + this.synchronization); // NOI18N
1284
if ((info & TRACE_RESOURCES) != 0)
1285            logMessage.append(", resources = " + this.resources.size()); // NOI18N
1286
if ((info & TRACE_ONE_PHASE) != 0 && this.onePhase)
1287            logMessage.append(", onePhase = true"); // NOI18N
1288
if (s != null)
1289            logMessage.append(", " + s + " for " + persistenceManager); // NOI18N
1290

1291        logger.finest("sqlstore.transactionimpl.general",logMessage.toString()); // NOI18N
1292
}
1293
1294    /**
1295     * Trace method call with extra string.
1296     */

1297    private void traceCallString(String JavaDoc call, String JavaDoc info) {
1298      Object JavaDoc[] items = new Object JavaDoc[] {Thread.currentThread(),this.toString(),call,info,persistenceManager};
1299      logger.finest("sqlstore.transactionimpl.call.info",items); // NOI18N
1300
}
1301
1302    /**
1303     * Translates a txType value into a string.
1304     *
1305     * @return Printable String for a txType value
1306     */

1307    private String JavaDoc txTypeString() {
1308        switch (txType) {
1309            case NON_MGD: return "NON_MGD"; // NOI18N
1310
case CMT: return "CMT"; // NOI18N
1311
case BMT_UT: return "BMT_UT"; // NOI18N
1312
case BMT_JDO: return "BMT_JDO"; // NOI18N
1313
default: break;
1314        }
1315        return "UNKNOWN"; // NOI18N
1316
}
1317
1318    /**
1319     * Translates a javax.transaction.Status value into a string.
1320     *
1321     * @param status Status object to translate.
1322     * @return Printable String for a Status object.
1323     */

1324    public static String JavaDoc statusString(int status) {
1325        switch (status) {
1326            case Status.STATUS_ACTIVE: return "STATUS_ACTIVE"; // NOI18N
1327
case Status.STATUS_MARKED_ROLLBACK: return "STATUS_MARKED_ROLLBACK"; // NOI18N
1328
case Status.STATUS_PREPARED: return "STATUS_PREPARED"; // NOI18N
1329
case Status.STATUS_COMMITTED: return "STATUS_COMMITTED"; // NOI18N
1330
case Status.STATUS_ROLLEDBACK: return "STATUS_ROLLEDBACK"; // NOI18N
1331
case Status.STATUS_UNKNOWN: return "STATUS_UNKNOWN"; // NOI18N
1332
case Status.STATUS_NO_TRANSACTION: return "STATUS_NO_TRANSACTION"; // NOI18N
1333
case Status.STATUS_PREPARING: return "STATUS_PREPARING"; // NOI18N
1334
case Status.STATUS_COMMITTING: return "STATUS_COMMITTING"; // NOI18N
1335
case Status.STATUS_ROLLING_BACK: return "STATUS_ROLLING_BACK"; // NOI18N
1336
default: break;
1337        }
1338        return "STATUS_Invalid[" + status + "]"; // NOI18N
1339
}
1340
1341    /**
1342     * Returns a Connection. If there is no existing one, asks
1343     * ConnectionFactory for a new Connection
1344     */

1345    public synchronized Connection JavaDoc getConnection() {
1346        boolean debug = logger.isLoggable(Logger.FINEST);
1347
1348        if (_connection == null) {
1349            // find a new connection
1350
if (connectionFactory == null) {
1351                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
1352                    "transaction.transactionimpl.getconnection.nullcf")); // NOI18N
1353
}
1354
1355            _connection = this.getConnectionInternal();
1356        }
1357
1358        _connectionReferenceCount++;
1359
1360        if (debug) {
1361            Object JavaDoc[] items = new Object JavaDoc[] {_connection, Boolean.valueOf(optimistic),
1362                new Integer JavaDoc(_connectionReferenceCount) , persistenceManager};
1363            logger.finest("sqlstore.transactionimpl.getconnection",items); // NOI18N
1364
}
1365
1366        // We cannot depend on NON_MGD flag here as this method can be called
1367
// outside of an active transaction.
1368
if (!EJBHelper.isManaged()) {
1369            try {
1370                //
1371
// For active pessimistic transaction or a committing transaction, we need to set
1372
// auto-commit feature off.
1373
//
1374
if ((!optimistic && isActive()) || startedCommit) {
1375                    // Set autocommit to false *only* if it's true
1376
// I.e., don't set to false multiple times (Sybase
1377
// throws exception in that case).
1378
if (_connection.getAutoCommit()) {
1379                        _connection.setAutoCommit(false);
1380                    }
1381                } else {
1382                    _connection.setAutoCommit(true);
1383                }
1384            } catch (java.sql.SQLException JavaDoc e) {
1385                logger.log(Logger.WARNING,"sqlstore.exception.log",e); // NOI18N
1386
}
1387        }
1388
1389        return _connection;
1390    }
1391
1392    /**
1393     * Replace a connection. Used in a managed environment only.
1394     * In a J2EE RI Connection need to be replaced at the beforeCompletion.
1395     */

1396    public void replaceConnection() {
1397        if (EJBHelper.isManaged()) {
1398            this.releaseConnection();
1399            this.closeConnection();
1400            this.getConnection();
1401        }
1402    }
1403
1404    /**
1405     * Close a connection.
1406     * Connection cannot be closed if it is part of the commit/rollback
1407     * operation or inside a pessimistic transaction
1408     */

1409    public synchronized void releaseConnection() {
1410        boolean debug = logger.isLoggable(Logger.FINEST);
1411
1412        if (_connectionReferenceCount > 0) {
1413            _connectionReferenceCount--;
1414        }
1415
1416        if (debug) {
1417            Object JavaDoc[] items = new Object JavaDoc[] {Boolean.valueOf(optimistic),
1418                Boolean.valueOf(startedCommit),
1419                new Integer JavaDoc(_connectionReferenceCount) , persistenceManager};
1420            logger.finest("sqlstore.transactionimpl.releaseconnection",items); // NOI18N
1421
}
1422
1423        // Fix for bug 4479807: Do not keep connection in the managed environment.
1424
if ( (!EJBHelper.isManaged() && optimistic == false) || startedCommit ) {
1425            // keep Connection. Do not close.
1426
return;
1427        }
1428
1429        if (_connectionReferenceCount == 0) {
1430            //
1431
// For optimistic transaction, we only release the connection when
1432
// no one is using it.
1433
//
1434
closeConnection();
1435        }
1436    }
1437
1438    private Connection JavaDoc getConnectionInternal() {
1439        if (isDataSource) {
1440            try {
1441                if (EJBHelper.isManaged()) {
1442                    // Delegate to the EJBHelper for details.
1443
if (isActive()) {
1444                        return EJBHelper.getConnection(connectionFactory,
1445                            username, password);
1446                    } else {
1447                        return EJBHelper.getNonTransactionalConnection(
1448                            connectionFactory, username, password);
1449                    }
1450                } else if (username != null) {
1451                    return ((DataSource JavaDoc)connectionFactory).getConnection(
1452                        username, password);
1453                } else {
1454                     return ((DataSource JavaDoc)connectionFactory).getConnection();
1455                }
1456
1457            } catch (java.sql.SQLException JavaDoc e) {
1458                String JavaDoc sqlState = e.getSQLState();
1459                int errorCode = e.getErrorCode();
1460
1461                if (sqlState == null) {
1462                    throw new JDODataStoreException(
1463                        I18NHelper.getMessage(messages,
1464                            "connectionefactoryimpl.sqlexception", // NOI18N
1465
"null", "" + errorCode), e); // NOI18N
1466
} else {
1467                    throw new JDODataStoreException(
1468                        I18NHelper.getMessage(messages,
1469                            "connectionefactoryimpl.sqlexception", // NOI18N
1470
sqlState, "" + errorCode), e); // NOI18N
1471
}
1472            }
1473        } else {
1474            return ((ConnectionFactory)connectionFactory).getConnection();
1475        }
1476    }
1477
1478    /**
1479     * Always Close a connection
1480     */

1481    private void closeConnection() {
1482        boolean debug = logger.isLoggable(Logger.FINEST);
1483        if (debug) {
1484            Object JavaDoc[] items = new Object JavaDoc[] {_connection , persistenceManager};
1485            logger.finest("sqlstore.transactionimpl.closeconnection",items); // NOI18N
1486
}
1487        try {
1488            if (_connection != null) {
1489                _connection.close();
1490            }
1491        } catch (Exception JavaDoc e) {
1492            // Recover?
1493
}
1494        _connection = null;
1495    }
1496
1497    /**
1498     * replaces rollbackResources() in ForteTran
1499     */

1500    private void rollbackConnection() {
1501        boolean debug = logger.isLoggable(Logger.FINEST);
1502        if (debug) {
1503            Object JavaDoc[] items = new Object JavaDoc[] {_connection , persistenceManager};
1504            logger.finest("sqlstore.transactionimpl.rollbackconnection",items); // NOI18N
1505
}
1506        if (_connection != null) {
1507            try {
1508                if (isDataSource)
1509                    _connection.rollback();
1510                else
1511                    ((ConnectionImpl)_connection).internalRollback();
1512            } catch (Exception JavaDoc e) {
1513                //Recover?
1514
}
1515        }
1516    }
1517    private int INTERNAL_ERROR = 1;
1518    private int INTERNAL_OK = 0;
1519
1520    /**
1521     * replaces commitResources() in ForteTran
1522     */

1523    private int commitConnection() {
1524        if (_connection != null) {
1525            try {
1526                if (isDataSource)
1527                    _connection.commit();
1528                else
1529                    ((ConnectionImpl)_connection).internalCommit();
1530            } catch (Exception JavaDoc e) {
1531                return INTERNAL_ERROR;
1532            }
1533        }
1534        return INTERNAL_OK;
1535    }
1536
1537
1538    /**
1539     * Returns a string representation of this transaction object.
1540     *
1541     * @return String describing contents of this Transaction object.
1542     */

1543    public String JavaDoc toString() {
1544        int i;
1545        Object JavaDoc o;
1546
1547        String JavaDoc s = " Transaction: \n status = " + this.statusString(this.status)+ "\n" // NOI18N
1548
+ " Transaction Object = Transaction@" + this.hashCode() + "\n" // NOI18N
1549
+ " threads = " + this.threads + "\n"; // NOI18N
1550

1551        if (this.timeout != 0)
1552            s = s + " timeout = " + this.timeout + "\n"; // NOI18N
1553
if (this.startedCommit)
1554            s = s + " startedCommit = true\n"; // NOI18N
1555
if (this.onePhase)
1556            s = s + " onePhase = true\n"; // NOI18N
1557

1558        if (synchronization != null) {
1559            s = s + "sync: " + synchronization + "\n"; // NOI18N
1560
}
1561        if (!this.resources.isEmpty()) {
1562            s = s + " # resources = " + this.resources.size() + "\n"; // NOI18N
1563
/*
1564            for (i = 0; i < this.resources.size(); i++) {
1565                XAResource res = (XAResource)this.resources.get(i);
1566                //
1567                // Make be null if vote readonly during commit processing
1568                // Bug 48325: avoid recursive toString() calls
1569                //
1570                if (res != null) {
1571                    s = s + " [" + i + "] " + // NOI18N
1572                        res.getClass().getName() + "\n"; // NOI18N
1573                }
1574            }
1575            */

1576        }
1577        return s;
1578
1579    }
1580}
1581
Popular Tags