Author: manaRH
Date: 2012-07-02 08:59:07 -0400 (Mon, 02 Jul 2012)
New Revision: 14972

Modified:
   
branches/community/Seam_2_3/jboss-seam/src/main/java/org/jboss/seam/Component.java
Log:
JBSEAM-4861, JBSEAM-4993 replaced factory lock with synchronized factory

Modified: 
branches/community/Seam_2_3/jboss-seam/src/main/java/org/jboss/seam/Component.java
===================================================================
--- 
branches/community/Seam_2_3/jboss-seam/src/main/java/org/jboss/seam/Component.java
  2012-06-28 11:18:47 UTC (rev 14971)
+++ 
branches/community/Seam_2_3/jboss-seam/src/main/java/org/jboss/seam/Component.java
  2012-07-02 12:59:07 UTC (rev 14972)
@@ -50,7 +50,6 @@
 import java.util.SortedSet;
 import java.util.TreeMap;
 import java.util.TreeSet;
-import java.util.concurrent.locks.ReentrantLock;
 
 import javassist.util.proxy.MethodFilter;
 import javassist.util.proxy.MethodHandler;
@@ -130,8 +129,6 @@
 
    private static final LogProvider log = 
Logging.getLogProvider(Component.class);
    
-   static ReentrantLock factoryLock = new ReentrantLock();
-   
    private ComponentType type;
    private String name;
    private ScopeType scope;
@@ -2057,7 +2054,7 @@
    private static Object getInstanceFromFactory(String name, ScopeType scope)
    {
       Init init = Init.instance();
-      if (init==null) //for unit tests, yew!
+      if (init == null) // for unit tests, yew!
       {
          return null;
       }
@@ -2066,45 +2063,62 @@
          Init.FactoryMethod factoryMethod = init.getFactory(name);
          Init.FactoryExpression methodBinding = 
init.getFactoryMethodExpression(name);
          Init.FactoryExpression valueBinding = 
init.getFactoryValueExpression(name);
-         if ( methodBinding!=null && getOutScope( methodBinding.getScope(), 
null ).isContextActive() ) //let the XML take precedence
-         {
+         if (methodBinding != null && getOutScope(methodBinding.getScope(), 
null).isContextActive())
+         {// let the XML take precedence
             Object result = methodBinding.getMethodBinding().invoke();
-            return handleFactoryMethodResult( name, null, result, 
methodBinding.getScope() );
+            return handleFactoryMethodResult(name, null, result, 
methodBinding.getScope());
          }
-         else if ( valueBinding!=null && getOutScope( valueBinding.getScope(), 
null ).isContextActive() ) //let the XML take precedence
-         {
+         else if (valueBinding != null && getOutScope(valueBinding.getScope(), 
null).isContextActive()) 
+         { // let the XML take precedence
             Object result = valueBinding.getValueBinding().getValue();
-            return handleFactoryMethodResult( name, null, result, 
valueBinding.getScope() );
+            return handleFactoryMethodResult(name, null, result, 
valueBinding.getScope());
          }
-         else if ( factoryMethod!=null && getOutScope( 
factoryMethod.getScope(), factoryMethod.getComponent() ).isContextActive() )
+         else if (factoryMethod != null && 
getOutScope(factoryMethod.getScope(), 
factoryMethod.getComponent()).isContextActive())
          {
-            Object factory = Component.getInstance( 
factoryMethod.getComponent().getName(), true );
-            factoryLock.lock();
-            try
+            Object factory = 
Component.getInstance(factoryMethod.getComponent().getName(), true);
+            ScopeType scopeResult = getOutScope(factoryMethod.getScope(), 
factoryMethod.getComponent());
+            ScopeType scopeFactory = factoryMethod.getComponent().getScope();
+            // we need this lock in the following cases: (1) the target scope 
is
+            // accessed by more than one thread (as we don't want to create the
+            // same object by two threads at the same time for the same scope)
+            // OR (2) the factory is accessed by more than one thread and is
+            // using interceptors (as accessing a factory multiple times might
+            // mess up interceptors). This assumes that (1) the scopes
+            // CONVERSATION, EVENT and PAGE can't be accessed by more than one
+            // thread anyway due to CONVERSATION being locked for the current
+            // thread anyway, and EVENT and PAGE being only short-lived anyway.
+            // (2) a factory that doesn't use injection can be accessed multi
+            // threaded. See JBSEAM-4669/JBSEAM-2419 for the original
+            // discussion.
+            boolean lockingNeeded = ((scopeResult != ScopeType.CONVERSATION && 
scopeResult != ScopeType.EVENT && scopeResult != ScopeType.PAGE) ||
+                  (scopeFactory != ScopeType.CONVERSATION && scopeFactory != 
ScopeType.EVENT && scopeFactory != ScopeType.PAGE && 
factoryMethod.getComponent().interceptionEnabled));
+
+            if (lockingNeeded)
             {
-               // check whether there has been created an instance by another 
thread while waiting for this function's lock
-               if (scope != STATELESS)
+               // Only one factory instance can access result scope
+               // CONVERSATION / EVENT / PAGE anyway due to
+               // the locking of the conversation.
+               if (scopeResult == ScopeType.CONVERSATION || scopeResult == 
ScopeType.EVENT || scopeResult == ScopeType.PAGE)
                {
-                  Object value = (scope == null) ? 
Contexts.lookupInStatefulContexts(name) : scope.getContext().get(name);
-                  if (value != null)
+                  synchronized (factory)
                   {
-                     return value;
+                     return createInstanceFromFactory(name, scope, 
factoryMethod, factory);
                   }
                }
-               
-               if (factory==null)
-               {
-                  return null;
-               }
+               // synchronize all instances of this factory as they might
+               // outject to the same scope (i.e. factory in EVENT scope,
+               // outjecting to APPLICATION scope).
                else
                {
-                  Object result = 
factoryMethod.getComponent().callComponentMethod( factory, 
factoryMethod.getMethod() );
-                  return handleFactoryMethodResult( name, 
factoryMethod.getComponent(), result, factoryMethod.getScope() );
+                  synchronized (factory.getClass())
+                  {
+                     return createInstanceFromFactory(name, scope, 
factoryMethod, factory);
+                  }
                }
             }
-            finally 
+            else
             {
-               factoryLock.unlock();
+               return createInstanceFromFactory(name, scope, factoryMethod, 
factory);
             }
          }
          else
@@ -2114,6 +2128,30 @@
       }
    }
 
+   private static Object createInstanceFromFactory(String name, ScopeType 
scope, Init.FactoryMethod factoryMethod, Object factory)
+   {
+      // check whether there has been created an instance by another thread
+      // while waiting for this function's lock
+      if (scope != STATELESS)
+      {
+         Object value = (scope == null) ? 
Contexts.lookupInStatefulContexts(name) : scope.getContext().get(name);
+         if (value != null)
+         {
+            return value;
+         }
+      }
+
+      if (factory == null)
+      {
+         return null;
+      }
+      else
+      {
+         Object result = 
factoryMethod.getComponent().callComponentMethod(factory, 
factoryMethod.getMethod());
+         return handleFactoryMethodResult(name, factoryMethod.getComponent(), 
result, factoryMethod.getScope());
+      }
+   }
+   
    private static Object handleFactoryMethodResult(String name, Component 
component, Object result, ScopeType scope) {
         // see if a value was outjected by the factory method
         Object value = Contexts.lookupInStatefulContexts(name);
@@ -2163,11 +2201,11 @@
          }
          
       } catch (Exception e) {
-         if (getScope()!=STATELESS) {
-                 getScope().getContext().remove(name); 
-         }
+              if (getScope()!=STATELESS) {
+                      getScope().getContext().remove(name); 
+              }
 
-         throw new InstantiationException("Could not instantiate Seam 
component: " + name, e);
+              throw new InstantiationException("Could not instantiate Seam 
component: " + name, e);
       }
 
       return instance;

_______________________________________________
seam-commits mailing list
[email protected]
https://lists.jboss.org/mailman/listinfo/seam-commits

Reply via email to