Save This Page
Home » openejb-3.1.2-src » org.apache » openejb » core » stateful » [javadoc | source]
    1   /**
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *     http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   package org.apache.openejb.core.stateful;
   18   
   19   import org.apache.openejb.ApplicationException;
   20   import org.apache.openejb.SystemException;
   21   import org.apache.openejb.core.BaseContext;
   22   import org.apache.openejb.core.stateful.StatefulContext;
   23   import org.apache.openejb.core.Operation;
   24   import org.apache.openejb.core.ThreadContext;
   25   import org.apache.openejb.core.interceptor.InterceptorStack;
   26   import org.apache.openejb.core.interceptor.InterceptorData;
   27   import org.apache.openejb.core.transaction.TransactionContext;
   28   import org.apache.openejb.util.LogCategory;
   29   import org.apache.openejb.util.Logger;
   30   
   31   import javax.ejb.SessionSynchronization;
   32   import javax.transaction.Status;
   33   import javax.transaction.Transaction;
   34   import javax.transaction.TransactionManager;
   35   import java.util.HashMap;
   36   import java.util.Map;
   37   import java.util.List;
   38   import java.lang.reflect.Method;
   39   
   40   public class SessionSynchronizationCoordinator implements javax.transaction.Synchronization {
   41       private static Logger logger = Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources");
   42   
   43       private static Map<Transaction,SessionSynchronizationCoordinator> coordinators = new HashMap<Transaction,SessionSynchronizationCoordinator>();
   44   
   45       private final Map<Object,ThreadContext> sessionSynchronizations = new HashMap<Object,ThreadContext>();
   46       private final TransactionManager transactionManager;
   47   
   48       private SessionSynchronizationCoordinator(TransactionManager transactionManager) {
   49           this.transactionManager = transactionManager;
   50       }
   51   
   52       public static void registerSessionSynchronization(StatefulInstanceManager.Instance instance, TransactionContext context) throws javax.transaction.SystemException, javax.transaction.RollbackException {
   53           SessionSynchronizationCoordinator coordinator = null;
   54   
   55           coordinator = coordinators.get(context.currentTx);
   56   
   57           if (coordinator == null) {
   58               coordinator = new SessionSynchronizationCoordinator(context.getTransactionManager());
   59               try {
   60                   context.currentTx.registerSynchronization(coordinator);
   61               } catch (Exception e) {
   62                   // todo this seems bad...
   63                   logger.error("Transaction.registerSynchronization failed.", e);
   64                   return;
   65               }
   66               coordinators.put(context.currentTx, coordinator);
   67           }
   68   
   69           coordinator._registerSessionSynchronization(instance, context.callContext);
   70       }
   71   
   72       private void _registerSessionSynchronization(StatefulInstanceManager.Instance instance, ThreadContext callContext) {
   73           boolean registered = sessionSynchronizations.containsKey(callContext.getPrimaryKey());
   74   
   75           if (registered) return;
   76   
   77           try {
   78               callContext = new ThreadContext(callContext.getDeploymentInfo(), callContext.getPrimaryKey());
   79           } catch (Exception e) {
   80           }
   81           sessionSynchronizations.put(callContext.getPrimaryKey(), callContext);
   82   
   83           Operation currentOperation = callContext.getCurrentOperation();
   84           callContext.setCurrentOperation(Operation.AFTER_BEGIN);
   85           BaseContext.State[] originalStates = callContext.setCurrentAllowedStates(StatefulContext.getStates());
   86           try {
   87   
   88               Method afterBegin = SessionSynchronization.class.getMethod("afterBegin");
   89   
   90               List<InterceptorData> interceptors = callContext.getDeploymentInfo().getMethodInterceptors(afterBegin);
   91               InterceptorStack interceptorStack = new InterceptorStack(instance.bean, afterBegin, Operation.AFTER_BEGIN, interceptors, instance.interceptors);
   92               interceptorStack.invoke();
   93   
   94           } catch (Exception e) {
   95               String message = "An unexpected system exception occured while invoking the afterBegin method on the SessionSynchronization object: " + e.getClass().getName() + " " + e.getMessage();
   96               logger.error(message, e);
   97               throw new RuntimeException(message, e);
   98   
   99           } finally {
  100               callContext.setCurrentOperation(currentOperation);
  101               callContext.setCurrentAllowedStates(originalStates);
  102           }
  103       }
  104   
  105       public void beforeCompletion() {
  106   
  107           Object[] contexts = sessionSynchronizations.values().toArray();
  108   
  109           for (int i = 0; i < contexts.length; i++) {
  110               // don't call beforeCompletion when transaction is marked rollback only
  111               if (getTransactionStatus() == Status.STATUS_MARKED_ROLLBACK) return;
  112   
  113               ThreadContext callContext = (ThreadContext) contexts[i];
  114   
  115               ThreadContext oldCallContext = ThreadContext.enter(callContext);
  116               StatefulInstanceManager instanceManager = null;
  117   
  118               try {
  119                   StatefulContainer container = (StatefulContainer) callContext.getDeploymentInfo().getContainer();
  120                   instanceManager = container.getInstanceManager();
  121                   /*
  122                   * the operation must be set before the instance is obtained from the pool, so
  123                   * that the instance manager doesn't mistake this as a concurrent access.
  124                   */
  125                   callContext.setCurrentOperation(Operation.BEFORE_COMPLETION);
  126                   callContext.setCurrentAllowedStates(StatefulContext.getStates());
  127   
  128                   StatefulInstanceManager.Instance instance = (StatefulInstanceManager.Instance) instanceManager.obtainInstance(callContext.getPrimaryKey(), callContext);
  129   
  130                   Method beforeCompletion = SessionSynchronization.class.getMethod("beforeCompletion");
  131   
  132                   List<InterceptorData> interceptors = callContext.getDeploymentInfo().getMethodInterceptors(beforeCompletion);
  133                   InterceptorStack interceptorStack = new InterceptorStack(instance.bean, beforeCompletion, Operation.BEFORE_COMPLETION, interceptors, instance.interceptors);
  134                   interceptorStack.invoke();
  135   
  136                   instanceManager.poolInstance(callContext, instance);
  137               } catch (org.apache.openejb.InvalidateReferenceException inv) {
  138   
  139               } catch (Exception e) {
  140   
  141                   String message = "An unexpected system exception occured while invoking the beforeCompletion method on the SessionSynchronization object: " + e.getClass().getName() + " " + e.getMessage();
  142   
  143                   /* [1] Log the exception or error */
  144                   logger.error(message, e);
  145   
  146                   /* [2] If the instance is in a transaction, mark the transaction for rollback. */
  147                   Transaction tx = null;
  148                   try {
  149                       tx = getTransactionManager().getTransaction();
  150                   } catch (Throwable t) {
  151                       logger.error("Could not retreive the current transaction from the transaction manager while handling a callback exception from the beforeCompletion method of bean " + callContext.getPrimaryKey());
  152                   }
  153                   try {
  154                       markTxRollbackOnly(tx);
  155                   } catch (Throwable t) {
  156                       logger.error("Could not mark the current transaction for rollback while handling a callback exception from the beforeCompletion method of bean " + callContext.getPrimaryKey());
  157                   }
  158   
  159                   /* [3] Discard the instance */
  160                   discardInstance(instanceManager, callContext);
  161   
  162                   /* [4] throw the java.rmi.RemoteException to the client */
  163                   throw new RuntimeException(message);
  164               } finally {
  165                   ThreadContext.exit(oldCallContext);
  166               }
  167           }
  168       }
  169   
  170       public void afterCompletion(int status) {
  171   
  172           Object[] contexts = sessionSynchronizations.values().toArray();
  173   
  174           try {
  175               Transaction tx = getTransactionManager().getTransaction();
  176               coordinators.remove(tx);
  177           } catch (Exception e) {
  178               logger.error("", e);
  179           }
  180           for (int i = 0; i < contexts.length; i++) {
  181   
  182               ThreadContext callContext = (ThreadContext) contexts[i];
  183   
  184               ThreadContext oldCallContext = ThreadContext.enter(callContext);
  185               StatefulInstanceManager instanceManager = null;
  186   
  187               try {
  188                   StatefulContainer container = (StatefulContainer) callContext.getDeploymentInfo().getContainer();
  189                   instanceManager = container.getInstanceManager();
  190                   /*
  191                   * the operation must be set before the instance is obtained from the pool, so
  192                   * that the instance manager doesn't mistake this as a concurrent access.
  193                   */
  194                   callContext.setCurrentOperation(Operation.AFTER_COMPLETION);
  195                   callContext.setCurrentAllowedStates(StatefulContext.getStates());
  196   
  197                   StatefulInstanceManager.Instance instance = (StatefulInstanceManager.Instance) instanceManager.obtainInstance(callContext.getPrimaryKey(), callContext);
  198   
  199                   Method afterCompletion = SessionSynchronization.class.getMethod("afterCompletion", boolean.class);
  200   
  201                   List<InterceptorData> interceptors = callContext.getDeploymentInfo().getMethodInterceptors(afterCompletion);
  202                   InterceptorStack interceptorStack = new InterceptorStack(instance.bean, afterCompletion, Operation.AFTER_COMPLETION, interceptors, instance.interceptors);
  203                   interceptorStack.invoke(status == Status.STATUS_COMMITTED);
  204   
  205                   instanceManager.poolInstance(callContext, instance);
  206               } catch (org.apache.openejb.InvalidateReferenceException inv) {
  207   
  208               } catch (Exception e) {
  209   
  210                   String message = "An unexpected system exception occured while invoking the afterCompletion method on the SessionSynchronization object: " + e.getClass().getName() + " " + e.getMessage();
  211   
  212                   /* [1] Log the exception or error */
  213                   logger.error(message, e);
  214   
  215                   /* [2] If the instance is in a transaction, mark the transaction for rollback. */
  216                   Transaction tx = null;
  217                   try {
  218                       tx = getTransactionManager().getTransaction();
  219                   } catch (Throwable t) {
  220                       logger.error("Could not retreive the current transaction from the transaction manager while handling a callback exception from the afterCompletion method of bean " + callContext.getPrimaryKey());
  221                   }
  222                   try {
  223                       // TODO: DMB: This may not be spec compliant
  224                       markTxRollbackOnly(tx);
  225                   } catch (Throwable t) {
  226                       logger.error("Could not mark the current transaction for rollback while handling a callback exception from the afterCompletion method of bean " + callContext.getPrimaryKey());
  227                   }
  228   
  229                   /* [3] Discard the instance */
  230                   discardInstance(instanceManager, callContext);
  231   
  232                   /* [4] throw the java.rmi.RemoteException to the client */
  233   
  234                   throw new RuntimeException(message);
  235               } finally {
  236                   ThreadContext.exit(oldCallContext);
  237               }
  238           }
  239       }
  240   
  241       protected void discardInstance(StatefulInstanceManager instanceManager, ThreadContext callContext) {
  242           try {
  243               instanceManager.freeInstance(callContext);
  244           } catch (org.apache.openejb.OpenEJBException oee) {
  245   
  246           }
  247       }
  248   
  249       protected void markTxRollbackOnly(Transaction tx) throws SystemException {
  250           try {
  251               if (tx != null) tx.setRollbackOnly();
  252           } catch (javax.transaction.SystemException se) {
  253               throw new org.apache.openejb.SystemException(se);
  254           }
  255       }
  256   
  257       protected TransactionManager getTransactionManager() {
  258           return transactionManager;
  259       }
  260   
  261       protected void throwExceptionToServer(Throwable sysException) throws ApplicationException {
  262           throw new ApplicationException(sysException);
  263       }
  264   
  265       protected int getTransactionStatus() {
  266           try {
  267               return transactionManager.getStatus();
  268           } catch (javax.transaction.SystemException e) {
  269               return Status.STATUS_NO_TRANSACTION;
  270           }
  271       }
  272   }

Save This Page
Home » openejb-3.1.2-src » org.apache » openejb » core » stateful » [javadoc | source]