What was the problem... the diff is more or less the entire file.  I am
curious, because I am still running into a hang, though it seems like it
might be MDB or SB related (not sure at the moment).

--jason

On Wed, 11 Jul 2001, Scott M Stark wrote:

>   User: starksm
>   Date: 01/07/11 14:47:14
>
>   Modified:    src/main/org/jboss/ejb/plugins
>                         EntityInstanceInterceptor.java
>   Log:
>   Fix a thread starvation problem due to incomplete condition notification
>   Add support for trace level diagnositics
>
>   Revision  Changes    Path
>   1.34      +408 -358  
>jboss/src/main/org/jboss/ejb/plugins/EntityInstanceInterceptor.java
>
>   Index: EntityInstanceInterceptor.java
>   ===================================================================
>   RCS file: 
>/cvsroot/jboss/jboss/src/main/org/jboss/ejb/plugins/EntityInstanceInterceptor.java,v
>   retrieving revision 1.33
>   retrieving revision 1.34
>   diff -u -r1.33 -r1.34
>   --- EntityInstanceInterceptor.java  2001/07/10 22:45:41     1.33
>   +++ EntityInstanceInterceptor.java  2001/07/11 21:47:14     1.34
>   @@ -1,358 +1,408 @@
>   -/*
>   - * JBoss, the OpenSource EJB server
>   - *
>   - * Distributable under LGPL license.
>   - * See terms of license at gnu.org.
>   - */
>   -package org.jboss.ejb.plugins;
>   -
>   -import java.lang.reflect.Method;
>   -import java.rmi.RemoteException;
>   -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.ejb.CacheKey;
>   -import org.jboss.metadata.EntityMetaData;
>   -import org.jboss.logging.Logger;
>   -import org.jboss.util.Sync;
>   -
>   -/**
>   - * The instance interceptors role is to acquire a context representing
>   - * the target object from the cache.
>   - *
>   - * <p>This particular container interceptor implements pessimistic locking
>   - *    on the transaction that is associated with the retrieved instance.  If
>   - *    there is a transaction associated with the target component and it is
>   - *    different from the transaction associated with the MethodInvocation
>   - *    coming in then the policy is to wait for transactional commit.
>   - *
>   - * <p>We also implement serialization of calls in here (this is a spec
>   - *    requirement). This is a fine grained notify, notifyAll mechanism. We
>   - *    notify on ctx serialization locks and notifyAll on global transactional
>   - *    locks.
>   - *
>   - * <p><b>WARNING: critical code</b>, get approval from senior developers
>   - *    before changing.
>   - *
>   - * @author <a href="mailto:[EMAIL PROTECTED]";>Marc Fleury</a>
>   - * @version $Revision: 1.33 $
>   - *
>   - * <p><b>Revisions:</b><br>
>   - * <p><b>2001/06/28: marcf</b>
>   - * <ol>
>   - *   <li>Moved to new synchronization
>   - *   <li>Pools are gone simple design
>   - *   <li>two levels of syncrhonization with Tx and ctx
>   - *   <li>remove busy wait from previous mechanisms
>   - * </ol>
>   - */
>   -public class EntityInstanceInterceptor
>   -   extends AbstractInterceptor
>   -{
>   -   // Constants -----------------------------------------------------
>   -
>   -   // Attributes ----------------------------------------------------
>   -
>   -   protected EntityContainer container;
>   -
>   -   // Static --------------------------------------------------------
>   -
>   -   // Constructors --------------------------------------------------
>   -
>   -   // Public --------------------------------------------------------
>   -
>   -   public void setContainer(Container container)
>   -   {
>   -      this.container = (EntityContainer)container;
>   -   }
>   -
>   -   public  Container getContainer()
>   -   {
>   -      return container;
>   -   }
>   -
>   -   // Interceptor implementation --------------------------------------
>   -
>   -   public Object invokeHome(MethodInvocation mi)
>   -      throws Exception
>   -   {
>   -      // Get context
>   -      EnterpriseContext ctx = 
>((EntityContainer)getContainer()).getInstancePool().get();
>   -
>   -      // Pass it to the method invocation
>   -      mi.setEnterpriseContext(ctx);
>   -
>   -      // Give it the transaction
>   -      ctx.setTransaction(mi.getTransaction());
>   -
>   -      // This context is brand new. We can lock without more "fuss"
>   -      // The reason we need to lock it is that it will be put in cache before the 
>end
>   -      // of the call.  So another thread could access it before we are done.
>   -
>   -      ctx.lock();
>   -
>   -      try
>   -      {
>   -         // Invoke through interceptors
>   -         return getNext().invokeHome(mi);
>   -      }
>   -      finally
>   -      {
>   -         //Other threads can be coming for this instance if it is in cache
>   -         synchronized(ctx) {
>   -            // Always unlock, no matter what
>   -            ctx.unlock();
>   -            // Wake everyone up in case of create with Tx contention
>   -            ctx.notifyAll();
>   -         }
>   -         //Do not send back to pools in any case, let the instance be GC'ed
>   -      }
>   -   }
>   -
>   -   public Object invoke(MethodInvocation mi)
>   -      throws Exception
>   -   {
>   -      // It's all about the context
>   -      EntityEnterpriseContext ctx = null;
>   -
>   -      // And it must correspond to the key.
>   -      CacheKey key = (CacheKey) mi.getId();
>   -
>   -      while (ctx == null)
>   -      {
>   -         ctx = (EntityEnterpriseContext) container.getInstanceCache().get(key);
>   -
>   -         //Next test is independent of whether the context is locked or not, it 
>is purely transactional
>   -         // Is the instance involved with another transaction? if so we implement 
>pessimistic locking
>   -         synchronized(ctx.getTxLock())
>   -         {
>   -            Transaction tx = ctx.getTransaction();
>   -
>   -            // Do we have a running transaction with the context?
>   -            if (tx != null &&
>   -                // And are we trying to enter with another transaction?
>   -                !tx.equals(mi.getTransaction()))
>   -            {
>   -               // That's no good, only one transaction per context
>   -               // Let's put the thread to sleep the transaction demarcation will 
>wake them up
>   -               Logger.debug("Transactional contention on context"+ctx.getId());
>   -
>   -               // Wait for it to finish, note that we use wait() and not 
>wait(5000), why?
>   -               // cause we got cojones, if there a problem in this code we want a 
>freeze not illusion
>   -               // Threads finishing the transaction must notifyAll() on the 
>ctx.txLock
>   -               try {ctx.getTxLock().wait();}
>   -
>   -               // We need to try again
>   -               finally {ctx = null; continue;}
>   -            }
>   -
>   -            /*
>   -              In future versions we can use copies of the instance per transaction
>   -            */
>   -         }
>   -
>   -         // The next test is the pure serialization from the EJB specification.
>   -         synchronized(ctx)
>   -         {
>   -            // synchronized is a time gap, when the thread enters here it can be 
>after "sleep"
>   -            // we need to make sure that stuff is still kosher
>   -
>   -            // Maybe my transaction already expired?
>   -            if (mi.getTransaction() != null && mi.getTransaction().getStatus() == 
>Status.STATUS_MARKED_ROLLBACK)
>   -               throw new RuntimeException("Transaction marked for rollback, 
>possibly a timeout");
>   -
>   -            // We do not use pools any longer so the only thing that can happen 
>is that
>   -            // a ctx has a null id (instance removed) (no more "wrong id" problem)
>   -            if (ctx.getId() == null)
>   -            {
>   -               // This will happen when the instance is removed from cache
>   -               // We need to go through the same mechs and get the new ctx
>   -               ctx = null;
>   -               continue;
>   -            }
>   -            // So the ctx is still valid and the transaction is still game and we 
>own the context
>   -            // so no one can change ctx.  Make sure that all access to ctx is 
>synchronized.
>   -
>   -            // The ctx is still kosher go on with the real serialization
>   -
>   -            //Is the context used already (with or without a transaction), is it 
>locked?
>   -            if (ctx.isLocked())
>   -            {
>   -               // It is locked but re-entrant calls permitted (reentrant home 
>ones are ok as well)
>   -               if (!isCallAllowed(mi))
>   -               {
>   -                  // This instance is in use and you are not permitted to reenter
>   -                  // Go to sleep and wait for the lock to be released
>   -                  Logger.debug("Thread contention on context"+key);
>   -
>   -                  // we want to know about freezes so we wait(), let us know if 
>this locks
>   -                  // Threads finishing invocation will come here and notify() on 
>the ctx
>   -                  try {ctx.wait();}
>   -                  catch (InterruptedException ignored) {}
>   -                  // We need to try again
>   -                  finally {ctx = null; continue;}
>   -               }
>   -               else
>   -               {
>   -                  //We are in a valid reentrant call so take the lock, take it!
>   -                  ctx.lock();
>   -               }
>   -            }
>   -            // No one is using that context
>   -            else
>   -            {
>   -
>   -               // We are now using the context
>   -               ctx.lock();
>   -            }
>   -
>   -            // The transaction is associated with the ctx while we own the lock
>   -            ctx.setTransaction(mi.getTransaction());
>   -
>   -         }// end sychronized(ctx)
>   -
>   -      }
>   -
>   -      // Set context on the method invocation
>   -      mi.setEnterpriseContext(ctx);
>   -
>   -      boolean exceptionThrown = false;
>   -
>   -      try {
>   -
>   -         // Go on, you won
>   -         return getNext().invoke(mi);
>   -
>   -      }
>   -      catch (RemoteException e)
>   -      {
>   -         exceptionThrown = true;
>   -         throw e;
>   -      } catch (RuntimeException e)
>   -      {
>   -         exceptionThrown = true;
>   -         throw e;
>   -      } catch (Error e)
>   -      {
>   -         exceptionThrown = true;
>   -         throw e;
>   -      }
>   -      finally
>   -      {
>   -         // ctx can be null if cache.get throws an Exception, for
>   -         // example when activating a bean.
>   -         if (ctx != null)
>   -         {
>   -
>   -            synchronized(ctx)
>   -            {
>   -               ctx.unlock();
>   -
>   -               Transaction tx = ctx.getTransaction();
>   -
>   -               // If an exception has been thrown,
>   -               if (exceptionThrown &&
>   -                   // if tx, the ctx has been registered in an 
>InstanceSynchronization.
>   -                   // that will remove the context, so we shouldn't.
>   -                   // if no synchronization then we need to do it by hand
>   -                   !ctx.isTxSynchronized())
>   -               {
>   -                  // Discard instance
>   -                  // EJB 1.1 spec 12.3.1
>   -                  container.getInstanceCache().remove(key);
>   -
>   -                  // A cache removal wakes everyone up
>   -                  ctx.notifyAll();
>   -               }
>   -
>   -               else if (ctx.getId() == null)
>   -               {
>   -                  // The key from the MethodInvocation still identifies the right 
>cachekey
>   -                  container.getInstanceCache().remove(key);
>   -
>   -                  // A cache removal wakes everyone up
>   -                  ctx.notifyAll();
>   -
>   -                  // no more pool return
>   -               }
>   -
>   -               // We are done using the context so we wake up the next thread 
>waiting for the ctx
>   -               // marcf: I suspect we could use it only if lock = 0 (code it in 
>the context.lock in fact)
>   -               // this doesn't hurt here, meaning that even if we don't wait for 
>0 to come up
>   -               // we will wake up a thread that will go back to sleep and the 
>next coming out of
>   -               // the body of code will wake the next one etc until we reach 0.  
>Reentrants are a pain
>   -               // a minor though and I really suspect not checking for 0 is quite 
>ok in all cases.
>   -               ctx.notify();
>   -            }
>   -         }// synchronized ctx
>   -      } // finally
>   -   }
>   -
>   -   // Private --------------------------------------------------------
>   -
>   -   private static Method getEJBHome;
>   -   private static Method getHandle;
>   -   private static Method getPrimaryKey;
>   -   private static Method isIdentical;
>   -   private static Method remove;
>   -
>   -   static
>   -   {
>   -      try
>   -      {
>   -         Class[] noArg = new Class[0];
>   -         getEJBHome = EJBObject.class.getMethod("getEJBHome", noArg);
>   -         getHandle = EJBObject.class.getMethod("getHandle", noArg);
>   -         getPrimaryKey = EJBObject.class.getMethod("getPrimaryKey", noArg);
>   -         isIdentical = EJBObject.class.getMethod("isIdentical", new Class[] 
>{EJBObject.class});
>   -         remove = EJBObject.class.getMethod("remove", noArg);
>   -      }
>   -      catch (Exception x) {x.printStackTrace();}
>   -   }
>   -
>   -   private boolean isCallAllowed(MethodInvocation mi)
>   -   {
>   -      boolean reentrant = 
>((EntityMetaData)container.getBeanMetaData()).isReentrant();
>   -
>   -      if (reentrant)
>   -      {
>   -         return true;
>   -      }
>   -      else
>   -      {
>   -         Method m = mi.getMethod();
>   -         if (m.equals(getEJBHome) ||
>   -             m.equals(getHandle) ||
>   -             m.equals(getPrimaryKey) ||
>   -             m.equals(isIdentical) ||
>   -             m.equals(remove))
>   -         {
>   -            return true;
>   -         }
>   -      }
>   -
>   -      return false;
>   -   }
>   -}
>   +/*
>   + * JBoss, the OpenSource EJB server
>   + *
>   + * Distributable under LGPL license.
>   + * See terms of license at gnu.org.
>   + */
>   +package org.jboss.ejb.plugins;
>   +
>   +import java.lang.reflect.Method;
>   +import java.rmi.RemoteException;
>   +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.ejb.CacheKey;
>   +import org.jboss.logging.log4j.JBossCategory;
>   +import org.jboss.metadata.EntityMetaData;
>   +import org.jboss.util.Sync;
>   +
>   +/**
>   + * The instance interceptors role is to acquire a context representing
>   + * the target object from the cache.
>   + *
>   + * <p>This particular container interceptor implements pessimistic locking
>   + *    on the transaction that is associated with the retrieved instance.  If
>   + *    there is a transaction associated with the target component and it is
>   + *    different from the transaction associated with the MethodInvocation
>   + *    coming in then the policy is to wait for transactional commit.
>   + *
>   + * <p>We also implement serialization of calls in here (this is a spec
>   + *    requirement). This is a fine grained notify, notifyAll mechanism. We
>   + *    notify on ctx serialization locks and notifyAll on global transactional
>   + *    locks.
>   + *
>   + * <p><b>WARNING: critical code</b>, get approval from senior developers
>   + *    before changing.
>   + *
>   + * @author <a href="mailto:[EMAIL PROTECTED]";>Marc Fleury</a>
>   + * @author <a href="mailto:[EMAIL PROTECTED]";>Scott Stark</a>
>   + * @version $Revision: 1.34 $
>   + *
>   + * <p><b>Revisions:</b><br>
>   + * <p><b>2001/06/28: marcf</b>
>   + * <ol>
>   + *   <li>Moved to new synchronization
>   + *   <li>Pools are gone simple design
>   + *   <li>two levels of syncrhonization with Tx and ctx
>   + *   <li>remove busy wait from previous mechanisms
>   + * </ol>
>   + * <p><b>2001/07/11: starksm</b>
>   + * <ol>
>   + *   <li>Fix a thread starvation problem due to incomplete condition notification
>   + *   <li>Add support for trace level diagnositics
>   + * </ol>
>   +
>   + */
>   +public class EntityInstanceInterceptor
>   +   extends AbstractInterceptor
>   +{
>   +   // Constants -----------------------------------------------------
>   +
>   +   // Attributes ----------------------------------------------------
>   +
>   +   protected EntityContainer container;
>   +
>   +   // Static --------------------------------------------------------
>   +   /** Use a JBoss custom log4j category for trace level logging */
>   +   static JBossCategory log = (JBossCategory) 
>JBossCategory.getInstance(EntityInstanceInterceptor.class);
>   +
>   +   // Constructors --------------------------------------------------
>   +
>   +   // Public --------------------------------------------------------
>   +
>   +   public void setContainer(Container container)
>   +   {
>   +      this.container = (EntityContainer)container;
>   +   }
>   +
>   +   public Container getContainer()
>   +   {
>   +      return container;
>   +   }
>   +
>   +   // Interceptor implementation --------------------------------------
>   +
>   +   public Object invokeHome(MethodInvocation mi)
>   +      throws Exception
>   +   {
>   +      // Get context
>   +      EnterpriseContext ctx = 
>((EntityContainer)getContainer()).getInstancePool().get();
>   +
>   +      // Pass it to the method invocation
>   +      mi.setEnterpriseContext(ctx);
>   +
>   +      // Give it the transaction
>   +      ctx.setTransaction(mi.getTransaction());
>   +
>   +      // This context is brand new. We can lock without more "fuss"
>   +      // The reason we need to lock it is that it will be put in cache before the 
>end
>   +      // of the call.  So another thread could access it before we are done.
>   +
>   +      ctx.lock();
>   +
>   +      try
>   +      {
>   +         // Invoke through interceptors
>   +         return getNext().invokeHome(mi);
>   +      }
>   +      finally
>   +      {
>   +         //Other threads can be coming for this instance if it is in cache
>   +         synchronized(ctx) {
>   +            // Always unlock, no matter what
>   +            ctx.unlock();
>   +            // Wake everyone up in case of create with Tx contention
>   +            ctx.notifyAll();
>   +         }
>   +         //Do not send back to pools in any case, let the instance be GC'ed
>   +      }
>   +   }
>   +
>   +   public Object invoke(MethodInvocation mi)
>   +      throws Exception
>   +   {
>   +      // It's all about the context
>   +      EntityEnterpriseContext ctx = null;
>   +
>   +      // And it must correspond to the key.
>   +      CacheKey key = (CacheKey) mi.getId();
>   +      boolean trace = log.isTraceEnabled();
>   +      if( trace )
>   +         log.trace("Begin invoke, key="+key);
>   +      while (ctx == null)
>   +      {
>   +         ctx = (EntityEnterpriseContext) container.getInstanceCache().get(key);
>   +         if( trace )
>   +            log.trace("Begin while ctx==null, ctx="+ctx);
>   +
>   +         //Next test is independent of whether the context is locked or not, it 
>is purely transactional
>   +         // Is the instance involved with another transaction? if so we implement 
>pessimistic locking
>   +         synchronized(ctx.getTxLock())
>   +         {
>   +            Transaction tx = ctx.getTransaction();
>   +
>   +            // Do we have a running transaction with the context?
>   +            if (tx != null &&
>   +                // And are we trying to enter with another transaction?
>   +                !tx.equals(mi.getTransaction()))
>   +            {
>   +               // That's no good, only one transaction per context
>   +               // Let's put the thread to sleep the transaction demarcation will 
>wake them up
>   +               if( trace )
>   +                  log.trace("Transactional contention on context"+ctx.getId());
>   +
>   +               // Wait for it to finish, note that we use wait() and not 
>wait(5000), why?
>   +               // cause we got cojones, if there a problem in this code we want a 
>freeze not illusion
>   +               // Threads finishing the transaction must notifyAll() on the 
>ctx.txLock
>   +               try
>   +               {
>   +                  if( trace )
>   +                     log.trace("Begin wait on TxLock="+tx);
>   +                  ctx.getTxLock().wait();
>   +                  if( trace )
>   +                     log.trace("End wait on TxLock="+tx);
>   +               }
>   +
>   +               // We need to try again
>   +               finally {ctx = null; continue;}
>   +            }
>   +
>   +            /*
>   +              In future versions we can use copies of the instance per transaction
>   +            */
>   +         }
>   +
>   +         // The next test is the pure serialization from the EJB specification.
>   +         synchronized(ctx)
>   +         {
>   +            if( trace )
>   +               log.trace("Begin synchronized(ctx), ctx="+ctx);
>   +            // synchronized is a time gap, when the thread enters here it can be 
>after "sleep"
>   +            // we need to make sure that stuff is still kosher
>   +
>   +            // Maybe my transaction already expired?
>   +            if (mi.getTransaction() != null && mi.getTransaction().getStatus() == 
>Status.STATUS_MARKED_ROLLBACK)
>   +               throw new RuntimeException("Transaction marked for rollback, 
>possibly a timeout");
>   +
>   +            // We do not use pools any longer so the only thing that can happen 
>is that
>   +            // a ctx has a null id (instance removed) (no more "wrong id" problem)
>   +            if (ctx.getId() == null)
>   +            {
>   +               // This will happen when the instance is removed from cache
>   +               // We need to go through the same mechs and get the new ctx
>   +               ctx = null;
>   +               if( trace )
>   +                  log.trace("End synchronized(ctx), ctx="+ctx+", null id");
>   +               continue;
>   +            }
>   +            // So the ctx is still valid and the transaction is still game and we 
>own the context
>   +            // so no one can change ctx.  Make sure that all access to ctx is 
>synchronized.
>   +
>   +            // The ctx is still kosher go on with the real serialization
>   +
>   +            //Is the context used already (with or without a transaction), is it 
>locked?
>   +            if (ctx.isLocked())
>   +            {
>   +               // It is locked but re-entrant calls permitted (reentrant home 
>ones are ok as well)
>   +               if (!isCallAllowed(mi))
>   +               {
>   +                  // This instance is in use and you are not permitted to reenter
>   +                  // Go to sleep and wait for the lock to be released
>   +                  if( trace )
>   +                     log.trace("Thread contention on context"+key);
>   +
>   +                  // we want to know about freezes so we wait(), let us know if 
>this locks
>   +                  // Threads finishing invocation will come here and notify() on 
>the ctx
>   +                  try
>   +                  {
>   +                     if( trace )
>   +                        log.trace("Begin ctx.wait(), ctx="+ctx);
>   +                     ctx.wait();
>   +                  }
>   +                  catch (InterruptedException ignored) {}
>   +                  // We need to try again
>   +                  finally
>   +                  {
>   +                     if( trace )
>   +                        log.trace("End ctx.wait(), ctx="+ctx+", 
>isLocked="+ctx.isLocked());
>   +                     ctx = null;
>   +                     continue;
>   +                  }
>   +               }
>   +               else
>   +               {
>   +                  //We are in a valid reentrant call so take the lock, take it!
>   +                  ctx.lock();
>   +                  if( trace )
>   +                     log.trace("In synchronized(ctx), ctx="+ctx+", reentrant 
>call, have lock");
>   +               }
>   +            }
>   +            // No one is using that context
>   +            else
>   +            {
>   +               // We are now using the context
>   +               ctx.lock();
>   +               if( trace )
>   +                  log.trace("In synchronized(ctx), ctx="+ctx+", unused ctx, have 
>lock");
>   +            }
>   +
>   +            // The transaction is associated with the ctx while we own the lock
>   +            ctx.setTransaction(mi.getTransaction());
>   +            if( trace )
>   +               log.trace("End synchronized(ctx), ctx="+ctx);
>   +
>   +         }// end sychronized(ctx)
>   +         if( trace )
>   +            log.trace("End while ctx==null, ctx="+ctx);
>   +      }
>   +
>   +      // Set context on the method invocation
>   +      mi.setEnterpriseContext(ctx);
>   +
>   +      boolean exceptionThrown = false;
>   +
>   +      try {
>   +
>   +         // Go on, you won
>   +         if( trace )
>   +            log.trace("Begin next invoker");
>   +         Object returnValue = getNext().invoke(mi);
>   +         if( trace )
>   +            log.trace("End next invoker");
>   +         return returnValue;
>   +      }
>   +      catch (RemoteException e)
>   +      {
>   +         exceptionThrown = true;
>   +         throw e;
>   +      } catch (RuntimeException e)
>   +      {
>   +         exceptionThrown = true;
>   +         throw e;
>   +      } catch (Error e)
>   +      {
>   +         exceptionThrown = true;
>   +         throw e;
>   +      }
>   +      finally
>   +      {
>   +         // ctx can be null if cache.get throws an Exception, for
>   +         // example when activating a bean.
>   +         if (ctx != null)
>   +         {
>   +
>   +            synchronized(ctx)
>   +            {
>   +               ctx.unlock();
>   +               if( trace )
>   +                  log.trace("Ending invoke, unlock ctx="+ctx);
>   +
>   +               Transaction tx = ctx.getTransaction();
>   +
>   +               // If an exception has been thrown,
>   +               if (exceptionThrown &&
>   +                   // if tx, the ctx has been registered in an 
>InstanceSynchronization.
>   +                   // that will remove the context, so we shouldn't.
>   +                   // if no synchronization then we need to do it by hand
>   +                   !ctx.isTxSynchronized())
>   +               {
>   +                  // Discard instance
>   +                  // EJB 1.1 spec 12.3.1
>   +                  container.getInstanceCache().remove(key);
>   +                                           if( trace )
>   +                     log.trace("Ending invoke, exceptionThrown, ctx="+ctx);
>   +               }
>   +
>   +               else if (ctx.getId() == null)
>   +               {
>   +                  // The key from the MethodInvocation still identifies the right 
>cachekey
>   +                  container.getInstanceCache().remove(key);
>   +                  if( trace )
>   +                     log.trace("Ending invoke, cache removal, ctx="+ctx);
>   +                  // no more pool return
>   +               }
>   +
>   +               // We are done using the context so we wake up the next thread 
>waiting for the ctx
>   +               // marcf: I suspect we could use it only if lock = 0 (code it in 
>the context.lock in fact)
>   +               // this doesn't hurt here, meaning that even if we don't wait for 
>0 to come up
>   +               // we will wake up a thread that will go back to sleep and the 
>next coming out of
>   +               // the body of code will wake the next one etc until we reach 0.  
>Reentrants are a pain
>   +               // a minor though and I really suspect not checking for 0 is quite 
>ok in all cases.
>   +               if( trace )
>   +                  log.trace("Ending invoke, send notifyAll ctx="+ctx);
>   +               ctx.notifyAll();
>   +            }
>   +         }// synchronized ctx
>   +         if( trace )
>   +            log.trace("End invoke, key="+key+", ctx="+ctx);
>   +      } // finally
>   +   }
>   +
>   +   // Private --------------------------------------------------------
>   +
>   +   private static Method getEJBHome;
>   +   private static Method getHandle;
>   +   private static Method getPrimaryKey;
>   +   private static Method isIdentical;
>   +   private static Method remove;
>   +
>   +   static
>   +   {
>   +      try
>   +      {
>   +         Class[] noArg = new Class[0];
>   +         getEJBHome = EJBObject.class.getMethod("getEJBHome", noArg);
>   +         getHandle = EJBObject.class.getMethod("getHandle", noArg);
>   +         getPrimaryKey = EJBObject.class.getMethod("getPrimaryKey", noArg);
>   +         isIdentical = EJBObject.class.getMethod("isIdentical", new Class[] 
>{EJBObject.class});
>   +         remove = EJBObject.class.getMethod("remove", noArg);
>   +      }
>   +      catch (Exception x) {x.printStackTrace();}
>   +   }
>   +
>   +   private boolean isCallAllowed(MethodInvocation mi)
>   +   {
>   +      boolean reentrant = 
>((EntityMetaData)container.getBeanMetaData()).isReentrant();
>   +
>   +      if (reentrant)
>   +      {
>   +         return true;
>   +      }
>   +      else
>   +      {
>   +         Method m = mi.getMethod();
>   +         if (m.equals(getEJBHome) ||
>   +             m.equals(getHandle) ||
>   +             m.equals(getPrimaryKey) ||
>   +             m.equals(isIdentical) ||
>   +             m.equals(remove))
>   +         {
>   +            return true;
>   +         }
>   +      }
>   +
>   +      return false;
>   +   }
>   +}
>
>
>
>
> _______________________________________________
> Jboss-development mailing list
> [EMAIL PROTECTED]
> http://lists.sourceforge.net/lists/listinfo/jboss-development
>


_______________________________________________
Jboss-development mailing list
[EMAIL PROTECTED]
http://lists.sourceforge.net/lists/listinfo/jboss-development

Reply via email to