public void beforeCompletion() {
      for (Synchronization synchronization : registry.values()) {

        Instance instance = synchronization.instance;

        // don't call beforeCompletion when transaction is marked rollback only
        if (txPolicy.isRollbackOnly()) return;

        // only call beforeCompletion on beans with session synchronization
        if (!synchronization.isCallSessionSynchronization()) continue;

        // Invoke beforeCompletion
        ThreadContext callContext =
            new ThreadContext(
                instance.beanContext, instance.primaryKey, Operation.BEFORE_COMPLETION);
        callContext.setCurrentAllowedStates(null);
        ThreadContext oldCallContext = ThreadContext.enter(callContext);
        try {
          instance.setInUse(true);

          BeanContext beanContext = instance.beanContext;
          List<InterceptorData> interceptors = beanContext.getCallbackInterceptors();
          InterceptorStack interceptorStack =
              new InterceptorStack(
                  instance.bean,
                  null,
                  Operation.BEFORE_COMPLETION,
                  interceptors,
                  instance.interceptors);
          interceptorStack.invoke();

          instance.setInUse(false);
        } catch (InvalidateReferenceException e) {
          // exception has alredy been handled
        } catch (Exception e) {
          String message =
              "An unexpected system exception occured while invoking the beforeCompletion method on the SessionSynchronization object";

          // [1] Log the exception or error
          logger.error(message, e);

          // [2] Mark the transaction for rollback.
          txPolicy.setRollbackOnly(e);

          // [3] Discard the instance
          discardInstance(callContext);

          // [4] throw the java.rmi.RemoteException to the client
          throw new RuntimeException(message, e);
        } finally {
          ThreadContext.exit(oldCallContext);
        }
      }
    }
  private Instance obtainInstance(Object primaryKey, ThreadContext callContext)
      throws OpenEJBException {
    if (primaryKey == null) {
      throw new SystemException(
          new NullPointerException(
              "Cannot obtain an instance of the stateful session bean with a null session id"));
    }

    Transaction currentTransaction = getTransaction(callContext);

    // Find the instance
    Instance instance = checkedOutInstances.get(primaryKey);
    if (instance == null) {
      try {
        instance = cache.checkOut(primaryKey);
      } catch (OpenEJBException e) {
        throw e;
      } catch (Exception e) {
        throw new SystemException("Unexpected load exception", e);
      }

      // Did we find the instance?
      if (instance == null) {
        throw new InvalidateReferenceException(new NoSuchObjectException("Not Found"));
      }

      // remember instance until it is returned to the cache
      checkedOutInstances.put(primaryKey, instance);
    }

    synchronized (instance) {
      // Is the instance alreayd in use?
      if (instance.isInUse()) {
        // the bean is already being invoked; the only reentrant/concurrent operations allowed are
        // Session synchronization callbacks
        Operation currentOperation = callContext.getCurrentOperation();
        if (currentOperation != Operation.AFTER_COMPLETION
            && currentOperation != Operation.BEFORE_COMPLETION) {
          throw new ApplicationException(new RemoteException("Concurrent calls not allowed."));
        }
      }

      if (instance.getTransaction() != null) {
        if (!instance.getTransaction().equals(currentTransaction)
            && !instance.getLock().tryLock()) {
          throw new ApplicationException(
              new RemoteException(
                  "Instance is in a transaction and cannot be invoked outside that transaction.  See EJB 3.0 Section 4.4.4"));
        }
      } else {
        instance.setTransaction(currentTransaction);
      }

      // Mark the instance in use so we can detect reentrant calls
      instance.setInUse(true);

      return instance;
    }
  }
    public void afterCompletion(Status status) {
      Throwable firstException = null;
      for (Synchronization synchronization : registry.values()) {

        Instance instance = synchronization.instance;

        ThreadContext callContext =
            new ThreadContext(
                instance.beanContext, instance.primaryKey, Operation.AFTER_COMPLETION);
        callContext.setCurrentAllowedStates(null);
        ThreadContext oldCallContext = ThreadContext.enter(callContext);
        try {
          instance.setInUse(true);
          if (synchronization.isCallSessionSynchronization()) {

            BeanContext beanContext = instance.beanContext;
            List<InterceptorData> interceptors = beanContext.getCallbackInterceptors();
            InterceptorStack interceptorStack =
                new InterceptorStack(
                    instance.bean,
                    null,
                    Operation.AFTER_COMPLETION,
                    interceptors,
                    instance.interceptors);
            interceptorStack.invoke(status == Status.COMMITTED);
          }
          instance.setTransaction(null);
          releaseInstance(instance);
        } catch (InvalidateReferenceException inv) {
          // exception has alredy been handled
        } catch (Throwable e) {
          String message =
              "An unexpected system exception occured while invoking the afterCompletion method on the SessionSynchronization object";

          // [1] Log the exception or error
          logger.error(message, e);

          // Transaction is complete so can not be rolled back

          // [3] Discard the instance
          discardInstance(callContext);

          // [4] throw throw first exception to the client
          if (firstException == null) firstException = e;
        } finally {
          ThreadContext.exit(oldCallContext);
        }
      }

      if (firstException != null) {
        throw new RuntimeException(
            "An unexpected system exception occured while invoking the afterCompletion method on the SessionSynchronization object",
            firstException);
      }
    }
  private void releaseInstance(Instance instance) {
    // Don't pool if the bean has been undeployed
    if (instance.beanContext.isDestroyed()) return;

    // verify the instance is not associated with a bean-managed transaction
    if (instance.getBeanTransaction() != null) {
      new IllegalStateException("Instance has an active bean-managed transaction");
    }

    // no longer in use
    instance.setInUse(false);

    if (instance.getTransaction() == null) {
      // return to cache
      cache.checkIn(instance.primaryKey);

      // no longer checked out
      checkedOutInstances.remove(instance.primaryKey);
    }
  }
 private void afterInvoke(ThreadContext callContext, TransactionPolicy txPolicy, Instance instance)
     throws OpenEJBException {
   try {
     unregisterEntityManagers(instance, callContext);
     if (instance != null && txPolicy instanceof BeanTransactionPolicy) {
       // suspend the currently running transaction if any
       SuspendedTransaction suspendedTransaction = null;
       try {
         BeanTransactionPolicy beanTxEnv = (BeanTransactionPolicy) txPolicy;
         suspendedTransaction = beanTxEnv.suspendUserTransaction();
       } catch (SystemException e) {
         handleSystemException(txPolicy, e, callContext);
       } finally {
         instance.setBeanTransaction(suspendedTransaction);
       }
     }
   } finally {
     if (instance != null) {
       instance.setInUse(false);
     }
     EjbTransactionUtil.afterInvoke(txPolicy, callContext);
   }
 }