org.activiti.engine.ProcessEngines Maven / Gradle / Ivy
The newest version!
/* Licensed 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.activiti.engine;
import org.activiti.engine.impl.ProcessEngineInfoImpl;
import org.activiti.engine.impl.util.IoUtil;
import org.activiti.engine.impl.util.ReflectUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
/**
* Helper for initializing and closing process engines in server environments.
* All created {@link ProcessEngine}s will be registered with this class.
* The activiti-webapp-init webapp will call the {@link #init()} method when the webapp is deployed and it will call the {@link #destroy()} method when the webapp is destroyed, using a
* context-listener ( org.activiti.impl.servlet.listener.ProcessEnginesServletContextListener
). That way, all applications can just use the {@link #getProcessEngines()} to obtain
* pre-initialized and cached process engines.
*
* Please note that there is no lazy initialization of process engines, so make sure the context-listener is configured or {@link ProcessEngine}s are already created so they were registered on
* this class.
*
* The {@link #init()} method will try to build one {@link ProcessEngine} for each activiti.cfg.xml file found on the classpath. If you have more then one, make sure you specify different
* process.engine.name values.
*
*/
public abstract class ProcessEngines {
private static Logger log = LoggerFactory.getLogger(ProcessEngines.class);
public static final String NAME_DEFAULT = "default";
protected static boolean isInitialized;
protected static Map processEngines = new HashMap();
protected static Map processEngineInfosByName = new HashMap();
protected static Map processEngineInfosByResourceUrl = new HashMap();
protected static List processEngineInfos = new ArrayList();
/**
* Initializes all process engines that can be found on the classpath for resources activiti.cfg.xml
(plain Activiti style configuration) and for resources
* activiti-context.xml
(Spring style configuration).
*/
public synchronized static void init() {
if (!isInitialized()) {
if (processEngines == null) {
// Create new map to store process-engines if current map is
// null
processEngines = new HashMap();
}
ClassLoader classLoader = ReflectUtil.getClassLoader();
Enumeration resources = null;
try {
resources = classLoader.getResources("activiti.cfg.xml");
} catch (IOException e) {
throw new ActivitiIllegalArgumentException("problem retrieving activiti.cfg.xml resources on the classpath: " + System.getProperty("java.class.path"), e);
}
// Remove duplicated configuration URL's using set. Some
// classloaders may return identical URL's twice, causing duplicate
// startups
Set configUrls = new HashSet();
while (resources.hasMoreElements()) {
configUrls.add(resources.nextElement());
}
for (Iterator iterator = configUrls.iterator(); iterator.hasNext();) {
URL resource = iterator.next();
log.info("Initializing process engine using configuration '{}'", resource.toString());
initProcessEngineFromResource(resource);
}
try {
resources = classLoader.getResources("activiti-context.xml");
} catch (IOException e) {
throw new ActivitiIllegalArgumentException("problem retrieving activiti-context.xml resources on the classpath: " + System.getProperty("java.class.path"), e);
}
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
log.info("Initializing process engine using Spring configuration '{}'", resource.toString());
initProcessEngineFromSpringResource(resource);
}
setInitialized(true);
} else {
log.info("Process engines already initialized");
}
}
protected static void initProcessEngineFromSpringResource(URL resource) {
try {
Class> springConfigurationHelperClass = ReflectUtil.loadClass("org.activiti.spring.SpringConfigurationHelper");
Method method = springConfigurationHelperClass.getDeclaredMethod("buildProcessEngine", new Class>[] { URL.class });
ProcessEngine processEngine = (ProcessEngine) method.invoke(null, new Object[] { resource });
String processEngineName = processEngine.getName();
ProcessEngineInfo processEngineInfo = new ProcessEngineInfoImpl(processEngineName, resource.toString(), null);
processEngineInfosByName.put(processEngineName, processEngineInfo);
processEngineInfosByResourceUrl.put(resource.toString(), processEngineInfo);
} catch (Exception e) {
throw new ActivitiException("couldn't initialize process engine from spring configuration resource " + resource.toString() + ": " + e.getMessage(), e);
}
}
/**
* Registers the given process engine. No {@link ProcessEngineInfo} will be available for this process engine. An engine that is registered will be closed when the {@link ProcessEngines#destroy()}
* is called.
*/
public static void registerProcessEngine(ProcessEngine processEngine) {
processEngines.put(processEngine.getName(), processEngine);
}
/**
* Unregisters the given process engine.
*/
public static void unregister(ProcessEngine processEngine) {
processEngines.remove(processEngine.getName());
}
private static ProcessEngineInfo initProcessEngineFromResource(URL resourceUrl) {
ProcessEngineInfo processEngineInfo = processEngineInfosByResourceUrl.get(resourceUrl.toString());
// if there is an existing process engine info
if (processEngineInfo != null) {
// remove that process engine from the member fields
processEngineInfos.remove(processEngineInfo);
if (processEngineInfo.getException() == null) {
String processEngineName = processEngineInfo.getName();
processEngines.remove(processEngineName);
processEngineInfosByName.remove(processEngineName);
}
processEngineInfosByResourceUrl.remove(processEngineInfo.getResourceUrl());
}
String resourceUrlString = resourceUrl.toString();
try {
log.info("initializing process engine for resource {}", resourceUrl);
ProcessEngine processEngine = buildProcessEngine(resourceUrl);
String processEngineName = processEngine.getName();
log.info("initialised process engine {}", processEngineName);
processEngineInfo = new ProcessEngineInfoImpl(processEngineName, resourceUrlString, null);
processEngines.put(processEngineName, processEngine);
processEngineInfosByName.put(processEngineName, processEngineInfo);
} catch (Throwable e) {
log.error("Exception while initializing process engine: {}", e.getMessage(), e);
processEngineInfo = new ProcessEngineInfoImpl(null, resourceUrlString, getExceptionString(e));
}
processEngineInfosByResourceUrl.put(resourceUrlString, processEngineInfo);
processEngineInfos.add(processEngineInfo);
return processEngineInfo;
}
private static String getExceptionString(Throwable e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
return sw.toString();
}
private static ProcessEngine buildProcessEngine(URL resource) {
InputStream inputStream = null;
try {
inputStream = resource.openStream();
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(inputStream);
return processEngineConfiguration.buildProcessEngine();
} catch (IOException e) {
throw new ActivitiIllegalArgumentException("couldn't open resource stream: " + e.getMessage(), e);
} finally {
IoUtil.closeSilently(inputStream);
}
}
/** Get initialization results. */
public static List getProcessEngineInfos() {
return processEngineInfos;
}
/**
* Get initialization results. Only info will we available for process engines which were added in the {@link ProcessEngines#init()}. No {@link ProcessEngineInfo} is available for engines which were
* registered programatically.
*/
public static ProcessEngineInfo getProcessEngineInfo(String processEngineName) {
return processEngineInfosByName.get(processEngineName);
}
public static ProcessEngine getDefaultProcessEngine() {
return getProcessEngine(NAME_DEFAULT);
}
/**
* obtain a process engine by name.
*
* @param processEngineName
* is the name of the process engine or null for the default process engine.
*/
public static ProcessEngine getProcessEngine(String processEngineName) {
if (!isInitialized()) {
init();
}
return processEngines.get(processEngineName);
}
/**
* retries to initialize a process engine that previously failed.
*/
public static ProcessEngineInfo retry(String resourceUrl) {
log.debug("retying initializing of resource {}", resourceUrl);
try {
return initProcessEngineFromResource(new URL(resourceUrl));
} catch (MalformedURLException e) {
throw new ActivitiIllegalArgumentException("invalid url: " + resourceUrl, e);
}
}
/**
* provides access to process engine to application clients in a managed server environment.
*/
public static Map getProcessEngines() {
return processEngines;
}
/**
* closes all process engines. This method should be called when the server shuts down.
*/
public synchronized static void destroy() {
if (isInitialized()) {
Map engines = new HashMap(processEngines);
processEngines = new HashMap();
for (String processEngineName : engines.keySet()) {
ProcessEngine processEngine = engines.get(processEngineName);
try {
processEngine.close();
} catch (Exception e) {
log.error("exception while closing {}", (processEngineName == null ? "the default process engine" : "process engine " + processEngineName), e);
}
}
processEngineInfosByName.clear();
processEngineInfosByResourceUrl.clear();
processEngineInfos.clear();
setInitialized(false);
}
}
public static boolean isInitialized() {
return isInitialized;
}
public static void setInitialized(boolean isInitialized) {
ProcessEngines.isInitialized = isInitialized;
}
}