use of org.apache.openejb.core.Operation in project tomee by apache.
the class EntityInstanceManager method poolInstance.
public void poolInstance(final ThreadContext callContext, final EntityBean bean, final Object primaryKey) throws OpenEJBException {
if (bean == null) {
return;
}
// primary key is null if its a servicing a home methods (create, find, ejbHome)
final TransactionPolicy txPolicy = callContext.getTransactionPolicy();
if (primaryKey != null && txPolicy != null && txPolicy.isTransactionActive()) {
final Key key = new Key(callContext.getBeanContext().getDeploymentID(), primaryKey);
SynchronizationWrapper wrapper = (SynchronizationWrapper) txPolicy.getResource(key);
if (wrapper != null) {
if (callContext.getCurrentOperation() == Operation.REMOVE) {
/*
* The bean is being returned to the pool after it has been removed. Its
* important at this point to mark the bean as disassociated to prevent
* it's ejbStore method from bean called (see SynchronizationWrapper.beforeCompletion() method)
* and that subsequent methods can not be invoked on the bean identity (see obtainInstance() method).
*/
wrapper.disassociate();
/*
* If the bean has been removed then the bean instance is no longer needed and can return to the methodReadyPool
* to service another identity.
*/
final Stack methodReadyPool = poolMap.get(callContext.getBeanContext().getDeploymentID());
methodReadyPool.push(bean);
} else {
if (callContext.getCurrentOperation() == Operation.CREATE) {
// Bean is being recreated (new-delete-new) so we need to reassociate it
wrapper.associate();
}
wrapper.setEntityBean(bean);
}
} else {
/*
A wrapper will not exist if the bean is being returned after a create operation.
In this case the transaction scope is broader then the create method itself; its a client
initiated transaction, so the bean must be registered with the tranaction and moved to the
tx ready pool
*/
wrapper = new SynchronizationWrapper(callContext.getBeanContext(), primaryKey, bean, true, key, txPolicy);
txPolicy.registerSynchronization(wrapper);
txPolicy.putResource(key, wrapper);
}
} else {
if (primaryKey != null && callContext.getCurrentOperation() != Operation.REMOVE) {
/*
* If the bean has a primary key; And its not being returned following a remove operation;
* then the bean is being returned to the method ready pool after successfully executing a business method or create
* method. In this case we need to call the bean instance's ejbPassivate before returning it to the pool per EJB 1.1
* Section 9.1.
*/
final Operation currentOp = callContext.getCurrentOperation();
callContext.setCurrentOperation(Operation.PASSIVATE);
try {
/*
In the event of an exception, OpenEJB is required to log the exception, evict the instance,
and mark the transaction for rollback. If there is a transaction to rollback, then the a
javax.transaction.TransactionRolledbackException must be throw to the client.
See EJB 1.1 specification, section 12.3.2
*/
bean.ejbPassivate();
} catch (final Throwable e) {
if (txPolicy.isTransactionActive()) {
txPolicy.setRollbackOnly(e);
throw new ApplicationException(new TransactionRolledbackException("Reflection exception thrown while attempting to call ejbPassivate() on the instance", e));
}
throw new ApplicationException(new RemoteException("Reflection exception thrown while attempting to call ejbPassivate() on the instance. Exception message = " + e.getMessage(), e));
} finally {
callContext.setCurrentOperation(currentOp);
}
}
/*
* The bean is returned to the method ready pool if its returned after servicing a find, ejbHome, business or create
* method and is not still part of a tx. While in the method ready pool the bean instance is not associated with a
* primary key and may be used to service a request for any bean of the same class.
*/
final Stack methodReadyPool = poolMap.get(callContext.getBeanContext().getDeploymentID());
methodReadyPool.push(bean);
}
}
use of org.apache.openejb.core.Operation in project tomee by apache.
the class EntityInstanceManager method getPooledInstance.
protected EntityBean getPooledInstance(final ThreadContext callContext) throws OpenEJBException {
final BeanContext beanContext = callContext.getBeanContext();
final Stack methodReadyPool = poolMap.get(beanContext.getDeploymentID());
if (methodReadyPool == null) {
throw new SystemException("Invalid deployment id " + beanContext.getDeploymentID() + " for this container");
}
EntityBean bean = (EntityBean) methodReadyPool.pop();
if (bean == null) {
try {
bean = (EntityBean) beanContext.getBeanClass().newInstance();
} catch (final Exception e) {
logger.error("Bean instantiation failed for class " + beanContext.getBeanClass(), e);
throw new SystemException(e);
}
final Operation currentOp = callContext.getCurrentOperation();
callContext.setCurrentOperation(Operation.SET_CONTEXT);
try {
/*
* setEntityContext executes in an unspecified transactional context. In this case we choose to
* allow it to have what every transaction context is current. Better then suspending it
* unnecessarily.
*
* We also chose not to invoke EntityContainer.invoke( ) method, which duplicate the exception handling
* logic but also attempt to manage the begining and end of a transaction. It its a container managed transaciton
* we don't want the TransactionScopeHandler commiting the transaction in afterInvoke() which is what it would attempt
* to do.
*/
bean.setEntityContext(createEntityContext());
} catch (final Exception e) {
/*
* The EJB 1.1 specification does not specify how exceptions thrown by setEntityContext impact the
* transaction, if there is one. In this case we choose the least disruptive operation, throwing an
* application exception and NOT automatically marking the transaciton for rollback.
*/
logger.error("Bean callback method failed ", e);
throw new ApplicationException(e);
} finally {
callContext.setCurrentOperation(currentOp);
}
} else {
reusingBean(bean, callContext);
}
if (callContext.getCurrentOperation() == Operation.BUSINESS || callContext.getCurrentOperation() == Operation.REMOVE) {
/*
* When a bean is retrieved from the bean pool to service a client's business method request it must be
* notified that its about to enter service by invoking its ejbActivate( ) method. A bean instance
* does not have its ejbActivate() invoked when:
* 1. Its being retreived to service an ejbCreate()/ejbPostCreate().
* 2. Its being retrieved to service an ejbFind method.
* 3. Its being retrieved to service an ejbRemove() method.
* See section 9.1.4 of the EJB 1.1 specification.
*/
final Operation currentOp = callContext.getCurrentOperation();
callContext.setCurrentOperation(Operation.ACTIVATE);
try {
/*
In the event of an exception, OpenEJB is required to log the exception, evict the instance,
and mark the transaction for rollback. If there is a transaction to rollback, then the a
javax.transaction.TransactionRolledbackException must be throw to the client.
See EJB 1.1 specification, section 12.3.2
*/
bean.ejbActivate();
} catch (final Throwable e) {
logger.error("Encountered exception during call to ejbActivate()", e);
final TransactionPolicy txPolicy = callContext.getTransactionPolicy();
if (txPolicy != null && txPolicy.isTransactionActive()) {
txPolicy.setRollbackOnly(e);
throw new ApplicationException(new TransactionRolledbackException("Reflection exception thrown while attempting to call ejbActivate() on the instance", e));
}
throw new ApplicationException(new RemoteException("Exception thrown while attempting to call ejbActivate() on the instance. Exception message = " + e.getMessage(), e));
} finally {
callContext.setCurrentOperation(currentOp);
}
}
return bean;
}
use of org.apache.openejb.core.Operation 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.core.Operation in project tomee by apache.
the class EntityContainer method ejbLoad_If_No_Transaction.
public void ejbLoad_If_No_Transaction(final ThreadContext callContext, final EntityBean bean) throws Exception {
final Operation orginalOperation = callContext.getCurrentOperation();
if (orginalOperation == Operation.BUSINESS || orginalOperation == Operation.REMOVE) {
final TransactionPolicy callerTxPolicy = callContext.getTransactionPolicy();
if (callerTxPolicy != null && callerTxPolicy.isTransactionActive()) {
return;
}
final BeanContext beanContext = callContext.getBeanContext();
final TransactionPolicy txPolicy = beanContext.getTransactionPolicyFactory().createTransactionPolicy(TransactionType.Supports);
try {
// double check we don't have an active transaction
if (!txPolicy.isTransactionActive()) {
callContext.setCurrentOperation(Operation.LOAD);
bean.ejbLoad();
}
} catch (final NoSuchEntityException e) {
instanceManager.discardInstance(callContext, bean);
throw new ApplicationException(new NoSuchObjectException("Entity not found: " + callContext.getPrimaryKey()));
} catch (final Exception e) {
instanceManager.discardInstance(callContext, bean);
throw e;
} finally {
callContext.setCurrentOperation(orginalOperation);
txPolicy.commit();
}
}
}
use of org.apache.openejb.core.Operation in project tomee by apache.
the class MdbContainer method invoke.
public Object invoke(final Object instance, final Method method, final InterfaceType type, Object... args) throws SystemException, ApplicationException {
if (args == null) {
args = NO_ARGS;
}
// get the context data
final ThreadContext callContext = ThreadContext.getThreadContext();
final BeanContext deployInfo = callContext.getBeanContext();
final MdbCallContext mdbCallContext = callContext.get(MdbCallContext.class);
if (mdbCallContext == null) {
throw new IllegalStateException("beforeDelivery was not called");
}
// verify the delivery method passed to beforeDeliver is the same method that was invoked
if (!mdbCallContext.deliveryMethod.getName().equals(method.getName()) || !Arrays.deepEquals(mdbCallContext.deliveryMethod.getParameterTypes(), method.getParameterTypes())) {
throw new IllegalStateException("Delivery method specified in beforeDelivery is not the delivery method called");
}
// remember the return value or exception so it can be logged
Object returnValue = null;
OpenEJBException openEjbException = null;
final Operation oldOperation = callContext.getCurrentOperation();
callContext.setCurrentOperation(type == InterfaceType.TIMEOUT ? Operation.TIMEOUT : Operation.BUSINESS);
try {
if (logger.isDebugEnabled()) {
logger.info("invoking method " + method.getName() + " on " + deployInfo.getDeploymentID());
}
// determine the target method on the bean instance class
final Method targetMethod = deployInfo.getMatchingBeanMethod(method);
callContext.set(Method.class, targetMethod);
// invoke the target method
returnValue = _invoke(instance, targetMethod, args, deployInfo, type, mdbCallContext);
return returnValue;
} catch (final ApplicationException | SystemException e) {
openEjbException = e;
throw e;
} finally {
callContext.setCurrentOperation(oldOperation);
// Log the invocation results
if (logger.isDebugEnabled()) {
if (openEjbException == null) {
logger.debug("finished invoking method " + method.getName() + ". Return value:" + returnValue);
} else {
final Throwable exception = openEjbException.getRootCause() != null ? openEjbException.getRootCause() : openEjbException;
logger.debug("finished invoking method " + method.getName() + " with exception " + exception);
}
}
}
}
Aggregations