AbstractTransactionalConnectionListener.java

/*
 * IronJacamar, a Java EE Connector Architecture implementation
 * Copyright 2016, Red Hat Inc, and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the Eclipse Public License 1.0 as
 * published by the Free Software Foundation.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Eclipse
 * Public License for more details.
 *
 * You should have received a copy of the Eclipse Public License 
 * along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.ironjacamar.core.connectionmanager.listener.stable;

import org.ironjacamar.common.api.metadata.common.FlushStrategy;
import org.ironjacamar.core.CoreBundle;
import org.ironjacamar.core.connectionmanager.ConnectionManager;
import org.ironjacamar.core.connectionmanager.Credential;
import org.ironjacamar.core.connectionmanager.listener.TransactionSynchronization;
import org.ironjacamar.core.connectionmanager.pool.ManagedConnectionPool;
import org.ironjacamar.core.connectionmanager.pool.stable.StablePool;
import org.ironjacamar.core.spi.transaction.TxUtils;

import static org.ironjacamar.core.connectionmanager.listener.ConnectionListener.DESTROY;

import javax.resource.ResourceException;
import javax.resource.spi.ManagedConnection;
import javax.transaction.Transaction;
import javax.transaction.xa.XAResource;

import org.jboss.logging.Messages;

/**
 * An abstract transactional connection listener for the stable configuration
 * @author <a href="mailto:jesper.pedersen@ironjacamar.org">Jesper Pedersen</a>
 */
public abstract class AbstractTransactionalConnectionListener extends
   org.ironjacamar.core.connectionmanager.listener.AbstractTransactionalConnectionListener
{

   /** The Message bundle */
   CoreBundle bundle = Messages.getBundle(CoreBundle.class);

   /**
    * Constructor
    * @param cm The connection manager
    * @param mc The managed connection
    * @param credential The credential
    * @param xaResource The associated XAResource
    * @param xaResourceTimeout The timeout for the XAResource instance
    * @param mcp The ManagedConnectionPool
    * @param flushStrategy The FlushStrategy
    */
   public AbstractTransactionalConnectionListener(ConnectionManager cm, ManagedConnection mc, Credential credential,
                                                  XAResource xaResource, int xaResourceTimeout,
                                                  ManagedConnectionPool mcp, FlushStrategy flushStrategy)
   {
      super(cm, mc, credential, xaResource, xaResourceTimeout, mcp, flushStrategy);
   }

   /**
    * {@inheritDoc}
    */
   public synchronized void enlist() throws ResourceException
   {
      if (isEnlisted())
      {
         try
         {
            StablePool sp = (StablePool)cm.getPool();
            Object tx = sp.verifyConnectionListener(this);
            if (tx != null)
               throw new ResourceException(tx.toString());
         }
         finally
         {
            setState(DESTROY);
         }
      }

      super.enlist();
   }

   /**
    * {@inheritDoc}
    */
   public synchronized void delist() throws ResourceException
   {
      if (!isEnlisted())
      {
         setState(DESTROY);
      }

      super.delist();
   }

   /**
    * Create the transaction synchronization object
    * @return The object
    */
   @Override
   protected TransactionSynchronization createTransactionSynchronization()
   {
      return new TransactionSynchronizationImpl();
   }
   
   /**
    * Transaction synchronization
    */
   class TransactionSynchronizationImpl implements TransactionSynchronization
   {
      /** Transaction */
      private Transaction transaction;

      /** Cancel */
      private boolean cancel;

      /** */
      private Throwable throwable;
      
      /**
       * Constructor
       */
      public TransactionSynchronizationImpl()
      {
      }

      /**
       * {@inheritDoc}
       */
      public void init(Transaction tx)
      {
         this.transaction = tx;
         this.cancel = false;
         this.throwable = new Throwable(bundle.unableToEnlist());
      }

      /**
       * {@inheritDoc}
       */
      public void enlist() throws ResourceException
      {
         ResourceException enlistError = null;
         try
         {
            if (!transaction.enlistResource(xaResource))
            {
               enlistError = new ResourceException(bundle.failedToEnlist(), throwable);
            }
         }
         catch (Exception e)
         {
            enlistError = new ResourceException(e);
            enlistError.initCause(throwable);
         }

         if (enlistError != null)
         {
            transactionSynchronization = null;
            enlisted = false;

            throw enlistError;
         }
      }

      /**
       * {@inheritDoc}
       */
      public void cancel()
      {
         cancel = true;
      }

      /**
       * {@inheritDoc}
       */
      public void beforeCompletion()
      {
         if (!cancel)
         {
            try
            {
               if (TxUtils.isUncommitted(transaction))
               {
                  if (TxUtils.isActive(transaction))
                  {
                     transaction.delistResource(xaResource, XAResource.TMSUCCESS);
                  }
                  else
                  {
                     transaction.delistResource(xaResource, XAResource.TMFAIL);
                  }
               }
            }
            catch (Exception e)
            {
               // TODO
            }
         }
      }

      /**
       * {@inheritDoc}
       */
      public void afterCompletion(int status)
      {
         if (!cancel)
         {
            // "Delist"
            transactionSynchronization = null;
            enlisted = false;

            if (connectionHandles.isEmpty())
            {
               cm.returnConnectionListener(AbstractTransactionalConnectionListener.this, false);
            }
         }
      }
   }
}