提交 5b23168b 编写于 作者: F frederikheremans

ACT-265 process-engine is always registered to ProcessEngines + ReflectUtil...

ACT-265 process-engine is always registered to ProcessEngines + ReflectUtil extended to use custom classloader chain
上级 60b12b37
......@@ -251,7 +251,7 @@ public class ProcessEngineBuilder {
}
public ProcessEngineBuilder configureFromPropertiesResource(String propertiesResource) {
InputStream inputStream = ReflectUtil.getClassLoader().getResourceAsStream(propertiesResource);
InputStream inputStream = ReflectUtil.getResourceAsStream(propertiesResource);
if (inputStream == null) {
throw new ActivitiException("configuration properties resource '" + propertiesResource + "' is unavailable on classpath "
+ System.getProperty("java.class.path"));
......@@ -315,6 +315,10 @@ public class ProcessEngineBuilder {
if(jpaEntityManagerFactory != null) {
processEngineConfiguration.enableJPA(jpaEntityManagerFactory, jpaHandleTransaction, jpaCloseEntityManager);
}
return processEngineConfiguration.buildProcessEngine();
ProcessEngine engine = processEngineConfiguration.buildProcessEngine();
ProcessEngines.registerProcessEngine(engine);
return engine;
}
}
......@@ -19,7 +19,6 @@ import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
......@@ -27,11 +26,14 @@ import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.activiti.engine.impl.ProcessEngineImpl;
import org.activiti.engine.impl.ProcessEngineInfoImpl;
import org.activiti.engine.impl.util.ReflectUtil;
/** Helper for initializing and closing process engines in server environments.
* <br>
* All created {@link ProcessEngine}s will be registered with this class.
* <br>
* The activiti-webapp-init webapp will
* call the {@link #init()} method when the webapp is deployed and it will call the
......@@ -41,7 +43,8 @@ import org.activiti.engine.impl.util.ReflectUtil;
* obtain pre-initialized and cached process engines. <br>
* <br>
* Please note that there is <b>no lazy initialization</b> of process engines, so make sure the
* context-listener is configured.<br>
* context-listener is configured or {@link ProcessEngine}s are already created so they were registered
* on this class.<br>
* <br>
* The {@link #init()} method will try to build one {@link ProcessEngine} for
* each activiti.properties file found on the classpath. If you have more then one,
......@@ -61,10 +64,12 @@ public abstract class ProcessEngines {
protected static Map<String, ProcessEngineInfo> processEngineInfosByName = new HashMap<String, ProcessEngineInfo>();
protected static Map<String, ProcessEngineInfo> processEngineInfosByResourceUrl = new HashMap<String, ProcessEngineInfo>();
protected static List<ProcessEngineInfo> processEngineInfos = new ArrayList<ProcessEngineInfo>();
/** is called when a server boots by the activiti-rest webapp. */
public synchronized static void init() {
if (!isInitialized) {
// Create a new hashMap in case the ProcessEngines.destroy() was called before and map is Unmodifiable
processEngines = new HashMap<String, ProcessEngine>();
ClassLoader classLoader = ReflectUtil.getClassLoader();
Enumeration<URL> resources = null;
try {
......@@ -81,6 +86,22 @@ public abstract class ProcessEngines {
log.info("Process engines already initialized");
}
}
/**
* 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(ProcessEngineImpl processEngine) {
processEngines.remove(processEngine.getName());
}
private static ProcessEngineInfo initProcessEnginFromResource(URL resourceUrl) {
ProcessEngineInfo processEngineInfo = processEngineInfosByResourceUrl.get(resourceUrl);
......@@ -134,12 +155,15 @@ public abstract class ProcessEngines {
}
}
/** get initialization results. */
/** Get initialization results. */
public static List<ProcessEngineInfo> getProcessEngineInfos() {
return processEngineInfos;
}
/** get initialization results. */
/** 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);
}
......@@ -173,11 +197,10 @@ public abstract class ProcessEngines {
}
/** closes all process engines. This method is called when a server shutsdown by the activiti-rest webapp. */
@SuppressWarnings("unchecked")
public synchronized static void destroy() {
if (isInitialized) {
Map<String, ProcessEngine> engines = new HashMap<String, ProcessEngine>(processEngines);
processEngines = Collections.unmodifiableMap(Collections.EMPTY_MAP);
processEngines = new HashMap<String, ProcessEngine>();
for (String processEngineName: engines.keySet()) {
ProcessEngine processEngine = engines.get(processEngineName);
......
......@@ -20,6 +20,7 @@ import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.ManagementService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
......@@ -112,6 +113,7 @@ public class ProcessEngineImpl implements ProcessEngine {
}
public void close() {
ProcessEngines.unregister(this);
if ((jobExecutor != null) && (jobExecutor.isActive())) {
jobExecutor.shutdown();
}
......
......@@ -172,7 +172,7 @@ public class BpmnParse extends Parse {
super(parser);
this.expressionManager = parser.getExpressionManager();
this.parseListeners = parser.getParseListeners();
setSchemaResource(ReflectUtil.getClassLoader().getResource(BpmnParser.SCHEMA_RESOURCE).toString());
setSchemaResource(ReflectUtil.getResource(BpmnParser.SCHEMA_RESOURCE).toString());
this.importers.put("http://schemas.xmlsoap.org/wsdl/", new WSDLImporter());
}
......
......@@ -186,7 +186,9 @@ public class ProcessEngineConfiguration {
protected Map<String, FormEngine> formEngines;
protected FormTypes formTypes;
protected static ThreadLocal<ClassLoader> currentClassLoaderParameter = new ThreadLocal<ClassLoader>();
protected ClassLoader classLoader;
public ProcessEngineConfiguration() {
processEngineName = ProcessEngines.NAME_DEFAULT;
......@@ -261,10 +263,15 @@ public class ProcessEngineConfiguration {
public ProcessEngine buildProcessEngine() {
configurationComplete();
classLoader = currentClassLoaderParameter.get();
return new ProcessEngineImpl(this);
}
public static void setCurrentClassLoaderParameter(ClassLoader currentClassLoader) {
currentClassLoaderParameter.set(currentClassLoader);
}
protected void configurationComplete() {
if (!isConfigurationCompleted) {
commandExecutorTxRequired = initializeInterceptorChain(commandInterceptorsTxRequired);
......@@ -733,8 +740,4 @@ public class ProcessEngineConfiguration {
public ClassLoader getClassLoader() {
return classLoader;
}
public void setClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
}
......@@ -134,7 +134,7 @@ public class DbSqlSessionFactory implements SessionFactory, ProcessEngineConfigu
protected SqlSessionFactory createSessionFactory(DataSource dataSource, TransactionFactory transactionFactory) {
try {
InputStream inputStream = ReflectUtil.getClassLoader().getResourceAsStream("org/activiti/db/ibatis/activiti.ibatis.mem.conf.xml");
InputStream inputStream = ReflectUtil.getResourceAsStream("org/activiti/db/ibatis/activiti.ibatis.mem.conf.xml");
// update the jdbc parameters to the configured ones...
Environment environment = new Environment("default", transactionFactory, dataSource);
......@@ -260,7 +260,7 @@ public class DbSqlSessionFactory implements SessionFactory, ProcessEngineConfigu
try {
Connection connection = sqlSession.getConnection();
String resource = "org/activiti/db/" + operation + "/activiti." + databaseName + "." + operation + ".sql";
InputStream inputStream = ReflectUtil.getClassLoader().getResourceAsStream(resource);
InputStream inputStream = ReflectUtil.getResourceAsStream(resource);
if (inputStream == null) {
throw new ActivitiException("resource '" + resource + "' is not available for creating the schema");
}
......
......@@ -51,7 +51,7 @@ public class DeploymentBuilderImpl implements DeploymentBuilder {
}
public DeploymentBuilder addClasspathResource(String resource) {
InputStream inputStream = ReflectUtil.getClassLoader().getResourceAsStream(resource);
InputStream inputStream = ReflectUtil.getResourceAsStream(resource);
if (inputStream==null) {
throw new ActivitiException("resource '"+resource+"' not found");
}
......
......@@ -83,7 +83,7 @@ public class ActivitiInternalTestCase extends PvmTestCase {
private static ProcessEngineInitializer getProcessEngineInitializer() {
String processEngineInitializerClassName = null;
InputStream initializersInputStream = ReflectUtil.getClassLoader().getResourceAsStream("activiti.initializer.properties");
InputStream initializersInputStream = ReflectUtil.getResourceAsStream("activiti.initializer.properties");
if (initializersInputStream!=null) {
Properties properties = new Properties();
try {
......
......@@ -12,10 +12,13 @@
*/
package org.activiti.engine.impl.util;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Arrays;
import java.util.logging.Logger;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.impl.interceptor.CommandContext;
......@@ -26,24 +29,82 @@ import org.activiti.engine.impl.interceptor.CommandContext;
*/
public abstract class ReflectUtil {
private static final Logger LOG = Logger.getLogger(ReflectUtil.class.getName());
public static ClassLoader getClassLoader() {
if(CommandContext.getCurrent() != null) {
final ClassLoader classLoader = CommandContext.getCurrent().getProcessEngineConfiguration().getClassLoader();
if(classLoader != null) {
return classLoader;
}
ClassLoader loader = getCustomClassLoader();
if(loader == null) {
loader = Thread.currentThread().getContextClassLoader();
}
return Thread.currentThread().getContextClassLoader();
return loader;
}
public static Class<?> loadClass(String className) {
try {
ClassLoader classLoader = getClassLoader();
return Class.forName(className, true, classLoader);
} catch (Exception e) {
throw new ActivitiException("couldn't load class "+className, e);
}
Class<?> clazz = null;
ClassLoader classLoader = getCustomClassLoader();
if(classLoader != null) {
LOG.finest("Trying to load class with custom classloader: " + className);
clazz = loadClassSilent(className, classLoader);
}
if(clazz == null) {
// Try the current Thread context classloader
LOG.finest("Trying to load class with current thread context classloader: " + className);
classLoader = Thread.currentThread().getContextClassLoader();
clazz = loadClassSilent(className, classLoader);
if(clazz == null) {
// Finally, try the classloader for this class
LOG.finest("Trying to load class with local classloader: " + className);
classLoader = ReflectUtil.class.getClassLoader();
clazz = loadClassSilent(className, classLoader);
}
}
if(clazz == null) {
throw new ActivitiException("Couldn't load class "+className);
}
return clazz;
}
public static InputStream getResourceAsStream(String name) {
InputStream resourceStream = null;
ClassLoader classLoader = getCustomClassLoader();
if(classLoader != null) {
resourceStream = classLoader.getResourceAsStream(name);
}
if(resourceStream == null) {
// Try the current Thread context classloader
classLoader = Thread.currentThread().getContextClassLoader();
resourceStream = classLoader.getResourceAsStream(name);
if(resourceStream == null) {
// Finally, try the classloader for this class
classLoader = ReflectUtil.class.getClassLoader();
resourceStream = classLoader.getResourceAsStream(name);
}
}
return resourceStream;
}
public static URL getResource(String name) {
URL url = null;
ClassLoader classLoader = getCustomClassLoader();
if(classLoader != null) {
url = classLoader.getResource(name);
}
if(url == null) {
// Try the current Thread context classloader
classLoader = Thread.currentThread().getContextClassLoader();
url = classLoader.getResource(name);
if(url == null) {
// Finally, try the classloader for this class
classLoader = ReflectUtil.class.getClassLoader();
url = classLoader.getResource(name);
}
}
return url;
}
public static Object instantiate(String className) {
try {
......@@ -164,4 +225,23 @@ public abstract class ReflectUtil {
}
return true;
}
private static ClassLoader getCustomClassLoader() {
if(CommandContext.getCurrent() != null) {
final ClassLoader classLoader = CommandContext.getCurrent().getProcessEngineConfiguration().getClassLoader();
if(classLoader != null) {
return classLoader;
}
}
return null;
}
private static Class<?> loadClassSilent(String className, ClassLoader classLoader) {
try {
return Class.forName(className, true, classLoader);
} catch (ClassNotFoundException cnfe) {
// Ignore exception, we return null;
return null;
}
}
}
......@@ -36,10 +36,12 @@ public class ResourceStreamSource implements StreamSource {
}
public InputStream getInputStream() {
InputStream inputStream = null;
if (classLoader==null) {
classLoader = ReflectUtil.getClassLoader();
inputStream = ReflectUtil.getResourceAsStream(resource);
} else {
classLoader.getResourceAsStream(resource);
}
InputStream inputStream = classLoader.getResourceAsStream(resource);
if (inputStream==null) {
throw new ActivitiException("resource '"+resource+"' doesn't exist");
}
......
......@@ -46,7 +46,7 @@ public class BpmnDeploymentTest extends ActivitiInternalTestCase {
assertTrue(contentFromDeployment.length() > 0);
assertTrue(contentFromDeployment.contains("process id=\"emptyProcess\""));
InputStream fileInputStream = ReflectUtil.getClassLoader().getResourceAsStream("org/activiti/engine/test/bpmn/deployment/BpmnDeploymentTest.testGetBpmnXmlFileThroughService.bpmn20.xml");
InputStream fileInputStream = ReflectUtil.getResourceAsStream("org/activiti/engine/test/bpmn/deployment/BpmnDeploymentTest.testGetBpmnXmlFileThroughService.bpmn20.xml");
String contentFromFile = readInputStreamToString(fileInputStream);
assertEquals(contentFromFile, contentFromDeployment);
}
......
......@@ -36,7 +36,7 @@ public class WSDLImporterTest {
@Test
public void testImport() throws Exception {
WSDLImporter importer = new WSDLImporter();
URL url = ReflectUtil.getClassLoader().getResource("org/activiti/engine/impl/webservice/counter.wsdl");
URL url = ReflectUtil.getResource("org/activiti/engine/impl/webservice/counter.wsdl");
importer.importFrom(url.toString());
List<WSService> services = new ArrayList<WSService>(importer.getServices());
......
......@@ -86,9 +86,10 @@ public class ProcessEngineFactoryBean implements FactoryBean<ProcessEngine>, Dis
if (deploymentResources.length > 0) {
autoDeployResources();
}
ProcessEngines.registerProcessEngine(processEngine);
return processEngine;
}
private void initializeSpringTransactionInterceptor() {
......@@ -112,7 +113,9 @@ public class ProcessEngineFactoryBean implements FactoryBean<ProcessEngine>, Dis
}
protected void initializeExpressionManager() {
processEngineConfiguration.setExpressionManager(new SpringExpressionManager(applicationContext));
if (applicationContext != null) {
processEngineConfiguration.setExpressionManager(new SpringExpressionManager(applicationContext));
}
}
private void initializeJPA() {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册