content: /**
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package org.apache.activemq.ra;
  
  import jakarta.jms.JMSException;
  import jakarta.resource.ResourceException;
  import jakarta.resource.spi.LocalTransaction;
  import javax.transaction.xa.XAException;
  import javax.transaction.xa.XAResource;
  import javax.transaction.xa.Xid;
  
  import org.apache.activemq.TransactionContext;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  /**
   * Used to provide a LocalTransaction and XAResource to a JMS session.
   */
  public class LocalAndXATransaction implements XAResource, LocalTransaction {
      private static final Logger LOG = LoggerFactory.getLogger(LocalAndXATransaction.class);
  
      private TransactionContext transactionContext;
      private boolean inManagedTx;
  
      public LocalAndXATransaction(TransactionContext transactionContext) {
          this.transactionContext = transactionContext;
      }
  
      public void setTransactionContext(TransactionContext transactionContext) {
          this.transactionContext = transactionContext;
      }
  
      public void setInManagedTx(boolean inManagedTx) throws JMSException {
          this.inManagedTx = inManagedTx;
          if (!inManagedTx) {
              transactionContext.cleanup();
          }
      }
  
      public void begin() throws ResourceException {
          try {
              transactionContext.begin();
              setInManagedTx(true);
          } catch (JMSException e) {
              throw new ResourceException("begin failed.", e);
          }
      }
  
      public void commit() throws ResourceException {
          try {
              transactionContext.commit();
          } catch (JMSException e) {
              throw new ResourceException("commit failed.", e);
          } finally {
              try {
                  setInManagedTx(false);
              } catch (JMSException e) {
                  throw new ResourceException("commit failed.", e);
              }
          }
      }
  
      public void rollback() throws ResourceException {
          try {
              transactionContext.rollback();
          } catch (JMSException e) {
              throw new ResourceException("rollback failed.", e);
          } finally {
              try {
                  setInManagedTx(false);
              } catch (JMSException e) {
                  throw new ResourceException("rollback failed.", e);
              }
          }
      }
  
      public void commit(Xid arg0, boolean arg1) throws XAException {
          transactionContext.commit(arg0, arg1);
      }
  
      public void end(Xid arg0, int arg1) throws XAException {
          LOG.debug("{} end {} with {}", new Object[]{this, arg0, arg1});
          try {
              transactionContext.end(arg0, arg1);
          } finally {
              try {
                  setInManagedTx(false);
              } catch (JMSException e) {
                  throw (XAException)new XAException(XAException.XAER_PROTO).initCause(e);
              }
              if ((arg1 & TMFAIL) != 0) {
                  // do no further work in this context
                  LOG.debug("Marking transaction: {} rollbackOnly", this);
                  transactionContext.setRollbackOnly(true);
              }
          }
      }
  
      public void forget(Xid arg0) throws XAException {
          transactionContext.forget(arg0);
      }
  
      public int getTransactionTimeout() throws XAException {
          return transactionContext.getTransactionTimeout();
      }
  
      public boolean isSameRM(XAResource xaresource) throws XAException {
          boolean isSame = false;
          if (xaresource != null) {
              // Do we have to unwrap?
              if (xaresource instanceof LocalAndXATransaction) {
                  xaresource = ((LocalAndXATransaction)xaresource).transactionContext;
              }
              isSame = transactionContext.isSameRM(xaresource);
          }
          LOG.trace("{} isSameRM({}) = {}", new Object[]{this, xaresource, isSame});
          return isSame;
      }
  
      public int prepare(Xid arg0) throws XAException {
          return transactionContext.prepare(arg0);
      }
  
      public Xid[] recover(int arg0) throws XAException {
          Xid[] answer = null;
          LOG.trace("{} recover({})", this, arg0);
          answer = transactionContext.recover(arg0);
          LOG.trace("{} recover({}) = {}", new Object[]{this, arg0, answer});
          return answer;
      }
  
      public void rollback(Xid arg0) throws XAException {
          transactionContext.rollback(arg0);
      }
  
      public boolean setTransactionTimeout(int arg0) throws XAException {
          return transactionContext.setTransactionTimeout(arg0);
      }
  
      public void start(Xid arg0, int arg1) throws XAException {
          LOG.trace("{} start {} with {}", new Object[]{this, arg0, arg1});
          transactionContext.start(arg0, arg1);
          try {
              setInManagedTx(true);
          } catch (JMSException e) {
              throw (XAException)new XAException(XAException.XAER_PROTO).initCause(e);
          }
      }
  
      public boolean isInManagedTx() {
          return inManagedTx;
      }
  
      public void cleanup() {
          transactionContext.cleanup();
          inManagedTx = false;
      }
  
      @Override
      public String toString() {
          return "[" + super.toString() + "," + transactionContext + "]";
      }
  }
  