/* * JBoss, Home of Professional Open Source. * Copyright 2008, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.ejb.plugins; import javax.transaction.Status; import javax.transaction.Synchronization; import javax.transaction.Transaction; import org.jboss.ejb.EntityEnterpriseContext; import org.jboss.metadata.ConfigurationMetaData; /** * @deprecated this interceptor was used with Instance Per Transaction containers which do not use a global cache * but cache instances per transaction and always passivate instances at commit time (commit option C). * The only difference from the EntityInstanceInterceptor is that it uses specific instance Synchronization implementation * which always passivates the instance at commit time which is equivalent to commit option C in standard container. * Now, the differences between IPT and standard container are: * <ul> * <li>org.jboss.ejb.plugins.PerTxEntityInstanceCache as the cache implementation;</li> * <li>NoLock as the locking policy;</li> * <li>empty container-cache-conf element.</li> * </ul> * (alex@jboss.org) * * The role of this interceptor is to synchronize the state of the cache with * the underlying storage. It does this with the ejbLoad and ejbStore * semantics of the EJB specification. In the presence of a transaction this * is triggered by transaction demarcation. It registers a callback with the * underlying transaction monitor through the JTA interfaces. If there is no * transaction the policy is to store state upon returning from invocation. * The synchronization polices A,B,C of the specification are taken care of * here. * * <p><b>WARNING: critical code</b>, get approval from senior developers * before changing. * * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @version $Revision: 81030 $ */ public class EntityMultiInstanceSynchronizationInterceptor extends EntitySynchronizationInterceptor { public void create() throws Exception { super.create(); } public void start() { // This is in here so that EntityMultiInstanceInterceptor can avoid doing a lock.sync(). // if (!container.getLockManager().lockClass.equals(org.jboss.ejb.plugins.lock.NoLock.class) && !container.getLockManager().lockClass.equals(org.jboss.ejb.plugins.lock.JDBCOptimisticLock.class) && !container.getLockManager().lockClass.equals(org.jboss.ejb.plugins.lock.MethodOnlyEJBLock.class) ) { throw new IllegalStateException("the <locking-policy> must be org.jboss.ejb.plugins.lock.NoLock, JDBCOptimisticLock, or MethodOnlyEJBLock for Instance Per Transaction:" + container.getLockManager().lockClass.getName()); } } protected Synchronization createSynchronization(Transaction tx, EntityEnterpriseContext ctx) { return new MultiInstanceSynchronization(tx, ctx); } // Protected ---------------------------------------------------- // Inner classes ------------------------------------------------- protected class MultiInstanceSynchronization implements Synchronization { /** * The transaction we follow. */ protected Transaction tx; /** * The context we manage. */ protected EntityEnterpriseContext ctx; /** * Create a new instance synchronization instance. */ MultiInstanceSynchronization(Transaction tx, EntityEnterpriseContext ctx) { this.tx = tx; this.ctx = ctx; } // Synchronization implementation ----------------------------- public void beforeCompletion() { //synchronization is handled by GlobalTxEntityMap. } 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); } } } }