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); } }