FileDocCategorySizeDatePackage
TransactionImpl.javaAPI DocGlassfish v2 API54680Fri May 04 22:35:06 BST 2007com.sun.jdo.spi.persistence.support.sqlstore.impl

TransactionImpl

public class TransactionImpl extends Object implements com.sun.jdo.spi.persistence.support.sqlstore.Transaction
The Transaction interface allows operations to be performed against the transaction in the target Transaction object. A Transaction object is created corresponding to each global transaction creation. The Transaction object can be used for resource enlistment, synchronization registration, transaction completion and status query operations. This implementation is completely internal. All externally documented methods are on the Transaction interface. Note on synchronized(this): There are a number of places that calls are made outside the transaction system. For example, Synchronization.beforeCompletion() and XAResource.start(). It is important that no locks are held when these callbacks are made. This requires more state checking up return from these calls, and the methods are careful to check state transitions after release the lock and reacquiring it. Also be careful NOT to call into a lower method with the lock, if that method may call out of the transaction system. Take care if you make methods "synchronized" because: synchronized methodName() is not the same lock as a more localized: synchronized(this) This is tested in the regression tests (see "Lock Test")

Fields Summary
static boolean
tracing
Trace level for sh:6. This is public to this transaction package and referenced: if (TransactionImpl.tracing) This is reset by calling TransactionImpl.setTrace().
private static final int
TRACE_THREADS
private static final int
TRACE_RESOURCES
private static final int
TRACE_SYNCHRONIZATIONS
private static final int
TRACE_ONE_PHASE
static String
globalLock
Package-visible lock for static attributes. Note that globalLock can be a higher-level lock, in that it may be locked before other lower-level objects are locked (i.e. the transaction object). It may NOT be locked the other way round.
private int
status
Transaction status (from javax.transaction.Status).
private int
timeout
Timeout for this transaction
public static final int
TRAN_DEFAULT_TIMEOUT
private int
queryTimeout
Query and Update Statement timeouts for the datastore associated with this transaction
private int
updateTimeout
private int
threads
Number of threads participating in this transaction.
public static final int
TRAN_MAX_THREADS
private boolean
startedCommit
The commit process has already begun (even though the status is still STATUS_ACTIVE). This is set during before-commit notification.
private boolean
onePhase
During prepare-processing we determine if we can commit this transaction in one-phase. See check in commitPrepare().
private Synchronization
synchronization
Array of registered Synchronization interfaces.
private ArrayList
resources
Array of registered Resource interfaces.
private static final int
RESOURCE_START
private static final int
RESOURCE_END
private com.sun.jdo.spi.persistence.support.sqlstore.PersistenceManagerFactory
pmFactory
PersistenceManagerFactory associated with this transaction
private com.sun.jdo.spi.persistence.support.sqlstore.PersistenceManager
persistenceManager
PersistenceManager associated with this transaction (1-1)
private Object
connectionFactory
Connection Factory from which this transaction gets Connections
private Transaction
jta
private boolean
isDataSource
Type of the datasource. True if it javax.sql.DataSource
private String
username
values for the datasource user and user password to access security connections
private String
password
private Connection
_connection
Associated Connection
private int
_connectionReferenceCount
Number of users (or threads) currently using this connection.
private boolean
retainValues
Flag that indicates how to handle objects after commit. If true, at commit instances retain their values and the instances
private boolean
restoreValues
Flag that indicates how to handle objects after roolback. If true, at rollback instances restore their values and the instances
private boolean
optimistic
Flag that indicates type of the transaction. Optimistic transactions do not hold data store locks until commit time.
private boolean
nontransactionalRead
Flag that indicates if queries and navigation are allowed without an active transaction
public static final int
NON_MGD
Possible values of txType
public static final int
CMT
public static final int
BMT_UT
public static final int
BMT_JDO
private int
txType
Flag to indicate usage mode (non-managed vs. managed, etc.)
private static com.sun.jdo.spi.persistence.utility.logging.Logger
logger
The logger
private static final ResourceBundle
messages
I18N message handler
private int
INTERNAL_ERROR
private int
INTERNAL_OK
Constructors Summary
public TransactionImpl(com.sun.jdo.spi.persistence.support.sqlstore.PersistenceManager pm, String username, String password, int seconds)
Constructor


          
             
        this.status = Status.STATUS_NO_TRANSACTION;
        this.timeout = seconds;
        this.startedCommit = false;
        this.onePhase = false;
        this.resources = new ArrayList();

        persistenceManager = pm;
        this.username = username;
        this.password = password;

        pmFactory = (PersistenceManagerFactory)pm.getPersistenceManagerFactory();
        connectionFactory = pmFactory.getConnectionFactory();
        if (!(connectionFactory instanceof ConnectionFactory)) {
            isDataSource = true;
        }

        optimistic = pmFactory.getOptimistic();
        retainValues = pmFactory.getRetainValues();
        nontransactionalRead = pmFactory.getNontransactionalRead();
        queryTimeout = pmFactory.getQueryTimeout();
        updateTimeout = pmFactory.getUpdateTimeout();

    
Methods Summary
public voidafterCompletion(int st)
Called in the managed environment only for transaction completion


        if (txType == NON_MGD) {
            throw new JDOUserException(I18NHelper.getMessage(messages,
                        "transaction.transactionimpl.nonmgd", "afterCompletion")); //NOI18N
        }
        st = EJBHelper.translateStatus(st); // translate Status

        if (this.tracing) {
            this.traceCallInfo("afterCompletion", TRACE_SYNCHRONIZATIONS, //NOI18N
            this.statusString(st));
        }

        if (st == Status.STATUS_ROLLEDBACK) {
            this.setStatus(Status.STATUS_ROLLING_BACK);
            this.internalRollback();
        }

        if (st != this.status) {
            if (synchronization != null) {
                // Allow user to do any cleanup.
                try {
                    synchronization.afterCompletion(st);
                } catch (Exception ex) {
                    logger.log(Logger.WARNING, I18NHelper.getMessage(
                           messages,
                           "transaction.transactionimpl.syncmanager.aftercompletion", // NOI18N
                           ex.getMessage()));
                }
            }

            // Force to close the persistence manager. 
            persistenceManager.forceClose();

            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                "transaction.transactionimpl.commitprepare.wrongstatus", // NOI18N
                "afterCompletion", this.statusString(this.status),  // NOI18N
                this.statusString(st)));
        }

        this.notifyAfterCompletion();
    
public voidbeforeCompletion()
Called in the managed environment only for transaction completion


        if (txType == NON_MGD) {
            // Error - should not be called
            throw new JDOUserException(I18NHelper.getMessage(messages,
                "transaction.transactionimpl.nonmgd", "beforeCompletion")); //NOI18N
        }

        Object o = null;

        try {
            o = EJBHelper.preInvoke(new Object[] {this, persistenceManager, jta});
            this.commitBefore(); // do actual beforeComplition
            this.commitPrepare(); // check internal status
            this.commitComplete();
        } finally {
            this.closeConnection();
            EJBHelper.postInvoke(o);
        }
    
public voidbegin()
Begin a transaction.


        persistenceManager.acquireExclusiveLock();

        try {

            // Check and set status...
            beginInternal();

            // BMT with JDO Transaction
            if (EJBHelper.isManaged()) {
                txType = BMT_JDO;
                try {
                    TransactionManager tm = EJBHelper.getLocalTransactionManager();

                    tm.begin();
                    jta = tm.getTransaction();
                    EJBHelper.registerSynchronization(jta, this);
                    pmFactory.registerPersistenceManager(persistenceManager, jta);

                } catch (JDOException e) {
                    throw e;     // re-throw it.

                } catch (Exception e) {
                    throw new JDOFatalInternalException(I18NHelper.getMessage(
                        messages, "transaction.transactionimpl.begin.failedlocaltx"), e); // NOI18N
                }
            } else {
                txType = NON_MGD;
            }
        } finally {
            persistenceManager.releaseExclusiveLock();
        }
    
public voidbegin(javax.transaction.Transaction t)
Begin a transaction in managed environment


        persistenceManager.acquireExclusiveLock();

        try {
            beginInternal();
            try {
                jta = t;
                EJBHelper.registerSynchronization(jta, this);
            } catch (Exception e) {
                throw new JDOFatalInternalException(I18NHelper.getMessage(
                    messages, "transaction.transactionimpl.begin.registersynchfailed"), e); // NOI18N
            }

            txType = CMT;
        } finally {
            persistenceManager.releaseExclusiveLock();
        }
    
private voidbeginInternal()
Status change and validation

        this.setTrace();

        if (this.tracing)
            this.traceCall("begin");  // NOI18N

        // RESOLVE: need to reset to NO_TX
        if (this.isActive()) {
            throw new JDOUserException(I18NHelper.getMessage(messages,
                "transaction.transactionimpl.begin.notnew",  // NOI18N
                this.statusString(this.status)));

        }
        this.setStatus(Status.STATUS_ACTIVE);
        this.threads = 1;
    
private voidcloseConnection()
Always Close a connection

        boolean debug = logger.isLoggable(Logger.FINEST);
        if (debug) {
            Object[] items = new Object[] {_connection , persistenceManager};
            logger.finest("sqlstore.transactionimpl.closeconnection",items); // NOI18N
        }
        try {
            if (_connection != null) {
                _connection.close();
            }
        } catch (Exception e) {
            // Recover?
        }
        _connection = null;
    
public voidcommit()
Commit the transaction represented by this Transaction object


        persistenceManager.acquireExclusiveLock();

        try {
            if (txType == CMT || txType == BMT_UT) {
                // Error - should not be called
                throw new JDOUserException(I18NHelper.getMessage(messages,
                     "transaction.transactionimpl.mgd", "commit")); //NOI18N
            } else if (txType == BMT_JDO) {
                // Send request to the container:
                try {
                    EJBHelper.getLocalTransactionManager().commit();
                    return;
                } catch (Exception e) {
                    throw new JDOException("", e); // NOI18N
                }
            }

            this.setTrace();

            if (this.tracing)
                this.traceCall("commit"); // NOI18N

            this.commitBefore();
            this.commitPrepare();
            this.commitComplete();
            this.notifyAfterCompletion();
        } finally {
            persistenceManager.releaseExclusiveLock();
        }
    
private voidcommitBefore()
Lower-level before-commit method - phase 0. This is called before commit processing actually begins. State transition: STATUS_ACTIVE starting state startedCommit set to avoid concurrent commits beforeCompletion() called while still active STATUS_PREPARING no longer active, about to "really" commit The startedCommit status is an "internal state" which is still active but prevents concurrent commits and some other operations. For exceptions see commit() method.

        boolean        rollbackOnly = false; //marked for rollback
        boolean        notified = false;

        if (this.tracing)
            this.traceCall("commitBefore"); // NOI18N
        //
        // Validate transaction state before we commit
        //

        if ((this.status == Status.STATUS_ROLLING_BACK)
            ||    (this.status == Status.STATUS_ROLLEDBACK)) {
            throw new JDOUserException(I18NHelper.getMessage(messages,
                "transaction.transactionimpl.rolledback", // NOI18N
                "commit", // NOI18N
                this.statusString(this.status)));
        }

        if (this.status == Status.STATUS_MARKED_ROLLBACK) {
            rollbackOnly = true;
        } else if (this.status != Status.STATUS_ACTIVE) {
            throw new JDOUserException(I18NHelper.getMessage(messages,
                "transaction.transactionimpl.commit_rollback.notactive", // NOI18N
                "commit", // NOI18N
                this.statusString(this.status)));
        }

        if (this.startedCommit) {
            throw new JDOUserException(I18NHelper.getMessage(messages,
                "transaction.transactionimpl.commitbefore.incommit", // NOI18N
                "commit")); // NOI18N
        }
        this.startedCommit = true;

        //
        // User notifications done outside of lock - check for concurrent
        // rollback or setRollbackOnly during notification.
        //
        if (!rollbackOnly) {
            this.notifyBeforeCompletion();
            notified = true;

            if (this.status == Status.STATUS_ACTIVE) {        // All ok
                this.setStatus(Status.STATUS_PREPARING);
            } else if (this.status == Status.STATUS_MARKED_ROLLBACK) {
                rollbackOnly = true;
            } else {    // Must have been concurrently rolled back
                throw new JDOUserException(I18NHelper.getMessage(messages,
                    "transaction.transactionimpl.commitbefore.rolledback")); // NOI18N
            }
        }
        if (rollbackOnly && txType == NON_MGD) {
            this.rollback();

            throw new JDOUserException(I18NHelper.getMessage(messages,
                notified ?
                   "transaction.transactionimpl.commitbefore.rollbackonly_insync" : // NOI18N
                   "transaction.transactionimpl.commitbefore.rollbackonly")); // NOI18N
        }
    
private voidcommitComplete()
Lower-level complete-commit method - phase 2. State transition: STATUS_PREPARED starting state STATUS_COMMITTING starting to do final phase commitResources() maybe one-phase STATUS_COMMITTED afterCompletion() no longer active For exceptions see commit() method.

        if (this.tracing)
            this.traceCallInfo("commitComplete", TRACE_ONE_PHASE, null); // NOI18N

        //
        // Validate initial state
        //
        if (this.status == Status.STATUS_ROLLING_BACK) {
            this.setStatus(Status.STATUS_ROLLING_BACK); //st);
            internalRollback();
        } else if (this.status == Status.STATUS_PREPARED) {
            this.setStatus(Status.STATUS_COMMITTING);
            internalCommit();
        } else {
            throw new JDOUserException(I18NHelper.getMessage(messages,
                "transaction.transactionimpl.commitprepare.wrongstatus", // NOI18N
                "commitComplete",  // NOI18N
                "STATUS_PREPARED", // NOI18N
                this.statusString(this.status)));
        }
    
private intcommitConnection()
replaces commitResources() in ForteTran


             
       
        if (_connection != null) {
            try {
                if (isDataSource)
                    _connection.commit();
                else
                    ((ConnectionImpl)_connection).internalCommit();
            } catch (Exception e) {
                return INTERNAL_ERROR;
            }
        }
        return INTERNAL_OK;
    
private voidcommitPrepare()
Lower-level prepare-commit method - phase 1. This is called once we've started "real commit" processing. State transition: STATUS_PREPARING starting state prepareResources() if not one-phase STATUS_PREPARED For exceptions see commit() method.

        if (this.tracing)
            this.traceCall("commitPrepare"); // NOI18N
        //
        // Once we've reached the Status.STATUS_PREPARING state we do not need
        // to check for concurrent state changes.  All user-level methods
        // (rollback, setRollbackOnly, register, enlist, etc) are no longer
        // allowed.
        //

        //
        // Validate initial state
        //
        if (this.status != Status.STATUS_PREPARING) {
            throw new JDOUserException(I18NHelper.getMessage(messages,
               "transaction.transactionimpl.commitprepare.wrongstatus", // NOI18N
                "commitPrepare",  // NOI18N
                "STATUS_PREPARING", // NOI18N
                this.statusString(this.status)));
        }

        //
        // If there is at most one resource then we can do this in 1-phase.
        //
        if (this.resources.size() <= 1)
            this.onePhase = true;

        /*
        //
        // Prepare resources if not one-phase
        //
        if (!this.onePhase) {
            int    error = this.prepareResources();
            if (error != XAResource.XA_OK) {
                this.forceRollback();

                throw (RollbackException)ErrorManager.createFormatAdd(
                        RollbackException.class,
                        ErrorManager.USER,
                        TransactionMsgCat.SH_ERR_TX_TR_CMT_RB_IN_PREP_XA,
                        this.XAErrorString(error));
            }
        }
        */

        this.setStatus(Status.STATUS_PREPARED);
    
intforceRollback()
[package-visible] Force rollback. This is called when something goes wrong during a late state check (i.e. some failure occurred during the prepare stage). Unless we're not already rolling back (or rolled back) this will blindly change the state of the transaction and complete the latter stage of rollback.

return
the final status of the transaction. See internalRollback() for exceptions

        if (this.tracing)
            this.traceCall("forceRollback"); // NOI18N

        if ((this.status == Status.STATUS_ROLLING_BACK)        // Already
            ||    (this.status == Status.STATUS_ROLLEDBACK)        // Done
            ||    (this.status == Status.STATUS_COMMITTED)        // Too late
            ||    (this.status == Status.STATUS_NO_TRANSACTION)    // Never was
           ) {
            return this.status;
        }
        this.internalRollback();
        this.notifyAfterCompletion();

        return this.status;
    
private voidforget()
Forget this transaction

        if (this.tracing)
            this.traceCall("forget"); // NOI18N

        //
        // Do not clear:
        //
        //    .tid            -- users can still browse transaction id
        //    .status            -- users can still check status
        //    .timeout        -- users can still check timeout
        //    .onePhase         -- remember if was committed 1-phase
        //
        this.threads = 0;
        this.startedCommit = false;

        // SHOULD BE CLOSED: closeConnection();
        if (_connection != null) {
            try {
                if (!_connection.isClosed()) {
                    closeConnection();
                    throw new JDOFatalInternalException(I18NHelper.getMessage(
                        messages, 
                        "transaction.transactionimpl.forget.connectionnotclosed")); // NOI18N
                }
            } catch (Exception e) {
            }
            _connection = null;
        }
        _connectionReferenceCount = 0;

        //
        // Do we need to invoke forget on the resource?
        //
        this.resources.clear();
            if (txType != NON_MGD) {
            persistenceManager.close();
        }

        jta = null;
        txType = NON_MGD;       // Restore the flag

        this.setTrace();
    
public synchronized java.sql.ConnectiongetConnection()
Returns a Connection. If there is no existing one, asks ConnectionFactory for a new Connection

        boolean debug = logger.isLoggable(Logger.FINEST);

        if (_connection == null) {
            // find a new connection
            if (connectionFactory == null) {
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages, 
                    "transaction.transactionimpl.getconnection.nullcf")); // NOI18N
            }

            _connection = this.getConnectionInternal();
        }

        _connectionReferenceCount++;

        if (debug) {
            Object[] items = new Object[] {_connection, Boolean.valueOf(optimistic), 
                new Integer(_connectionReferenceCount) , persistenceManager};
            logger.finest("sqlstore.transactionimpl.getconnection",items); // NOI18N
        }

        // We cannot depend on NON_MGD flag here as this method can be called
        // outside of an active transaction.
        if (!EJBHelper.isManaged()) {
            try {
                //
                // For active pessimistic transaction or a committing transaction, we need to set
                // auto-commit feature off.
                //
                if ((!optimistic && isActive()) || startedCommit) {
                    // Set autocommit to false *only* if it's true
                    // I.e., don't set to false multiple times (Sybase
                    // throws exception in that case).
                    if (_connection.getAutoCommit()) {
                        _connection.setAutoCommit(false);
                    }
                } else {
                    _connection.setAutoCommit(true);
                }
            } catch (java.sql.SQLException e) {
                logger.log(Logger.WARNING,"sqlstore.exception.log",e);  // NOI18N
            }
        }

        return _connection;
    
private java.sql.ConnectiongetConnectionInternal()

        if (isDataSource) {
            try {
                if (EJBHelper.isManaged()) {
                    // Delegate to the EJBHelper for details.
                    if (isActive()) {
                        return EJBHelper.getConnection(connectionFactory,
                            username, password);
                    } else {
                        return EJBHelper.getNonTransactionalConnection(
                            connectionFactory, username, password);
                    }
                } else if (username != null) {
                    return ((DataSource)connectionFactory).getConnection(
                        username, password);
                } else {
                     return ((DataSource)connectionFactory).getConnection();
                }

            } catch (java.sql.SQLException e) {
                String sqlState = e.getSQLState();
                int  errorCode = e.getErrorCode();

                if (sqlState == null) {
                    throw new JDODataStoreException(
                        I18NHelper.getMessage(messages,
                            "connectionefactoryimpl.sqlexception", // NOI18N
                            "null", "" + errorCode), e); // NOI18N
                } else {
                    throw new JDODataStoreException(
                        I18NHelper.getMessage(messages,
                            "connectionefactoryimpl.sqlexception", // NOI18N
                            sqlState, "" + errorCode), e); // NOI18N
                }
            }
        } else {
            return ((ConnectionFactory)connectionFactory).getConnection();
        }
    
public booleangetNontransactionalRead()

        return nontransactionalRead;
    
public booleangetOptimistic()

        return optimistic;
    
public com.sun.jdo.api.persistence.support.PersistenceManagergetPersistenceManager()
Returns PersistenceManager associated with this transaction

        return persistenceManager.getCurrentWrapper();
    
public intgetQueryTimeout()
Gets the number of seconds to wait for a query statement to execute in the datastore associated with this Transaction instance

return
timout value in seconds; zero means unlimited

        return queryTimeout;
    
public booleangetRestoreValues()

        return restoreValues;
    
public booleangetRetainValues()

        return retainValues;
    
public intgetStatus()
Obtain the status of this transaction object.

return
The transaction status.

        //
        // Leave this as "synchronized" as I want to test that from callbacks
        // (i.e. beforeCompletion, xaRes.prepare) the lock is released, and
        // that other threads can access this object.  See note at top of file.
        //
        synchronized (this.globalLock) {
            return this.status;
        }
    
public javax.transaction.SynchronizationgetSynchronization()

        persistenceManager.acquireShareLock();

        try {
            return synchronization;
        } finally {
            persistenceManager.releaseShareLock();
        }
    
public intgetTransactionType()

        return txType;
    
public intgetUpdateTimeout()
Gets the number of seconds to wait for an update statement to execute in the datastore associated with this Transaction instance

return
timout value in seconds; zero means unlimited

        return updateTimeout;
    
private voidinternalCommit()
Internal method to process commit operation

        /*
         * CODE FOR XAResource support
        //
        // Commit resources.  If onePhase then we can expect a rollback
        // indication so be prepared to deal with that.
        //
        int    error = this.commitResources();
        if (error != XAResource.XA_OK) {
            this.forceRollback();

            throw (RollbackException)ErrorManager.createFormatAdd(
                    RollbackException.class,
                    ErrorManager.USER,
                    TransactionMsgCat.SH_ERR_TX_TR_CMT_RB_IN_CMT_COMP_XA,
                    this.XAErrorString(error));
        }
         * END CODE FOR XAResource support
         */

        if (txType == NON_MGD) {
            int     error = this.commitConnection();
            if (error != INTERNAL_OK) {
                this.forceRollback();
                throw new JDOUserException(I18NHelper.getMessage(messages,
                    "transaction.transactionimpl.commitcomplete.error", // NOI18N
                    "Connection Error")); // NOI18N
            }
            this.closeConnection();
        }
        this.setStatus(Status.STATUS_COMMITTED);
    
private voidinternalRollback()
Lower-level rollback method. This is expected to be called once the caller has confirmed that itself has set the status to STATUS_ROLLING_BACK. This is to avoid concurrent rollbacks.

        if (this.tracing)
            this.traceCall("internalRollback"); // NOI18N

        if (this.status == Status.STATUS_ROLLEDBACK) {
            return;
        }

        if (this.status != Status.STATUS_ROLLING_BACK) {
            throw new JDOUserException(I18NHelper.getMessage(messages,
                "transaction.transactionimpl.commitprepare.wrongstatus", // NOI18N
                "internalRollback",  // NOI18N
                "STATUS_ROLLING_BACK", // NOI18N
                this.statusString(this.status)));
        }

        if (txType == NON_MGD) {
            this.rollbackConnection();
        }

        this.setStatus(Status.STATUS_ROLLEDBACK);
    
public booleanisActive()

        return (this.status == Status.STATUS_ACTIVE ||
            this.status == Status.STATUS_MARKED_ROLLBACK);
    
booleanisTerminated()
Confirm that transaction is terminated.

return
True if transaction is completed.

        synchronized (this.globalLock) {
            return ((this.status == Status.STATUS_COMMITTED)
                ||    (this.status == Status.STATUS_ROLLEDBACK)
                ||    (this.status == Status.STATUS_NO_TRANSACTION));
        }
    
private voidnotifyAfterCompletion()
Notify registered Synchronization interfaces with afterCompletion(). We assume that no status changes occur while executing this method.

        try {
            persistenceManager.afterCompletion(this.status);

        } finally {
            if (synchronization != null) {
                try {
                    synchronization.afterCompletion(this.status);
                } catch (Exception ex) {
                    logger.log(Logger.WARNING, I18NHelper.getMessage(
                         messages,
                         "transaction.transactionimpl.syncmanager.aftercompletion", // NOI18N
                         ex.getMessage()));
                }
            }
        }

        this.forget();
    
private voidnotifyBeforeCompletion()
Notify registered Synchronization interfaces with beforeCompletion(). This method is only called before a commit so we stop iterating if we encounter an invalid status. Which could have been set by a rollback during (or concurrent with) the notification.

        if (synchronization != null) {
            try {
                synchronization.beforeCompletion();
            } catch (Exception ex) {
                //
                // RESOLVE: ignored ?
                //
            }
        }
        persistenceManager.beforeCompletion();
    
public synchronized voidreleaseConnection()
Close a connection. Connection cannot be closed if it is part of the commit/rollback operation or inside a pessimistic transaction

        boolean debug = logger.isLoggable(Logger.FINEST);

        if (_connectionReferenceCount > 0) {
            _connectionReferenceCount--;
        }

        if (debug) {
            Object[] items = new Object[] {Boolean.valueOf(optimistic),
                Boolean.valueOf(startedCommit), 
                new Integer(_connectionReferenceCount) , persistenceManager};
            logger.finest("sqlstore.transactionimpl.releaseconnection",items); // NOI18N
        }

        // Fix for bug 4479807: Do not keep connection in the managed environment.
        if ( (!EJBHelper.isManaged() && optimistic == false) || startedCommit ) {
            // keep Connection. Do not close.
            return;
        }

        if (_connectionReferenceCount == 0) {
            //
            // For optimistic transaction, we only release the connection when
            // no one is using it.
            //
            closeConnection();
        }
    
public voidreplaceConnection()
Replace a connection. Used in a managed environment only. In a J2EE RI Connection need to be replaced at the beforeCompletion.

        if (EJBHelper.isManaged()) {
            this.releaseConnection();
            this.closeConnection();
            this.getConnection();
        }
    
public voidrollback()
Rollback the transaction represented by this transaction object.


        persistenceManager.acquireExclusiveLock();

        try {
            if (txType == CMT || txType == BMT_UT) {
                // Error - should not be called
                throw new JDOUserException(I18NHelper.getMessage(messages,
                     "transaction.transactionimpl.mgd", "rollback")); //NOI18N
            }

            this.setTrace();

            if (this.tracing)
                this.traceCall("rollback"); // NOI18N

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

                throw new JDOUserException(I18NHelper.getMessage(messages,
                    "transaction.transactionimpl.commit_rollback.notactive", // NOI18N
                    "rollback", // NOI18N
                    this.statusString(this.status)));
            }

            this.setStatus(Status.STATUS_ROLLING_BACK);

            this.internalRollback();
            this.closeConnection();

            if (txType == BMT_JDO) {
                // Send request to the container:
                try {
                    EJBHelper.getLocalTransactionManager().rollback();
                } catch (Exception e) {
                    throw new JDOException("", e); // NOI18N
                }
            } else { //NON_MGD
                //This has effect of rolling back changes also
                //which would not happen in case of BMT_JDO
                //Is this the desired behavior ?
                //TransactionImpl.notifyAfterCompletion()
                //PersistenceManagerImp.afterCompletion()
                //SQLStateManager.rollback()
                this.notifyAfterCompletion();
            }
        } finally {
            persistenceManager.releaseExclusiveLock();
        }
    
private voidrollbackConnection()
replaces rollbackResources() in ForteTran

        boolean debug = logger.isLoggable(Logger.FINEST);
        if (debug) {
            Object[] items = new Object[] {_connection , persistenceManager};
            logger.finest("sqlstore.transactionimpl.rollbackconnection",items); // NOI18N
        }
        if (_connection != null) {
            try {
                if (isDataSource)
                    _connection.rollback();
                else
                    ((ConnectionImpl)_connection).internalRollback();
            } catch (Exception e) {
                //Recover?
            }
        }
    
public voidsetNontransactionalRead(boolean flag)

        //
        // First do a quick check to make sure the transaction is active.
        // This allows us to throw an exception immediately.
        // Cannot change flag to false inside an active optimistic tx
        //
        if (isActive() && optimistic && !flag)
            throw new JDOUnsupportedOptionException(I18NHelper.getMessage(messages,
                "transaction.transactionimpl.setoptimistic.notallowed")); // NOI18N

        //
        // Now get an exclusive lock so we can modify the nontransactionalRead flag.
        //
        persistenceManager.acquireExclusiveLock();

        try {
            // Cannot change flag to false inside an active optimistic tx
            if (isActive() && optimistic && !flag)
                throw new JDOUnsupportedOptionException(I18NHelper.getMessage(messages,
                    "transaction.transactionimpl.setoptimistic.notallowed")); // NOI18N

            this.nontransactionalRead = flag;
            persistenceManager.notifyNontransactionalRead(flag);

            // Adjust depending flags
            if (flag == false) {
                retainValues = flag;
                optimistic = flag;

                // Notify PM about Tx type change
                persistenceManager.notifyOptimistic(flag);
            }
        } finally {
            persistenceManager.releaseExclusiveLock();
        }
    
public voidsetOptimistic(boolean flag)

        //
        // First do a quick check to make sure the transaction is active.
        // This allows us to throw an exception immediately.
        //
        if (!isTerminated()) {
            throw new JDOUnsupportedOptionException(I18NHelper.getMessage(messages,
                  "transaction.transactionimpl.setoptimistic.notallowed")); // NOI18N
        }

        //
        // Now, get an exclusive lock in order to actually modify the optimistic flag.
        //
        persistenceManager.acquireExclusiveLock();

        try {
            if (isTerminated()) {
                this.optimistic = flag;

                // Adjust depending flags
                if (flag) {
                    nontransactionalRead = flag;
                    persistenceManager.notifyNontransactionalRead(flag);
                }
            } else {
                throw new JDOUnsupportedOptionException(I18NHelper.getMessage(messages,
                      "transaction.transactionimpl.setoptimistic.notallowed")); // NOI18N
            }

            // Notify PM about Tx type change
            persistenceManager.notifyOptimistic(flag);
        } finally {
            persistenceManager.releaseExclusiveLock();
        }
    
public voidsetPersistenceManager(com.sun.jdo.spi.persistence.support.sqlstore.PersistenceManager pm)
Set PersistenceManager

    
public voidsetQueryTimeout(int timeout)
Sets the number of seconds to wait for a query statement to execute in the datastore associated with this Transaction instance

param
timeout new timout value in seconds; zero means unlimited

        queryTimeout = timeout;
    
public voidsetRestoreValues(boolean flag)

        //
        // First do a quick check to make sure the transaction is active.
        // This allows us to throw an exception immediately.
        // Cannot change flag to true inside an active tx
        //
        if (isActive())
            throw new JDOUnsupportedOptionException(I18NHelper.getMessage(messages,
                "transaction.transactionimpl.setoptimistic.notallowed")); // NOI18N

        //
        // Now get an exclusive lock so we can modify the restoreValues flag.
        //
        persistenceManager.acquireExclusiveLock();

        try {
            // Cannot change flag to true inside an active  tx
            if (isActive())
                throw new JDOUnsupportedOptionException(I18NHelper.getMessage(messages,
                    "transaction.transactionimpl.setoptimistic.notallowed")); // NOI18N

            this.restoreValues = flag;

        } finally {
            persistenceManager.releaseExclusiveLock();
        }
    
public voidsetRetainValues(boolean flag)

        //
        // First do a quick check to make sure the transaction is active.
        // This allows us to throw an exception immediately.
        // Cannot change flag to true inside an active pessimistic tx
        //
        if (isActive() && !optimistic && flag)
            throw new JDOUnsupportedOptionException(I18NHelper.getMessage(messages,
                "transaction.transactionimpl.setoptimistic.notallowed")); // NOI18N

        //
        // Now get an exclusive lock so we can modify the retainValues flag.
        //
        persistenceManager.acquireExclusiveLock();

        try {
            // Cannot change flag to true inside an active pessimistic tx
            if (isActive() && !optimistic && flag)
                throw new JDOUnsupportedOptionException(I18NHelper.getMessage(messages,
                    "transaction.transactionimpl.setoptimistic.notallowed")); // NOI18N

            this.retainValues = flag;

            // Adjust depending flags
            if (flag) {
                nontransactionalRead = flag;
                persistenceManager.notifyNontransactionalRead(flag);
            }
        } finally {
            persistenceManager.releaseExclusiveLock();
        }
    
public voidsetRollbackOnly()
Modify the transaction object such that the only possible outcome of the transaction is to roll back.

        if (this.tracing)
            this.traceCall("setRollbackOnly"); // NOI18N

        if ((this.status == Status.STATUS_ROLLING_BACK)
                ||    (this.status == Status.STATUS_ROLLEDBACK)
                ||     (this.status == Status.STATUS_MARKED_ROLLBACK)) {
            //
            // Already rolled back, rollback in progress or already marked.
            //
            return;
        }

        if (txType != NON_MGD) {
            try {
                jta.setRollbackOnly();
            } catch (Exception e) {
                throw new JDOException("", e); // NOI18N
            }
        } else {
            this.setStatus(Status.STATUS_MARKED_ROLLBACK);
        }

    
private voidsetStatus(int status)
Set status under lock (may be a nested lock which is ok)

        synchronized(this.globalLock) {
            if (this.tracing) {
                Object[] items= new Object[] {Thread.currentThread(),this.toString(), 
                    this.statusString(this.status), this.statusString(status), persistenceManager};
                logger.finest("sqlstore.transactionimpl.status",items); // NOI18N
            }
            this.status = status;
            persistenceManager.notifyStatusChange(isActive());
        }
    
public voidsetSynchronization(javax.transaction.Synchronization sync)

        if (this.tracing)
        this.traceCall("setSynchronization"); // NOI18N

        persistenceManager.acquireExclusiveLock();

        try {
            synchronization = sync;

            if (this.tracing) {
                this.traceCallInfo("setSynchronization", // NOI18N
                    TRACE_SYNCHRONIZATIONS, null);
            }

        } finally {
            persistenceManager.releaseExclusiveLock();
        }
    
static voidsetTrace()
Set the global transaction tracing.

        TransactionImpl.tracing = logger.isLoggable(Logger.FINEST);
    
public voidsetUpdateTimeout(int timeout)
Sets the number of seconds to wait for an update statement to execute in the datastore associated with this Transaction instance

param
timeout new timout value in seconds; zero means unlimited

        updateTimeout = timeout;
    
public static java.lang.StringstatusString(int status)
Translates a javax.transaction.Status value into a string.

param
status Status object to translate.
return
Printable String for a Status object.

        switch (status) {
            case Status.STATUS_ACTIVE:            return "STATUS_ACTIVE"; // NOI18N
            case Status.STATUS_MARKED_ROLLBACK:   return "STATUS_MARKED_ROLLBACK"; // NOI18N
            case Status.STATUS_PREPARED:          return "STATUS_PREPARED"; // NOI18N
            case Status.STATUS_COMMITTED:         return "STATUS_COMMITTED"; // NOI18N
            case Status.STATUS_ROLLEDBACK:        return "STATUS_ROLLEDBACK"; // NOI18N
            case Status.STATUS_UNKNOWN:           return "STATUS_UNKNOWN"; // NOI18N
            case Status.STATUS_NO_TRANSACTION:    return "STATUS_NO_TRANSACTION"; // NOI18N
            case Status.STATUS_PREPARING:         return "STATUS_PREPARING"; // NOI18N
            case Status.STATUS_COMMITTING:        return "STATUS_COMMITTING"; // NOI18N
            case Status.STATUS_ROLLING_BACK:      return "STATUS_ROLLING_BACK"; // NOI18N
            default:                              break;
        }
        return "STATUS_Invalid[" + status + "]"; // NOI18N
    
public java.lang.StringtoString()
Returns a string representation of this transaction object.

return
String describing contents of this Transaction object.

        int        i;
        Object    o;

        String    s = "  Transaction: \n   status        = " + this.statusString(this.status)+ "\n" // NOI18N
                  +    "   Transaction Object       = Transaction@" + this.hashCode() + "\n" // NOI18N
                  +    "   threads       = " + this.threads + "\n"; // NOI18N

        if (this.timeout != 0)
            s = s + "   timeout       = " + this.timeout + "\n"; // NOI18N
        if (this.startedCommit)
            s = s +    "   startedCommit = true\n"; // NOI18N
        if (this.onePhase)
            s = s +    "   onePhase      = true\n"; // NOI18N

        if (synchronization != null) {
            s = s + "sync:     " + synchronization + "\n"; // NOI18N
        }
        if (!this.resources.isEmpty()) {
            s = s +    "   # resources   = " + this.resources.size() + "\n"; // NOI18N
            /*
            for (i = 0; i < this.resources.size(); i++) {
                XAResource        res = (XAResource)this.resources.get(i);
                //
                // Make be null if vote readonly during commit processing
                // Bug 48325: avoid recursive toString() calls
                //
                if (res != null) {
                    s = s + "    [" + i + "] " + // NOI18N
                        res.getClass().getName() + "\n"; // NOI18N
                }
            }
            */
        }
        return s;

    
private voidtraceCall(java.lang.String call)
Trace method call.

        Object[] items = new Object[]{Thread.currentThread(),this.toString(),call,
             this.statusString(this.status),txTypeString(), persistenceManager};
        logger.finest("sqlstore.transactionimpl.call",items); // NOI18N
    
private voidtraceCallInfo(java.lang.String call, int info, java.lang.String s)
Trace method call with extra info.


        //TODO : Optimize this when converting to resource budles
        StringBuffer logMessage = new StringBuffer();
        logMessage.append("Thread.currentThread()").append("Tran[") // NOI18N
            .append(this.toString()).append("].").append(call) // NOI18N
            .append(": status = ").append(this.statusString(this.status)); // NOI18N

        if ((info & TRACE_THREADS) != 0)
            logMessage.append(", threads = " + this.threads); // NOI18N
        if ((info & TRACE_SYNCHRONIZATIONS) != 0)
            logMessage.append(", sync = " + this.synchronization); // NOI18N
        if ((info & TRACE_RESOURCES) != 0)
            logMessage.append(", resources = " + this.resources.size()); // NOI18N
        if ((info & TRACE_ONE_PHASE) != 0 && this.onePhase)
            logMessage.append(", onePhase = true"); // NOI18N
        if (s != null)
            logMessage.append(", " + s + " for " + persistenceManager); // NOI18N
        
        logger.finest("sqlstore.transactionimpl.general",logMessage.toString()); // NOI18N
    
private voidtraceCallString(java.lang.String call, java.lang.String info)
Trace method call with extra string.

      Object[] items = new Object[] {Thread.currentThread(),this.toString(),call,info,persistenceManager};
      logger.finest("sqlstore.transactionimpl.call.info",items); // NOI18N
    
private java.lang.StringtxTypeString()
Translates a txType value into a string.

return
Printable String for a txType value

        switch (txType) {
            case NON_MGD:                   return "NON_MGD"; // NOI18N
            case CMT:                       return "CMT"; // NOI18N
            case BMT_UT:                    return "BMT_UT"; // NOI18N
            case BMT_JDO:                   return "BMT_JDO"; // NOI18N
            default:                        break;
        }
        return "UNKNOWN"; // NOI18N
    
public booleanverify(java.lang.String username, java.lang.String password)
Verify that username and password are equal to ones stored before

param
username as String
param
password as String
return
true if they are equal

        if ((this.username != null && !this.username.equals(username)) ||
            (this.username == null && username != null) ||
            (this.password != null && !this.password.equals(password)) ||
            (this.password  == null && password != null)) {
            return false;
        }
        return true;