package org.camunda.bpm.extension.osgi.configadmin.impl; import java.util.Collections; import java.util.Dictionary; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.camunda.bpm.engine.ProcessEngine; import org.camunda.bpm.engine.ProcessEngineConfiguration; import org.camunda.bpm.extension.osgi.classloading.BundleDelegatingClassLoader; import org.camunda.bpm.extension.osgi.classloading.ClassLoaderWrapper; import org.camunda.bpm.extension.osgi.configadmin.ManagedProcessEngineFactory; import org.camunda.bpm.extension.osgi.engine.ProcessEngineFactory; import org.osgi.framework.Bundle; import org.osgi.framework.Constants; import org.osgi.framework.ServiceRegistration; import org.osgi.service.cm.ConfigurationException; @SuppressWarnings("rawtypes") public class ManagedProcessEngineFactoryImpl implements ManagedProcessEngineFactory { private Map<String, ProcessEngine> existingEngines = new ConcurrentHashMap<String, ProcessEngine>(); private Map<String, ServiceRegistration<ProcessEngine>> existingRegisteredEngines = new ConcurrentHashMap<String, ServiceRegistration<ProcessEngine>>(); private volatile Bundle bundle; /** * Default constructor for Apache Felix Dependency Manager. */ public ManagedProcessEngineFactoryImpl() { } public ManagedProcessEngineFactoryImpl(Bundle bundle) { this.bundle = bundle; } @Override public String getName() { return SERVICE_PID; } @Override public void updated(String pid, Dictionary properties) throws ConfigurationException { if (existingEngines.containsKey(pid)) { existingEngines.get(pid).close(); existingEngines.remove(pid); existingRegisteredEngines.get(pid).unregister(); existingRegisteredEngines.remove(pid); } if (!hasPropertiesConfiguration(properties)) { return; } ClassLoader previous = Thread.currentThread().getContextClassLoader(); ProcessEngine engine; try { ClassLoader cl = new BundleDelegatingClassLoader(bundle); Thread.currentThread().setContextClassLoader( new ClassLoaderWrapper(cl, ProcessEngineFactory.class.getClassLoader(), ProcessEngineConfiguration.class.getClassLoader(), previous)); ProcessEngineConfiguration processEngineConfiguration = createProcessEngineConfiguration(properties); processEngineConfiguration.setClassLoader(cl); engine = processEngineConfiguration.buildProcessEngine(); } finally { Thread.currentThread().setContextClassLoader(previous); } existingEngines.put(pid, engine); Hashtable<String, Object> props = new Hashtable<String, Object>(); props.put("process-engine-name", engine.getName()); ServiceRegistration<ProcessEngine> serviceRegistration = this.bundle.getBundleContext().registerService(ProcessEngine.class, engine, props); existingRegisteredEngines.put(pid, serviceRegistration); } /** * It happends that the factory get called with properties that only contain * service.pid and service.factoryPid. If that happens we don't want to create * an engine. * * @param properties * @return */ @SuppressWarnings("unchecked") private boolean hasPropertiesConfiguration(Dictionary properties) { HashMap<Object, Object> mapProperties = new HashMap<Object, Object>(properties.size()); for (Object key : Collections.list(properties.keys())) { mapProperties.put(key, properties.get(key)); } mapProperties.remove(Constants.SERVICE_PID); mapProperties.remove("service.factoryPid"); return !mapProperties.isEmpty(); } @SuppressWarnings("unchecked") private ProcessEngineConfiguration createProcessEngineConfiguration(Dictionary properties) throws ConfigurationException { ProcessEngineConfigurationFromProperties processEngineConfiguration = new ProcessEngineConfigurationFromProperties(); processEngineConfiguration.configure(properties); return processEngineConfiguration; } @Override public void deleted(String pid) { ProcessEngine engine = existingEngines.get(pid); if (engine != null) { engine.close(); existingEngines.remove(pid); existingRegisteredEngines.get(pid).unregister(); existingRegisteredEngines.remove(pid); } } }