package pl.net.bluesoft.rnd.processtool.plugins;
import static pl.net.bluesoft.util.lang.FormatUtil.nvl;
import static pl.net.bluesoft.util.lang.Strings.hasText;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import javax.transaction.UserTransaction;
import org.aperteworkflow.search.SearchProvider;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import pl.net.bluesoft.rnd.processtool.ProcessToolContext;
import pl.net.bluesoft.rnd.processtool.ProcessToolContextFactory;
import pl.net.bluesoft.rnd.processtool.ReturningProcessToolContextCallback;
import pl.net.bluesoft.rnd.processtool.dao.ProcessDefinitionDAO;
import pl.net.bluesoft.rnd.processtool.dao.ProcessDictionaryDAO;
import pl.net.bluesoft.rnd.processtool.dao.ProcessInstanceDAO;
import pl.net.bluesoft.rnd.processtool.dao.ProcessInstanceFilterDAO;
import pl.net.bluesoft.rnd.processtool.dao.ProcessInstanceSimpleAttributeDAO;
import pl.net.bluesoft.rnd.processtool.dao.ProcessStateActionDAO;
import pl.net.bluesoft.rnd.processtool.dao.UserDataDAO;
import pl.net.bluesoft.rnd.processtool.dao.UserProcessQueueDAO;
import pl.net.bluesoft.rnd.processtool.dao.UserSubstitutionDAO;
import pl.net.bluesoft.rnd.processtool.dao.impl.ProcessDefinitionDAOImpl;
import pl.net.bluesoft.rnd.processtool.dao.impl.ProcessDictionaryDAOImpl;
import pl.net.bluesoft.rnd.processtool.dao.impl.ProcessInstanceDAOImpl;
import pl.net.bluesoft.rnd.processtool.dao.impl.ProcessInstanceFilterDAOImpl;
import pl.net.bluesoft.rnd.processtool.dao.impl.ProcessInstanceSimpleAttributeDAOImpl;
import pl.net.bluesoft.rnd.processtool.dao.impl.ProcessStateActionDAOImpl;
import pl.net.bluesoft.rnd.processtool.dao.impl.UserDataDAOImpl;
import pl.net.bluesoft.rnd.processtool.dao.impl.UserProcessQueueDAOImpl;
import pl.net.bluesoft.rnd.processtool.dao.impl.UserSubstitutionDAOImpl;
import pl.net.bluesoft.rnd.processtool.dict.DictionaryLoader;
import pl.net.bluesoft.rnd.processtool.dict.exception.DictionaryLoadingException;
import pl.net.bluesoft.rnd.processtool.dict.xml.ProcessDictionaries;
import pl.net.bluesoft.rnd.processtool.event.ProcessToolEventBusManager;
import pl.net.bluesoft.rnd.processtool.model.Cacheable;
import pl.net.bluesoft.rnd.processtool.model.config.ProcessDefinitionConfig;
import pl.net.bluesoft.rnd.processtool.model.config.ProcessQueueConfig;
import pl.net.bluesoft.rnd.processtool.model.config.ProcessStateAction;
import pl.net.bluesoft.rnd.processtool.model.config.ProcessToolAutowire;
import pl.net.bluesoft.rnd.processtool.model.dict.db.ProcessDBDictionary;
import pl.net.bluesoft.rnd.processtool.model.dict.db.ProcessDBDictionaryPermission;
import pl.net.bluesoft.rnd.processtool.steps.ProcessToolProcessStep;
import pl.net.bluesoft.rnd.processtool.ui.widgets.ProcessToolActionButton;
import pl.net.bluesoft.rnd.processtool.ui.widgets.ProcessToolWidget;
import pl.net.bluesoft.rnd.processtool.ui.widgets.annotations.AliasName;
import pl.net.bluesoft.rnd.processtool.ui.widgets.taskitem.TaskItemProvider;
import pl.net.bluesoft.rnd.util.func.Func;
import pl.net.bluesoft.rnd.util.i18n.I18NProvider;
import pl.net.bluesoft.rnd.util.i18n.I18NSourceFactory;
import pl.net.bluesoft.rnd.util.i18n.impl.PropertiesBasedI18NProvider;
import pl.net.bluesoft.rnd.util.i18n.impl.PropertyLoader;
import pl.net.bluesoft.util.cache.Caches;
import pl.net.bluesoft.util.eventbus.EventBusManager;
import pl.net.bluesoft.util.lang.FormatUtil;
import pl.net.bluesoft.util.lang.Strings;
/**
* @author tlipski@bluesoft.net.pl
* @author amichalak@bluesoft.net.pl
* @author kkolodziej@bluesoft.net.pl
*/
public class ProcessToolRegistryImpl implements ProcessToolRegistry {
private static final Logger logger = Logger.getLogger(ProcessToolRegistryImpl.class.getName());
private final List<ProcessToolServiceBridge> SERVICE_BRIDGE_REGISTRY = new LinkedList<ProcessToolServiceBridge>();
private final Map<String, Class<? extends ProcessToolWidget>> WIDGET_REGISTRY = new HashMap<String, Class<? extends ProcessToolWidget>>();
private final Map<String, Class<? extends ProcessToolActionButton>> BUTTON_REGISTRY = new HashMap<String, Class<? extends ProcessToolActionButton>>();
private final Map<String, List<String>> RESOURCE_REGISTRY = new HashMap<String, List<String>>();
private final Map<String, I18NProvider> I18N_PROVIDER_REGISTRY = new HashMap<String, I18NProvider>();
private final Map<String, Func<? extends ProcessToolProcessStep>> STEP_REGISTRY = new HashMap<String, Func<? extends ProcessToolProcessStep>>();
private final Map<String, Class<? extends TaskItemProvider>> TASK_ITEM_REGISTRY = new HashMap<String, Class<? extends TaskItemProvider>>();
private ExecutorService executorService = Executors.newCachedThreadPool();
private EventBusManager eventBusManager = new ProcessToolEventBusManager(this, executorService);
private Map<String, Class> annotatedClasses = new HashMap<String, Class>();
private Map<String, byte[]> hibernateResources = new HashMap<String, byte[]>();
private Map<String, ClassLoader> classLoaders = new HashMap<String, ClassLoader>();
private Map<String, Map> caches = new HashMap<String, Map>();
private ProcessToolContextFactory processToolContextFactory;
private SessionFactory sessionFactory;
private PluginManager pluginManager;
private SearchProvider searchProvider;
private boolean jta;
private BundleContext bundleContext;
private String bpmDefinitionLanguage;
{
//init default provider, regardless of OSGi stuff
final ClassLoader classloader = getClass().getClassLoader();
I18N_PROVIDER_REGISTRY.put("", new PropertiesBasedI18NProvider(new PropertyLoader() {
@Override
public InputStream loadProperty(String path) throws IOException {
return classloader.getResourceAsStream(path);
}
}, "messages"));
}
public synchronized void unregisterWidget(String name) {
WIDGET_REGISTRY.remove(name);
}
public synchronized void registerWidget(String name, Class<? extends ProcessToolWidget> cls) {
WIDGET_REGISTRY.put(name, cls);
}
public <T extends ProcessToolWidget> T makeWidget(String name) throws IllegalAccessException, InstantiationException {
Class<? extends ProcessToolWidget> aClass = WIDGET_REGISTRY.get(name);
if (aClass == null) {
throw new IllegalAccessException("No class nicknamed by: " + name);
}
return (T) aClass.newInstance();
}
public <T extends ProcessToolActionButton> T makeButton(String name) throws IllegalAccessException, InstantiationException {
Class<? extends ProcessToolActionButton> aClass = BUTTON_REGISTRY.get(name);
if (aClass == null) {
throw new IllegalAccessException("No class nicknamed by: " + name);
}
return (T) aClass.newInstance();
}
public ProcessToolRegistryImpl() {
this.processToolContextFactory = null;
buildSessionFactory();
updateCaches();
}
public ClassLoader getModelAwareClassLoader(ClassLoader parent) {
return new ExtClassLoader(parent);
}
public void setOsgiBundleContext(BundleContext context) {
this.bundleContext = context;
}
private class ExtClassLoader extends ClassLoader {
private ExtClassLoader(ClassLoader parent) {
super(parent);
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
Class aClass = annotatedClasses.get(name);
if (aClass != null) {
return aClass;
}
for (ClassLoader loader : classLoaders.values()) {
try {
Class<?> aClass1 = loader.loadClass(name);
if (aClass1 != null) return aClass1;
} catch (Exception e) {
//do nothing
}
}
return super.loadClass(name);
}
}
public synchronized void addClassLoader(String name, ClassLoader loader) {
classLoaders.put(name, loader);
}
public synchronized void removeClassLoader(String name) {
classLoaders.remove(name);
}
@Override
public EventBusManager getEventBusManager() {
return eventBusManager;
}
public ExecutorService getExecutorService() {
return executorService;
}
@Override
public PluginManager getPluginManager() {
return pluginManager;
}
@Override
public void setPluginManager(PluginManager pluginManager) {
this.pluginManager = pluginManager;
}
@Override
public <T> T lookupService(String name) {
ServiceReference serviceReference = bundleContext.getServiceReference(name);
if (serviceReference == null) return null;
return (T) bundleContext.getService(serviceReference);
}
public void setBpmDefinitionLanguage(String bpmDefinitionLanguage) {
this.bpmDefinitionLanguage = bpmDefinitionLanguage;
}
@Override
public String getBpmDefinitionLanguage() {
return bpmDefinitionLanguage;
}
public synchronized boolean addAnnotatedClass(Class<?>... classes) {
boolean needUpdate = false;
for (Class cls : classes) {
Class annotatedClass = annotatedClasses.get(cls.getName());
if (annotatedClass == null || !annotatedClass.equals(cls)) {
needUpdate = true;
annotatedClasses.put(cls.getName(), cls);
}
}
return needUpdate;
}
public synchronized boolean removeAnnotatedClass(Class... classes) {
boolean needUpdate = false;
for (Class cls : classes) {
if (annotatedClasses.containsKey(cls.getName())) {
needUpdate = true;
annotatedClasses.remove(cls.getName());
}
}
return needUpdate;
}
public synchronized void addHibernateResource(String name, byte[] resource) {
hibernateResources.put(name, resource);
}
public synchronized void removeHibernateResource(String name) {
hibernateResources.remove(name);
}
public void buildSessionFactory() {
jta = false;
boolean startJtaTransaction = true;
String dataSourceName = checkForDataSource();
UserTransaction ut = dataSourceName != null ? findUserTransaction() : null; //do not even try...
Configuration configuration = new Configuration().configure();
for (Class cls : annotatedClasses.values()) {
configuration.addAnnotatedClass(cls);
}
for (String name : hibernateResources.keySet()) {
byte[] b = hibernateResources.get(name);
if (b != null && b.length > 0) {
configuration.addInputStream(new ByteArrayInputStream(b));
}
}
if (dataSourceName == null) {
logger.severe("Aperte Workflow runs using embedded datasource. This approach is useful only for development and demoing purposes.");
/*
<!--<property name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property>-->
<!--<property name="hibernate.connection.url">jdbc:hsqldb:${liferay.home}/data/hsql/aperteworkflow</property>-->
<!--<property name="hibernate.connection.username">sa</property>-->
<!--<property name="hibernate.connection.password"></property>-->
*/
configuration.setProperty("hibernate.connection.driver_class", "org.hsqldb.jdbcDriver");
String url = "jdbc:hsqldb:" + ProcessToolContext.Util.getHomePath() + "/aperteworkflow-hsql";
configuration.setProperty("hibernate.connection.url", url);
configuration.setProperty("hibernate.connection.username", "sa");
configuration.setProperty("hibernate.connection.password", "");
logger.severe("Configured Aperte Workflow to use Hypersonic DB driver org.hsqldb.jdbcDriver, url: " + url);
} else {
logger.info("Configuring Aperte Workflow to use data source: " + dataSourceName);
configuration.setProperty("hibernate.connection.datasource", dataSourceName);
}
String managerLookupClassName=null;
if (ut != null) { //try to autodetect JTA settings
logger.warning("UserTransaction found, attempting to autoconfigure Hibernate to use JTA");
managerLookupClassName = System.getProperty("org.aperteworkflow.hibernate.transaction.manager_lookup_class");
if (managerLookupClassName == null) {
try {
Class.forName("bitronix.tm.BitronixTransactionManager").getName();
managerLookupClassName = "org.hibernate.transaction.BTMTransactionManagerLookup";
logger.warning("Found class bitronix.tm.BitronixTransactionManager, Bitronix TM detected!");
} catch (ClassNotFoundException e) {
//nothing, go on.
}
}
if (managerLookupClassName == null) {
if (System.getProperty("jboss.home.dir") != null) {
logger.warning("Found JBoss AS environment, using JBoss Arjuna TM");
managerLookupClassName = "org.hibernate.transaction.JBossTransactionManagerLookup";
startJtaTransaction = false; //hibernate forces autocommit on transaction update, which throws exception on jboss.
}
}
logger.warning("Configured hibernate.transaction.manager_lookup_class to " + managerLookupClassName);
}
if (managerLookupClassName != null) {
configuration.setProperty("hibernate.transaction.factory_class",
nvl(System.getProperty("org.aperteworkflow.hibernate.transaction.factory_class"),
"org.hibernate.transaction.JTATransactionFactory"));
configuration.setProperty("hibernate.transaction.manager_lookup_class", managerLookupClassName);
configuration.setProperty("current_session_context_class", "jta");
jta = true;
} else {
logger.warning("UserTransaction or factory class not found, attempting to autoconfigure Hibernate to use per-Thread session context");
configuration.setProperty("current_session_context_class", "thread");
}
if (startJtaTransaction && ut != null && jta) { //needed for tomcat/bitronix
try {
ut.begin();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
ClassLoader cl = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(new ExtClassLoader(cl));
sessionFactory = configuration.buildSessionFactory();
} finally {
Thread.currentThread().setContextClassLoader(cl);
}
if (processToolContextFactory != null) {
processToolContextFactory.updateSessionFactory(sessionFactory);
}
if (startJtaTransaction && ut != null && jta) { //needed for tomcat/bitronix
try {
ut.commit();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
if (dataSourceName == null) {
logger.severe("Aperte Workflow runs using embedded datasource. This approach is useful only for development and demoing purposes.");
}
}
/*
<!--<property name="hibernate.connection.datasource">java:comp/env/jdbc/aperte-workflow-ds</property>-->
*/
private String checkForDataSource() {
String dsName = nvl(System.getProperty("org.aperteworkflow.datasource"), "java:comp/env/jdbc/aperte-workflow-ds");
try {
DataSource lookup = (DataSource) new InitialContext().lookup(dsName);
lookup.getConnection().close();
return dsName;
} catch (Exception e) {
dsName = nvl(System.getProperty("org.aperteworkflow.datasource"), "jdbc/aperte-workflow-ds");
try {
DataSource lookup = (DataSource) new InitialContext().lookup(dsName);
lookup.getConnection().close();
return dsName;
} catch (Exception e1) {
logger.log(Level.SEVERE, "Aperte Workflow datasource bound to name " + dsName +
" not found or is badly configured, falling back to preconfigured HSQLDB." +
" DO NOT USE THAT IN PRODUCTION ENVIRONMENT!", e);
}
}
return null;
}
private UserTransaction findUserTransaction() {
UserTransaction ut=null;
if (!"true".equalsIgnoreCase(System.getProperty("org.aperteworkflow.nojta"))) {
try {
ut = (UserTransaction) new InitialContext().lookup("java:comp/UserTransaction");
} catch (Exception e) {
logger.warning("java:comp/UserTransaction not found, looking for UserTransaction");
try {
ut = (UserTransaction) new InitialContext().lookup("UserTransaction");
} catch (Exception e1) {
logger.warning("UserTransaction not found in JNDI, JTA not available!");
}
}
} else {
logger.warning("User transaction lookup disabled via org.aperteworkflow.nojta setting");
}
return ut;
}
public <T extends ProcessToolWidget> T makeWidget(Class<? extends ProcessToolWidget> aClass) throws IllegalAccessException, InstantiationException {
return (T) aClass.newInstance();
}
public void registerI18NProvider(I18NProvider i18Provider, String providerId) {
I18N_PROVIDER_REGISTRY.put(providerId, i18Provider);
I18NSourceFactory.invalidateCache();
logger.warning("Registered I18NProvider: " + providerId);
}
public void unregisterI18NProvider(String providerId) {
I18N_PROVIDER_REGISTRY.remove(providerId);
I18NSourceFactory.invalidateCache();
logger.warning("Unregistered I18NProvider: " + providerId);
}
public Collection<I18NProvider> getI18NProviders() {
return I18N_PROVIDER_REGISTRY.values();
}
@Override
public boolean hasI18NProvider(String providerId) {
return I18N_PROVIDER_REGISTRY.containsKey(providerId);
}
@Override
public <T> T withProcessToolContext(ReturningProcessToolContextCallback<T> callback) {
if (processToolContextFactory == null) {
throw new RuntimeException("No process tool context factory implementation registered");
}
return processToolContextFactory.withProcessToolContext(callback);
}
@Override
public <T> T withExistingOrNewContext(ReturningProcessToolContextCallback<T> callback) {
if (processToolContextFactory == null) {
throw new RuntimeException("No process tool context factory implementation registered");
}
return processToolContextFactory.withExistingOrNewContext(callback);
}
@Override
public ProcessDictionaryDAO getProcessDictionaryDAO(Session hibernateSession) {
return new ProcessDictionaryDAOImpl(hibernateSession);
}
@Override
public ProcessInstanceDAO getProcessInstanceDAO(Session hibernateSession) {
return new ProcessInstanceDAOImpl(hibernateSession, searchProvider);
}
@Override
public ProcessInstanceSimpleAttributeDAO getProcessInstanceSimpleAttributeDAO(
Session hibernateSession) {
return new ProcessInstanceSimpleAttributeDAOImpl(hibernateSession);
}
@Override
public ProcessStateActionDAO getProcessStateAction(Session hibernateSession) {
return new ProcessStateActionDAOImpl(hibernateSession);
}
@Override
public ProcessInstanceFilterDAO getProcessInstanceFilterDAO(Session hibernateSession) {
return new ProcessInstanceFilterDAOImpl(hibernateSession);
}
@Override
public UserDataDAO getUserDataDAO(Session hibernateSession) {
return new UserDataDAOImpl(hibernateSession);
}
@Override
public UserSubstitutionDAO getUserSubstitutionDAO(Session hibernateSession) {
return new UserSubstitutionDAOImpl(hibernateSession);
}
@Override
public ProcessDefinitionDAO getProcessDefinitionDAO(Session hibernateSession) {
return new ProcessDefinitionDAOImpl(hibernateSession);
}
@Override
public UserProcessQueueDAO getUserProcessQueueDAO(Session hibernateSession)
{
return new UserProcessQueueDAOImpl(hibernateSession);
}
@Override
public boolean registerModelExtension(Class<?>... cls) {
logger.warning("Registered model extensions: " + FormatUtil.joinClassNames(cls));
return addAnnotatedClass(cls);
}
@Override
public void commitModelExtensions() {
buildSessionFactory();
}
public ProcessToolContextFactory getProcessToolContextFactory() {
return processToolContextFactory;
}
public void setProcessToolContextFactory(ProcessToolContextFactory processToolContextFactory) {
this.processToolContextFactory = processToolContextFactory;
}
@Override
public void unregisterProcessToolContextFactory(Class<?> cls) {
if (processToolContextFactory == null ||
processToolContextFactory.getClass().getName().equals(cls.getName())) {
processToolContextFactory = null;
}
}
@Override
public SessionFactory getSessionFactory() {
return sessionFactory;
}
@Override
public boolean unregisterModelExtension(Class<?>... cls) {
logger.warning("Unregistered model extensions: " + FormatUtil.joinClassNames(cls));
return removeAnnotatedClass(cls);
}
@Override
public Map<String, Class<? extends ProcessToolWidget>> getAvailableWidgets() {
return new HashMap(WIDGET_REGISTRY);
}
@Override
public void registerWidget(Class<?> cls) {
registerWidget(cls.getName(), (Class<? extends ProcessToolWidget>) cls);
logger.info("Registered widget extension: " + cls.getName());
AliasName annotation = (AliasName) cls.getAnnotation(AliasName.class);
if (annotation != null) {
registerWidget(annotation.name(), (Class<? extends ProcessToolWidget>) cls);
logger.info("Registered widget alias: " + annotation.name() + " -> " + cls.getName());
}
}
@Override
public void unregisterWidget(Class<?> cls) {
unregisterWidget(cls.getName());
logger.info("Unregistered widget extension: " + cls.getName());
AliasName annotation = (AliasName) cls.getAnnotation(AliasName.class);
if (annotation != null) {
unregisterWidget(annotation.name());
logger.info("Unregistered widget alias: " + annotation.name() + " -> " + cls.getName());
}
}
@Override
public void registerButton(Class<?> cls) {
AliasName annotation = cls.getAnnotation(AliasName.class);
if (annotation != null) {
BUTTON_REGISTRY.put(annotation.name(), (Class<? extends ProcessToolActionButton>) cls);
logger.info("Registered button alias: " + annotation.name() + " -> " + cls.getName());
}
}
@Override
public void unregisterButton(Class<?> cls) {
AliasName annotation = cls.getAnnotation(AliasName.class);
if (annotation != null) {
BUTTON_REGISTRY.remove(annotation.name());
logger.info("Unregistered button alias: " + annotation.name() + " -> " + cls.getName());
}
}
@Override
public Map<String,Class<? extends ProcessToolActionButton>> getAvailableButtons() {
return new HashMap<String, Class<? extends ProcessToolActionButton>>(BUTTON_REGISTRY);
}
private class StepClassFunc implements Func<ProcessToolProcessStep> {
private Class<? extends ProcessToolProcessStep> cls;
private StepClassFunc(Class<? extends ProcessToolProcessStep> cls) {
this.cls = cls;
}
@Override
public ProcessToolProcessStep invoke() {
try {
return cls.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public void registerStep(String name, Func<? extends ProcessToolProcessStep> f) {
STEP_REGISTRY.put(name, f);
logger.info("Registered step extension: " + name);
}
public void registerStep(Class<? extends ProcessToolProcessStep> cls) {
registerStep(cls.getName(), new StepClassFunc(cls));
AliasName annotation = cls.getAnnotation(AliasName.class);
if (annotation != null) {
registerStep(annotation.name(), new StepClassFunc(cls));
}
}
public void unregisterStep(String name) {
STEP_REGISTRY.remove(name);
logger.info("Unregistered step extension: " + name);
}
public void unregisterStep(Class<? extends ProcessToolProcessStep> cls) {
unregisterStep(cls.getName());
AliasName annotation = cls.getAnnotation(AliasName.class);
if (annotation != null) {
unregisterStep(annotation.name());
}
}
public Map<String,ProcessToolProcessStep> getAvailableSteps() {
Map<String,ProcessToolProcessStep> steps = new HashMap<String,ProcessToolProcessStep>();
for (Map.Entry<String, Func<? extends ProcessToolProcessStep>> e : STEP_REGISTRY.entrySet()) {
steps.put(e.getKey(), e.getValue().invoke());
}
return steps;
}
public ProcessToolProcessStep getStep(String name) {
Func<? extends ProcessToolProcessStep> func = STEP_REGISTRY.get(name);
if (func != null) return func.invoke();
return null;
}
@Override
public void registerTaskItemProvider(Class<?> cls) {
AliasName annotation = cls.getAnnotation(AliasName.class);
if (annotation != null) {
TASK_ITEM_REGISTRY.put(annotation.name(), (Class<? extends TaskItemProvider>) cls);
logger.warning("Registered task item alias: " + annotation.name() + " -> " + cls.getName());
}
}
@Override
public void unregisterTaskItemProvider(Class<?> cls) {
unregisterTaskItemProvider(cls.getName());
AliasName annotation = cls.getAnnotation(AliasName.class);
if (annotation != null) {
unregisterTaskItemProvider(annotation.name());
}
}
public void unregisterTaskItemProvider(String name) {
TASK_ITEM_REGISTRY.remove(name);
}
@Override
public TaskItemProvider makeTaskItemProvider(String name) throws IllegalAccessException, InstantiationException {
Class<? extends TaskItemProvider> aClass = TASK_ITEM_REGISTRY.get(name);
if (aClass == null) {
throw new IllegalAccessException("No class nicknamed by: " + name);
}
return aClass.newInstance();
}
@Override
public Map<String, Class<? extends TaskItemProvider>> getAvailableTaskItemProviders() {
return Collections.unmodifiableMap(TASK_ITEM_REGISTRY);
}
@Override
public void registerGlobalDictionaries(InputStream is) {
if (is != null) {
ProcessDictionaries dictionaries = (ProcessDictionaries) DictionaryLoader.getInstance().unmarshall(is);
String processBpmKey = dictionaries.getProcessBpmDefinitionKey();
if (Strings.hasText(processBpmKey)) {
logger.warning("Global process dictionary should not be defined for a specific process: "
+ dictionaries.getProcessBpmDefinitionKey());
}
Session session = sessionFactory.openSession();
try {
Transaction tx = session.beginTransaction();
saveDictionaryInternal(session, null, dictionaries);
tx.commit();
logger.warning("Registered global dictionaries");
}
finally {
session.close();
}
}
}
@Override
public void registerProcessDictionaries(InputStream is) {
if (is != null) {
ProcessDictionaries dictionaries = (ProcessDictionaries) DictionaryLoader.getInstance().unmarshall(is);
String processBpmKey = dictionaries.getProcessBpmDefinitionKey();
if (!Strings.hasText(processBpmKey)) {
throw new DictionaryLoadingException("No process name specified in the dictionaries XML");
}
Session session = sessionFactory.openSession();
try {
Transaction tx = session.beginTransaction();
ProcessDefinitionConfig definitionConfig = getProcessDefinitionDAO(session).getActiveConfigurationByKey(processBpmKey);
if (definitionConfig == null) {
throw new DictionaryLoadingException("No active definition config with BPM key: " + processBpmKey);
}
saveDictionaryInternal(session, definitionConfig, dictionaries);
tx.commit();
logger.warning("Registered dictionaries for process: " + processBpmKey);
}
finally {
session.close();
}
}
}
private void saveDictionaryInternal(Session session, ProcessDefinitionConfig definitionConfig, ProcessDictionaries dictionaries) {
ProcessDictionaryDAO dao = getProcessDictionaryDAO(session);
List<ProcessDBDictionary> processDBDictionaries = DictionaryLoader.getDictionariesFromXML(dictionaries);
for (ProcessDBDictionary dict : processDBDictionaries) {
for (ProcessDBDictionaryPermission perm : dict.getPermissions()) {
if (!Strings.hasText(perm.getRoleName())) {
perm.setRoleName(PATTERN_MATCH_ALL);
}
if (!Strings.hasText(perm.getPrivilegeName())) {
perm.setPrivilegeName(PRIVILEGE_EDIT);
}
}
}
DictionaryLoader.validateDictionaries(processDBDictionaries);
dao.createOrUpdateDictionaries(definitionConfig, processDBDictionaries,
dictionaries.getOverwrite() != null && dictionaries.getOverwrite());
}
@Override
public void deployOrUpdateProcessDefinition(final InputStream jpdlStream,
final ProcessDefinitionConfig cfg,
final ProcessQueueConfig[] queues,
final InputStream imageStream,
InputStream logoStream) {
if (processToolContextFactory == null) {
throw new RuntimeException("No process tool context factory implementation registered");
}
processToolContextFactory.deployOrUpdateProcessDefinition(jpdlStream, cfg, queues, imageStream, logoStream);
}
@Override
public void deployOrUpdateProcessDefinition(InputStream jpdlStream,
InputStream processToolConfigStream,
InputStream queueConfigStream,
InputStream imageStream,
InputStream logoStream) {
if (processToolContextFactory == null) {
throw new RuntimeException("No process tool context factory implementation registered");
}
processToolContextFactory.deployOrUpdateProcessDefinition(jpdlStream, processToolConfigStream, queueConfigStream, imageStream, logoStream);
}
@Override
public void addServiceLoader(ProcessToolServiceBridge serviceBridge) {
if (serviceBridge != null) {
SERVICE_BRIDGE_REGISTRY.add(serviceBridge);
logger.warning("Registered service bridge: " + serviceBridge.getClass().getName());
}
}
@Override
public void removeServiceLoader(ProcessToolServiceBridge serviceBridge) {
if (serviceBridge != null) {
SERVICE_BRIDGE_REGISTRY.remove(serviceBridge);
logger.warning("Removed service bridge: " + serviceBridge.getClass().getName());
}
}
@Override
public List<ProcessToolServiceBridge> getServiceLoaders() {
return SERVICE_BRIDGE_REGISTRY;
}
@Override
public void removeRegisteredService(Class<?> serviceClass) {
boolean result = false;
for (ProcessToolServiceBridge bridge : SERVICE_BRIDGE_REGISTRY) {
if (result = bridge.removeService(serviceClass)) {
break;
}
}
logger.warning((result ? "Succeeded to" : "Failed to") + " remove registered service: " + serviceClass.getName());
}
@Override
public <T> void registerService(Class<T> serviceClass, T instance, Properties properties) {
boolean result = false;
for (ProcessToolServiceBridge bridge : SERVICE_BRIDGE_REGISTRY) {
if (result = bridge.registerService(serviceClass, instance, properties)) {
break;
}
}
logger.warning((result ? "Succeeded to" : "Failed to") + " register service: " + serviceClass.getName());
}
@Override
public <T> T getRegisteredService(Class<T> serviceClass) {
Object service = null;
for (ProcessToolServiceBridge bridge : SERVICE_BRIDGE_REGISTRY) {
service = bridge.loadService(serviceClass);
if (service != null) {
break;
}
}
if (service == null) {
throw new NoSuchServiceException("Service " + serviceClass.getName() + " not found!");
}
return (T) service;
}
@Override
public boolean isJta() {
return jta;
}
public SearchProvider getSearchProvider() {
return searchProvider;
}
public void setSearchProvider(SearchProvider searchProvider) {
this.searchProvider = searchProvider;
}
@Override
public void registerResource(String bundleSymbolicName, String path) {
List<String> resources = RESOURCE_REGISTRY.get(bundleSymbolicName);
if (resources == null) {
resources = new ArrayList<String>();
RESOURCE_REGISTRY.put(bundleSymbolicName, resources);
}
resources.add(path);
}
@Override
public void removeRegisteredResources(String bundleSymbolicName) {
RESOURCE_REGISTRY.remove(bundleSymbolicName);
logger.warning("Removed resources for bundle: " + bundleSymbolicName);
}
@Override
public InputStream loadResource(String bundleSymbolicName, String path) {
boolean searchResource = false;
if (hasText(bundleSymbolicName)) {
if (RESOURCE_REGISTRY.containsKey(bundleSymbolicName)) {
List<String> resources = RESOURCE_REGISTRY.get(bundleSymbolicName);
if (resources.contains(path)) {
searchResource = true;
}
}
}
else {
searchResource = true;
}
if (searchResource) {
for (ProcessToolServiceBridge bridge : SERVICE_BRIDGE_REGISTRY) {
try {
InputStream stream = bridge.loadResource(bundleSymbolicName, path);
if (stream != null) {
return stream;
}
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
}
return null;
}
@Override
public InputStream loadResource(String path) {
return loadResource(null, path);
}
private void updateCaches() {
Class<? extends Cacheable<String, String>>[] cachedEntities = new Class[] {ProcessToolAutowire.class};
Session session = sessionFactory.openSession();
try {
Transaction tx = session.beginTransaction();
for (Class<? extends Cacheable<String, String>> entityClass : cachedEntities) {
Map<String, String> cache = Caches.synchronizedCache(100);
List<Cacheable<String, String>> list = session.createCriteria(entityClass).list();
for (Cacheable<String, String> obj : list) {
cache.put(obj.getKey(), obj.getValue());
}
registerCache(entityClass.getName(), cache);
}
tx.commit();
}
finally {
session.close();
}
}
@Override
public <K, V> Map<K, V> getCache(String cacheName) {
return caches.get(cacheName);
}
public <K, V> void registerCache(String cacheName, Map<K, V> cache) {
caches.put(cacheName, cache);
logger.warning("Registered cache named: " + cacheName);
}
}