/*
(non-Javadoc)

@see com.ibm.tx.remote.RemoteTransactionController#unexportTransaction(java.lang.String)
431637
@Override
    public void unexportTransaction(String globalId) throws SystemException {

        // look up the tran or just get the one off the thread

        // blow up if there's no tran
        final UOWCoordinator uowCoord = _uowc.getUOWCoord();
        if (uowCoord == null || !uowCoord.isGlobal()) {
            throw new SystemException("No global transaction");
        }

        // Resume transaction association as we are coming back on server
        ((DistributableTransaction) uowCoord).resumeAssociation();
    }
1275924
public static boolean beginOrJoinTransaction()
   {
      boolean newTransaction = false;
      try {
         newTransaction = userTransaction.getStatus() == Status.STATUS_NO_TRANSACTION;
         if (newTransaction) {
            userTransaction.begin();
         }
      }
      catch (Exception e) {
         throw new RuntimeException("Unable to start transaction.", e);
      }

      return newTransaction;
   }
1177186
@Override
  public void setTransactionIsolation(int level) throws SQLException
  {
    logger.debug(
        "void setTransactionIsolation(int level), level = {}", level);
    raiseSQLExceptionIfConnectionIsClosed();
    if (level == Connection.TRANSACTION_NONE
        || level == Connection.TRANSACTION_READ_COMMITTED)
    {
      this.transactionIsolation = level;
    }
    else
    {
      throw new SQLFeatureNotSupportedException(
          "Transaction Isolation " + level + " not supported.",
          FEATURE_UNSUPPORTED.getSqlState(),
          FEATURE_UNSUPPORTED.getMessageCode());
    }
  }
1024555
public TransactionImpl getTransaction()
    {
        TxBuffer buf = (TxBuffer) txRepository.get();
        return buf != null ? buf.getInternTx() : null;
    }
751046
void addTransaction(Transaction t, boolean runSanityChecks) {
        unCacheTransactions();
        if (transactions == null) {
            transactions = new ArrayList<>();
        }
        t.setParent(this);
        if (runSanityChecks && transactions.size() == 0 && !t.isCoinBase())
            throw new RuntimeException("Attempted to add a non-coinbase transaction as the first transaction: " + t);
        else if (runSanityChecks && transactions.size() > 0 && t.isCoinBase())
            throw new RuntimeException("Attempted to add a coinbase transaction when there already is one: " + t);
        transactions.add(t);
        adjustLength(transactions.size(), t.length);
        // Force a recalculation next time the values are needed.
        merkleRoot = null;
        hash = null;
    }
1256619
protected int getTransactionIsolation(final String dataSourceName) {
		Map<String, String> props = getConnPropsByDataSourceName(dataSourceName);
		String val = props.get(PROPS_TRANSACTION_ISOLATION);
		return val == null ? -1 : Integer.parseInt(val);
	}
856281
public static void rollbackTransaction() {
        Connection connection = tl_conn.get();
        if (connection == null) {
            throw new RuntimeException("You do not start a Transaction so you can not rollback a transaction!");
        }
        try {
            connection.rollback();
            connection.close();
            tl_conn.remove();
            tl_sp.remove();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
807439
protected void unsetUserTransaction(ServiceReference<UserTransaction> ref) {
        if (TraceComponent.isAnyTracingEnabled() && LoggingUtil.SESSION_LOGGER_WAS.isLoggable(Level.FINE)) {
            LoggingUtil.SESSION_LOGGER_WAS.logp(Level.FINE, methodClassName, "unsetUserTransaction", "unsetting " + ref);
        }
        userTransactionRef.unsetReference(ref);
    }
1041695
public void registerTransaction(TransactionImpl tran) {
        if (tc.isEntryEnabled())
            Tr.entry(tc, "registerTransaction", new Object[] { this, tran });

        _recoveringTransactions.add(tran);

        if (tc.isEntryEnabled())
            Tr.exit(tc, "registerTransaction", _recoveringTransactions.size());
    }
1328815
protected boolean isExistingTransaction(Object transaction) {
        ContextSourceAndHibernateTransactionObject actualTransactionObject = (ContextSourceAndHibernateTransactionObject) transaction;

        return super.isExistingTransaction(actualTransactionObject
                .getHibernateTransactionObject());
    }
1199998
@Override
    public synchronized UserTransaction getUserTransaction()
    {
        // d367572.1 start
        if (state == PRE_CREATE)
        {
            if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                Tr.debug(tc, "Incorrect state: " + getStateName(state));
            throw new IllegalStateException(getStateName(state));
        }
        // d367572.1 end

        return UserTransactionWrapper.INSTANCE; // d631349

    }
663558
@Override
    public boolean importTransaction(String globalId, int expires) throws SystemException {

        //The first thing we need to do is distinguish between local and remote invocations. If the UOW currently associated
        //with the thread is a global txn then we know the invocation must be local. The other case is where the remote servers
        //web container has begun a local txn in the absence of the global context. We do know that there was a global txn on 
        //invocation else there wouldn't even be a cc available.
        final UOWCoordinator uowCoord = _uowc.getUOWCoord();
        _threadUOWCoord.set(uowCoord);

        if (uowCoord != null && uowCoord.isGlobal()) {
            if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                Tr.debug(tc, "The Web Service request is a local invocation");

            ((DistributableTransaction) uowCoord).resumeAssociation();
            return false;
        }

        if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
            Tr.debug(tc, "The Web Service request is a remote invocation");

        try {
            TMHelper.checkTMState();
        } catch (NotSupportedException e) {
            final SystemException se = new SystemException();
            se.initCause(e);
            throw se;
        }

        //The web container will start a local tran as there will not be a global context
        //on thread. We need to suspend this before attaching the global tran
        final LocalTransactionCoordinator ltc = LocalTranCurrentSet.instance().suspend();
        if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
            Tr.debug(tc, "Suspended LTC", ltc);

        boolean createdNewTransaction = false;

        DistributableTransaction tx = getTransactionForID(globalId);

        if (tx == null) {
            tx = new EmbeddableTransactionImpl(expires, globalId);
            createdNewTransaction = true;

            new TransactionWrapper((EmbeddableTransactionImpl) tx);
        }

        _threadImportedTran.set(tx);

        // Add association to police single thread per tran
        tx.addAssociation();

        // Resume transaction on this thread
        try {
            _tm.resume((Transaction) tx);
        } catch (Exception e) {
            SystemException se = new SystemException();
            se.initCause(e);
            throw se;
        }

        return createdNewTransaction;
    }
980897
@SuppressWarnings("unchecked")
    @Override
    public <RESULT> OptionalThing<RESULT> required(TransactionShow<RESULT> txLambda) {
        try {
            return wrapOptional((RESULT) transactionManagerAdapter.required(adapter -> {
                return performTx(txLambda, adapter, TransactionGenre.REQUIRED);
            }), txLambda);
        } catch (Throwable e) {
            handleTransactionFailure(txLambda, e);
            return null; // unreachable
        }
    }
1199807
@Override
    public final synchronized void rollback(ContainerTx tx)
                    throws RemoteException
    {
        final boolean isTraceOn = TraceComponent.isAnyTracingEnabled();
        if (isTraceOn && tc.isEntryEnabled())
            Tr.entry(tc, "rollback: " + StateStrs[state], tx);

        if (removed) {
            if (isTraceOn && tc.isEntryEnabled())
                Tr.exit(tc, "rollback: removed");
            return;
        }

        switch (state)
        {
        // These are the "normal" rollback points
            case COMMITTING_OUTSIDE_METHOD:
            case TX_METHOD_READY:
            case AFTER_BEGIN: // d159152

                setState(METHOD_READY);
                break;

            // We also could be rolledback "unexpectedly" at these points
            case TX_IN_METHOD:
            case REMOVING: // d159152

                setState(IN_METHOD);
                break;

            // Rollback in the DESTROYED state can/should only occur if there
            // was an exception from the customer beforeCompletion method.
            // Otherwise, the bean should have been delisted.                d160910
            case DESTROYED:
                if (ivBeforeCompletion != null || sessionSync != null)
                {
                    if (isTraceOn && tc.isDebugEnabled())
                        Tr.debug(tc, "SessionSynchronization.beforeCompletion exception?");
                }
                else
                {
                    if (isTraceOn && tc.isEntryEnabled())
                        Tr.exit(tc, "rollback: InvalidBeanOStateException: " +
                                    StateStrs[state]);
                    throw new InvalidBeanOStateException(StateStrs[state],
                                    "COMMITTING_OUTSIDE_METHOD | " +
                                                    "TX_METHOD_READY | TX_IN_METHOD");
                }
                break;

            default:
                if (isTraceOn && tc.isEntryEnabled())
                    Tr.exit(tc, "rollback: InvalidBeanOStateException: " +
                                StateStrs[state]);
                throw new InvalidBeanOStateException(StateStrs[state],
                                "COMMITTING_OUTSIDE_METHOD | " +
                                                "TX_METHOD_READY | TX_IN_METHOD");

        }

        if (tx.ivRemoveBeanO == this)
        {
            completeRemoveMethod(tx); // d647928
        }
        else
        {
            // Perform normal afterCompletion processing.... calling
            // afterCompletion if present.
            // Save the above determined state and set to AFTER_COMPLETION for
            // the duration of the afterCompletion callback.                d159152
            int savedState = state;
            setState(AFTER_COMPLETION);

            // Session Synchronization AfterCompletion needs to be called if either
            // the annotation (or XML) was specified or the bean implemented
            // the interface and a global transaction is active.        F743-25855
            if ((ivAfterCompletion != null || sessionSync != null) &&
                tx.isTransactionGlobal())
            {
                EJBThreadData threadData = EJSContainer.getThreadData();

                threadData.pushContexts(this);
                try
                {
                    if (ivAfterCompletion != null) {
                        invokeSessionSynchMethod(ivAfterCompletion, new Object[] { false });
                    } else {
                        sessionSync.afterCompletion(false);
                    }
                } finally
                {
                    threadData.popContexts();
                }
            }

            setState(savedState); // d159152
        }

        // currentTx is now reset in atCommit/atRollback AFTER the final pin
        // is undone.                                                      d258770
        // currentTx = null;                                            // PQ99986

        if (isTraceOn && tc.isEntryEnabled())
            Tr.exit(tc, "rollback: " + StateStrs[state]);
    }
882367
@Override
	public Connection getConnection() {
		Optional<LocalTransactionContext> txContext = currentTxContext();
		try {
			if (txContext.isPresent()) {
				return txContext.get().getConnection();
			} else {
				if (!this.unmanagedTransaction.isPresent()) {
					this.unmanagedTransaction = Optional
							.of(new LocalTransactionContext(this.connectionSupplier, this.sqlFilterManager));
				}
				return this.unmanagedTransaction.get().getConnection();
			}
		} catch (SQLException ex) {
			ex.printStackTrace();
			return null;
		}
	}
813613
@Override
    public void localTransactionStarted(ConnectionEvent event) {

        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
            Tr.entry(this, tc, "localTransactionStarted");
        }

        if (event.getId() == ConnectionEvent.LOCAL_TRANSACTION_STARTED) {

            //
            // The LocalTransactionStarted event for local transaction connections is analogous to the
            //  InteractionPending event for xa transaction connections.  JMS's usage of ManagedSessions
            //  is very dependent on the ability to use these two events for properly enlisting their
            //  unshared connections.  When a ManagedSession is first created, it is done under an LTC.
            //  When that LTC ends, some partial cleanup is done on the MCWrapper, but it is not put
            //  back into the pool because the unshared connection handle is still active.  One of the
            //  items that gets cleaned up is the coordinator within the MCWrapper.  This makes sense
            //  since the LTC has ended.  But, when it is determined by JMS that it's time to get
            //  enlisted in the current transaction, a null coordinator causes all kinds of problems
            //  (reference the string of defects that have attempted to correct this situation).  The
            //  solution determined seems to be the right one.  In both localTransactionStarted
            //  and interactionPending methods, we need to check if the MCWrapper coordinator is null and
            //  if it is null, then go out to the TM and get it updated.
            //
            // Note that this special null coordinator processing is due to the SmartHandle support
            //  utilized by JMS and RRA.  Without smart handles, the coordinator would have gotten
            //  re-initialized during the handle re-association logic.
            //
            // In addition, we have determined that the check for involvedInTransaction() is not necessary
            //  (and causes problems for the scenario described just previous).  Since the getCurrentTranWrapper()
            //  already checks for a valid state setting before returning, we can just rely on that method to
            //  do the proper checking instead of calling the involvedInTransaction() method.
            //
            UOWCoordinator uowCoordinator = mcWrapper.getUOWCoordinator();

            if (uowCoordinator == null) {
                uowCoordinator = mcWrapper.updateUOWCoordinator();
                if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                    Tr.debug(this, tc, "uowCoord was null, updating it to current coordinator");
                }
            }

            // if the coordinator is still null, then we are running with NO transaction
            //  context on the thread.  This case currently needs to be supported because
            //  servlets can spin their own threads which would not have context.
            // Note: it is very rare that users do this.  All other occurances are
            //  considered to be an error.
            if (uowCoordinator == null) {
                if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
                    Tr.exit(this, tc, "localTransactionStarted", "no transaction context, return without enlisting");
                }
                return;
            }

            /*
             * We know we are in a transaction but we need to verify that it is not a global transaction
             * before continuing.
             */
            if (tc.isDebugEnabled() && uowCoordinator.isGlobal()) {
                IllegalStateException ise = new IllegalStateException("Illegal attempt to start a local transaction within a global (user) transaction");
                Tr.debug(this, tc, "ILLEGAL_USE_OF_LOCAL_TRANSACTION_J2CA0295", ise);
            }

            /*
             * The ManagedConnection should be associated with a transaction. And, if it's not,
             * the getCurrentTranWrapper() method will detect the situation and throw an
             * exception.
             *
             * enlist() the ManagedConnection from the transaction.
             */

            try {
                mcWrapper.getCurrentTranWrapper().enlist();
            } catch (ResourceException e) {
                /*
                 * // Can't enlist, something went wrong.
                 * // Destroy the connection(s) so it can't cause any future problems.
                 * try {
                 * mcWrapper.markStale();
                 * mcWrapper.releaseToPoolManager();
                 * }
                 * catch (Exception ex) {
                 * // Nothing to do here. PoolManager has already logged it.
                 * // Since we are in cleanup mode, we will not surface a Runtime exception to the ResourceAdapter
                 * FFDCFilter.processException(ex, "com.ibm.ejs.j2c.ConnectionEventListener.localTransactionStarted", "473", this);
                 * if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                 * Tr.debug(this, tc, "localTransactionStarted: Error when trying to enlist " + mcWrapper.getPoolManager().getPmiName() +
                 * " caught exception, but will continue processing: ", ex);
                 * }
                 * }
                 */

                FFDCFilter.processException(e, "com.ibm.ejs.j2c.ConnectionEventListener.localTransactionStarted", "481", this);
                // add datasource name to message
                Tr.error(tc, "ENLIST_FAILED_J2CA0074", "localTransactionStarted", e, mcWrapper.gConfigProps.cfName);
                // Moved event.getSource() inside of catch block for performance reasons
                ManagedConnection mc = null;
                try {
                    mc = (ManagedConnection) event.getSource();
                } catch (ClassCastException cce) {
                    Tr.error(tc, "GET_SOURCE_CLASS_CAST_EXCP_J2CA0098", cce);
                    throw new IllegalStateException("ClassCastException occurred attempting to cast event.getSource to ManagedConnection");
                }
                ConnectionEvent errorEvent = new ConnectionEvent(mc, ConnectionEvent.CONNECTION_ERROR_OCCURRED);
                this.connectionErrorOccurred(errorEvent);

                RuntimeException rte = new IllegalStateException(e.getMessage());
                throw rte;
            }
        } else {
            // Connection Event passed in doesn't match the method called.
            // This should never happen unless there is an error in the ResourceAdapter.
            processBadEvent("localTransactionStarted", ConnectionEvent.LOCAL_TRANSACTION_STARTED, event);
        }

        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
            Tr.exit(this, tc, "localTransactionStarted");
        }
        return;
    }
368473
void rollback(long fromTransactionId) {
        long traceId = LoggerHelpers.traceEnterWithContext(log, this.traceObjectId, "rollback", fromTransactionId);
        List<Long> rolledBack = new ArrayList<>();
        while (!this.transactions.isEmpty() && this.transactions.peekLast().getTransactionId() >= fromTransactionId) {
            ContainerMetadataUpdateTransaction txn = this.transactions.removeLast();
            txn.seal();
            rolledBack.add(txn.getTransactionId());
        }

        // At this point, the transaction list is either empty or its last one is sealed; any further changes would
        // require creating a new transaction.
        LoggerHelpers.traceLeave(log, this.traceObjectId, "rollback", traceId, rolledBack);
    }