You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by ad...@apache.org on 2015/02/06 00:25:50 UTC

svn commit: r1657714 - in /ofbiz/trunk/framework: service/src/org/ofbiz/service/ webtools/src/org/ofbiz/webtools/artifactinfo/ webtools/src/org/ofbiz/webtools/labelmanager/

Author: adrianc
Date: Thu Feb  5 23:25:50 2015
New Revision: 1657714

URL: http://svn.apache.org/r1657714
Log:
Revert rev 1622256 to fix a service definition caching problem - https://issues.apache.org/jira/browse/OFBIZ-6060.

I'm reverting this instead of fixing it because the original commit was a first step in an effort to eliminate ThreadLocal variables in the framework (so we can make better use of multi-threading). But since then I have come to the conclusion that it will not be possible without a framework redesign.

Modified:
    ofbiz/trunk/framework/service/src/org/ofbiz/service/DispatchContext.java
    ofbiz/trunk/framework/service/src/org/ofbiz/service/GenericAbstractDispatcher.java
    ofbiz/trunk/framework/service/src/org/ofbiz/service/GenericDispatcherFactory.java
    ofbiz/trunk/framework/service/src/org/ofbiz/service/LocalDispatcher.java
    ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelService.java
    ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java
    ofbiz/trunk/framework/webtools/src/org/ofbiz/webtools/artifactinfo/ArtifactInfoFactory.java
    ofbiz/trunk/framework/webtools/src/org/ofbiz/webtools/labelmanager/LabelReferences.java

Modified: ofbiz/trunk/framework/service/src/org/ofbiz/service/DispatchContext.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/DispatchContext.java?rev=1657714&r1=1657713&r2=1657714&view=diff
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/DispatchContext.java (original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/DispatchContext.java Thu Feb  5 23:25:50 2015
@@ -19,28 +19,86 @@
 package org.ofbiz.service;
 
 import java.io.Serializable;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
 
 import javax.wsdl.WSDLException;
 
+import org.ofbiz.base.component.ComponentConfig;
+import org.ofbiz.base.concurrent.ExecutionPool;
+import org.ofbiz.base.config.GenericConfigException;
+import org.ofbiz.base.config.MainResourceHandler;
+import org.ofbiz.base.config.ResourceHandler;
+import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.cache.UtilCache;
 import org.ofbiz.entity.Delegator;
+import org.ofbiz.entity.GenericEntityConfException;
+import org.ofbiz.entity.config.model.DelegatorElement;
+import org.ofbiz.entity.config.model.EntityConfig;
 import org.ofbiz.security.Security;
+import org.ofbiz.service.config.ServiceConfigUtil;
+import org.ofbiz.service.config.model.GlobalServices;
+import org.ofbiz.service.eca.ServiceEcaUtil;
 import org.w3c.dom.Document;
 
 /**
- * Service dispatch context. A collection of objects and convenience methods
- * to be used by service implementations.
+ * Dispatcher Context
  */
 @SuppressWarnings("serial")
-public final class DispatchContext implements Serializable {
+public class DispatchContext implements Serializable {
 
     public static final String module = DispatchContext.class.getName();
 
-    private final LocalDispatcher dispatcher;
+    private static final UtilCache<String, Map<String, ModelService>> modelServiceMapByModel = UtilCache.createUtilCache("service.ModelServiceMapByModel", 0, 0, false);
 
-    DispatchContext(LocalDispatcher dispatcher) {
+    // these four fields represent the immutable state of a DispatchContext object
+    private final String name;
+    private final transient ClassLoader loader;
+    private final transient LocalDispatcher dispatcher;
+    private final String model;
+
+    /**
+     * Creates new DispatchContext as an immutable object.
+     * The "dispatcher" argument can be null if the "name" argument matches the name of a valid entity model reader.
+     * The thread safety of a DispatchContext object is a consequence of its immutability.
+     *
+     * @param name The immutable name of the DispatchContext
+     * @param loader The immutable class loader
+     * @param dispatcher The immutable dispatcher associated to the DispatchContext
+     *
+     */
+    public DispatchContext(String name, ClassLoader loader, LocalDispatcher dispatcher) {
+        this.name = name;
+        this.loader = loader;
         this.dispatcher = dispatcher;
+        String modelName = null;
+        if (this.dispatcher != null) {
+            Delegator delegator = dispatcher.getDelegator();
+            if (delegator != null) {
+                DelegatorElement delegatorInfo = null;
+                try {
+                    delegatorInfo = EntityConfig.getInstance().getDelegator(delegator.getDelegatorBaseName());
+                } catch (GenericEntityConfException e) {
+                    Debug.logWarning(e, "Exception thrown while getting delegator config: ", module);
+                }
+                if (delegatorInfo != null) {
+                    modelName = delegatorInfo.getEntityModelReader();
+                }
+            }
+        }
+        if (modelName == null) {
+            // if a modelName is not associated to the dispatcher (e.g. dispatcher is null) then use the name
+            // of the DispatchContext as the model reader name
+            modelName = name;
+        }
+        this.model = modelName;
+        getGlobalServiceMap();
     }
 
     /**
@@ -48,7 +106,7 @@ public final class DispatchContext imple
      * @return ClassLoader of the context
      */
     public ClassLoader getClassLoader() {
-        return dispatcher.getClassLoader();
+        return this.loader;
     }
 
     /**
@@ -56,7 +114,7 @@ public final class DispatchContext imple
      * @return String name of the LocalDispatcher object
      */
     public String getName() {
-        return dispatcher.getName();
+        return name;
     }
 
     /**
@@ -64,7 +122,7 @@ public final class DispatchContext imple
      * @return LocalDispatcher that was used to create this context
      */
     public LocalDispatcher getDispatcher() {
-        return dispatcher;
+        return this.dispatcher;
     }
 
     /**
@@ -141,20 +199,84 @@ public final class DispatchContext imple
     }
 
     /**
-     * Gets the ModelService instance that corresponds to the given name
+     * Gets the ModelService instance that corresponds to given the name
      * @param serviceName Name of the service
      * @return GenericServiceModel that corresponds to the serviceName
      */
     public ModelService getModelService(String serviceName) throws GenericServiceException {
-        return dispatcher.getModelService(serviceName);
+        Map<String, ModelService> serviceMap = getGlobalServiceMap();
+        ModelService retVal = null;
+        if (serviceMap != null) {
+            retVal = serviceMap.get(serviceName);
+            if (retVal != null && !retVal.inheritedParameters()) {
+                retVal.interfaceUpdate(this);
+            }
+        }
+        if (retVal == null) {
+            throw new GenericServiceException("Cannot locate service by name (" + serviceName + ")");
+        }
+        return retVal;
     }
 
     public Set<String> getAllServiceNames() {
-        return dispatcher.getAllServiceNames();
+        Set<String> serviceNames = new TreeSet<String>();
+
+        Map<String, ModelService> globalServices = modelServiceMapByModel.get(this.model);
+        if (globalServices != null) {
+            serviceNames.addAll(globalServices.keySet());
+        }
+        return serviceNames;
     }
 
     public Document getWSDL(String serviceName, String locationURI) throws GenericServiceException, WSDLException {
         ModelService model = this.getModelService(serviceName);
         return model.toWSDL(locationURI);
     }
+
+    private Callable<Map<String, ModelService>> createServiceReaderCallable(final ResourceHandler handler) {
+        return new Callable<Map<String, ModelService>>() {
+            public Map<String, ModelService> call() throws Exception {
+                return ModelServiceReader.getModelServiceMap(handler, DispatchContext.this.getDelegator());
+            }
+        };
+    }
+
+    private Map<String, ModelService> getGlobalServiceMap() {
+        Map<String, ModelService> serviceMap = modelServiceMapByModel.get(this.model);
+        if (serviceMap == null) {
+            serviceMap = new HashMap<String, ModelService>();
+
+            List<Future<Map<String, ModelService>>> futures = new LinkedList<Future<Map<String, ModelService>>>();
+            List<GlobalServices> globalServicesList = null;
+            try {
+                globalServicesList = ServiceConfigUtil.getServiceEngine().getGlobalServices();
+            } catch (GenericConfigException e) {
+                // FIXME: Refactor API so exceptions can be thrown and caught.
+                Debug.logError(e, module);
+                throw new RuntimeException(e.getMessage());
+            }
+            for (GlobalServices globalServices : globalServicesList) {
+                ResourceHandler handler = new MainResourceHandler(ServiceConfigUtil.SERVICE_ENGINE_XML_FILENAME, globalServices.getLoader(), globalServices.getLocation());
+                futures.add(ExecutionPool.GLOBAL_FORK_JOIN.submit(createServiceReaderCallable(handler)));
+            }
+
+            // get all of the component resource model stuff, ie specified in each ofbiz-component.xml file
+            for (ComponentConfig.ServiceResourceInfo componentResourceInfo: ComponentConfig.getAllServiceResourceInfos("model")) {
+                futures.add(ExecutionPool.GLOBAL_FORK_JOIN.submit(createServiceReaderCallable(componentResourceInfo.createResourceHandler())));
+            }
+            for (Map<String, ModelService> servicesMap: ExecutionPool.getAllFutures(futures)) {
+                if (servicesMap != null) {
+                    serviceMap.putAll(servicesMap);
+                }
+            }
+
+            if (serviceMap != null) {
+                Map<String, ModelService> cachedServiceMap = modelServiceMapByModel.putIfAbsentAndGet(this.model, serviceMap);
+                if (cachedServiceMap == serviceMap) { // same object: this means that the object created by this thread was actually added to the cache
+                    ServiceEcaUtil.reloadConfig();
+                }
+            }
+        }
+        return serviceMap;
+    }
 }

Modified: ofbiz/trunk/framework/service/src/org/ofbiz/service/GenericAbstractDispatcher.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/GenericAbstractDispatcher.java?rev=1657714&r1=1657713&r2=1657714&view=diff
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/GenericAbstractDispatcher.java (original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/GenericAbstractDispatcher.java Thu Feb  5 23:25:50 2015
@@ -40,7 +40,8 @@ public abstract class GenericAbstractDis
 
     public static final String module = GenericAbstractDispatcher.class.getName();
 
-    protected ServiceDispatcher globalDispatcher = null;
+    protected DispatchContext ctx = null;
+    protected ServiceDispatcher dispatcher = null;
     protected String name = null;
 
     public GenericAbstractDispatcher() {}
@@ -134,7 +135,7 @@ public abstract class GenericAbstractDis
      * @see org.ofbiz.service.LocalDispatcher#schedule(java.lang.String, java.util.Map, long, int, int, int, long)
      */
     public void schedule(String serviceName, Map<String, ? extends Object> context, long startTime, int frequency, int interval, int count, long endTime) throws GenericServiceException {
-        ModelService model = getModelService(serviceName);
+        ModelService model = ctx.getModelService(serviceName);
         schedule(null, serviceName, context, startTime, frequency, interval, count, endTime, model.maxRetry);
     }
 
@@ -179,28 +180,28 @@ public abstract class GenericAbstractDis
      * @see org.ofbiz.service.LocalDispatcher#getJobManager()
      */
     public JobManager getJobManager() {
-        return globalDispatcher.getJobManager();
+        return dispatcher.getJobManager();
     }
 
     /**
      * @see org.ofbiz.service.LocalDispatcher#getJMSListeneFactory()
      */
     public JmsListenerFactory getJMSListeneFactory() {
-        return globalDispatcher.getJMSListenerFactory();
+        return dispatcher.getJMSListenerFactory();
     }
 
     /**
      * @see org.ofbiz.service.LocalDispatcher#getDelegator()
      */
     public Delegator getDelegator() {
-        return globalDispatcher.getDelegator();
+        return dispatcher.getDelegator();
     }
 
     /**
      * @see org.ofbiz.service.LocalDispatcher#getSecurity()
      */
     public Security getSecurity() {
-        return globalDispatcher.getSecurity();
+        return dispatcher.getSecurity();
     }
 
     /**
@@ -211,18 +212,25 @@ public abstract class GenericAbstractDis
     }
 
     /**
+     * @see org.ofbiz.service.LocalDispatcher#getDispatchContext()
+     */
+    public DispatchContext getDispatchContext() {
+        return ctx;
+    }
+
+    /**
      * @see org.ofbiz.service.LocalDispatcher#deregister()
      */
     public void deregister() {
         ServiceContainer.removeFromCache(getName());
-        globalDispatcher.deregister(this);
+        dispatcher.deregister(this);
     }
 
     /**
      * @see org.ofbiz.service.LocalDispatcher#registerCallback(String, GenericServiceCallback)
      */
     public void registerCallback(String serviceName, GenericServiceCallback cb) {
-        globalDispatcher.registerCallback(serviceName, cb);
+        dispatcher.registerCallback(serviceName, cb);
     }
 }
 

Modified: ofbiz/trunk/framework/service/src/org/ofbiz/service/GenericDispatcherFactory.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/GenericDispatcherFactory.java?rev=1657714&r1=1657713&r2=1657714&view=diff
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/GenericDispatcherFactory.java (original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/GenericDispatcherFactory.java Thu Feb  5 23:25:50 2015
@@ -19,22 +19,16 @@
 package org.ofbiz.service;
 
 import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
 
 import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.UtilValidate;
 import org.ofbiz.entity.Delegator;
-import org.ofbiz.entity.GenericEntityConfException;
-import org.ofbiz.entity.config.model.DelegatorElement;
-import org.ofbiz.entity.config.model.EntityConfig;
 
 /**
  * A default {@link LocalDispatcherFactory} implementation.
  */
 public class GenericDispatcherFactory implements LocalDispatcherFactory {
 
-    public static final String module = GenericDispatcherFactory.class.getName();
     protected static boolean ecasDisabled = false;
 
     @Override
@@ -42,25 +36,11 @@ public class GenericDispatcherFactory im
         if (UtilValidate.isEmpty(name)) {
             throw new IllegalArgumentException("The name of a LocalDispatcher cannot be a null or empty String");
         }
-        // attempts to retrieve an already registered LocalDispatcher with the name "name"
+        // attempts to retrieve an already registered DispatchContext with the name "name"
         LocalDispatcher dispatcher = ServiceDispatcher.getLocalDispatcher(name, delegator);
-        // if not found then create a new GenericDispatcher object
+        // if not found then create a new GenericDispatcher object; the constructor will also register a new DispatchContext in the ServiceDispatcher with name "dispatcherName"
         if (dispatcher == null) {
-            ServiceDispatcher globalDispatcher = ServiceDispatcher.getInstance(delegator);
-            String modelName = name;
-            if (delegator != null) {
-                DelegatorElement delegatorInfo = null;
-                try {
-                    delegatorInfo = EntityConfig.getInstance().getDelegator(delegator.getDelegatorBaseName());
-                } catch (GenericEntityConfException e) {
-                    Debug.logWarning(e, "Exception thrown while getting delegator config: ", module);
-                }
-                if (delegatorInfo != null) {
-                    modelName = delegatorInfo.getEntityModelReader();
-                }
-            }
-            Map<String, ModelService> serviceMap = globalDispatcher.getGlobalServiceMap(modelName);
-            dispatcher = globalDispatcher.register(new GenericDispatcher(name, globalDispatcher, serviceMap));
+            dispatcher = new GenericDispatcher(name, delegator);
         }
         return dispatcher;
     }
@@ -68,23 +48,23 @@ public class GenericDispatcherFactory im
     // The default LocalDispatcher implementation.
     private class GenericDispatcher extends GenericAbstractDispatcher {
 
-        private final ClassLoader loader;
-        private final Map<String, ModelService> serviceMap;
-
-        private GenericDispatcher(String name, ServiceDispatcher globalDispatcher, Map<String, ModelService> serviceMap) {
+        private GenericDispatcher(String name, Delegator delegator) {
             ClassLoader loader;
             try {
                 loader = Thread.currentThread().getContextClassLoader();
             } catch (SecurityException e) {
                 loader = this.getClass().getClassLoader();
             }
-            this.loader = loader;
             this.name = name;
-            this.globalDispatcher = globalDispatcher;
-            this.serviceMap = serviceMap;
-            if (Debug.verboseOn()) {
-                Debug.logVerbose("Created Dispatcher for: " + name, module);
-            }
+            this.dispatcher = ServiceDispatcher.getInstance(delegator);
+            /* 
+             * FIXME: "this" reference escape. DispatchContext constructor uses
+             * this object before it is fully constructed.
+             */
+            DispatchContext ctx = new DispatchContext(name, loader, this);
+            this.dispatcher.register(ctx);
+            this.ctx = ctx;
+            if (Debug.verboseOn()) Debug.logVerbose("[GenericDispatcher] : Created Dispatcher for: " + name, module);
         }
 
         @Override
@@ -103,16 +83,14 @@ public class GenericDispatcherFactory im
         }
 
         @Override
-        public Map<String, Object> runSync(String serviceName, Map<String, ? extends Object> context)
-                throws ServiceValidationException, GenericServiceException {
-            ModelService service = getModelService(serviceName);
-            return globalDispatcher.runSync(this.name, service, context);
+        public Map<String, Object> runSync(String serviceName, Map<String, ? extends Object> context) throws ServiceValidationException, GenericServiceException {
+            ModelService service = ctx.getModelService(serviceName);
+            return dispatcher.runSync(this.name, service, context);
         }
 
         @Override
-        public Map<String, Object> runSync(String serviceName, Map<String, ? extends Object> context, int transactionTimeout,
-                boolean requireNewTransaction) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
-            ModelService service = getModelService(serviceName);
+        public Map<String, Object> runSync(String serviceName, Map<String, ? extends Object> context, int transactionTimeout, boolean requireNewTransaction) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+            ModelService service = ctx.getModelService(serviceName);
             // clone the model service for updates
             ModelService cloned = new ModelService(service);
             cloned.requireNewTransaction = requireNewTransaction;
@@ -122,25 +100,23 @@ public class GenericDispatcherFactory im
             if (transactionTimeout != -1) {
                 cloned.transactionTimeout = transactionTimeout;
             }
-            return globalDispatcher.runSync(this.name, cloned, context);
+            return dispatcher.runSync(this.name, cloned, context);
         }
 
         @Override
-        public Map<String, Object> runSync(String serviceName, int transactionTimeout, boolean requireNewTransaction,
-                Object... context) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+        public Map<String, Object> runSync(String serviceName, int transactionTimeout, boolean requireNewTransaction, Object... context) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
             return runSync(serviceName, ServiceUtil.makeContext(context), transactionTimeout, requireNewTransaction);
         }
 
         @Override
         public void runSyncIgnore(String serviceName, Map<String, ? extends Object> context) throws GenericServiceException {
-            ModelService service = getModelService(serviceName);
-            globalDispatcher.runSyncIgnore(this.name, service, context);
+            ModelService service = ctx.getModelService(serviceName);
+            dispatcher.runSyncIgnore(this.name, service, context);
         }
 
         @Override
-        public void runSyncIgnore(String serviceName, Map<String, ? extends Object> context, int transactionTimeout,
-                boolean requireNewTransaction) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
-            ModelService service = getModelService(serviceName);
+        public void runSyncIgnore(String serviceName, Map<String, ? extends Object> context, int transactionTimeout, boolean requireNewTransaction) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+            ModelService service = ctx.getModelService(serviceName);
             // clone the model service for updates
             ModelService cloned = new ModelService(service);
             cloned.requireNewTransaction = requireNewTransaction;
@@ -150,20 +126,17 @@ public class GenericDispatcherFactory im
             if (transactionTimeout != -1) {
                 cloned.transactionTimeout = transactionTimeout;
             }
-            globalDispatcher.runSyncIgnore(this.name, cloned, context);
+            dispatcher.runSyncIgnore(this.name, cloned, context);
         }
 
         @Override
-        public void runSyncIgnore(String serviceName, int transactionTimeout, boolean requireNewTransaction, Object... context)
-                throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+        public void runSyncIgnore(String serviceName, int transactionTimeout, boolean requireNewTransaction, Object... context) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
             runSyncIgnore(serviceName, ServiceUtil.makeContext(context), transactionTimeout, requireNewTransaction);
         }
 
         @Override
-        public void runAsync(String serviceName, Map<String, ? extends Object> context, GenericRequester requester,
-                boolean persist, int transactionTimeout, boolean requireNewTransaction) throws ServiceAuthException,
-                ServiceValidationException, GenericServiceException {
-            ModelService service = getModelService(serviceName);
+        public void runAsync(String serviceName, Map<String, ? extends Object> context, GenericRequester requester, boolean persist, int transactionTimeout, boolean requireNewTransaction) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+            ModelService service = ctx.getModelService(serviceName);
             // clone the model service for updates
             ModelService cloned = new ModelService(service);
             cloned.requireNewTransaction = requireNewTransaction;
@@ -173,104 +146,67 @@ public class GenericDispatcherFactory im
             if (transactionTimeout != -1) {
                 cloned.transactionTimeout = transactionTimeout;
             }
-            globalDispatcher.runAsync(this.name, cloned, context, requester, persist);
+            dispatcher.runAsync(this.name, cloned, context, requester, persist);
         }
 
         @Override
-        public void runAsync(String serviceName, GenericRequester requester, boolean persist, int transactionTimeout,
-                boolean requireNewTransaction, Object... context) throws ServiceAuthException, ServiceValidationException,
-                GenericServiceException {
+        public void runAsync(String serviceName, GenericRequester requester, boolean persist, int transactionTimeout, boolean requireNewTransaction, Object... context) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
             runAsync(serviceName, ServiceUtil.makeContext(context), requester, persist, transactionTimeout, requireNewTransaction);
         }
 
         @Override
-        public void runAsync(String serviceName, Map<String, ? extends Object> context, GenericRequester requester,
-                boolean persist) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
-            ModelService service = getModelService(serviceName);
-            globalDispatcher.runAsync(this.name, service, context, requester, persist);
+        public void runAsync(String serviceName, Map<String, ? extends Object> context, GenericRequester requester, boolean persist) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+            ModelService service = ctx.getModelService(serviceName);
+            dispatcher.runAsync(this.name, service, context, requester, persist);
         }
 
         @Override
-        public void runAsync(String serviceName, GenericRequester requester, boolean persist, Object... context)
-                throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+        public void runAsync(String serviceName, GenericRequester requester, boolean persist, Object... context) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
             runAsync(serviceName, ServiceUtil.makeContext(context), requester, persist);
         }
 
         @Override
-        public void runAsync(String serviceName, Map<String, ? extends Object> context, GenericRequester requester)
-                throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+        public void runAsync(String serviceName, Map<String, ? extends Object> context, GenericRequester requester) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
             runAsync(serviceName, context, requester, true);
         }
 
         @Override
-        public void runAsync(String serviceName, GenericRequester requester, Object... context) throws ServiceAuthException,
-                ServiceValidationException, GenericServiceException {
+        public void runAsync(String serviceName, GenericRequester requester, Object... context) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
             runAsync(serviceName, ServiceUtil.makeContext(context), requester);
         }
 
         @Override
-        public void runAsync(String serviceName, Map<String, ? extends Object> context, boolean persist)
-                throws ServiceAuthException, ServiceValidationException, GenericServiceException {
-            ModelService service = getModelService(serviceName);
-            globalDispatcher.runAsync(this.name, service, context, persist);
+        public void runAsync(String serviceName, Map<String, ? extends Object> context, boolean persist) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+            ModelService service = ctx.getModelService(serviceName);
+            dispatcher.runAsync(this.name, service, context, persist);
         }
 
         @Override
-        public void runAsync(String serviceName, boolean persist, Object... context) throws ServiceAuthException,
-                ServiceValidationException, GenericServiceException {
+        public void runAsync(String serviceName, boolean persist, Object... context) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
             runAsync(serviceName, ServiceUtil.makeContext(context), persist);
         }
 
         @Override
-        public void runAsync(String serviceName, Map<String, ? extends Object> context) throws ServiceAuthException,
-                ServiceValidationException, GenericServiceException {
+        public void runAsync(String serviceName, Map<String, ? extends Object> context) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
             runAsync(serviceName, context, true);
         }
 
         @Override
-        public GenericResultWaiter runAsyncWait(String serviceName, Map<String, ? extends Object> context, boolean persist)
-                throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+        public GenericResultWaiter runAsyncWait(String serviceName, Map<String, ? extends Object> context, boolean persist) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
             GenericResultWaiter waiter = new GenericResultWaiter();
             this.runAsync(serviceName, context, waiter, persist);
             return waiter;
         }
 
         @Override
-        public GenericResultWaiter runAsyncWait(String serviceName, boolean persist, Object... context)
-                throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+        public GenericResultWaiter runAsyncWait(String serviceName, boolean persist, Object... context) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
             return runAsyncWait(serviceName, ServiceUtil.makeContext(context), persist);
         }
 
         @Override
-        public GenericResultWaiter runAsyncWait(String serviceName, Map<String, ? extends Object> context)
-                throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+        public GenericResultWaiter runAsyncWait(String serviceName, Map<String, ? extends Object> context) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
             return runAsyncWait(serviceName, context, true);
         }
-
-        @Override
-        public DispatchContext getDispatchContext() {
-            return new DispatchContext(this);
-        }
-
-        @Override
-        public Set<String> getAllServiceNames() {
-            Set<String> serviceNames = new TreeSet<String>();
-            serviceNames.addAll(serviceMap.keySet());
-            return serviceNames;
-        }
-
-        @Override
-        public ModelService getModelService(String serviceName) throws GenericServiceException {
-            ModelService modelService = serviceMap.get(serviceName);
-            if (modelService == null) {
-                throw new GenericServiceException("ModelService not found for name: " + serviceName);
-            }
-            return modelService;
-        }
-
-        @Override
-        public ClassLoader getClassLoader() {
-            return loader;
-        }
     }
+
 }

Modified: ofbiz/trunk/framework/service/src/org/ofbiz/service/LocalDispatcher.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/LocalDispatcher.java?rev=1657714&r1=1657713&r2=1657714&view=diff
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/LocalDispatcher.java (original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/LocalDispatcher.java Thu Feb  5 23:25:50 2015
@@ -19,7 +19,6 @@
 package org.ofbiz.service;
 
 import java.util.Map;
-import java.util.Set;
 
 import org.ofbiz.entity.Delegator;
 import org.ofbiz.security.Security;
@@ -27,11 +26,11 @@ import org.ofbiz.service.jms.JmsListener
 import org.ofbiz.service.job.JobManager;
 
 /**
- * A local service dispatcher.
- * <p> A LocalDispatcher is associated with an application. Applications never talk directly to the ServiceDispatcher.
- * The LocalDispatcher contains an API for invoking services, which are routed through the ServiceDispatcher.
- * However, applications may be running in different threads than the actual ServiceDispatcher, so it is left to the
- * LocalDispatcher to keep a reference to the application's classloader.</p>
+ * A local service dispatcher. This is the main API for the service engine.
+ * <p>Instances of <code>LocalDispatcher</code> are based on a {@link org.ofbiz.entity.Delegator}
+ * instance and an entity model reader name. You can get a <code>LocalDispatcher</code> instance
+ * by calling the {@link org.ofbiz.service.ServiceDispatcher#getLocalDispatcher(String, Delegator)}
+ * factory method.</p>
  */
 public interface LocalDispatcher {
 
@@ -346,11 +345,5 @@ public interface LocalDispatcher {
      * De-Registers this LocalDispatcher
      */
     void deregister();
-
-    ModelService getModelService(String serviceName) throws GenericServiceException;
-
-    Set<String> getAllServiceNames();
-
-    ClassLoader getClassLoader();
 }
 

Modified: ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelService.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelService.java?rev=1657714&r1=1657713&r2=1657714&view=diff
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelService.java (original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelService.java Thu Feb  5 23:25:50 2015
@@ -1092,9 +1092,9 @@ public class ModelService extends Abstra
 
     /**
      * Run the interface update and inherit all interface parameters
-     * @param serviceMap The Map to use for service lookups
+     * @param dctx The DispatchContext to use for service lookups
      */
-    public synchronized void interfaceUpdate(Map<String, ModelService> serviceMap) throws GenericServiceException {
+    public synchronized void interfaceUpdate(DispatchContext dctx) throws GenericServiceException {
         if (!inheritedParameters) {
             // services w/ engine 'group' auto-implement the grouped services
             if (this.engineName.equals("group") && implServices.size() == 0) {
@@ -1111,15 +1111,13 @@ public class ModelService extends Abstra
             }
 
             // handle interfaces
-            if (UtilValidate.isNotEmpty(implServices) && serviceMap != null) {
+            if (UtilValidate.isNotEmpty(implServices) && dctx != null) {
                 for (ModelServiceIface iface: implServices) {
                     String serviceName = iface.getService();
                     boolean optional = iface.isOptional();
-                    ModelService model = serviceMap.get(serviceName);
+
+                    ModelService model = dctx.getModelService(serviceName);
                     if (model != null) {
-                        if (!model.inheritedParameters()) {
-                            model.interfaceUpdate(serviceMap);
-                        }
                         for (ModelParam newParam: model.contextParamList) {
                             ModelParam existingParam = this.contextInfo.get(newParam.name);
                             if (existingParam != null) {

Modified: ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java?rev=1657714&r1=1657713&r2=1657714&view=diff
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java (original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java Thu Feb  5 23:25:50 2015
@@ -18,30 +18,22 @@
  *******************************************************************************/
 package org.ofbiz.service;
 
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.Future;
 
 import javax.transaction.Transaction;
 
-import org.ofbiz.base.component.ComponentConfig;
-import org.ofbiz.base.concurrent.ExecutionPool;
 import org.ofbiz.base.config.GenericConfigException;
-import org.ofbiz.base.config.MainResourceHandler;
-import org.ofbiz.base.config.ResourceHandler;
 import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.GeneralRuntimeException;
 import org.ofbiz.base.util.UtilMisc;
 import org.ofbiz.base.util.UtilProperties;
 import org.ofbiz.base.util.UtilTimer;
 import org.ofbiz.base.util.UtilValidate;
-import org.ofbiz.base.util.cache.UtilCache;
 import org.ofbiz.entity.Delegator;
 import org.ofbiz.entity.DelegatorFactory;
 import org.ofbiz.entity.GenericDelegator;
@@ -54,7 +46,6 @@ import org.ofbiz.security.Security;
 import org.ofbiz.security.SecurityConfigurationException;
 import org.ofbiz.security.SecurityFactory;
 import org.ofbiz.service.config.ServiceConfigUtil;
-import org.ofbiz.service.config.model.GlobalServices;
 import org.ofbiz.service.config.model.StartupService;
 import org.ofbiz.service.eca.ServiceEcaRule;
 import org.ofbiz.service.eca.ServiceEcaUtil;
@@ -69,12 +60,8 @@ import org.ofbiz.service.semaphore.Servi
 import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
 
 /**
- * The global service dispatcher.
- * <p>The Service Dispatcher handles dispatching services to the appropriate Service Engine where it is then invoked.
- * There is exactly one ServiceDispatcher for each Entity Delegator. If there are multiple delegators in an application
- * there will also be multiple dispatchers. The ServiceDispatcher is accessed via a LocalDispatcher. There can be many
- * LocalDispatchers associated with a ServiceDispatcher. Each LocalDispatcher is uniquely named and contains its own
- * list of service definitions.</p>
+ * The global service dispatcher. This is the "engine" part of the
+ * Service Engine.
  */
 public class ServiceDispatcher {
 
@@ -82,7 +69,6 @@ public class ServiceDispatcher {
     public static final int lruLogSize = 200;
     public static final int LOCK_RETRIES = 3;
 
-    private static final UtilCache<String, Map<String, ModelService>> modelServiceMapByModel = UtilCache.createUtilCache("service.ModelServiceMapByModel", 0, 0, false);
     protected static final Map<RunningService, ServiceDispatcher> runLog = new ConcurrentLinkedHashMap.Builder<RunningService, ServiceDispatcher>().maximumWeightedCapacity(lruLogSize).build();
     protected static ConcurrentHashMap<String, ServiceDispatcher> dispatchers = new ConcurrentHashMap<String, ServiceDispatcher>();
     // FIXME: These fields are not thread-safe. They are modified by EntityDataLoadContainer.
@@ -94,7 +80,7 @@ public class ServiceDispatcher {
     protected Delegator delegator = null;
     protected GenericEngineFactory factory = null;
     protected Security security = null;
-    protected ConcurrentHashMap<String, LocalDispatcher> localDispatchers = new ConcurrentHashMap<String, LocalDispatcher>();
+    protected Map<String, DispatchContext> localContext = new HashMap<String, DispatchContext>();
     protected Map<String, List<GenericServiceCallback>> callbacks = new HashMap<String, List<GenericServiceCallback>>();
     protected JobManager jm = null;
     protected JmsListenerFactory jlf = null;
@@ -188,25 +174,21 @@ public class ServiceDispatcher {
     }
 
     /**
-     * Registers the LocalDispatcher with this ServiceDispatcher
-     * @param local
+     * Registers the loader with this ServiceDispatcher
+     * @param context the context of the local dispatcher
      */
-    public LocalDispatcher register(LocalDispatcher local) {
-        if (Debug.infoOn()) {
-            Debug.logInfo("Registering dispatcher: " + local.getName(), module);
-        }
-        localDispatchers.putIfAbsent(local.getName(), local);
-        return localDispatchers.get(local.getName());
+    public void register(DispatchContext context) {
+        if (Debug.infoOn()) Debug.logInfo("Registering dispatcher: " + context.getName(), module);
+        this.localContext.put(context.getName(), context);
     }
-
     /**
      * De-Registers the loader with this ServiceDispatcher
      * @param local the LocalDispatcher to de-register
      */
     public void deregister(LocalDispatcher local) {
         if (Debug.infoOn()) Debug.logInfo("De-Registering dispatcher: " + local.getName(), module);
-        localDispatchers.remove(local.getName());
-        if (localDispatchers.size() == 0) {
+        localContext.remove(local.getName());
+        if (localContext.size() == 0) {
             try {
                  this.shutdown();
              } catch (GenericServiceException e) {
@@ -273,7 +255,7 @@ public class ServiceDispatcher {
         Map<String, List<ServiceEcaRule>> eventMap = null;
         Map<String, Object> ecaContext = null;
         RunningService rs = null;
-        DispatchContext ctx = getLocalContext(localName);
+        DispatchContext ctx = localContext.get(localName);
         GenericEngine engine = null;
         Transaction parentTransaction = null;
         boolean isFailure = false;
@@ -659,7 +641,7 @@ public class ServiceDispatcher {
         Locale locale = this.checkLocale(context);
 
         // setup the engine and context
-        DispatchContext ctx = getLocalContext(localName);
+        DispatchContext ctx = localContext.get(localName);
         GenericEngine engine = this.getGenericEngine(service.engineName);
 
         // for isolated transactions
@@ -840,11 +822,7 @@ public class ServiceDispatcher {
      * @param name of the context to find.
      */
     public DispatchContext getLocalContext(String name) {
-        LocalDispatcher local = localDispatchers.get(name);
-        if (local != null) {
-            return new DispatchContext(local);
-        }
-        return null;
+        return localContext.get(name);
     }
 
     /**
@@ -853,7 +831,7 @@ public class ServiceDispatcher {
      * @return LocalDispatcher matching the loader name
      */
     public LocalDispatcher getLocalDispatcher(String name) {
-        return localDispatchers.get(name);
+        return localContext.get(name).getDispatcher();
     }
 
     /**
@@ -862,7 +840,7 @@ public class ServiceDispatcher {
      * @return true if the local context is found in this dispatcher.
      */
     public boolean containsContext(String name) {
-        return localDispatchers.containsKey(name);
+        return localContext.containsKey(name);
     }
 
     protected void shutdown() throws GenericServiceException {
@@ -1075,58 +1053,4 @@ public class ServiceDispatcher {
         return runLog;
     }
 
-    private Callable<Map<String, ModelService>> createServiceReaderCallable(final ResourceHandler handler) {
-        return new Callable<Map<String, ModelService>>() {
-            public Map<String, ModelService> call() throws Exception {
-                return ModelServiceReader.getModelServiceMap(handler, delegator);
-            }
-        };
-    }
-
-    Map<String, ModelService> getGlobalServiceMap(String model) {
-        Map<String, ModelService> serviceMap = modelServiceMapByModel.get(model);
-        if (serviceMap == null) {
-            serviceMap = new HashMap<String, ModelService>();
-            List<Future<Map<String, ModelService>>> futures = new LinkedList<Future<Map<String, ModelService>>>();
-            List<GlobalServices> globalServicesList = null;
-            try {
-                globalServicesList = ServiceConfigUtil.getServiceEngine().getGlobalServices();
-            } catch (GenericConfigException e) {
-                // FIXME: Refactor API so exceptions can be thrown and caught.
-                Debug.logError(e, module);
-                throw new RuntimeException(e.getMessage());
-            }
-            for (GlobalServices globalServices : globalServicesList) {
-                ResourceHandler handler = new MainResourceHandler(ServiceConfigUtil.SERVICE_ENGINE_XML_FILENAME, globalServices.getLoader(), globalServices.getLocation());
-                futures.add(ExecutionPool.GLOBAL_FORK_JOIN.submit(createServiceReaderCallable(handler)));
-            }
-
-            // get all of the component resource model stuff, ie specified in each ofbiz-component.xml file
-            for (ComponentConfig.ServiceResourceInfo componentResourceInfo: ComponentConfig.getAllServiceResourceInfos("model")) {
-                futures.add(ExecutionPool.GLOBAL_FORK_JOIN.submit(createServiceReaderCallable(componentResourceInfo.createResourceHandler())));
-            }
-            for (Map<String, ModelService> servicesMap: ExecutionPool.getAllFutures(futures)) {
-                if (servicesMap != null) {
-                    serviceMap.putAll(servicesMap);
-                }
-            }
-            for (ModelService modelService : serviceMap.values()) {
-                if (!modelService.inheritedParameters()) {
-                    try {
-                        modelService.interfaceUpdate(serviceMap);
-                    } catch (GenericServiceException e) {
-                        Debug.logError(e, module);
-                        throw new RuntimeException(e.getMessage());
-                    }
-                }
-            }
-            serviceMap = Collections.unmodifiableMap(serviceMap);
-            Map<String, ModelService> cachedServiceMap = modelServiceMapByModel.putIfAbsentAndGet(model, serviceMap);
-            if (cachedServiceMap == serviceMap) { // same object: this means that the object created by this thread was actually added to the cache
-                ServiceEcaUtil.reloadConfig();
-            }
-        }
-        return serviceMap;
-    }
-
 }

Modified: ofbiz/trunk/framework/webtools/src/org/ofbiz/webtools/artifactinfo/ArtifactInfoFactory.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/webtools/src/org/ofbiz/webtools/artifactinfo/ArtifactInfoFactory.java?rev=1657714&r1=1657713&r2=1657714&view=diff
==============================================================================
--- ofbiz/trunk/framework/webtools/src/org/ofbiz/webtools/artifactinfo/ArtifactInfoFactory.java (original)
+++ ofbiz/trunk/framework/webtools/src/org/ofbiz/webtools/artifactinfo/ArtifactInfoFactory.java Thu Feb  5 23:25:50 2015
@@ -51,9 +51,7 @@ import org.ofbiz.entity.model.ModelEntit
 import org.ofbiz.entity.model.ModelReader;
 import org.ofbiz.service.DispatchContext;
 import org.ofbiz.service.GenericServiceException;
-import org.ofbiz.service.LocalDispatcher;
 import org.ofbiz.service.ModelService;
-import org.ofbiz.service.ServiceContainer;
 import org.ofbiz.service.eca.ServiceEcaRule;
 import org.ofbiz.webapp.control.ConfigXMLReader;
 import org.ofbiz.webapp.control.ConfigXMLReader.ControllerConfig;
@@ -133,13 +131,16 @@ public class ArtifactInfoFactory {
         this.delegatorName = delegatorName;
         this.entityModelReader = ModelReader.getModelReader(delegatorName);
         DelegatorElement delegatorInfo = EntityConfig.getInstance().getDelegator(delegatorName);
-        String modelName = "main";
+        String modelName;
         if (delegatorInfo != null) {
             modelName = delegatorInfo.getEntityModelReader();
+        } else {
+            modelName = "main";
         }
-        Delegator delegator = DelegatorFactory.getDelegator(delegatorName);
-        LocalDispatcher dispatcher = ServiceContainer.getLocalDispatcher(modelName, delegator);
-        this.dispatchContext = dispatcher.getDispatchContext();
+        // since we do not associate a dispatcher to this DispatchContext, it is important to set a name of an existing entity model reader:
+        // in this way it will be possible to retrieve the service models from the cache
+        this.dispatchContext = new DispatchContext(modelName, this.getClass().getClassLoader(), null);
+
         this.prepareAll();
     }
 

Modified: ofbiz/trunk/framework/webtools/src/org/ofbiz/webtools/labelmanager/LabelReferences.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/webtools/src/org/ofbiz/webtools/labelmanager/LabelReferences.java?rev=1657714&r1=1657713&r2=1657714&view=diff
==============================================================================
--- ofbiz/trunk/framework/webtools/src/org/ofbiz/webtools/labelmanager/LabelReferences.java (original)
+++ ofbiz/trunk/framework/webtools/src/org/ofbiz/webtools/labelmanager/LabelReferences.java Thu Feb  5 23:25:50 2015
@@ -47,10 +47,8 @@ import org.ofbiz.entity.model.ModelEntit
 import org.ofbiz.entity.model.ModelField;
 import org.ofbiz.service.DispatchContext;
 import org.ofbiz.service.GenericServiceException;
-import org.ofbiz.service.LocalDispatcher;
 import org.ofbiz.service.ModelParam;
 import org.ofbiz.service.ModelService;
-import org.ofbiz.service.ServiceContainer;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.xml.sax.SAXException;
@@ -79,12 +77,15 @@ public class LabelReferences {
         } catch (GenericEntityConfException e) {
             Debug.logWarning(e, "Exception thrown while getting delegator config: ", module);
         }
-        String modelName = "main";
+        String modelName;
         if (delegatorInfo != null) {
             modelName = delegatorInfo.getEntityModelReader();
+        } else {
+            modelName = "main";
         }
-        LocalDispatcher dispatcher = ServiceContainer.getLocalDispatcher(modelName, delegator);
-        this.dispatchContext = dispatcher.getDispatchContext();
+        // since we do not associate a dispatcher to this DispatchContext, it is important to set a name of an existing entity model reader:
+        // in this way it will be possible to retrieve the service models from the cache
+        this.dispatchContext = new DispatchContext(modelName, this.getClass().getClassLoader(), null);
         Collection<LabelInfo> infoList = this.labels.values();
         for (LabelInfo labelInfo : infoList) {
             this.labelSet.add(labelInfo.getLabelKey());