User: fleury  
  Date: 00/09/26 11:47:14

  Modified:    src/main/org/jboss/ejb/plugins
                        EntitySynchronizationInterceptor.java
  Log:
  The synchronization deals with state and transaction call backs properly
  
  Revision  Changes    Path
  1.15      +423 -385  
jboss/src/main/org/jboss/ejb/plugins/EntitySynchronizationInterceptor.java
  
  Index: EntitySynchronizationInterceptor.java
  ===================================================================
  RCS file: 
/products/cvs/ejboss/jboss/src/main/org/jboss/ejb/plugins/EntitySynchronizationInterceptor.java,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- EntitySynchronizationInterceptor.java     2000/09/12 05:04:48     1.14
  +++ EntitySynchronizationInterceptor.java     2000/09/26 18:47:13     1.15
  @@ -1,385 +1,423 @@
  -/*
  -* jBoss, the OpenSource EJB server
  -*
  -* Distributable under GPL license.
  -* See terms of license at gnu.org.
  -*/
  -package org.jboss.ejb.plugins;
  -
  -import java.lang.reflect.Method;
  -import java.rmi.RemoteException;
  -import java.rmi.ServerException;
  -import java.util.Map;
  -import java.util.HashMap;
  -import java.util.ArrayList;
  -
  -import javax.ejb.EJBObject;
  -import javax.ejb.CreateException;
  -import javax.ejb.EJBException;
  -import javax.ejb.NoSuchEntityException;
  -import javax.ejb.RemoveException;
  -import javax.ejb.EntityBean;
  -import javax.transaction.Status;
  -import javax.transaction.Synchronization;
  -import javax.transaction.Transaction;
  -import javax.transaction.TransactionManager;
  -import javax.transaction.RollbackException;
  -import javax.transaction.SystemException;
  -
  -import org.jboss.ejb.Container;
  -import org.jboss.ejb.EntityContainer;
  -import org.jboss.ejb.EntityPersistenceManager;
  -import org.jboss.ejb.EntityEnterpriseContext;
  -import org.jboss.ejb.EnterpriseContext;
  -import org.jboss.ejb.InstanceCache;
  -import org.jboss.ejb.InstancePool;
  -import org.jboss.ejb.MethodInvocation;
  -
  -import org.jboss.logging.Logger;
  -
  -/**
  -*   This container filter takes care of EntityBean persistance.
  -*   Specifically, it calls ejbStore at appropriate times
  -*
  -*   Possible options:
  -*   After each call
  -*   On tx commit
  -*      
  -*   @see <related>
  -*   @author Rickard �berg ([EMAIL PROTECTED])
  -*   @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
  -*   @version $Revision: 1.14 $
  -*/
  -public class EntitySynchronizationInterceptor
  -extends AbstractInterceptor
  -{
  -    // Constants -----------------------------------------------------
  -    
  -    /**
  -     *  Cache a "ready" instance between transactions.
  -     *  Data will <em>not</em> be reloaded from persistent storage when
  -     *  a new transaction is started.
  -     *  This option should only be used if the instance has exclusive
  -     *  access to its persistent storage.
  -     */
  -    public static final int A = 0; // Keep instance cached
  -
  -    /**
  -     *  Cache a "ready" instance between transactions and reload data
  -     *  from persistent storage on transaction start.
  -     */
  -    public static final int B = 1; // Invalidate state
  -
  -    /**
  -     *  Passivate instance after each transaction.
  -     */
  -    public static final int C = 2; // Passivate
  -    
  -    // Attributes ----------------------------------------------------
  -    
  -    /**
  -     *  The current commit option.
  -     */
  -    protected int commitOption = A;
  -    
  -    /**
  -     *  The container of this interceptor.
  -     */
  -    protected EntityContainer container;
  -    
  -    // Static --------------------------------------------------------
  -    
  -    // Constructors --------------------------------------------------
  -    
  -    // Public --------------------------------------------------------
  -    public void setContainer(Container container) 
  -    { 
  -       this.container = (EntityContainer)container; 
  -    }
  -    
  -    public Container getContainer()
  -    {
  -       return container;
  -    }
  -
  -    /**
  -     *  Setter for property commitOption.
  -     */
  -    public void setCommitOption(int commitOption)
  -    {
  -       this.commitOption = commitOption;
  -    }
  -
  -    /**
  -     *  Getter for property commitOption.
  -     */
  -    public int getCommitOption()
  -    {
  -       return commitOption;
  -    }
  -
  -    /**
  -     *  Register a transaction synchronization callback with a context.
  -     */
  -    private void register(EntityEnterpriseContext ctx, Transaction tx)
  -    {
  -       // Create a new synchronization
  -       InstanceSynchronization synch = new InstanceSynchronization(tx, ctx);
  -
  -       try {
  -          // OSH: An extra check to avoid warning.
  -          // Can go when we are sure that we no longer get
  -          // the JTA violation warning.
  -          if (tx.getStatus() == Status.STATUS_MARKED_ROLLBACK) {
  -             ctx.setValid(false);
  -             return;
  -          }
  -
  -          tx.registerSynchronization(synch);
  -       } catch (RollbackException e) {
  -          ctx.setValid(false);
  -       } catch (Exception e) {
  -          throw new EJBException(e);
  -       }
  -    }
  -
  -    private void deregister(EntityEnterpriseContext ctx)
  -    {
  -       // MF FIXME: I suspect this is redundant now
  -       // (won't the pool clean it up?)
  -       
  -       // Deassociate ctx with tx
  -       // OSH: TxInterceptor seems to do this: ctx.setTransaction(null);
  -       // OSH: Pool seems to do this: ctx.setInvoked(false);
  -    }
  -    
  -    // Interceptor implementation --------------------------------------
  -    
  -    public Object invokeHome(MethodInvocation mi)
  -    throws Exception
  -    {
  -       try {
  -          return getNext().invokeHome(mi);
  -       } finally {
  -          // Anonymous was sent in, so if it has an id it was created
  -          EntityEnterpriseContext ctx = 
(EntityEnterpriseContext)mi.getEnterpriseContext();
  -          if (ctx.getId() != null) {
  -             Transaction tx = mi.getTransaction();
  -
  -             if (tx != null && tx.getStatus() == Status.STATUS_ACTIVE)
  -                register(ctx, tx); // Set tx
  -          
  -             // Currently synched with underlying storage
  -             ctx.setValid(true);
  -          }
  -       }
  -    }
  -    
  -    public Object invoke(MethodInvocation mi)
  -    throws Exception
  -    {
  -       // We are going to work with the context a lot
  -       EntityEnterpriseContext ctx = 
(EntityEnterpriseContext)mi.getEnterpriseContext();
  -       
  -       // The Tx coming as part of the Method Invocation 
  -       Transaction tx = mi.getTransaction();
  -       
  -       //Logger.debug("CTX in: isValid():"+ctx.isValid()+" 
isInvoked():"+ctx.isInvoked());
  -       //Logger.debug("newTx: "+ tx);
  -       
  -       // Is my state valid?
  -       if (!ctx.isValid()) {
  -          // If not tell the persistence manager to load the state
  -          ((EntityContainer)getContainer()).getPersistenceManager().loadEntity(ctx);
  -         
  -          // Now the state is valid
  -          ctx.setValid(true);
  -       }
  -       
  -       // So we can go on with the invocation
  -       Logger.log("Tx is "+ ((tx == null)? "null" : tx.toString()));
  -       if (tx != null && tx.getStatus() == Status.STATUS_ACTIVE) {
  -          try {
  -             return getNext().invoke(mi);
  -          } finally {
  -             // Do we have a valid bean (not removed)
  -             if (ctx.getId() != null) {
  -                // If the context was not invoked previously...
  -                if (!ctx.isInvoked()) {
  -                   // It is now and this will cause ejbStore to be called...
  -                   ctx.setInvoked(true);
  -                 
  -                   // ... on a transaction callback that we register here.
  -                   register(ctx, tx);
  -                }
  -             } else // Entity was removed
  -                if (ctx.getTransaction() != null)
  -                  deregister(ctx); // Disassociate ctx
  -          
  -             //Logger.debug("CTX out: isValid():"+ctx.isValid()+" 
isInvoked():"+ctx.isInvoked());
  -             //Logger.debug("PresentTx:"+tx);
  -          }
  -       } else { // No tx
  -          try {
  -             Object result = getNext().invoke(mi);
  -          
  -             // Store after each invocation -- not on exception though, or removal
  -             // And skip reads too ("get" methods)
  -             // OSH FIXME: Isn't this startsWith("get") optimization a violation of
  -             // the EJB specification? Think of SequenceBean.getNext().
  -             if (ctx.getId() != null && !mi.getMethod().getName().startsWith("get"))
  -                
((EntityContainer)getContainer()).getPersistenceManager().storeEntity(ctx);
  -          
  -             return result;
  -          } catch (Exception e) {
  -             // Exception - force reload on next call
  -             ctx.setValid(false);
  -             throw e;
  -          }
  -       }
  -    }
  -    
  -    // Protected  ----------------------------------------------------
  -    
  -    // Inner classes -------------------------------------------------
  -
  -    private class InstanceSynchronization
  -    implements Synchronization
  -    {
  -       /**
  -        *  The transaction we follow.
  -        */
  -       private Transaction tx;
  -
  -       /**
  -        *  The context we manage.
  -        */
  -       private EntityEnterpriseContext ctx;
  -
  -       /**
  -        *  Flag that we need to unlock context.
  -        */
  -       boolean lockedCtx = false;
  -
  -       /**
  -        *  Create a new instance synchronization instance.
  -        */
  -       InstanceSynchronization(Transaction tx, EntityEnterpriseContext ctx)
  -       {
  -          this.tx = tx;
  -          this.ctx = ctx;
  -       }
  -
  -       // Synchronization implementation -----------------------------
  -
  -       public void beforeCompletion()
  -       {
  -          Logger.log("beforeCompletion called");
  -          try {
  -             try {
  -                // Lock instance
  -                container.getInstanceCache().get(ctx.getCacheKey());
  -                lockedCtx = true;
  -              
  -                // Store instance if business method was
  -                if (ctx.isInvoked())
  -                   container.getPersistenceManager().storeEntity(ctx);
  -             } catch (NoSuchEntityException e) {
  -                // Object has been removed -- ignore
  -             }
  -          } catch (RemoteException e) {
  -             // Store failed -> rollback!
  -             try {
  -                tx.setRollbackOnly();
  -             } catch (SystemException ex) {
  -                // DEBUG ex.printStackTrace();
  -             }
  -          }
  -       }
  -       
  -       public void afterCompletion(int status)
  -       {
  -          Logger.log("afterCompletion called");
  -          // If rolled back -> invalidate instance
  -          if (status == Status.STATUS_ROLLEDBACK) {
  -// OSH FIXME:
  -// afterCompletion() was not called on rollback in with the old org.jboss.tm
  -// package, but now it is. The code below, however, makes the bean have a
  -// null primary key on the next call. Commenting it out as to get old behaviour.
  -// What is the correct thing to do here?
  -//          try {
  -//              ctx.setId(null);
  -//              ctx.setTransaction(null);
  -//              container.getInstanceCache().remove(ctx.getId());
  -//              container.getInstancePool().free(ctx); // TODO: should this be 
done? still valid instance?
  -//          } catch (Exception e) {
  -//              // Ignore
  -//          }
  -// At least we should invalidate the state and release the context if it was locked.
  -            ctx.setValid(false); 
  -            if (lockedCtx)
  -              container.getInstanceCache().release(ctx);
  -          } else {
  -             // The transaction is done
  -             ctx.setTransaction(null);
  -
  -             // We are afterCompletion so the invoked can be set to false (db sync 
is done)
  -             ctx.setInvoked(false);
  -
  -             switch (commitOption) {
  -                // Keep instance cached after tx commit
  -                case A:
  -                   try {
  -                      // The state is still valid (only point of access is us)
  -                      ctx.setValid(true); 
  -
  -                      // Release it though
  -                      container.getInstanceCache().release(ctx);
  -                   } catch (Exception e) {
  -                      Logger.debug(e);
  -                   }
  -                   break;
  -
  -                // Keep instance active, but invalidate state
  -                case B:
  -                   try {
  -                      // Invalidate state (there might be other points of entry)
  -                      ctx.setValid(false); 
  -
  -                      // Release it though
  -                      container.getInstanceCache().release(ctx);
  -                   } catch (Exception e) {
  -                      Logger.debug(e);
  -                   }
  -                   break;
  -
  -                // Invalidate everything AND Passivate instance
  -                case C:
  -                   try {
  -                      //Lock in cache
  -                      // OSH: Already did this in beforeCompletion(): 
container.getInstanceCache().get(ctx.getCacheKey()); 
  -
  -                      // Passivate instance
  -                      container.getPersistenceManager().passivateEntity(ctx); 
  -
  -                      // Remove from the cache, it is not active anymore
  -                      container.getInstanceCache().remove(ctx.getId()); 
  -
  -                      // Back to the pool
  -                      container.getInstancePool().free(ctx); 
  -                   } catch (Exception e) {
  -                      Logger.debug(e);
  -                   }
  -                   break;
  -             }
  -          }
  -         
  -          // OSH: What is this for? Who is waiting?
  -          // Notify all who are waiting for this tx to end
  -          synchronized (tx) {
  -             tx.notifyAll();
  -          }
  -       }
  -    }
  -}
  -
  +/*
  +* jBoss, the OpenSource EJB server
  +*
  +* Distributable under GPL license.
  +* See terms of license at gnu.org.
  +*/
  +package org.jboss.ejb.plugins;
  +
  +import java.lang.reflect.Method;
  +import java.rmi.RemoteException;
  +import java.rmi.ServerException;
  +import java.util.Map;
  +import java.util.HashMap;
  +import java.util.ArrayList;
  +
  +import javax.ejb.EJBObject;
  +import javax.ejb.CreateException;
  +import javax.ejb.EJBException;
  +import javax.ejb.NoSuchEntityException;
  +import javax.ejb.RemoveException;
  +import javax.ejb.EntityBean;
  +import javax.transaction.Status;
  +import javax.transaction.Synchronization;
  +import javax.transaction.Transaction;
  +import javax.transaction.TransactionManager;
  +import javax.transaction.RollbackException;
  +import javax.transaction.SystemException;
  +
  +import org.jboss.ejb.Container;
  +import org.jboss.ejb.EntityContainer;
  +import org.jboss.ejb.EntityPersistenceManager;
  +import org.jboss.ejb.EntityEnterpriseContext;
  +import org.jboss.ejb.EnterpriseContext;
  +import org.jboss.ejb.InstanceCache;
  +import org.jboss.ejb.InstancePool;
  +import org.jboss.ejb.MethodInvocation;
  +
  +import org.jboss.logging.Logger;
  +
  +/**
  +*   This container filter takes care of EntityBean persistance.
  +*   Specifically, it calls ejbStore at appropriate times
  +*
  +*   Possible options:
  +*   After each call
  +*   On tx commit
  +*      
  +*   @see <related>
  +*   @author Rickard �berg ([EMAIL PROTECTED])
  +*   @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
  +*   @version $Revision: 1.15 $
  +*/
  +public class EntitySynchronizationInterceptor
  +extends AbstractInterceptor
  +{
  +     // Constants -----------------------------------------------------
  +     
  +     /**
  +     *  Cache a "ready" instance between transactions.
  +     *  Data will <em>not</em> be reloaded from persistent storage when
  +     *  a new transaction is started.
  +     *  This option should only be used if the instance has exclusive
  +     *  access to its persistent storage.
  +     */
  +     public static final int A = 0; // Keep instance cached
  +     
  +     /**
  +     *  Cache a "ready" instance between transactions and reload data
  +     *  from persistent storage on transaction start.
  +     */
  +     public static final int B = 1; // Invalidate state
  +     
  +     /**
  +     *  Passivate instance after each transaction.
  +     */
  +     public static final int C = 2; // Passivate
  +     
  +     // Attributes ----------------------------------------------------
  +     
  +     /**
  +     *  The current commit option.
  +     */
  +     protected int commitOption = A;
  +     
  +     /**
  +     *  The container of this interceptor.
  +     */
  +     protected EntityContainer container;
  +     
  +     // Static --------------------------------------------------------
  +     
  +     // Constructors --------------------------------------------------
  +     
  +     // Public --------------------------------------------------------
  +     public void setContainer(Container container) 
  +     { 
  +             this.container = (EntityContainer)container; 
  +     }
  +     
  +     public Container getContainer()
  +     {
  +             return container;
  +     }
  +     
  +     /**
  +     *  Setter for property commitOption.
  +     */
  +     public void setCommitOption(int commitOption)
  +     {
  +             this.commitOption = commitOption;
  +     }
  +     
  +     /**
  +     *  Getter for property commitOption.
  +     */
  +     public int getCommitOption()
  +     {
  +             return commitOption;
  +     }
  +     
  +     /**
  +     *  Register a transaction synchronization callback with a context.
  +     */
  +     private void register(EntityEnterpriseContext ctx, Transaction tx)
  +     {
  +             // Create a new synchronization
  +             InstanceSynchronization synch = new InstanceSynchronization(tx, ctx);
  +             
  +             try {
  +                     // OSH: An extra check to avoid warning.
  +                     // Can go when we are sure that we no longer get
  +                     // the JTA violation warning.
  +                     if (tx.getStatus() == Status.STATUS_MARKED_ROLLBACK) {
  +                             
  +                             ctx.setValid(false);
  +                             
  +                             return;
  +                     }
  +                     
  +                     // We want to be notified when the transaction commits
  +                     tx.registerSynchronization(synch);
  +             
  +             } catch (RollbackException e) {
  +                     
  +                     // The state in the instance is to be discarded, we force a 
reload of state
  +                     ctx.setValid(false);
  +             
  +             } catch (Exception e) {
  +                     
  +                     throw new EJBException(e);
  +             
  +             }
  +     }
  +     
  +     private void deregister(EntityEnterpriseContext ctx)
  +     {
  +             // MF FIXME: I suspect this is redundant now
  +             // (won't the pool clean it up?)
  +             
  +             // Deassociate ctx with tx
  +             // OSH: TxInterceptor seems to do this: ctx.setTransaction(null);
  +             // OSH: Pool seems to do this: ctx.setInvoked(false);
  +     }
  +     
  +     // Interceptor implementation --------------------------------------
  +     
  +     public Object invokeHome(MethodInvocation mi)
  +     throws Exception
  +     {
  +             try {
  +                     return getNext().invokeHome(mi);
  +             } finally {
  +                     // Anonymous was sent in, so if it has an id it was created
  +                     EntityEnterpriseContext ctx = 
(EntityEnterpriseContext)mi.getEnterpriseContext();
  +                     if (ctx.getId() != null) {
  +                             Transaction tx = mi.getTransaction();
  +                             
  +                             if (tx != null && tx.getStatus() == 
Status.STATUS_ACTIVE)
  +                                     register(ctx, tx); // Set tx
  +                             
  +                             // Currently synched with underlying storage
  +                             ctx.setValid(true);
  +                     }
  +             }
  +     }
  +     
  +     public Object invoke(MethodInvocation mi)
  +     throws Exception
  +     {
  +             // We are going to work with the context a lot
  +             EntityEnterpriseContext ctx = 
(EntityEnterpriseContext)mi.getEnterpriseContext();
  +             
  +             // The Tx coming as part of the Method Invocation 
  +             Transaction tx = mi.getTransaction();
  +             
  +             //Logger.debug("CTX in: isValid():"+ctx.isValid()+" 
isInvoked():"+ctx.isInvoked());
  +             //Logger.debug("newTx: "+ tx);
  +             
  +             // Is my state valid?
  +             if (!ctx.isValid()) {
  +                     
  +                     // If not tell the persistence manager to load the state
  +                     
((EntityContainer)getContainer()).getPersistenceManager().loadEntity(ctx);
  +                     
  +                     // Now the state is valid
  +                     ctx.setValid(true);
  +             }
  +             
  +             // So we can go on with the invocation
  +             Logger.log("Tx is "+ ((tx == null)? "null" : tx.toString()));
  +             
  +             // Invocation with a running Transaction
  +             
  +             if (tx != null && tx.getStatus() == Status.STATUS_ACTIVE) {
  +                     
  +                     try {
  +                             
  +                             //Invoke down the chain
  +                             return getNext().invoke(mi);
  +                     
  +                     } 
  +                     
  +                     finally {
  +                             
  +                             // Do we have a valid bean (not removed)
  +                             if (ctx.getId() != null) {
  +                                     
  +                                     // If the context was not invoked previously...
  +                                     if (!ctx.isInvoked()) {
  +                                             
  +                                             // It is now and this will cause 
ejbStore to be called...
  +                                             ctx.setInvoked(true);
  +                                             
  +                                             // ... on a transaction callback that 
we register here.
  +                                             register(ctx, tx);
  +                                     }
  +                             }
  +                             
  +                             // Entity was removed
  +                             else {
  +                                     
  +                                     if (ctx.getTransaction() != null) {
  +                                             
  +                                             //DEBUG Logger.debug("CTX out: 
isValid():"+ctx.isValid()+" isInvoked():"+ctx.isInvoked());
  +                                             //DEBUG Logger.debug("PresentTx:"+tx);
  +                                             
  +                                             // If a ctx still has a transaction we 
would need to deresgister the sync
  +                                             // The simplest is to tell the pool to 
kill the instance if tx is present
  +                                     
  +                                     }
  +                             }
  +                     }
  +             }
  +             
  +             //    
  +             else { // No tx
  +                     try {
  +                             Object result = getNext().invoke(mi);
  +                             
  +                             // Store after each invocation -- not on exception 
though, or removal
  +                             // And skip reads too ("get" methods)
  +                             // OSH FIXME: Isn't this startsWith("get") 
optimization a violation of
  +                             // the EJB specification? Think of 
SequenceBean.getNext().
  +                             if (ctx.getId() != null && 
!mi.getMethod().getName().startsWith("get"))
  +                                     
((EntityContainer)getContainer()).getPersistenceManager().storeEntity(ctx);
  +                             
  +                             return result;
  +                     } catch (Exception e) {
  +                             // Exception - force reload on next call
  +                             ctx.setValid(false);
  +                             throw e;
  +                     }
  +             }
  +     }
  +     
  +     
  +     // Protected  ----------------------------------------------------
  +     
  +     // Inner classes -------------------------------------------------
  +     
  +     private class InstanceSynchronization
  +     implements Synchronization
  +     {
  +             /**
  +             *  The transaction we follow.
  +             */
  +             private Transaction tx;
  +             
  +             /**
  +             *  The context we manage.
  +             */
  +             private EntityEnterpriseContext ctx;
  +             
  +             /**
  +             *  Create a new instance synchronization instance.
  +             */
  +             InstanceSynchronization(Transaction tx, EntityEnterpriseContext ctx)
  +             {
  +                     this.tx = tx;
  +                     this.ctx = ctx;
  +             }
  +             
  +             // Synchronization implementation -----------------------------
  +             
  +             public void beforeCompletion()
  +             {
  +                     Logger.log("beforeCompletion called for ctx "+ctx.hashCode());
  +                     
  +                     if (ctx.getId() != null) {
  +                             try {
  +                                     try {
  +                                             
  +                                             // MF FIXME: should we throw an 
exception if lock is present (app error)
  +                                             // it would mean that someone is 
commiting when all the work is not done
  +                                             
  +                                             // Store instance if business method 
was invoked
  +                                             if (ctx.isInvoked())  {
  +                                                     
  +                                                     //DEBUG 
Logger.log("EntitySynchronization sync calling store on ctx "+ctx.hashCode());
  +                                                     
  +                                                     
Logger.log("EntitySynchronization sync calling store on ctx "+ctx.hashCode());
  +                                                     
  +                                                     
container.getPersistenceManager().storeEntity(ctx);
  +                                             }
  +                                     } catch (NoSuchEntityException e) {
  +                                             // Object has been removed -- ignore
  +                                     }
  +                             } catch (RemoteException e) {
  +                                     Logger.exception(e);
  +                                     
  +                                     // Store failed -> rollback!
  +                                     try {
  +                                             tx.setRollbackOnly();
  +                                     } catch (SystemException ex) {
  +                                             // DEBUG ex.printStackTrace();
  +                                     }
  +                             }
  +                     }
  +             }
  +             
  +             public void afterCompletion(int status)
  +             {
  +                     if (ctx.getId() != null) {
  +                             Logger.log("afterCompletion called for ctx 
"+ctx.hashCode());
  +                             // If rolled back -> invalidate instance
  +                             if (status == Status.STATUS_ROLLEDBACK) {
  +                                     try {
  +                                             
  +                                             // finish the transaction association
  +                                             ctx.setTransaction(null);
  +                                             
  +                                             ctx.setValid(false); 
  +                                                     
  +                                             // remove from the cache
  +                                             
container.getInstanceCache().remove(ctx.getId());
  +                                             
  +                                             // return to pool
  +                                             container.getInstancePool().free(ctx); 
  +                                             
  +                                             // wake threads waiting
  +                                             synchronized(ctx) { ctx.notifyAll();}
  +                                     
  +                                     } catch (Exception e) {
  +                                             // Ignore
  +                                     }
  +                             
  +                             
  +                             
  +                             } else {
  +                                     // The transaction is done
  +                                     ctx.setTransaction(null);
  +                                     
  +                                     // We are afterCompletion so the invoked can 
be set to false (db sync is done)
  +                                     ctx.setInvoked(false);
  +                                     
  +                                     switch (commitOption) {
  +                                             // Keep instance cached after tx commit
  +                                             case A:
  +                                                     try {
  +                                                             // The state is still 
valid (only point of access is us)
  +                                                             ctx.setValid(true); 
  +                                             
  +                                                     } catch (Exception e) {
  +                                                             Logger.debug(e);
  +                                                     }
  +                                             break;
  +                                             
  +                                             // Keep instance active, but 
invalidate state
  +                                             case B:
  +                                                     try {
  +                                                             // Invalidate state 
(there might be other points of entry)
  +                                                             ctx.setValid(false); 
  +                                                             
  +                                                     } catch (Exception e) {
  +                                                             Logger.debug(e);
  +                                                     }
  +                                             break;
  +                                             
  +                                             // Invalidate everything AND Passivate 
instance
  +                                             case C:
  +                                                     try {
  +                                                             
  +                                                             // Passivate instance
  +                                                             
container.getPersistenceManager().passivateEntity(ctx); 
  +                                                             
  +                                                             // Remove from the 
cache, it is not active anymore
  +                                                             
container.getInstanceCache().remove(ctx.getId()); 
  +                                                             
  +                                                             // Back to the pool
  +                                                             
container.getInstancePool().free(ctx); 
  +                                                     } catch (Exception e) {
  +                                                             Logger.debug(e);
  +                                                     }
  +                                             break;
  +                                     }
  +                             }
  +                     }
  +                     // Notify all who are waiting for this tx to end, they are 
waiting since the locking logic
  +                     synchronized (ctx) {ctx.notifyAll();}
  +             }
  +     }
  +}
  +
  
  
  

Reply via email to