[seam-commits] Seam SVN: r9505 - in branches/enterprise/JBPAPP_4_3_FP01/src: test/unit/org/jboss/seam/test/unit and 1 other directory.

seam-commits at lists.jboss.org seam-commits at lists.jboss.org
Wed Nov 5 05:01:54 EST 2008


Author: manaRH
Date: 2008-11-05 05:01:54 -0500 (Wed, 05 Nov 2008)
New Revision: 9505

Added:
   branches/enterprise/JBPAPP_4_3_FP01/src/test/unit/org/jboss/seam/test/unit/FooBar.java
Modified:
   branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/core/BijectionInterceptor.java
   branches/enterprise/JBPAPP_4_3_FP01/src/test/unit/org/jboss/seam/test/unit/InterceptorTest.java
Log:
JBPAPP-1122

Modified: branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/core/BijectionInterceptor.java
===================================================================
--- branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/core/BijectionInterceptor.java	2008-11-04 23:54:11 UTC (rev 9504)
+++ branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/core/BijectionInterceptor.java	2008-11-05 10:01:54 UTC (rev 9505)
@@ -1,13 +1,13 @@
 //$Id$
 package org.jboss.seam.core;
 
+import java.util.concurrent.locks.ReentrantLock;
+
 import org.jboss.seam.Component;
 import org.jboss.seam.annotations.intercept.AroundInvoke;
 import org.jboss.seam.annotations.intercept.Interceptor;
 import org.jboss.seam.intercept.AbstractInterceptor;
 import org.jboss.seam.intercept.InvocationContext;
-import org.jboss.seam.log.LogProvider;
-import org.jboss.seam.log.Logging;
 
 /**
  * Before invoking the component, inject all dependencies. After
@@ -20,40 +20,89 @@
 {
    private static final long serialVersionUID = 4686458105931528659L;
    
-   private static final LogProvider log = Logging.getLogProvider(BijectionInterceptor.class);
+   private boolean injected;
    
-   private boolean reentrant; //OK, since all Seam components are single-threaded
+   private int counter = 0;
    
+   private ReentrantLock lock = new ReentrantLock();
+   
    @AroundInvoke
    public Object aroundInvoke(InvocationContext invocation) throws Exception
    {
-      if (reentrant)
+      Component component = getComponent();
+      boolean enforceRequired = !component.isLifecycleMethod( invocation.getMethod() );  
+      
+      try
       {
-         if ( log.isTraceEnabled() )
+         lock.lock();
+         try
          {
-            log.trace("reentrant call to component: " + getComponent().getName() );
+            if (!injected)
+            {
+               component.inject( invocation.getTarget(), enforceRequired );
+               injected = true;
+            }
+            counter++;
          }
-         return invocation.proceed();
-      }
-      else
-      {
-         reentrant = true;
+         
+         finally
+         {
+            lock.unlock();
+         }
+         
+         Object result = invocation.proceed();   
+         
+         lock.lock();
          try
          {
-            Component component = getComponent();
-            boolean enforceRequired = !component.isLifecycleMethod( invocation.getMethod() );
-            component.inject( invocation.getTarget(), enforceRequired );
-            Object result = invocation.proceed();            
-            component.outject( invocation.getTarget(), enforceRequired );
-            component.disinject( invocation.getTarget() );
-            return result;
+            counter--;
             
+            if (counter == 0)
+            {
+               try
+               {                     
+                  component.outject( invocation.getTarget(), enforceRequired );
+               }
+               finally
+               {
+                  // Avoid an extra lock by disinjecting here instead of the finally block
+                  if (injected)
+                  {
+                     injected = false;
+                     component.disinject( invocation.getTarget() );
+                  }
+               }   
+            }
          }
          finally
          {
-            reentrant = false;
+            lock.unlock();
          }
+         
+         return result;
       }
+      finally
+      {
+         if (injected)
+         {
+            lock.lock();
+            try   
+            {
+               component.disinject( invocation.getTarget() );
+               counter--;
+               
+               if (counter == 0)
+               {
+                  injected = false;
+               }
+            }
+            finally
+            {
+               lock.unlock();
+            }
+            
+         }
+      }
    }
 
 }

Added: branches/enterprise/JBPAPP_4_3_FP01/src/test/unit/org/jboss/seam/test/unit/FooBar.java
===================================================================
--- branches/enterprise/JBPAPP_4_3_FP01/src/test/unit/org/jboss/seam/test/unit/FooBar.java	                        (rev 0)
+++ branches/enterprise/JBPAPP_4_3_FP01/src/test/unit/org/jboss/seam/test/unit/FooBar.java	2008-11-05 10:01:54 UTC (rev 9505)
@@ -0,0 +1,23 @@
+ package org.jboss.seam.test.unit;
+import java.util.concurrent.CountDownLatch;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+ at Name("fooBar")
+ at Scope(ScopeType.APPLICATION)
+public class FooBar
+{
+   @In Foo foo;
+   
+   public Foo delayedGetFoo(CountDownLatch latch)
+   {
+      try
+      {
+         latch.await();
+      }
+      catch (InterruptedException ex) {}
+      
+      return foo;
+   }
+} 
\ No newline at end of file


Property changes on: branches/enterprise/JBPAPP_4_3_FP01/src/test/unit/org/jboss/seam/test/unit/FooBar.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Modified: branches/enterprise/JBPAPP_4_3_FP01/src/test/unit/org/jboss/seam/test/unit/InterceptorTest.java
===================================================================
--- branches/enterprise/JBPAPP_4_3_FP01/src/test/unit/org/jboss/seam/test/unit/InterceptorTest.java	2008-11-04 23:54:11 UTC (rev 9504)
+++ branches/enterprise/JBPAPP_4_3_FP01/src/test/unit/org/jboss/seam/test/unit/InterceptorTest.java	2008-11-05 10:01:54 UTC (rev 9505)
@@ -2,6 +2,7 @@
 package org.jboss.seam.test.unit;
 
 import java.lang.reflect.Method;
+import java.util.concurrent.CountDownLatch;
 
 import javax.faces.context.ExternalContext;
 import javax.faces.event.PhaseId;
@@ -25,6 +26,7 @@
 import org.jboss.seam.core.Manager;
 import org.jboss.seam.ejb.RemoveInterceptor;
 import org.jboss.seam.faces.FacesMessages;
+import org.jboss.seam.intercept.InvocationContext;
 import org.jboss.seam.mock.MockApplication;
 import org.jboss.seam.mock.MockExternalContext;
 import org.jboss.seam.mock.MockFacesContext;
@@ -235,6 +237,101 @@
    }
    
    @Test
+   public void testReentrantBijection() throws Exception
+   {
+      MockServletContext servletContext = new MockServletContext();
+      ServletLifecycle.beginApplication(servletContext);
+      MockExternalContext externalContext = new MockExternalContext(servletContext);
+      Context appContext = new ApplicationContext( externalContext.getApplicationMap() );
+      appContext.set( Seam.getComponentName(Init.class), new Init() );
+      appContext.set( Seam.getComponentName(ConversationEntries.class) + ".component", 
+            new Component(ConversationEntries.class, appContext) );
+      appContext.set( Seam.getComponentName(Manager.class) + ".component", 
+            new Component(Manager.class, appContext) );
+      appContext.set( Seam.getComponentName(Foo.class) + ".component", 
+            new Component(Foo.class, appContext) );
+      appContext.set( Seam.getComponentName(FooBar.class) + ".component", 
+            new Component(FooBar.class, appContext) );      
+      FacesLifecycle.beginRequest(externalContext);
+      Manager.instance().setCurrentConversationId("1");
+      FacesLifecycle.resumeConversation(externalContext);
+      FacesLifecycle.setPhaseId(PhaseId.RENDER_RESPONSE);      
+      
+      final Foo foo = new Foo();
+      final FooBar fooBar = new FooBar();
+      Contexts.getSessionContext().set("foo", foo);
+      
+      final BijectionInterceptor bi = new BijectionInterceptor();
+      bi.setComponent( new Component(FooBar.class, appContext) );
+      
+      final Method m = FooBar.class.getMethod("delayedGetFoo", CountDownLatch.class);
+      
+      final CountDownLatch latchA = new CountDownLatch(1);
+      final CountDownLatch latchB = new CountDownLatch(1);
+      final CountDownLatch latchC = new CountDownLatch(1);
+      final CountDownLatch latchD = new CountDownLatch(1);
+      
+      final InvocationContext invocationA = new MockInvocationContext() {
+         @Override public Object getTarget() { return fooBar; }         
+         @Override public Method getMethod() { return m; }
+         @Override public Object[] getParameters() { return new Object[] { latchA }; }
+      };
+      final InvocationContext invocationB = new MockInvocationContext() {
+         @Override public Object getTarget() { return fooBar; }         
+         @Override public Method getMethod() { return m; }
+         @Override public Object[] getParameters() { return new Object[] { latchB }; }
+      };            
+            
+      new Thread(new Runnable() {
+         public void run() {
+            try
+            {
+               Foo result = (Foo) bi.aroundInvoke( invocationA );
+               assert result == foo;               
+            }
+            catch (Exception ex) 
+            { 
+               throw new RuntimeException(ex); 
+            }
+            finally
+            {
+               latchC.countDown();
+            }
+         }     
+      }).start();    
+      
+      new Thread(new Runnable() {
+         public void run() {
+            try
+            {
+               Foo result = (Foo) bi.aroundInvoke( invocationB );
+               assert result == foo;
+            }
+            catch (Exception ex) 
+            { 
+               throw new RuntimeException(ex); 
+            }
+            finally
+            {
+               latchD.countDown();
+            }
+         }     
+      }).start();       
+      
+      // Allow invocationA to complete
+      latchA.countDown();      
+      
+      // Wait for invocationA to finalise
+      latchC.await();
+      
+      // Allow invocationB to proceed
+      latchB.countDown();
+      
+      // Wait for invocationB
+      latchD.await();
+   }
+   
+   @Test
    public void testConversationInterceptor() throws Exception
    {
       MockServletContext servletContext = new MockServletContext();




More information about the seam-commits mailing list