blob: c6b7e11b4c7b49e6d0bfa0ea1afa6442cd77d3a9 [file] [log] [blame]
/*******************************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*******************************************************************************/
package org.ofbiz.service;
import java.io.Serializable;
import java.net.URL;
import java.util.Collection;
import java.util.HashMap;
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 javolution.util.FastList;
import javolution.util.FastMap;
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.UtilXml;
import org.ofbiz.base.util.cache.UtilCache;
import org.ofbiz.entity.Delegator;
import org.ofbiz.security.Security;
import org.ofbiz.security.authz.Authorization;
import org.ofbiz.service.config.ServiceConfigUtil;
import org.ofbiz.service.eca.ServiceEcaUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Dispatcher Context
*/
@SuppressWarnings("serial")
public class DispatchContext implements Serializable {
public static final String module = DispatchContext.class.getName();
protected static final String GLOBAL_KEY = "global.services";
public static UtilCache<String, Map<String, ModelService>> modelServiceMapByDispatcher = UtilCache.createUtilCache("service.ModelServiceMapByDispatcher", 0, 0, false);
protected transient LocalDispatcher dispatcher;
protected transient ClassLoader loader;
protected Collection<URL> localReaders;
protected Map<String, Object> attributes;
protected String name;
/**
* Creates new DispatchContext
* @param localReaders a collection of reader URLs
* @param loader the classloader to use for dispatched services
*/
public DispatchContext(String name, Collection<URL> localReaders, ClassLoader loader, LocalDispatcher dispatcher) {
this.name = name;
this.localReaders = localReaders;
this.loader = loader;
this.dispatcher = dispatcher;
this.attributes = FastMap.newInstance();
}
public void loadReaders() {
this.getLocalServiceMap();
this.getGlobalServiceMap();
}
/**
* Returns the service attribute for the given name, or null if there is no attribute by that name.
* @param name a String specifying the name of the attribute
* @return an Object containing the value of the attribute, or null if there is no attribute by that name.
*/
public Object getAttribute(String name) {
if (attributes.containsKey(name))
return attributes.get(name);
return null;
}
/**
* Binds an object to a given attribute name in this context.
* @param name a String specifying the name of the attribute
* @param object an Object representing the attribute to be bound.
*/
public void setAttribute(String name, Object object) {
attributes.put(name, object);
}
/**
* Gets the classloader of this context
* @return ClassLoader of the context
*/
public ClassLoader getClassLoader() {
return this.loader;
}
/**
* Gets the collection of readers associated with this context
* @return Collection of reader URLs
*/
public Collection<URL> getReaders() {
return localReaders;
}
/**
* Gets the name of the local dispatcher
* @return String name of the LocalDispatcher object
*/
public String getName() {
return name;
}
/**
* Uses an existing map of name value pairs and extracts the keys which are used in serviceName
* Note: This goes not guarantee the context will be 100% valid, there may be missing fields
* @param serviceName The name of the service to obtain parameters for
* @param mode The mode to use for building the new map (i.e. can be IN or OUT)
* @param context The initial set of values to pull from
* @return Map contains any valid values
* @throws GenericServiceException
*/
public Map<String, Object> makeValidContext(String serviceName, String mode, Map<String, ? extends Object> context) throws GenericServiceException {
ModelService model = this.getModelService(serviceName);
return makeValidContext(model, mode, context);
}
/**
* Uses an existing map of name value pairs and extracts the keys which are used in serviceName
* Note: This goes not guarantee the context will be 100% valid, there may be missing fields
* @param model The ModelService object of the service to obtain parameters for
* @param mode The mode to use for building the new map (i.e. can be IN or OUT)
* @param context The initial set of values to pull from
* @return Map contains any valid values
* @throws GenericServiceException
*/
public Map<String, Object> makeValidContext(ModelService model, String mode, Map<String, ? extends Object> context) throws GenericServiceException {
Map<String, Object> newContext;
int modeInt = 0;
if (mode.equalsIgnoreCase("in")) {
modeInt = 1;
} else if (mode.equalsIgnoreCase("out")) {
modeInt = 2;
}
if (model == null) {
throw new GenericServiceException("Model service is null! Should never happen.");
} else {
switch (modeInt) {
case 2:
newContext = model.makeValid(context, ModelService.OUT_PARAM, true, null);
break;
case 1:
newContext = model.makeValid(context, ModelService.IN_PARAM, true, null);
break;
default:
throw new GenericServiceException("Invalid mode, should be either IN or OUT");
}
return newContext;
}
}
/**
* 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 {
//long timeStart = System.currentTimeMillis();
ModelService retVal = getLocalModelService(serviceName);
if (retVal == null) {
retVal = getGlobalModelService(serviceName);
}
if (retVal == null) {
throw new GenericServiceException("Cannot locate service by name (" + serviceName + ")");
}
//Debug.logTiming("Got ModelService for name [" + serviceName + "] in [" + (System.currentTimeMillis() - timeStart) + "] milliseconds", module);
return retVal;
}
private ModelService getLocalModelService(String serviceName) throws GenericServiceException {
Map<String, ModelService> serviceMap = this.getLocalServiceMap();
ModelService retVal = null;
if (serviceMap != null) {
retVal = serviceMap.get(serviceName);
if (retVal != null && !retVal.inheritedParameters()) {
retVal.interfaceUpdate(this);
}
}
return retVal;
}
private ModelService getGlobalModelService(String serviceName) throws GenericServiceException {
Map<String, ModelService> serviceMap = this.getGlobalServiceMap();
ModelService retVal = null;
if (serviceMap != null) {
retVal = serviceMap.get(serviceName);
if (retVal != null && !retVal.inheritedParameters()) {
retVal.interfaceUpdate(this);
}
}
return retVal;
}
/**
* Gets the LocalDispatcher used with this context
* @return LocalDispatcher that was used to create this context
*/
public LocalDispatcher getDispatcher() {
return this.dispatcher;
}
/**
* Sets the LocalDispatcher used with this context
* @param dispatcher The LocalDispatcher to re-assign to this context
*/
public void setDispatcher(LocalDispatcher dispatcher) {
this.dispatcher = dispatcher;
}
/**
* Gets the Delegator associated with this context/dispatcher
* @return Delegator associated with this context
*/
public Delegator getDelegator() {
return dispatcher.getDelegator();
}
/**
* Gets the Authorization object associated with this dispatcher
* @return Authorization object associated with this dispatcher
*/
public Authorization getAuthorization() {
return dispatcher.getAuthorization();
}
/**
* Gets the Security object associated with this dispatcher
* @return Security object associated with this dispatcher
*/
public Security getSecurity() {
return dispatcher.getSecurity();
}
private Map<String, ModelService> getLocalServiceMap() {
Map<String, ModelService> serviceMap = modelServiceMapByDispatcher.get(name);
if (serviceMap == null) {
synchronized (this) {
serviceMap = modelServiceMapByDispatcher.get(name);
if (serviceMap == null) {
if (this.localReaders != null) {
serviceMap = FastMap.newInstance();
for (URL readerURL: this.localReaders) {
Map<String, ModelService> readerServiceMap = ModelServiceReader.getModelServiceMap(readerURL, this);
if (readerServiceMap != null) {
serviceMap.putAll(readerServiceMap);
}
}
serviceMap = new HashMap<String, ModelService>(serviceMap);
}
if (serviceMap != null) {
modelServiceMapByDispatcher.put(name, serviceMap);
// NOTE: the current ECA per dispatcher for local services stuff is a bit broken, so now just doing this on the global def load: ServiceEcaUtil.reloadConfig();
}
}
}
}
return serviceMap;
}
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);
}
};
}
private Map<String, ModelService> getGlobalServiceMap() {
Map<String, ModelService> serviceMap = modelServiceMapByDispatcher.get(GLOBAL_KEY);
if (serviceMap == null) {
synchronized (this) {
serviceMap = modelServiceMapByDispatcher.get(GLOBAL_KEY);
if (serviceMap == null) {
serviceMap = FastMap.newInstance();
Element rootElement;
try {
rootElement = ServiceConfigUtil.getXmlRootElement();
} catch (GenericConfigException e) {
Debug.logError(e, "Error getting Service Engine XML root element", module);
return null;
}
List<Future<Map<String, ModelService>>> futures = FastList.newInstance();
for (Element globalServicesElement: UtilXml.childElementList(rootElement, "global-services")) {
ResourceHandler handler = new MainResourceHandler(
ServiceConfigUtil.SERVICE_ENGINE_XML_FILENAME, globalServicesElement);
futures.add(ExecutionPool.GLOBAL_EXECUTOR.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_EXECUTOR.submit(createServiceReaderCallable(componentResourceInfo.createResourceHandler())));
}
for (Map<String, ModelService> servicesMap: ExecutionPool.getAllFutures(futures)) {
if (servicesMap != null) {
serviceMap.putAll(servicesMap);
}
}
if (serviceMap != null) {
modelServiceMapByDispatcher.put(GLOBAL_KEY, serviceMap);
ServiceEcaUtil.reloadConfig();
}
}
}
}
return serviceMap;
}
public Set<String> getAllServiceNames() {
Set<String> serviceNames = new TreeSet<String>();
Map<String, ModelService> globalServices = modelServiceMapByDispatcher.get(GLOBAL_KEY);
Map<String, ModelService> localServices = modelServiceMapByDispatcher.get(name);
if (globalServices != null) {
serviceNames.addAll(globalServices.keySet());
}
if (localServices != null) {
serviceNames.addAll(localServices.keySet());
}
return serviceNames;
}
public Document getWSDL(String serviceName, String locationURI) throws GenericServiceException, WSDLException {
ModelService model = this.getModelService(serviceName);
return model.toWSDL(locationURI);
}
}