public void afterCompletion(int status) { boolean trace = log.isTraceEnabled(); // This is an independent point of entry. We need to make sure the // thread is associated with the right context class loader ClassLoader oldCl = SecurityActions.getContextClassLoader(); SecurityActions.setContextClassLoader(container.getClassLoader()); container.pushENC(); ctx.hasTxSynchronization(false); ctx.setTransaction(null); try { try { // If rolled back -> invalidate instance if (status != Status.STATUS_ROLLEDBACK) { switch (commitOption) { // Keep instance cached after tx commit case ConfigurationMetaData.A_COMMIT_OPTION: throw new IllegalStateException( "Commit option A not allowed with this Interceptor"); // Keep instance active, but invalidate state case ConfigurationMetaData.B_COMMIT_OPTION: break; // Invalidate everything AND Passivate instance case ConfigurationMetaData.C_COMMIT_OPTION: break; case ConfigurationMetaData.D_COMMIT_OPTION: throw new IllegalStateException( "Commit option D not allowed with this Interceptor"); } } try { if (ctx.getId() != null) container.getPersistenceManager().passivateEntity(ctx); } catch (Exception ignored) { } container.getInstancePool().free(ctx); } finally { if (trace) log.trace("afterCompletion, clear tx for ctx=" + ctx + ", tx=" + tx); } } // synchronized(lock) finally { container.popENC(); SecurityActions.setContextClassLoader(oldCl); } }
/** Register a transaction synchronization callback with a context. */ protected void register(EntityEnterpriseContext ctx, Transaction tx) { boolean trace = log.isTraceEnabled(); if (trace) log.trace("register, ctx=" + ctx + ", tx=" + tx); EntityContainer ctxContainer = null; try { ctxContainer = (EntityContainer) ctx.getContainer(); if (!ctx.hasTxSynchronization()) { // Create a new synchronization Synchronization synch = createSynchronization(tx, ctx); // We want to be notified when the transaction commits tx.registerSynchronization(synch); ctx.hasTxSynchronization(true); } // mark it dirty in global tx entity map if it is not read only if (!ctxContainer.isReadOnly()) { ctx.getTxAssociation().scheduleSync(tx, ctx); } } catch (RollbackException e) { // The state in the instance is to be discarded, we force a reload of state synchronized (ctx) { ctx.setValid(false); ctx.hasTxSynchronization(false); ctx.setTransaction(null); ctx.setTxAssociation(GlobalTxEntityMap.NONE); } throw new EJBException(e); } catch (Throwable t) { // If anything goes wrong with the association remove the ctx-tx association ctx.hasTxSynchronization(false); ctx.setTxAssociation(GlobalTxEntityMap.NONE); if (t instanceof RuntimeException) throw (RuntimeException) t; else if (t instanceof Error) throw (Error) t; else if (t instanceof Exception) throw new EJBException((Exception) t); else throw new NestedRuntimeException(t); } }
public void afterCompletion(int status) { boolean trace = log.isTraceEnabled(); // This is an independent point of entry. We need to make sure the // thread is associated with the right context class loader ClassLoader oldCl = SecurityActions.getContextClassLoader(); boolean setCl = !oldCl.equals(container.getClassLoader()); if (setCl) { SecurityActions.setContextClassLoader(container.getClassLoader()); } container.pushENC(); int commitOption = ctx.isPassivateAfterCommit() ? ConfigurationMetaData.C_COMMIT_OPTION : EntitySynchronizationInterceptor.this.commitOption; lock.sync(); // The context is no longer synchronized on the TX ctx.hasTxSynchronization(false); ctx.setTxAssociation(GlobalTxEntityMap.NONE); ctx.setTransaction(null); try { try { // If rolled back -> invalidate instance if (status == Status.STATUS_ROLLEDBACK) { // remove from the cache container.getInstanceCache().remove(ctx.getCacheKey()); } else { switch (commitOption) { // Keep instance cached after tx commit case ConfigurationMetaData.A_COMMIT_OPTION: case ConfigurationMetaData.D_COMMIT_OPTION: // The state is still valid (only point of access is us) ctx.setValid(true); break; // Keep instance active, but invalidate state case ConfigurationMetaData.B_COMMIT_OPTION: // Invalidate state (there might be other points of entry) ctx.setValid(false); break; // Invalidate everything AND Passivate instance case ConfigurationMetaData.C_COMMIT_OPTION: try { // We weren't removed, passivate // Here we own the lock, so we don't try to passivate // we just passivate if (ctx.getId() != null) { container.getInstanceCache().remove(ctx.getId()); container.getPersistenceManager().passivateEntity(ctx); } // If we get this far, we return to the pool container.getInstancePool().free(ctx); } catch (Exception e) { log.debug("Exception releasing context", e); } break; } } } finally { if (trace) log.trace("afterCompletion, clear tx for ctx=" + ctx + ", tx=" + tx); lock.endTransaction(tx); if (trace) log.trace("afterCompletion, sent notify on TxLock for ctx=" + ctx); } } // synchronized(lock) finally { lock.releaseSync(); container.getLockManager().removeLockRef(lock.getId()); container.popENC(); if (setCl) { SecurityActions.setContextClassLoader(oldCl); } } }