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 2014/09/03 15:45:44 UTC
svn commit: r1622256 - in /ofbiz/trunk/framework:
service/src/org/ofbiz/service/ webtools/src/org/ofbiz/webtools/artifactinfo/
webtools/src/org/ofbiz/webtools/labelmanager/
Author: adrianc
Date: Wed Sep 3 13:45:44 2014
New Revision: 1622256
URL: http://svn.apache.org/r1622256
Log:
A code cleanup/reorganization in the service engine.
The LocalDispatcher dispatcher is supposed to represent the state of a single application, but that state was split between LocalDispatcher and DispatchContext. In addition, both classes shared a lot of fields.
This commit moves application state to LocalDispatcher and DispatchContext becomes a lightweight container for objects service implementations need to use.
In addition, some minor thread-safety issues were fixed.
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=1622256&r1=1622255&r2=1622256&view=diff
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/DispatchContext.java (original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/DispatchContext.java Wed Sep 3 13:45:44 2014
@@ -19,86 +19,28 @@
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;
/**
- * Dispatcher Context
+ * Service dispatch context. A collection of objects and convenience methods
+ * to be used by service implementations.
*/
@SuppressWarnings("serial")
-public class DispatchContext implements Serializable {
+public final class DispatchContext implements Serializable {
public static final String module = DispatchContext.class.getName();
- private static final UtilCache<String, Map<String, ModelService>> modelServiceMapByModel = UtilCache.createUtilCache("service.ModelServiceMapByModel", 0, 0, false);
+ private final 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;
+ DispatchContext(LocalDispatcher dispatcher) {
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();
}
/**
@@ -106,7 +48,7 @@ public class DispatchContext implements
* @return ClassLoader of the context
*/
public ClassLoader getClassLoader() {
- return this.loader;
+ return dispatcher.getClassLoader();
}
/**
@@ -114,7 +56,7 @@ public class DispatchContext implements
* @return String name of the LocalDispatcher object
*/
public String getName() {
- return name;
+ return dispatcher.getName();
}
/**
@@ -122,7 +64,7 @@ public class DispatchContext implements
* @return LocalDispatcher that was used to create this context
*/
public LocalDispatcher getDispatcher() {
- return this.dispatcher;
+ return dispatcher;
}
/**
@@ -199,84 +141,20 @@ public class DispatchContext implements
}
/**
- * Gets the ModelService instance that corresponds to given the name
+ * Gets the ModelService instance that corresponds to the given name
* @param serviceName Name of the service
* @return GenericServiceModel that corresponds to the serviceName
*/
public ModelService getModelService(String serviceName) throws GenericServiceException {
- 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;
+ return dispatcher.getModelService(serviceName);
}
public Set<String> getAllServiceNames() {
- Set<String> serviceNames = new TreeSet<String>();
-
- Map<String, ModelService> globalServices = modelServiceMapByModel.get(this.model);
- if (globalServices != null) {
- serviceNames.addAll(globalServices.keySet());
- }
- return serviceNames;
+ return dispatcher.getAllServiceNames();
}
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=1622256&r1=1622255&r2=1622256&view=diff
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/GenericAbstractDispatcher.java (original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/GenericAbstractDispatcher.java Wed Sep 3 13:45:44 2014
@@ -40,8 +40,7 @@ public abstract class GenericAbstractDis
public static final String module = GenericAbstractDispatcher.class.getName();
- protected DispatchContext ctx = null;
- protected ServiceDispatcher dispatcher = null;
+ protected ServiceDispatcher globalDispatcher = null;
protected String name = null;
public GenericAbstractDispatcher() {}
@@ -135,7 +134,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 = ctx.getModelService(serviceName);
+ ModelService model = getModelService(serviceName);
schedule(null, serviceName, context, startTime, frequency, interval, count, endTime, model.maxRetry);
}
@@ -180,28 +179,28 @@ public abstract class GenericAbstractDis
* @see org.ofbiz.service.LocalDispatcher#getJobManager()
*/
public JobManager getJobManager() {
- return dispatcher.getJobManager();
+ return globalDispatcher.getJobManager();
}
/**
* @see org.ofbiz.service.LocalDispatcher#getJMSListeneFactory()
*/
public JmsListenerFactory getJMSListeneFactory() {
- return dispatcher.getJMSListenerFactory();
+ return globalDispatcher.getJMSListenerFactory();
}
/**
* @see org.ofbiz.service.LocalDispatcher#getDelegator()
*/
public Delegator getDelegator() {
- return dispatcher.getDelegator();
+ return globalDispatcher.getDelegator();
}
/**
* @see org.ofbiz.service.LocalDispatcher#getSecurity()
*/
public Security getSecurity() {
- return dispatcher.getSecurity();
+ return globalDispatcher.getSecurity();
}
/**
@@ -212,25 +211,18 @@ 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());
- dispatcher.deregister(this);
+ globalDispatcher.deregister(this);
}
/**
* @see org.ofbiz.service.LocalDispatcher#registerCallback(String, GenericServiceCallback)
*/
public void registerCallback(String serviceName, GenericServiceCallback cb) {
- dispatcher.registerCallback(serviceName, cb);
+ globalDispatcher.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=1622256&r1=1622255&r2=1622256&view=diff
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/GenericDispatcherFactory.java (original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/GenericDispatcherFactory.java Wed Sep 3 13:45:44 2014
@@ -19,16 +19,22 @@
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
@@ -36,11 +42,25 @@ 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 DispatchContext with the name "name"
+ // attempts to retrieve an already registered LocalDispatcher with the name "name"
LocalDispatcher dispatcher = ServiceDispatcher.getLocalDispatcher(name, delegator);
- // if not found then create a new GenericDispatcher object; the constructor will also register a new DispatchContext in the ServiceDispatcher with name "dispatcherName"
+ // if not found then create a new GenericDispatcher object
if (dispatcher == null) {
- dispatcher = new GenericDispatcher(name, delegator);
+ 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));
}
return dispatcher;
}
@@ -48,23 +68,23 @@ public class GenericDispatcherFactory im
// The default LocalDispatcher implementation.
private class GenericDispatcher extends GenericAbstractDispatcher {
- private GenericDispatcher(String name, Delegator delegator) {
+ private final ClassLoader loader;
+ private final Map<String, ModelService> serviceMap;
+
+ private GenericDispatcher(String name, ServiceDispatcher globalDispatcher, Map<String, ModelService> serviceMap) {
ClassLoader loader;
try {
loader = Thread.currentThread().getContextClassLoader();
} catch (SecurityException e) {
loader = this.getClass().getClassLoader();
}
+ this.loader = loader;
this.name = name;
- 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);
+ this.globalDispatcher = globalDispatcher;
+ this.serviceMap = serviceMap;
+ if (Debug.verboseOn()) {
+ Debug.logVerbose("Created Dispatcher for: " + name, module);
+ }
}
@Override
@@ -83,14 +103,16 @@ public class GenericDispatcherFactory im
}
@Override
- 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);
+ 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);
}
@Override
- 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);
+ public Map<String, Object> runSync(String serviceName, Map<String, ? extends Object> context, int transactionTimeout,
+ boolean requireNewTransaction) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+ ModelService service = getModelService(serviceName);
// clone the model service for updates
ModelService cloned = new ModelService(service);
cloned.requireNewTransaction = requireNewTransaction;
@@ -100,23 +122,25 @@ public class GenericDispatcherFactory im
if (transactionTimeout != -1) {
cloned.transactionTimeout = transactionTimeout;
}
- return dispatcher.runSync(this.name, cloned, context);
+ return globalDispatcher.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 = ctx.getModelService(serviceName);
- dispatcher.runSyncIgnore(this.name, service, context);
+ ModelService service = getModelService(serviceName);
+ globalDispatcher.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 = ctx.getModelService(serviceName);
+ public void runSyncIgnore(String serviceName, Map<String, ? extends Object> context, int transactionTimeout,
+ boolean requireNewTransaction) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+ ModelService service = getModelService(serviceName);
// clone the model service for updates
ModelService cloned = new ModelService(service);
cloned.requireNewTransaction = requireNewTransaction;
@@ -126,17 +150,20 @@ public class GenericDispatcherFactory im
if (transactionTimeout != -1) {
cloned.transactionTimeout = transactionTimeout;
}
- dispatcher.runSyncIgnore(this.name, cloned, context);
+ globalDispatcher.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 = ctx.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 = getModelService(serviceName);
// clone the model service for updates
ModelService cloned = new ModelService(service);
cloned.requireNewTransaction = requireNewTransaction;
@@ -146,67 +173,104 @@ public class GenericDispatcherFactory im
if (transactionTimeout != -1) {
cloned.transactionTimeout = transactionTimeout;
}
- dispatcher.runAsync(this.name, cloned, context, requester, persist);
+ globalDispatcher.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 = ctx.getModelService(serviceName);
- dispatcher.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 = getModelService(serviceName);
+ globalDispatcher.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 = ctx.getModelService(serviceName);
- dispatcher.runAsync(this.name, service, context, persist);
+ 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);
}
@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=1622256&r1=1622255&r2=1622256&view=diff
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/LocalDispatcher.java (original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/LocalDispatcher.java Wed Sep 3 13:45:44 2014
@@ -19,6 +19,7 @@
package org.ofbiz.service;
import java.util.Map;
+import java.util.Set;
import org.ofbiz.entity.Delegator;
import org.ofbiz.security.Security;
@@ -26,11 +27,11 @@ import org.ofbiz.service.jms.JmsListener
import org.ofbiz.service.job.JobManager;
/**
- * 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>
+ * 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>
*/
public interface LocalDispatcher {
@@ -345,5 +346,11 @@ 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=1622256&r1=1622255&r2=1622256&view=diff
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelService.java (original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelService.java Wed Sep 3 13:45:44 2014
@@ -1092,9 +1092,9 @@ public class ModelService extends Abstra
/**
* Run the interface update and inherit all interface parameters
- * @param dctx The DispatchContext to use for service lookups
+ * @param serviceMap The Map to use for service lookups
*/
- public synchronized void interfaceUpdate(DispatchContext dctx) throws GenericServiceException {
+ public synchronized void interfaceUpdate(Map<String, ModelService> serviceMap) throws GenericServiceException {
if (!inheritedParameters) {
// services w/ engine 'group' auto-implement the grouped services
if (this.engineName.equals("group") && implServices.size() == 0) {
@@ -1111,13 +1111,15 @@ public class ModelService extends Abstra
}
// handle interfaces
- if (UtilValidate.isNotEmpty(implServices) && dctx != null) {
+ if (UtilValidate.isNotEmpty(implServices) && serviceMap != null) {
for (ModelServiceIface iface: implServices) {
String serviceName = iface.getService();
boolean optional = iface.isOptional();
-
- ModelService model = dctx.getModelService(serviceName);
+ ModelService model = serviceMap.get(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=1622256&r1=1622255&r2=1622256&view=diff
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java (original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java Wed Sep 3 13:45:44 2014
@@ -18,22 +18,30 @@
*******************************************************************************/
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;
@@ -46,6 +54,7 @@ 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;
@@ -60,8 +69,12 @@ import org.ofbiz.service.semaphore.Servi
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
/**
- * The global service dispatcher. This is the "engine" part of the
- * Service Engine.
+ * 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>
*/
public class ServiceDispatcher {
@@ -69,6 +82,7 @@ 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.
@@ -80,7 +94,7 @@ public class ServiceDispatcher {
protected Delegator delegator = null;
protected GenericEngineFactory factory = null;
protected Security security = null;
- protected Map<String, DispatchContext> localContext = new HashMap<String, DispatchContext>();
+ protected ConcurrentHashMap<String, LocalDispatcher> localDispatchers = new ConcurrentHashMap<String, LocalDispatcher>();
protected Map<String, List<GenericServiceCallback>> callbacks = new HashMap<String, List<GenericServiceCallback>>();
protected JobManager jm = null;
protected JmsListenerFactory jlf = null;
@@ -174,21 +188,25 @@ public class ServiceDispatcher {
}
/**
- * Registers the loader with this ServiceDispatcher
- * @param context the context of the local dispatcher
+ * Registers the LocalDispatcher with this ServiceDispatcher
+ * @param local
*/
- public void register(DispatchContext context) {
- if (Debug.infoOn()) Debug.logInfo("Registering dispatcher: " + context.getName(), module);
- this.localContext.put(context.getName(), context);
+ 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());
}
+
/**
* 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);
- localContext.remove(local.getName());
- if (localContext.size() == 0) {
+ localDispatchers.remove(local.getName());
+ if (localDispatchers.size() == 0) {
try {
this.shutdown();
} catch (GenericServiceException e) {
@@ -255,7 +273,7 @@ public class ServiceDispatcher {
Map<String, List<ServiceEcaRule>> eventMap = null;
Map<String, Object> ecaContext = null;
RunningService rs = null;
- DispatchContext ctx = localContext.get(localName);
+ DispatchContext ctx = getLocalContext(localName);
GenericEngine engine = null;
Transaction parentTransaction = null;
boolean isFailure = false;
@@ -641,7 +659,7 @@ public class ServiceDispatcher {
Locale locale = this.checkLocale(context);
// setup the engine and context
- DispatchContext ctx = localContext.get(localName);
+ DispatchContext ctx = getLocalContext(localName);
GenericEngine engine = this.getGenericEngine(service.engineName);
// for isolated transactions
@@ -822,7 +840,11 @@ public class ServiceDispatcher {
* @param name of the context to find.
*/
public DispatchContext getLocalContext(String name) {
- return localContext.get(name);
+ LocalDispatcher local = localDispatchers.get(name);
+ if (local != null) {
+ return new DispatchContext(local);
+ }
+ return null;
}
/**
@@ -831,7 +853,7 @@ public class ServiceDispatcher {
* @return LocalDispatcher matching the loader name
*/
public LocalDispatcher getLocalDispatcher(String name) {
- return localContext.get(name).getDispatcher();
+ return localDispatchers.get(name);
}
/**
@@ -840,7 +862,7 @@ public class ServiceDispatcher {
* @return true if the local context is found in this dispatcher.
*/
public boolean containsContext(String name) {
- return localContext.containsKey(name);
+ return localDispatchers.containsKey(name);
}
protected void shutdown() throws GenericServiceException {
@@ -1053,4 +1075,58 @@ 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=1622256&r1=1622255&r2=1622256&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 Wed Sep 3 13:45:44 2014
@@ -47,9 +47,12 @@ import org.ofbiz.entity.config.model.Del
import org.ofbiz.entity.config.model.EntityConfig;
import org.ofbiz.entity.model.ModelEntity;
import org.ofbiz.entity.model.ModelReader;
+import org.ofbiz.entity.*;
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;
@@ -129,16 +132,13 @@ public class ArtifactInfoFactory {
this.delegatorName = delegatorName;
this.entityModelReader = ModelReader.getModelReader(delegatorName);
DelegatorElement delegatorInfo = EntityConfig.getInstance().getDelegator(delegatorName);
- String modelName;
+ String modelName = "main";
if (delegatorInfo != null) {
modelName = delegatorInfo.getEntityModelReader();
- } else {
- modelName = "main";
}
- // 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);
-
+ Delegator delegator = DelegatorFactory.getDelegator(delegatorName);
+ LocalDispatcher dispatcher = ServiceContainer.getLocalDispatcher(modelName, delegator);
+ this.dispatchContext = dispatcher.getDispatchContext();
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=1622256&r1=1622255&r2=1622256&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 Wed Sep 3 13:45:44 2014
@@ -47,8 +47,10 @@ 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;
@@ -77,15 +79,12 @@ public class LabelReferences {
} catch (GenericEntityConfException e) {
Debug.logWarning(e, "Exception thrown while getting delegator config: ", module);
}
- String modelName;
+ String modelName = "main";
if (delegatorInfo != null) {
modelName = delegatorInfo.getEntityModelReader();
- } else {
- modelName = "main";
}
- // 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);
+ LocalDispatcher dispatcher = ServiceContainer.getLocalDispatcher(modelName, delegator);
+ this.dispatchContext = dispatcher.getDispatchContext();
Collection<LabelInfo> infoList = this.labels.values();
for (LabelInfo labelInfo : infoList) {
this.labelSet.add(labelInfo.getLabelKey());