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);
}
}
}