public void timedOut(Instance instance) {
      BeanContext beanContext = instance.beanContext;

      ThreadContext threadContext =
          new ThreadContext(beanContext, instance.primaryKey, Operation.PRE_DESTROY);
      threadContext.setCurrentAllowedStates(null);
      ThreadContext oldContext = ThreadContext.enter(threadContext);
      try {
        Method remove =
            instance.bean instanceof SessionBean ? SessionBean.class.getMethod("ejbRemove") : null;

        List<InterceptorData> callbackInterceptors = beanContext.getCallbackInterceptors();
        InterceptorStack interceptorStack =
            new InterceptorStack(
                instance.bean,
                remove,
                Operation.PRE_DESTROY,
                callbackInterceptors,
                instance.interceptors);

        interceptorStack.invoke();
      } catch (Throwable e) {
        logger.error(
            "An unexpected exception occured while invoking the ejbRemove method on the timed-out Stateful SessionBean instance",
            e);
      } finally {
        logger.info("Removing the timed-out stateful session bean instance " + instance.primaryKey);
        ThreadContext.exit(oldContext);
      }
    }
    public void beforeStore(Instance instance) {
      BeanContext beanContext = instance.beanContext;

      ThreadContext threadContext =
          new ThreadContext(beanContext, instance.primaryKey, Operation.PASSIVATE);
      ThreadContext oldContext = ThreadContext.enter(threadContext);
      try {
        Method passivate =
            instance.bean instanceof SessionBean
                ? SessionBean.class.getMethod("ejbPassivate")
                : null;

        List<InterceptorData> callbackInterceptors = beanContext.getCallbackInterceptors();
        InterceptorStack interceptorStack =
            new InterceptorStack(
                instance.bean,
                passivate,
                Operation.PASSIVATE,
                callbackInterceptors,
                instance.interceptors);

        interceptorStack.invoke();

      } catch (Throwable e) {
        logger.error(
            "An unexpected exception occured while invoking the ejbPassivate method on the Stateful SessionBean instance",
            e);
      } finally {
        ThreadContext.exit(oldContext);
      }
    }
    public void afterLoad(Instance instance) throws SystemException, ApplicationException {
      BeanContext beanContext = instance.beanContext;

      ThreadContext threadContext =
          new ThreadContext(instance.beanContext, instance.primaryKey, Operation.ACTIVATE);
      ThreadContext oldContext = ThreadContext.enter(threadContext);
      try {
        Method remove =
            instance.bean instanceof SessionBean
                ? SessionBean.class.getMethod("ejbActivate")
                : null;

        List<InterceptorData> callbackInterceptors = beanContext.getCallbackInterceptors();
        InterceptorStack interceptorStack =
            new InterceptorStack(
                instance.bean,
                remove,
                Operation.ACTIVATE,
                callbackInterceptors,
                instance.interceptors);

        interceptorStack.invoke();
      } catch (Throwable callbackException) {
        discardInstance(threadContext);
        handleSystemException(
            threadContext.getTransactionPolicy(), callbackException, threadContext);
      } finally {
        ThreadContext.exit(oldContext);
      }
    }
    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);
      }
    }
    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 void registerSessionSynchronization(
        Instance instance, BeanContext beanContext, Object primaryKey, boolean synchronize) {

      Synchronization synchronization = registry.get(primaryKey);

      if (synchronization == null) {
        synchronization = new Synchronization(instance);
        registry.put(primaryKey, synchronization);
      }

      boolean wasSynchronized = synchronization.setCallSessionSynchronization(synchronize);

      // check if afterBegin has already been invoked or if this is not a session synchronization
      // bean
      if (wasSynchronized || !synchronize) {
        return;
      }

      // Invoke afterBegin
      ThreadContext callContext =
          new ThreadContext(instance.beanContext, instance.primaryKey, Operation.AFTER_BEGIN);
      callContext.setCurrentAllowedStates(null);
      ThreadContext oldCallContext = ThreadContext.enter(callContext);
      try {

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

      } catch (Exception e) {
        String message =
            "An unexpected system exception occured while invoking the afterBegin method on the SessionSynchronization object";

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

        // Caller handles transaction rollback and discardInstance

        // [4] throw the java.rmi.RemoteException to the client
        throw new RuntimeException(message, e);
      } finally {
        ThreadContext.exit(oldCallContext);
      }
    }
  protected Object removeEJBObject(
      BeanContext beanContext,
      Object primKey,
      Class callInterface,
      Method callMethod,
      Object[] args,
      InterfaceType interfaceType)
      throws OpenEJBException {
    if (primKey == null) throw new NullPointerException("primKey is null");

    ThreadContext callContext = new ThreadContext(beanContext, primKey);
    ThreadContext oldCallContext = ThreadContext.enter(callContext);
    try {
      // Security check
      checkAuthorization(callMethod, interfaceType);

      // If a bean managed transaction is active, the bean can not be removed
      if (interfaceType.isComponent()) {
        Instance instance = checkedOutInstances.get(primKey);

        /**
         * According to EJB 3.0 "4.4.4 Restrictions for Transactions" any remove methods from home
         * or component interfaces must not be allowed if the bean instance is in a transaction.
         * Unfortunately, the Java EE 5 TCK has tests that ignore the restrictions in 4.4.4 and
         * expect beans in transactions can be removed via their home or component interface. The
         * test to see if the bean instance implements javax.ejb.SessionBean is a workaround for
         * passing the TCK while the tests in question can be challenged or the spec can be
         * changed/updated.
         */
        if (instance != null && instance.bean instanceof javax.ejb.SessionBean) {
          throw new ApplicationException(
              new RemoveException("A stateful EJB enrolled in a transaction can not be removed"));
        }
      }

      // Start transaction
      TransactionPolicy txPolicy =
          createTransactionPolicy(
              callContext.getBeanContext().getTransactionType(callMethod, interfaceType),
              callContext);

      Object returnValue = null;
      boolean retain = false;
      Instance instance = null;
      Method runMethod = null;
      try {
        // Obtain instance
        instance = obtainInstance(primKey, callContext);

        // Resume previous Bean transaction if there was one
        if (txPolicy instanceof BeanTransactionPolicy) {
          // Resume previous Bean transaction if there was one
          SuspendedTransaction suspendedTransaction = instance.getBeanTransaction();
          if (suspendedTransaction != null) {
            instance.setBeanTransaction(null);
            BeanTransactionPolicy beanTxEnv = (BeanTransactionPolicy) txPolicy;
            beanTxEnv.resumeUserTransaction(suspendedTransaction);
          }
        }

        // Register the entity managers
        registerEntityManagers(instance, callContext);

        // Register for synchronization callbacks
        registerSessionSynchronization(instance, callContext);

        // Setup for remove invocation
        callContext.setCurrentOperation(Operation.REMOVE);
        callContext.setCurrentAllowedStates(null);
        callContext.setInvokedInterface(callInterface);
        runMethod = beanContext.getMatchingBeanMethod(callMethod);
        callContext.set(Method.class, runMethod);

        // Do not pass arguments on home.remove(remote) calls
        Class<?> declaringClass = callMethod.getDeclaringClass();
        if (declaringClass.equals(EJBHome.class) || declaringClass.equals(EJBLocalHome.class)) {
          args = new Object[] {};
        }

        // Initialize interceptor stack
        List<InterceptorData> interceptors = beanContext.getMethodInterceptors(runMethod);
        InterceptorStack interceptorStack =
            new InterceptorStack(
                instance.bean, runMethod, Operation.REMOVE, interceptors, instance.interceptors);

        // Invoke
        if (args == null) {
          returnValue = interceptorStack.invoke();
        } else {
          returnValue = interceptorStack.invoke(args);
        }
      } catch (InvalidateReferenceException e) {
        throw e;
      } catch (Throwable e) {
        if (interfaceType.isBusiness()) {
          retain = beanContext.retainIfExeption(runMethod);
          handleException(callContext, txPolicy, e);
        } else {
          try {
            handleException(callContext, txPolicy, e);
          } catch (ApplicationException ae) {
            // Don't throw application exceptions for non-business interface removes
          }
        }
      } finally {
        if (!retain) {
          try {
            callContext.setCurrentOperation(Operation.PRE_DESTROY);
            List<InterceptorData> callbackInterceptors = beanContext.getCallbackInterceptors();
            InterceptorStack interceptorStack =
                new InterceptorStack(
                    instance.bean,
                    null,
                    Operation.PRE_DESTROY,
                    callbackInterceptors,
                    instance.interceptors);
            interceptorStack.invoke();
          } catch (Throwable callbackException) {
            String logMessage =
                "An unexpected exception occured while invoking the preDestroy method on the removed Stateful SessionBean instance; "
                    + callbackException.getClass().getName()
                    + " "
                    + callbackException.getMessage();

            /* [1] Log the exception or error */
            logger.error(logMessage);

          } finally {
            callContext.setCurrentOperation(Operation.REMOVE);
          }

          // todo destroy extended persistence contexts
          discardInstance(callContext);
        }

        // Commit transaction
        afterInvoke(callContext, txPolicy, instance);
      }

      return returnValue;
    } finally {
      ThreadContext.exit(oldCallContext);
    }
  }
  public void freeInstance(ThreadContext callContext) {
    BeanContext beanContext = callContext.getBeanContext();
    Data data = (Data) beanContext.getContainerData();
    Future<Instance> instanceFuture = data.singleton.get();

    // Possible the instance was never created
    if (instanceFuture == null) return;

    Instance instance;
    try {
      instance = instanceFuture.get();
    } catch (InterruptedException e) {
      Thread.interrupted();
      logger.error(
          "Singleton shutdown failed because the thread was interrupted: "
              + beanContext.getDeploymentID(),
          e);
      return;
    } catch (ExecutionException e) {
      // Instance was never initialized
      return;
    }

    try {
      callContext.setCurrentOperation(Operation.PRE_DESTROY);
      callContext.setCurrentAllowedStates(null);

      Method remove = instance.bean instanceof SessionBean ? beanContext.getCreateMethod() : null;

      List<InterceptorData> callbackInterceptors = beanContext.getCallbackInterceptors();
      InterceptorStack interceptorStack =
          new InterceptorStack(
              instance.bean,
              remove,
              Operation.PRE_DESTROY,
              callbackInterceptors,
              instance.interceptors);

      // Transaction Demarcation for Singleton PostConstruct method
      TransactionType transactionType;

      if (beanContext.getComponentType() == BeanType.SINGLETON) {
        Set<Method> callbacks =
            callbackInterceptors.get(callbackInterceptors.size() - 1).getPreDestroy();
        if (callbacks.isEmpty()) {
          transactionType = TransactionType.RequiresNew;
        } else {
          transactionType = beanContext.getTransactionType(callbacks.iterator().next());
          if (transactionType == TransactionType.Required) {
            transactionType = TransactionType.RequiresNew;
          }
        }
      } else {
        transactionType =
            beanContext.isBeanManagedTransaction()
                ? TransactionType.BeanManaged
                : TransactionType.NotSupported;
      }
      TransactionPolicy transactionPolicy =
          EjbTransactionUtil.createTransactionPolicy(transactionType, callContext);
      try {
        // Call the chain
        interceptorStack.invoke();
        if (instance.creationalContext != null) {
          instance.creationalContext.release();
        }
      } catch (Throwable e) {
        // RollBack Transaction
        EjbTransactionUtil.handleSystemException(transactionPolicy, e, callContext);
      } finally {
        EjbTransactionUtil.afterInvoke(transactionPolicy, callContext);
      }

    } catch (Throwable re) {
      logger.error("Singleton shutdown failed: " + beanContext.getDeploymentID(), re);
    }
  }