User: fleury  
  Date: 00/10/02 19:34:54

  Modified:    src/main/org/jboss/ejb/plugins
                        EntityInstanceInterceptor.java
  Log:
  reentrancy is not the only criteria for going in.
  
  Some calls need to happen on different threads (not reentrant) so we just lock on 
the context and wait.
  In clear this removes the Exception on "reentrant" which is not correct for Entities
  
  Revision  Changes    Path
  1.14      +234 -220  
jboss/src/main/org/jboss/ejb/plugins/EntityInstanceInterceptor.java
  
  Index: EntityInstanceInterceptor.java
  ===================================================================
  RCS file: 
/products/cvs/ejboss/jboss/src/main/org/jboss/ejb/plugins/EntityInstanceInterceptor.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- EntityInstanceInterceptor.java    2000/09/29 21:25:18     1.13
  +++ EntityInstanceInterceptor.java    2000/10/03 02:34:54     1.14
  @@ -43,229 +43,243 @@
   *   @see <related>
   *   @author Rickard �berg ([EMAIL PROTECTED])
   *   @author <a href="[EMAIL PROTECTED]">Marc Fleury</a>
  -*   @version $Revision: 1.13 $
  +*   @version $Revision: 1.14 $
   */
   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();
  -             mi.setEnterpriseContext(ctx);
  -             
  -             // It is a new context for sure so we can lock it
  -             ctx.lock();
  -             
  -             try
  -             {
  -                     // Invoke through interceptors
  -                     return getNext().invokeHome(mi);
  -             } finally
  -             {
  -                     // Always unlock, no matter what
  -                     ctx.unlock();
  -                     
  -                     // Still free? Not free if create() was called successfully
  -                     if (mi.getEnterpriseContext().getId() == null)
  -                     {
  -                             
container.getInstancePool().free(mi.getEnterpriseContext());
  -                     } 
  -                     else
  -                     {
  -                             // DEBUG           Logger.debug("Entity was created; 
not returned to pool");
  -                             synchronized (ctx) {
  -                                     
  -                                     //Let the waiters know
  -                                     ctx.notifyAll();
  -                             }
  -                     }
  -             }
  -     }
  -     
  -     public Object invoke(MethodInvocation mi)
  -     throws Exception
  -     {
  -             // The id store is a CacheKey in the case of Entity 
  -             CacheKey key = (CacheKey) mi.getId();
  -             
  -             // Get cache
  -             InstanceCache cache = 
((EntityContainer)getContainer()).getInstanceCache();
  -             
  -             EnterpriseContext ctx = null;
  -             
  -             // We synchronize the locking logic (so that the invoke is 
unsynchronized and can be reentrant)
  -             synchronized (cache)
  -             {
  -                     do
  -                     {
  -                             // Get context
  -                             ctx = cache.get(key);
  -                             
  -                             // Do we have a running transaction with the context
  -                             if (ctx.getTransaction() != null &&
  -                                     // And are we trying to enter with another 
transaction
  -                                     
!ctx.getTransaction().equals(mi.getTransaction())) 
  -                             {
  -                                     // Let's put the thread to sleep a lock 
release will wake the thread
  -                                     synchronized (ctx)
  -                                     {
  -                                             // Possible deadlock
  -                                             Logger.log("LOCKING-WAITING for id 
"+ctx.getId()+" ctx.hash "+ctx.hashCode()+" tx.hash "+ctx.hashCode());
  -                                             
  -                                             try{ctx.wait(5000);}
  -                                                     catch (InterruptedException 
ie) {}
  -                                     }
  -                                     
  -                                     // Try your luck again
  -                                     ctx = null;
  -                                     continue;
  -                             }
  -                             
  -                             if (!ctx.isLocked()){
  -                                     
  -                                     //take it!
  -                                     ctx.lock();  
  -                             }
  -                             
  -                             else 
  -                             {
  -                                     if (!isCallAllowed(mi)) {
  -                                             
  -                                             // Not allowed reentrant call
  -                                             throw new RemoteException("Reentrant 
call");
  -                                             
  -                                     } else
  -                                     {
  -                                             //take it!
  -                                             ctx.lock();  
  -                                     }
  -                             }
  -                     
  -                     } while (ctx == null);
  -             }
  -                     
  -             // Set context on the method invocation
  -             mi.setEnterpriseContext(ctx);
  -             
  -             try {
  -                     // Go on, you won
  -                     return getNext().invoke(mi);
  -             
  -             } 
  -             catch (RemoteException e)
  -             {
  -                     // Discard instance
  -                     // EJB 1.1 spec 12.3.1
  -                     
((EntityContainer)getContainer()).getInstanceCache().remove(key.id);
  -                     
  -                     throw e;
  -             } catch (RuntimeException e)
  -             {
  -                     // Discard instance
  -                     // EJB 1.1 spec 12.3.1
  -                     
((EntityContainer)getContainer()).getInstanceCache().remove(key.id);
  -                     
  -                     throw e;
  -             } catch (Error e)
  -             {
  -                     // Discard instance
  -                     // EJB 1.1 spec 12.3.1
  -                     
((EntityContainer)getContainer()).getInstanceCache().remove(key.id);
  -                     
  -                     throw e;
  -             } finally
  -             {
  -                     //         Logger.debug("Release instance for "+id);
  -                     if (ctx != null)
  -                     {
  -                             
  -                             synchronized (ctx) {
  -                                     
  -                                     // unlock the context
  -                                     ctx.unlock();
  -                                     
  -                                     if (ctx.getId() == null)                       
      
  -                                     {
  -                                             // Remove from cache
  -                                             cache.remove(key.id);
  -                                             
  -                                             // It has been removed -> send to free 
pool
  -                                             container.getInstancePool().free(ctx);
  -                                     }
  -                                     
  -                                     // notify the thread waiting on ctx
  -                                     ctx.notifyAll();
  -                             }
  -                     }
  -             }
  -     }
  -     
  -     // 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;
  -     }
  +    // 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();
  +       mi.setEnterpriseContext(ctx);
  +       
  +       // It is a new context for sure so we can lock it
  +       ctx.lock();
  +       
  +       try
  +       {
  +         // Invoke through interceptors
  +         return getNext().invokeHome(mi);
  +       } finally
  +       {
  +         // Always unlock, no matter what
  +         ctx.unlock();
  +         
  +         // Still free? Not free if create() was called successfully
  +         if (mi.getEnterpriseContext().getId() == null)
  +         {
  +          container.getInstancePool().free(mi.getEnterpriseContext());
  +         } 
  +         else
  +         {
  +          // DEBUG           Logger.debug("Entity was created; not returned to 
pool");
  +          synchronized (ctx) {
  +              
  +              //Let the waiters know
  +              ctx.notifyAll();
  +          }
  +         }
  +       }
  +    }
  +    
  +    public Object invoke(MethodInvocation mi)
  +    throws Exception
  +    {
  +       // The id store is a CacheKey in the case of Entity 
  +       CacheKey key = (CacheKey) mi.getId();
  +       
  +       // Get cache
  +       InstanceCache cache = ((EntityContainer)getContainer()).getInstanceCache();
  +       
  +       EnterpriseContext ctx = null;
  +       
  +       // We synchronize the locking logic (so that the invoke is unsynchronized 
and can be reentrant)
  +       synchronized (cache)
  +       {
  +         do
  +         {
  +          // Get context
  +          ctx = cache.get(key);
  +          
  +          // Do we have a running transaction with the context
  +          if (ctx.getTransaction() != null &&
  +              // And are we trying to enter with another transaction
  +              !ctx.getTransaction().equals(mi.getTransaction())) 
  +          {
  +              // Let's put the thread to sleep a lock release will wake the thread
  +              synchronized (ctx)
  +              {
  +                 // Possible deadlock
  +                 Logger.log("LOCKING-WAITING for id "+ctx.getId()+" ctx.hash 
"+ctx.hashCode()+" tx.hash "+ctx.getTransaction().hashCode());
  +                 
  +                 try{ctx.wait(5000);}
  +                   catch (InterruptedException ie) {}
  +              }
  +              
  +              // Try your luck again
  +              ctx = null;
  +              continue;
  +          }
  +          
  +          if (!ctx.isLocked()){
  +              
  +              //take it!
  +              ctx.lock();  
  +          }                                                            
  +          
  +          else 
  +                {
  +                    if (!isCallAllowed(mi)) {
  +                        
  +                        // Go to sleep and wait for the lock to be released
  +                        // This is not one of the "home calls" so we need to wait 
for the lock
  +                        synchronized (ctx)
  +                        {
  +                            // Possible deadlock
  +                            Logger.log("LOCKING-WAITING for id "+ctx.getId()+" 
ctx.hash "+ctx.hashCode());
  +                            
  +                            try{ctx.wait(5000);}
  +                                catch (InterruptedException ie) {}
  +                        }
  +                        
  +                        // Try your luck again
  +                        ctx = null;
  +                        continue;
  +                        // Not allowed reentrant call
  +                        //throw new RemoteException("Reentrant call");
  +                    
  +              } else
  +              {
  +                 //We are in a home call so take the lock, take it!
  +                 ctx.lock();  
  +              }
  +          }
  +                                                                     
  +         } while (ctx == null);
  +       }
  +         
  +       // Set context on the method invocation
  +       mi.setEnterpriseContext(ctx);
  +       
  +       try {
  +         // Go on, you won
  +         return getNext().invoke(mi);
  +       
  +       } 
  +       catch (RemoteException e)
  +       {
  +         // Discard instance
  +         // EJB 1.1 spec 12.3.1
  +         ((EntityContainer)getContainer()).getInstanceCache().remove(key.id);
  +         
  +         throw e;
  +       } catch (RuntimeException e)
  +       {
  +         // Discard instance
  +         // EJB 1.1 spec 12.3.1
  +         ((EntityContainer)getContainer()).getInstanceCache().remove(key.id);
  +         
  +         throw e;
  +       } catch (Error e)
  +       {
  +         // Discard instance
  +         // EJB 1.1 spec 12.3.1
  +         ((EntityContainer)getContainer()).getInstanceCache().remove(key.id);
  +         
  +         throw e;
  +       } finally
  +       {
  +         //         Logger.debug("Release instance for "+id);
  +         if (ctx != null)
  +         {
  +          
  +          synchronized (ctx) {
  +              
  +              // unlock the context
  +              ctx.unlock();
  +              
  +              if (ctx.getId() == null)                             
  +              {
  +                 // Remove from cache
  +                 cache.remove(key.id);
  +                 
  +                 // It has been removed -> send to free pool
  +                 container.getInstancePool().free(ctx);
  +              }
  +              
  +              // notify the thread waiting on ctx
  +              ctx.notifyAll();
  +          }
  +         }
  +       }
  +    }
  +    
  +    // 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;
  +    }
   }
   
  
  
  

Reply via email to