Search in sources :

Example 1 with SessionBean

use of jakarta.ejb.SessionBean in project tomee by apache.

the class SingletonInstanceManager method freeInstance.

public void freeInstance(final ThreadContext callContext) {
    final BeanContext beanContext = callContext.getBeanContext();
    final Data data = (Data) beanContext.getContainerData();
    final Future<Instance> instanceFuture = data.singleton.get();
    // Possible the instance was never created
    if (instanceFuture == null) {
        return;
    }
    final Instance instance;
    try {
        instance = instanceFuture.get();
    } catch (final InterruptedException e) {
        Thread.interrupted();
        logger.error("Singleton shutdown failed because the thread was interrupted: " + beanContext.getDeploymentID(), e);
        return;
    } catch (final ExecutionException e) {
        // Instance was never initialized
        return;
    }
    try {
        callContext.setCurrentOperation(Operation.PRE_DESTROY);
        callContext.setCurrentAllowedStates(null);
        final Method remove = instance.bean instanceof SessionBean ? beanContext.getCreateMethod() : null;
        final List<InterceptorData> callbackInterceptors = beanContext.getCallbackInterceptors();
        final 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) {
            final 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;
        }
        final TransactionPolicy transactionPolicy = EjbTransactionUtil.createTransactionPolicy(transactionType, callContext);
        try {
            // Call the chain
            final CdiEjbBean<Object> bean = beanContext.get(CdiEjbBean.class);
            if (bean != null) {
                // TODO: see if it should be called before or after next call
                bean.getInjectionTarget().preDestroy(instance.bean);
            }
            interceptorStack.invoke();
            if (instance.creationalContext != null) {
                instance.creationalContext.release();
            }
        } catch (final Throwable e) {
            // RollBack Transaction
            EjbTransactionUtil.handleSystemException(transactionPolicy, e, callContext);
        } finally {
            EjbTransactionUtil.afterInvoke(transactionPolicy, callContext);
        }
    } catch (final Throwable re) {
        logger.error("Singleton shutdown failed: " + beanContext.getDeploymentID(), re);
    }
}
Also used : TransactionType(org.apache.openejb.core.transaction.TransactionType) SystemInstance(org.apache.openejb.loader.SystemInstance) TransactionPolicy(org.apache.openejb.core.transaction.TransactionPolicy) InterceptorData(org.apache.openejb.core.interceptor.InterceptorData) Method(java.lang.reflect.Method) SessionBean(jakarta.ejb.SessionBean) BeanContext(org.apache.openejb.BeanContext) InterceptorData(org.apache.openejb.core.interceptor.InterceptorData) InterceptorStack(org.apache.openejb.core.interceptor.InterceptorStack) ExecutionException(java.util.concurrent.ExecutionException)

Example 2 with SessionBean

use of jakarta.ejb.SessionBean in project tomee by apache.

the class StatelessInstanceManager method freeInstance.

@SuppressWarnings("unchecked")
private void freeInstance(final ThreadContext callContext, final Instance instance) {
    try {
        callContext.setCurrentOperation(Operation.PRE_DESTROY);
        final BeanContext beanContext = callContext.getBeanContext();
        final Method remove = instance.bean instanceof SessionBean ? removeSessionBeanMethod : null;
        final List<InterceptorData> callbackInterceptors = beanContext.getCallbackInterceptors();
        final InterceptorStack interceptorStack = new InterceptorStack(instance.bean, remove, Operation.PRE_DESTROY, callbackInterceptors, instance.interceptors);
        final CdiEjbBean<Object> bean = beanContext.get(CdiEjbBean.class);
        if (bean != null) {
            // TODO: see if it should be called before or after next call
            bean.getInjectionTarget().preDestroy(instance.bean);
        }
        interceptorStack.invoke();
        if (instance.creationalContext != null) {
            instance.creationalContext.release();
        }
    } catch (final Throwable re) {
        logger.error("The bean instance " + instance + " threw a system exception:" + re, re);
    }
}
Also used : BeanContext(org.apache.openejb.BeanContext) InterceptorData(org.apache.openejb.core.interceptor.InterceptorData) InterceptorStack(org.apache.openejb.core.interceptor.InterceptorStack) Method(java.lang.reflect.Method) SessionBean(jakarta.ejb.SessionBean)

Example 3 with SessionBean

use of jakarta.ejb.SessionBean in project tomee by apache.

the class MdbInstanceManager method freeInstance.

@SuppressWarnings("unchecked")
private void freeInstance(final ThreadContext callContext, final Instance instance) {
    try {
        callContext.setCurrentOperation(Operation.PRE_DESTROY);
        final BeanContext beanContext = callContext.getBeanContext();
        final Method remove = instance.bean instanceof SessionBean ? removeSessionBeanMethod : null;
        final List<InterceptorData> callbackInterceptors = beanContext.getCallbackInterceptors();
        final InterceptorStack interceptorStack = new InterceptorStack(instance.bean, remove, Operation.PRE_DESTROY, callbackInterceptors, instance.interceptors);
        final CdiEjbBean<Object> bean = beanContext.get(CdiEjbBean.class);
        if (bean != null) {
            // TODO: see if it should be called before or after next call
            bean.getInjectionTarget().preDestroy(instance.bean);
        }
        interceptorStack.invoke();
        if (instance.creationalContext != null) {
            instance.creationalContext.release();
        }
    } catch (final Throwable re) {
        logger.error("The bean instance " + instance + " threw a system exception:" + re, re);
    }
}
Also used : BeanContext(org.apache.openejb.BeanContext) InterceptorData(org.apache.openejb.core.interceptor.InterceptorData) InterceptorStack(org.apache.openejb.core.interceptor.InterceptorStack) Method(java.lang.reflect.Method) SessionBean(jakarta.ejb.SessionBean)

Example 4 with SessionBean

use of jakarta.ejb.SessionBean in project tomee by apache.

the class ManagedContainer method removeEJBObject.

protected Object removeEJBObject(final BeanContext beanContext, final Object primKey, final Class callInterface, final Method callMethod, Object[] args, final InterfaceType interfaceType) throws OpenEJBException {
    if (primKey == null) {
        throw new NullPointerException("primKey is null");
    }
    final ThreadContext callContext = new ThreadContext(beanContext, primKey);
    final ThreadContext oldCallContext = ThreadContext.enter(callContext);
    try {
        // Security check
        final boolean internalRemove = BeanContext.Removable.class == callMethod.getDeclaringClass();
        if (!internalRemove) {
            checkAuthorization(callMethod, interfaceType);
        }
        // If a bean managed transaction is active, the bean can not be removed
        if (interfaceType.isComponent()) {
            final 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
             * jakarta.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 SessionBean) {
                throw new ApplicationException(new RemoveException("A stateful EJB enrolled in a transaction can not be removed"));
            }
        }
        // Start transaction
        final TransactionPolicy txPolicy = EjbTransactionUtil.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
                final SuspendedTransaction suspendedTransaction = instance.getBeanTransaction();
                if (suspendedTransaction != null) {
                    instance.setBeanTransaction(null);
                    final BeanTransactionPolicy beanTxEnv = (BeanTransactionPolicy) txPolicy;
                    beanTxEnv.resumeUserTransaction(suspendedTransaction);
                }
            }
            if (!internalRemove) {
                // 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
                final Class<?> declaringClass = callMethod.getDeclaringClass();
                if (declaringClass.equals(EJBHome.class) || declaringClass.equals(EJBLocalHome.class)) {
                    args = new Object[] {};
                }
                // Initialize interceptor stack
                final List<InterceptorData> interceptors = beanContext.getMethodInterceptors(runMethod);
                final 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 (final InvalidateReferenceException e) {
            throw new ApplicationException(e.getRootCause());
        } catch (final Throwable e) {
            if (interfaceType.isBusiness()) {
                retain = beanContext.retainIfExeption(runMethod);
                handleException(callContext, txPolicy, e);
            } else {
                try {
                    handleException(callContext, txPolicy, e);
                } catch (final ApplicationException ae) {
                // Don't throw application exceptions for non-business interface removes
                }
            }
        } finally {
            if (!retain) {
                try {
                    callContext.setCurrentOperation(Operation.PRE_DESTROY);
                    final List<InterceptorData> callbackInterceptors = beanContext.getCallbackInterceptors();
                    final InterceptorStack interceptorStack = new InterceptorStack(instance.bean, null, Operation.PRE_DESTROY, callbackInterceptors, instance.interceptors);
                    interceptorStack.invoke();
                } catch (final Throwable callbackException) {
                    final 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);
    }
}
Also used : BeanTransactionPolicy(org.apache.openejb.core.transaction.BeanTransactionPolicy) SystemInstance(org.apache.openejb.loader.SystemInstance) EJBHome(jakarta.ejb.EJBHome) ThreadContext(org.apache.openejb.core.ThreadContext) JtaTransactionPolicy(org.apache.openejb.core.transaction.JtaTransactionPolicy) TransactionPolicy(org.apache.openejb.core.transaction.TransactionPolicy) BeanTransactionPolicy(org.apache.openejb.core.transaction.BeanTransactionPolicy) Method(java.lang.reflect.Method) SuspendedTransaction(org.apache.openejb.core.transaction.BeanTransactionPolicy.SuspendedTransaction) SessionBean(jakarta.ejb.SessionBean) EJBLocalHome(jakarta.ejb.EJBLocalHome) BeanContext(org.apache.openejb.BeanContext) InvalidateReferenceException(org.apache.openejb.InvalidateReferenceException) ApplicationException(org.apache.openejb.ApplicationException) RemoveException(jakarta.ejb.RemoveException) InterceptorData(org.apache.openejb.core.interceptor.InterceptorData) InterceptorStack(org.apache.openejb.core.interceptor.InterceptorStack)

Example 5 with SessionBean

use of jakarta.ejb.SessionBean in project tomee by apache.

the class StatefulContainer method removeEJBObject.

protected Object removeEJBObject(final BeanContext beanContext, final Object primKey, final Class callInterface, final Method callMethod, Object[] args, final InterfaceType interfaceType) throws OpenEJBException {
    if (primKey == null) {
        throw new NullPointerException("primKey is null");
    }
    final CdiEjbBean cdiEjbBean = beanContext.get(CdiEjbBean.class);
    if (cdiEjbBean != null) {
        final Class scope = cdiEjbBean.getScope();
        if (callMethod.getDeclaringClass() != BeanContext.Removable.class && scope != Dependent.class) {
            throw new UnsupportedOperationException("Can not call EJB Stateful Bean Remove Method without scoped @Dependent.  Found scope: @" + scope.getSimpleName());
        }
    }
    final boolean internalRemove = BeanContext.Removable.class == callMethod.getDeclaringClass();
    final ThreadContext callContext = new ThreadContext(beanContext, primKey);
    final ThreadContext oldCallContext = ThreadContext.enter(callContext);
    Object runAs = null;
    try {
        if (oldCallContext != null) {
            final BeanContext oldBc = oldCallContext.getBeanContext();
            if (oldBc.getRunAsUser() != null || oldBc.getRunAs() != null) {
                runAs = AbstractSecurityService.class.cast(securityService).overrideWithRunAsContext(callContext, beanContext, oldBc);
            }
        }
        // Security check
        if (!internalRemove) {
            checkAuthorization(callMethod, interfaceType);
        }
        // If a bean managed transaction is active, the bean can not be removed
        if (interfaceType.isComponent()) {
            final 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
             * jakarta.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 SessionBean) {
                throw new ApplicationException(new RemoveException("A stateful EJB enrolled in a transaction can not be removed"));
            }
        }
        // Start transaction
        final TransactionPolicy txPolicy = EjbTransactionUtil.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, callMethod, beanContext.isPassivatingScope());
            // Resume previous Bean transaction if there was one
            if (txPolicy instanceof BeanTransactionPolicy) {
                // Resume previous Bean transaction if there was one
                final SuspendedTransaction suspendedTransaction = instance.getBeanTransaction();
                if (suspendedTransaction != null) {
                    instance.setBeanTransaction(null);
                    final BeanTransactionPolicy beanTxEnv = (BeanTransactionPolicy) txPolicy;
                    beanTxEnv.resumeUserTransaction(suspendedTransaction);
                }
            }
            if (!internalRemove) {
                // 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
                final Class<?> declaringClass = callMethod.getDeclaringClass();
                if (declaringClass.equals(EJBHome.class) || declaringClass.equals(EJBLocalHome.class)) {
                    args = new Object[] {};
                }
                // Initialize interceptor stack
                final List<InterceptorData> interceptors = beanContext.getMethodInterceptors(runMethod);
                final InterceptorStack interceptorStack = new InterceptorStack(instance.bean, runMethod, Operation.REMOVE, interceptors, instance.interceptors);
                // Invoke
                final CdiEjbBean<Object> bean = beanContext.get(CdiEjbBean.class);
                if (bean != null) {
                    // TODO: see if it should be called before or after next call
                    bean.getInjectionTarget().preDestroy(instance.bean);
                }
                if (args == null) {
                    returnValue = interceptorStack.invoke();
                } else {
                    returnValue = interceptorStack.invoke(args);
                }
            }
        } catch (final InvalidateReferenceException e) {
            throw new ApplicationException(e.getRootCause());
        } catch (final Throwable e) {
            if (interfaceType.isBusiness()) {
                retain = beanContext.retainIfExeption(runMethod);
                handleException(callContext, txPolicy, e);
            } else {
                try {
                    handleException(callContext, txPolicy, e);
                } catch (final ApplicationException ae) {
                // Don't throw application exceptions for non-business interface removes
                }
            }
        } finally {
            if (runAs != null) {
                try {
                    securityService.associate(runAs);
                } catch (final LoginException e) {
                // no-op
                }
            }
            if (!retain) {
                try {
                    callContext.setCurrentOperation(Operation.PRE_DESTROY);
                    final List<InterceptorData> callbackInterceptors = beanContext.getCallbackInterceptors();
                    if (instance != null) {
                        final InterceptorStack interceptorStack = new InterceptorStack(instance.bean, null, Operation.PRE_DESTROY, callbackInterceptors, instance.interceptors);
                        interceptorStack.invoke();
                    }
                } catch (final Throwable t) {
                    final String logMessage = "An unexpected exception occured while invoking the preDestroy method on the Stateful SessionBean instance: " + (null != instance ? instance.bean.getClass().getName() : beanContext.getBeanClass().getName());
                    logger.error(logMessage, t);
                } finally {
                    callContext.setCurrentOperation(Operation.REMOVE);
                }
                discardInstance(primKey, instance);
            }
            // un register EntityManager
            final Map<EntityManagerFactory, JtaEntityManagerRegistry.EntityManagerTracker> unregisteredEntityManagers = unregisterEntityManagers(instance, callContext);
            // Commit transaction
            afterInvoke(callContext, txPolicy, instance);
            // Un register and close extended persistence contexts
            /*
                7.6.2 Container-managed Extended Persistence Context
                A container-managed extended persistence context can only be initiated within the scope of a stateful
                session bean. It exists from the point at which the stateful session bean that declares a dependency on an
                entity manager of type PersistenceContextType.EXTENDED is created, and is said to be bound
                to the stateful session bean. The dependency on the extended persistence context is declared by means
                of the PersistenceContext annotation or persistence-context-ref deployment descriptor element.
                The persistence context is closed by the container when the @Remove method of the stateful session
                bean completes (or the stateful session bean instance is otherwise destroyed).
                */
            closeEntityManagers(unregisteredEntityManagers);
        }
        return returnValue;
    } finally {
        ThreadContext.exit(oldCallContext);
    }
}
Also used : BeanTransactionPolicy(org.apache.openejb.core.transaction.BeanTransactionPolicy) SystemInstance(org.apache.openejb.loader.SystemInstance) CdiEjbBean(org.apache.openejb.cdi.CdiEjbBean) Dependent(jakarta.enterprise.context.Dependent) SessionBean(jakarta.ejb.SessionBean) EJBHome(jakarta.ejb.EJBHome) ThreadContext(org.apache.openejb.core.ThreadContext) JtaTransactionPolicy(org.apache.openejb.core.transaction.JtaTransactionPolicy) TransactionPolicy(org.apache.openejb.core.transaction.TransactionPolicy) BeanTransactionPolicy(org.apache.openejb.core.transaction.BeanTransactionPolicy) Method(java.lang.reflect.Method) SuspendedTransaction(org.apache.openejb.core.transaction.BeanTransactionPolicy.SuspendedTransaction) EJBLocalHome(jakarta.ejb.EJBLocalHome) BeanContext(org.apache.openejb.BeanContext) InvalidateReferenceException(org.apache.openejb.InvalidateReferenceException) ApplicationException(org.apache.openejb.ApplicationException) RemoveException(jakarta.ejb.RemoveException) InterceptorData(org.apache.openejb.core.interceptor.InterceptorData) InterceptorStack(org.apache.openejb.core.interceptor.InterceptorStack) EntityManagerFactory(jakarta.persistence.EntityManagerFactory) LoginException(javax.security.auth.login.LoginException)

Aggregations

SessionBean (jakarta.ejb.SessionBean)6 Method (java.lang.reflect.Method)6 InterceptorStack (org.apache.openejb.core.interceptor.InterceptorStack)6 BeanContext (org.apache.openejb.BeanContext)5 InterceptorData (org.apache.openejb.core.interceptor.InterceptorData)5 SystemInstance (org.apache.openejb.loader.SystemInstance)4 ApplicationException (org.apache.openejb.ApplicationException)3 TransactionPolicy (org.apache.openejb.core.transaction.TransactionPolicy)3 EJBHome (jakarta.ejb.EJBHome)2 EJBLocalHome (jakarta.ejb.EJBLocalHome)2 RemoveException (jakarta.ejb.RemoveException)2 InvalidateReferenceException (org.apache.openejb.InvalidateReferenceException)2 ThreadContext (org.apache.openejb.core.ThreadContext)2 BeanTransactionPolicy (org.apache.openejb.core.transaction.BeanTransactionPolicy)2 SuspendedTransaction (org.apache.openejb.core.transaction.BeanTransactionPolicy.SuspendedTransaction)2 JtaTransactionPolicy (org.apache.openejb.core.transaction.JtaTransactionPolicy)2 NoSuchEJBException (jakarta.ejb.NoSuchEJBException)1 Dependent (jakarta.enterprise.context.Dependent)1 EntityManagerFactory (jakarta.persistence.EntityManagerFactory)1 InvocationTargetException (java.lang.reflect.InvocationTargetException)1