use of org.apache.openejb.InvalidateReferenceException in project tomee by apache.
the class ManagedContainer method obtainInstance.
private Instance obtainInstance(final Object primaryKey, final 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"));
}
final Transaction currentTransaction = getTransaction(callContext);
// Find the instance
Instance instance = checkedOutInstances.get(primaryKey);
if (instance == null) {
try {
instance = cache.checkOut(primaryKey);
} catch (final OpenEJBException e) {
throw e;
} catch (final 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 (this) {
if (instance.isInUse()) {
// the bean is already being invoked; the only reentrant/concurrent operations allowed are Session synchronization callbacks
final 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;
}
}
use of org.apache.openejb.InvalidateReferenceException in project tomee by apache.
the class EntityInstanceManager method obtainInstance.
public EntityBean obtainInstance(final ThreadContext callContext) throws OpenEJBException {
// primary key is null if its a servicing a home methods (create, find, ejbHome)
final Object primaryKey = callContext.getPrimaryKey();
final TransactionPolicy txPolicy = callContext.getTransactionPolicy();
if (callContext.getPrimaryKey() != null && txPolicy != null && txPolicy.isTransactionActive()) {
final Key key = new Key(callContext.getBeanContext().getDeploymentID(), primaryKey);
SynchronizationWrapper wrapper = (SynchronizationWrapper) txPolicy.getResource(key);
if (wrapper != null) {
if (!wrapper.isAssociated()) {
/*
* If the bean identity was removed (via ejbRemove()) within the same transaction,
* then it's SynchronizationWrapper will be in the txReady pool but marked as disassociated.
* This allows us to prevent a condition where the caller removes the bean and then attempts to
* call a business method on that bean within the same transaction. After a bean is removed any
* subsequent invocations on that bean with the same transaction should throw a NoSuchEntityException.
* its likely that the application server would have already made the reference invalid, but this bit of
* code is an extra precaution.
*/
throw new InvalidateReferenceException(new NoSuchObjectException("Entity not found: " + primaryKey));
} else if (callContext.getCurrentOperation() == Operation.REMOVE) {
/*
* To avoid calling ejbStore( ) on a bean that after its removed, we can not delegate
* the wrapper is marked as disassociated from the transaction to avoid processing the
* beforeCompletion( ) method on the SynchronizationWrapper object.
*/
wrapper.disassociate();
}
if (wrapper.isAvailable() || wrapper.primaryKey.equals(primaryKey)) {
return wrapper.getEntityBean();
} else {
// its simpler to implement.
return wrapper.getEntityBean();
}
} else {
/*
* If no synchronized wrapper for the key exists
* Then the bean entity is being access by this transaction for the first time,
* so it needs to be enrolled in the transaction.
*/
final EntityBean bean = getPooledInstance(callContext);
wrapper = new SynchronizationWrapper(callContext.getBeanContext(), primaryKey, bean, false, key, txPolicy);
if (callContext.getCurrentOperation() == Operation.REMOVE) {
/*
* To avoid calling ejbStore( ) on a bean that after its removed, we can not delegate
* the wrapper is marked as disassociated from the transaction to avoid processing the
* beforeCompletion( ) method on the SynchronizationWrapper object.
*
* We have to still use a wrapper so we can detect when a business method is called after
* a ejbRemove() and act to prevent it from being processed.
*/
wrapper.disassociate();
}
txPolicy.registerSynchronization(wrapper);
loadingBean(bean, callContext);
final Operation orginalOperation = callContext.getCurrentOperation();
callContext.setCurrentOperation(Operation.LOAD);
try {
bean.ejbLoad();
} catch (final NoSuchEntityException e) {
wrapper.disassociate();
throw new InvalidateReferenceException(new NoSuchObjectException("Entity not found: " + primaryKey, e));
} catch (final Exception e) {
logger.error("Exception encountered during ejbLoad():", e);
// djencks not sure about this dissociate call
wrapper.disassociate();
throw new OpenEJBException(e);
} finally {
callContext.setCurrentOperation(orginalOperation);
}
txPolicy.putResource(key, wrapper);
return bean;
}
} else {
// returned to the pool -- depending on if the tx is a client initiated or container initiated.
return getPooledInstance(callContext);
}
}
use of org.apache.openejb.InvalidateReferenceException 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
* 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 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);
}
}
Aggregations