Save This Page
Home » jboss-5.0.0.CR1-src » org » jboss » ejb » plugins » [javadoc | source]
    1   /*
    2   * JBoss, Home of Professional Open Source
    3   * Copyright 2005, JBoss Inc., and individual contributors as indicated
    4   * by the @authors tag. See the copyright.txt in the distribution for a
    5   * full listing of individual contributors.
    6   *
    7   * This is free software; you can redistribute it and/or modify it
    8   * under the terms of the GNU Lesser General Public License as
    9   * published by the Free Software Foundation; either version 2.1 of
   10   * the License, or (at your option) any later version.
   11   *
   12   * This software is distributed in the hope that it will be useful,
   13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   15   * Lesser General Public License for more details.
   16   *
   17   * You should have received a copy of the GNU Lesser General Public
   18   * License along with this software; if not, write to the Free
   19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
   21   */
   22   package org.jboss.ejb.plugins;
   23   
   24   import java.io.PrintWriter;
   25   import java.io.StringWriter;
   26   
   27   import java.rmi.RemoteException;
   28   import java.rmi.ServerException;
   29   import java.rmi.NoSuchObjectException;
   30   import java.lang.reflect.Method;
   31   
   32   import javax.transaction.TransactionManager;
   33   import javax.transaction.TransactionRolledbackException;
   34   import javax.transaction.SystemException;
   35   import javax.transaction.Transaction;
   36   import javax.transaction.Synchronization;
   37   import javax.transaction.RollbackException;
   38   
   39   import javax.ejb.EJBException;
   40   import javax.ejb.NoSuchEntityException;
   41   import javax.ejb.NoSuchObjectLocalException;
   42   import javax.ejb.TransactionRolledbackLocalException;
   43   import javax.ejb.TimedObject;
   44   import javax.ejb.Timer;
   45   
   46   import org.jboss.invocation.Invocation;
   47   import org.jboss.invocation.InvocationType;
   48   import org.jboss.tm.TxUtils;
   49   
   50   /**
   51    * A common superclass for the transaction interceptors.
   52    * <p/>
   53    * The only important method in this class is invokeNext which is incharge
   54    * of invoking the next interceptor and if an exception is thrown, it must
   55    * follow the rules in the EJB 2.0 specification section 18.3.  These
   56    * rules specify if the transaction is rolled back and what exception
   57    * should be thrown.
   58    *
   59    * @author <a href="mailto:osh@sparre.dk">Ole Husgaard</a>
   60    * @author <a href="mailto:dain@daingroup.com">Dain Sundstrom</a>
   61    * @version $Revision: 37459 $
   62    */
   63   abstract class AbstractTxInterceptor
   64           extends AbstractInterceptor
   65   {
   66   
   67      /** A reference to {@link javax.ejb.TimedObject#ejbTimeout}. */
   68      protected static final Method ejbTimeout;
   69      static
   70      {
   71         try
   72         {
   73            ejbTimeout = TimedObject.class.getMethod("ejbTimeout", new Class[]{Timer.class});
   74         }
   75         catch (Exception e)
   76         {
   77            throw new ExceptionInInitializerError(e);
   78         }
   79      }
   80   
   81      /**
   82       * Local reference to the container's TransactionManager.
   83       */
   84      protected TransactionManager tm;
   85   
   86      public void create() throws Exception
   87      {
   88         super.create();
   89         tm = getContainer().getTransactionManager();
   90      }
   91   
   92      /**
   93       * This method calls the next interceptor in the chain.
   94       * <p/>
   95       * All Throwables are caught and divided into two groups: application
   96       * exceptions and system exceptions.  Application exception are simply
   97       * rethrown.  System exceptions result in the transaction being marked
   98       * for rollback only.  If the transaction was not started by the container
   99       * (i.e., it was inherited from the client) the system exception is wrapped
  100       * in a TransactionRolledBack[Local]Exception.
  101       *
  102       * @param invocation  The <code>Invocation</code> of this call.
  103       * @param inheritedTx If <code>true</code> the transaction has just been started
  104       *                    in this interceptor.
  105       * @throws Exception if an exception occures in the interceptor chain.  The
  106       *                   actual exception throw is governed by the rules in the EJB 2.0
  107       *                   specification section 18.3
  108       */
  109      protected Object invokeNext(Invocation invocation, boolean inheritedTx)
  110              throws Exception
  111      {
  112         InvocationType type = invocation.getType();
  113         try
  114         {
  115            if (type == InvocationType.REMOTE || type == InvocationType.LOCAL || type == InvocationType.SERVICE_ENDPOINT)
  116            {
  117               // register the Timer with the transaction
  118               if (ejbTimeout.equals(invocation.getMethod()))
  119                  registerTimer(invocation);
  120   
  121               return getNext().invoke(invocation);
  122            }
  123            else
  124            {
  125               return getNext().invokeHome(invocation);
  126            }
  127         }
  128         catch (Throwable e)
  129         {
  130            // if this is an ApplicationException, just rethrow it
  131            if (e instanceof Exception &&
  132                    !(e instanceof RuntimeException || e instanceof RemoteException))
  133            {
  134               throw (Exception) e;
  135            }
  136   
  137            // attempt to rollback the transaction
  138            Transaction tx = invocation.getTransaction();
  139            if (tx == null)
  140            {
  141               // Look for a hanging active user transaction that we should mark rollback
  142               try
  143               {
  144                  tx = tm.getTransaction();
  145                  if (TxUtils.isActive(tx) == false)
  146                     tx = null;
  147               }
  148               catch (Exception ex)
  149               {
  150                  log.warn("Unable to determine transaction context", ex);
  151               }
  152            }
  153            if (tx != null)
  154            {
  155               try
  156               {
  157                  tx.setRollbackOnly();
  158               }
  159               catch (SystemException ex)
  160               {
  161                  log.error("SystemException while setting transaction " +
  162                          "for rollback only", ex);
  163               }
  164               catch (IllegalStateException ex)
  165               {
  166                  log.error("IllegalStateException while setting transaction " +
  167                          "for rollback only", ex);
  168               }
  169            } 
  170   
  171            // is this a local invocation
  172            boolean isLocal =
  173                    type == InvocationType.LOCAL ||
  174                    type == InvocationType.LOCALHOME;
  175   
  176            // if this transaction was NOT inherited from the caller we simply
  177            // rethrow the exception, and LogInterceptor will handle 
  178            // all exception conversions.
  179            if (!inheritedTx)
  180            {
  181               if (e instanceof Exception)
  182               {
  183                  throw (Exception) e;
  184               }
  185               if (e instanceof Error)
  186               {
  187                  throw (Error) e;
  188               }
  189   
  190               // we have some funky throwable, wrap it
  191               if (isLocal)
  192               {
  193                  String msg = formatException("Unexpected Throwable", e);
  194                  throw new EJBException(msg);
  195               }
  196               else
  197               {
  198                  ServerException ex = new ServerException("Unexpected Throwable");
  199                  ex.detail = e;
  200                  throw ex;
  201               }
  202            }
  203    
  204            // to be nice we coerce the execption to an interface friendly type
  205            // before wrapping it with a transaction rolled back exception
  206            Throwable cause;
  207            if (e instanceof NoSuchEntityException)
  208            {
  209               NoSuchEntityException nsee = (NoSuchEntityException) e;
  210               if (isLocal)
  211               {
  212                  cause = new NoSuchObjectLocalException(nsee.getMessage(),
  213                          nsee.getCausedByException());
  214               }
  215               else
  216               {
  217                  cause = new NoSuchObjectException(nsee.getMessage());
  218   
  219                  // set the detil of the exception
  220                  ((NoSuchObjectException) cause).detail =
  221                          nsee.getCausedByException();
  222               }
  223            }
  224            else
  225            {
  226               if (isLocal)
  227               {
  228                  // local transaction rolled back exception can only wrap 
  229                  // an exception so we create an EJBException for the cause
  230                  if (e instanceof Exception)
  231                  {
  232                     cause = e;
  233                  }
  234                  else if (e instanceof Error)
  235                  {
  236                     String msg = formatException("Unexpected Error", e);
  237                     cause = new EJBException(msg);
  238                  }
  239                  else
  240                  {
  241                     String msg = formatException("Unexpected Throwable", e);
  242                     cause = new EJBException(msg);
  243                  }
  244               }
  245               else
  246               {
  247                  // remote transaction rolled back exception can wrap
  248                  // any throwable so we are ok
  249                  cause = e;
  250               }
  251            }
  252            
  253            // We inherited tx: Tell caller we marked for rollback only.
  254            if (isLocal)
  255            {
  256               if (cause instanceof TransactionRolledbackLocalException)
  257               {
  258                  throw (TransactionRolledbackLocalException) cause;
  259               }
  260               else
  261               {
  262                  throw new TransactionRolledbackLocalException(cause.getMessage(),
  263                          (Exception) cause);
  264               }
  265            }
  266            else
  267            {
  268               if (cause instanceof TransactionRolledbackException)
  269               {
  270                  throw (TransactionRolledbackException) cause;
  271               }
  272               else
  273               {
  274                  TransactionRolledbackException ex =
  275                          new TransactionRolledbackException(cause.getMessage());
  276                  ex.detail = cause;
  277                  throw ex;
  278               }
  279            }
  280         }
  281      }
  282   
  283      private void registerTimer(Invocation invocation)
  284              throws RollbackException, SystemException
  285      {
  286         Timer timer = (Timer) invocation.getArguments()[0];
  287         Transaction transaction = invocation.getTransaction();
  288         if (transaction != null && timer instanceof Synchronization)
  289            transaction.registerSynchronization((Synchronization) timer);
  290      }
  291   
  292      private String formatException(String msg, Throwable t)
  293      {
  294         StringWriter sw = new StringWriter();
  295         PrintWriter pw = new PrintWriter(sw);
  296         if (msg != null)
  297         {
  298            pw.println(msg);
  299         }
  300         t.printStackTrace(pw);
  301         return sw.toString();
  302      }
  303   }

Save This Page
Home » jboss-5.0.0.CR1-src » org » jboss » ejb » plugins » [javadoc | source]