You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by do...@apache.org on 2014/08/13 21:38:30 UTC

svn commit: r1617813 - /ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java

Author: doogie
Date: Wed Aug 13 19:38:30 2014
New Revision: 1617813

URL: http://svn.apache.org/r1617813
Log:
Initialize the eca handler in asycnhronously.  This requires the previous
patch, that initializes the eca handlers DispatchContext asynchronously.
With it, when the eca attempts to initialize, the DelegatorContext will
also initialize at the same time; this will end up calling back into the
same delegator, and a deadlock will occur.

When both are asynchronous, then the eca initialization will return
quickly, and upon first access, the DispatchContext future will be
waited for.

Modified:
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java?rev=1617813&r1=1617812&r2=1617813&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java Wed Aug 13 19:38:30 2014
@@ -30,13 +30,16 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
 import java.util.concurrent.LinkedBlockingDeque;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
 
 import javax.xml.parsers.ParserConfigurationException;
 
+import org.ofbiz.base.concurrent.ConstantFuture;
 import org.ofbiz.base.concurrent.ExecutionPool;
 import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.GeneralRuntimeException;
@@ -105,7 +108,7 @@ public class GenericDelegator implements
 
     protected DistributedCacheClear distributedCacheClear = null;
     protected boolean warnNoEcaHandler = false;
-    protected EntityEcaHandler<?> entityEcaHandler = null;
+    protected final AtomicReference<Future<EntityEcaHandler<?>>> entityEcaHandler = new AtomicReference<Future<EntityEcaHandler<?>>>();
     protected final AtomicReference<SequenceUtil> AtomicRefSequencer = new AtomicReference<SequenceUtil>(null);
     protected EntityCrypto crypto = null;
 
@@ -320,9 +323,23 @@ public class GenericDelegator implements
     @Override
     public synchronized void initEntityEcaHandler() {
         // Nothing to do if already assigned: the class loader has already been called, the class instantiated and casted to EntityEcaHandler
-        if (this.entityEcaHandler != null || this.warnNoEcaHandler) {
+        if (this.entityEcaHandler.get() != null || this.warnNoEcaHandler) {
             return;
         }
+
+        Callable<EntityEcaHandler<?>> creator = new Callable<EntityEcaHandler<?>>() {
+            public EntityEcaHandler<?> call() {
+                return createEntityEcaHandler();
+            }
+        };
+        FutureTask<EntityEcaHandler<?>> futureTask = new FutureTask<EntityEcaHandler<?>>(creator);
+        if (this.entityEcaHandler.compareAndSet(null, futureTask)) {
+            // This needs to use BATCH, as the service engine might add it's own items into a thread pool.
+            ExecutionPool.GLOBAL_BATCH.submit(futureTask);
+        }
+    }
+
+    protected EntityEcaHandler<?> createEntityEcaHandler() {
         // If useEntityEca is false do nothing: the entityEcaHandler member field with a null value would cause its code to do nothing
         if (this.delegatorInfo.getEntityEcaEnabled()) {
             //time to do some tricks with manual class loading that resolves circular dependencies, like calling services
@@ -332,8 +349,9 @@ public class GenericDelegator implements
 
             try {
                 Class<?> eecahClass = loader.loadClass(entityEcaHandlerClassName);
-                this.entityEcaHandler = UtilGenerics.cast(eecahClass.newInstance());
-                this.entityEcaHandler.setDelegator(this);
+                EntityEcaHandler<?> entityEcaHandler = UtilGenerics.cast(eecahClass.newInstance());
+                entityEcaHandler.setDelegator(this);
+                return entityEcaHandler;
             } catch (ClassNotFoundException e) {
                 Debug.logWarning(e, "EntityEcaHandler class with name " + entityEcaHandlerClassName + " was not found, Entity ECA Rules will be disabled", module);
             } catch (InstantiationException e) {
@@ -347,6 +365,7 @@ public class GenericDelegator implements
             Debug.logInfo("Entity ECA Handler disabled for delegator [" + delegatorFullName + "]", module);
             this.warnNoEcaHandler = true;
         }
+        return null;
     }
 
     /* (non-Javadoc)
@@ -2431,7 +2450,7 @@ public class GenericDelegator implements
         if (this.testRollbackInProgress) {
             return createEntityEcaRuleRunner(null, null);
         }
-        return createEntityEcaRuleRunner(this.entityEcaHandler, entityName);
+        return createEntityEcaRuleRunner(getEntityEcaHandler(), entityName);
     }
 
     protected static <T> EntityEcaRuleRunner<T> createEntityEcaRuleRunner(EntityEcaHandler<T> entityEcaHandler, String entityName) {
@@ -2443,7 +2462,7 @@ public class GenericDelegator implements
      */
     @Override
     public <T> void setEntityEcaHandler(EntityEcaHandler<T> entityEcaHandler) {
-        this.entityEcaHandler = entityEcaHandler;
+        this.entityEcaHandler.set(new ConstantFuture<EntityEcaHandler<?>>(entityEcaHandler));
         this.warnNoEcaHandler = false;
     }
 
@@ -2452,7 +2471,15 @@ public class GenericDelegator implements
      */
     @Override
     public <T> EntityEcaHandler<T> getEntityEcaHandler() {
-        return UtilGenerics.cast(this.entityEcaHandler);
+        Future<EntityEcaHandler<?>> future = this.entityEcaHandler.get();
+        try {
+            return UtilGenerics.cast(future != null ? future.get() : null);
+        } catch (ExecutionException e) {
+            Debug.logError(e, "Could not fetch EntityEcaHandler from the asynchronous instantiation", module);
+        } catch (InterruptedException e) {
+            Debug.logError(e, "Could not fetch EntityEcaHandler from the asynchronous instantiation", module);
+        }
+        return null;
     }
 
     /* (non-Javadoc)
@@ -2793,7 +2820,7 @@ public class GenericDelegator implements
         newDelegator.cache = this.cache;
         newDelegator.distributedCacheClear = this.distributedCacheClear;
         newDelegator.originalDelegatorName = getOriginalDelegatorName();
-        newDelegator.entityEcaHandler = this.entityEcaHandler;
+        newDelegator.entityEcaHandler.set(this.entityEcaHandler.get());
         newDelegator.crypto = this.crypto;
         // In case this delegator is in testMode give it a reference to
         // the rollback list
@@ -2818,7 +2845,7 @@ public class GenericDelegator implements
     @Override
     public GenericDelegator makeTestDelegator(String delegatorName) {
         GenericDelegator testDelegator = this.cloneDelegator(delegatorName);
-        testDelegator.entityEcaHandler = null;
+        testDelegator.entityEcaHandler.set(null);
         testDelegator.initEntityEcaHandler();
         testDelegator.setTestMode(true);
         return testDelegator;