org.jbpm.JbpmContext Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jbpm;
import java.io.Serializable;
import java.sql.Connection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.jbpm.configuration.ObjectFactory;
import org.jbpm.db.ContextSession;
import org.jbpm.db.GraphSession;
import org.jbpm.db.JobSession;
import org.jbpm.db.LoggingSession;
import org.jbpm.db.TaskMgmtSession;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;
import org.jbpm.persistence.PersistenceService;
import org.jbpm.persistence.db.DbPersistenceService;
import org.jbpm.security.AuthenticationService;
import org.jbpm.svc.ServiceFactory;
import org.jbpm.svc.Services;
import org.jbpm.taskmgmt.exe.TaskInstance;
import org.jbpm.tx.TxService;
/**
* is used to surround persistent operations to processes.
*
* Obtain a JbpmContext via {@link JbpmConfiguration#createJbpmContext()} and manipulate it
* inside a try-finally block as follows.
*
*
*
* JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
* try {
* TaskInstance taskInstance = ...
*
* ...do your process operations...
*
* // in case you update a process object that was not fetched
* // with a ...ForUpdate method, you have to save it.
* jbpmContext.save(processInstance);
* finally {
* jbpmContext.close();
* }
*
*
* A JbpmContext separates jBPM from a sprecific environment. For each service that jBPM uses,
* there is an interface specified in the jBPM codebase. jBPM also includes implementations that
* implement these services by using services in a specific environment. e.g. a hibernate
* session, a JMS asynchronous messaging system, ...
*
*
* A JbpmContext can demarcate a transaction. When a PersistenceService is fetched from the
* JbpmContext, the default implementation for the persistence service will create a hibernate
* session and start a transaction. So that transactions can be configured in the hibernate
* configuration.
*
*
* A JbpmContext allows the user to overwrite (or make complete) the configuration by injecting
* objects programmatically. like e.g. a hibernate session factory or a hibernate session or any
* other resource that can be fetched or created from the configuration.
*
*
* Last but not least, JbpmContext provides convenient access to the most common operations such
* as {@link #getTaskList(String)}, {@link #newProcessInstance(String)}
* {@link #loadTaskInstanceForUpdate(long)} and {@link #save(ProcessInstance)}.
*
*
* All the ...ForUpdate(...)
methods will automatically save the loaded objects at
* jbpmContext.close();
*
*/
public class JbpmContext implements Serializable {
private static final long serialVersionUID = 1L;
public static final String DEFAULT_JBPM_CONTEXT_NAME = "default.jbpm.context";
private final Services services;
private final ObjectFactory objectFactory;
private Set autoSaveProcessInstances;
private boolean isClosed;
public JbpmContext(Services services, ObjectFactory objectFactory) {
if (services == null) {
throw new IllegalArgumentException("null services");
}
this.services = services;
this.objectFactory = objectFactory;
}
private void ensureOpen() {
if (isClosed) {
throw new JbpmException(this + " is closed");
}
}
public boolean isClosed() {
return isClosed;
}
/**
* make sure to close this context in a finally block.
*/
public void close() {
if (isClosed) return;
RuntimeException saveException = autoSave();
RuntimeException serviceException = closeServices();
isClosed = true;
if (saveException != null) {
throw saveException;
}
if (serviceException != null) {
throw serviceException;
}
}
private RuntimeException autoSave() {
if (autoSaveProcessInstances != null) {
try {
for (Iterator iter = autoSaveProcessInstances.iterator(); iter.hasNext();) {
ProcessInstance processInstance = (ProcessInstance) iter.next();
save(processInstance);
}
}
catch (RuntimeException e) {
return e;
}
}
return null;
}
private RuntimeException closeServices() {
try {
services.close();
return null;
}
catch (RuntimeException e) {
return e;
}
finally {
JbpmConfiguration configuration = getJbpmConfiguration();
if (configuration != null) configuration.popJbpmContext(this);
}
}
/**
* obtains the current JbpmContext from a thread local. The current contexts are maintained in
* a stack so that you can do nested context operations for different jbpm configurations.
*
*
* it is strongly recommended that client code invokes
* {@link JbpmConfiguration#getCurrentJbpmContext()} in preference to this method.
*
*/
public static JbpmContext getCurrentJbpmContext() {
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getCurrentJbpmConfiguration();
return jbpmConfiguration != null ? jbpmConfiguration.getCurrentJbpmContext() : null;
}
// convenience methods //////////////////////////////////////////////////////
/**
* deploys a process definition. For parsing process definitions from archives, see the static
* parseXxx methods on {@link ProcessDefinition}.
*/
public void deployProcessDefinition(ProcessDefinition processDefinition) {
getGraphSession().deployProcessDefinition(processDefinition);
}
/**
* fetches the tasklist for the current authenticated actor. With the default configured
* authentication service, you can set the authenticated user with {@link #setActorId(String)}
* , then all the subsequent operations will be performed on behalf of that actor.
*/
public List getTaskList() {
String actorId = getActorId();
return getTaskMgmtSession().findTaskInstances(actorId);
}
/**
* fetches the tasklist for the given actor.
*/
public List getTaskList(String actorId) {
return getTaskMgmtSession().findTaskInstances(actorId);
}
/**
* fetches all the task instances for which at least one of the given actorIds is a candidate
* (pooled actor). Typically, for an actor, his/her personal actorId plus all the actorIds
* representing the groups that person belongs to form the actorIds. Then the user interface
* should show only the option to take these tasks to the actor's personal task list (with
* {@link TaskInstance#setActorId(String)}). Only task instances that are assigned to the
* actor directly should be offered the possibility for performing the actual task.
*/
public List getGroupTaskList(List actorIds) {
return getTaskMgmtSession().findPooledTaskInstances(actorIds);
}
/**
* loads a task instance from the db.
*
* @throws JbpmException in case no such task instance exists
* @see #getTaskInstance(long)
* @see #loadTaskInstanceForUpdate(long)
* @see #getTaskInstanceForUpdate(long)
*/
public TaskInstance loadTaskInstance(long taskInstanceId) {
return getTaskMgmtSession().loadTaskInstance(taskInstanceId);
}
/**
* gets a task instance from the db.
*
* @return the task instance or null in case no such task instance exists.
* @see #loadTaskInstance(long)
* @see #loadTaskInstanceForUpdate(long)
* @see #getTaskInstanceForUpdate(long)
*/
public TaskInstance getTaskInstance(long taskInstanceId) {
return getTaskMgmtSession().getTaskInstance(taskInstanceId);
}
/**
* loads a task instance from the db and registers it for auto-save. The loaded task instance
* will be save automatically at the {@link #close()}. This is a convenience method in case
* you plan to do update operations on this task instance.
*
* @throws JbpmException in case no such task instance exists
* @see #loadTaskInstance(long)
* @see #getTaskInstance(long)
* @see #getTaskInstanceForUpdate(long)
*/
public TaskInstance loadTaskInstanceForUpdate(long taskInstanceId) {
TaskInstance taskInstance = getTaskMgmtSession().loadTaskInstance(taskInstanceId);
addAutoSaveTaskInstance(taskInstance);
return taskInstance;
}
/**
* gets a task instance from the db and registers it for auto-save. The loaded task instance
* will be save automatically at the {@link #close()}. This is a convenience method in case
* you plan to do update operations on this task instance.
*
* @return the task instance or null in case no such task instance exists.
* @see #loadTaskInstance(long)
* @see #getTaskInstance(long)
* @see #loadTaskInstanceForUpdate(long)
*/
public TaskInstance getTaskInstanceForUpdate(long taskInstanceId) {
TaskInstance taskInstance = getTaskMgmtSession().getTaskInstance(taskInstanceId);
if (taskInstance != null) {
addAutoSaveTaskInstance(taskInstance);
}
return taskInstance;
}
/**
* loads a token from the db.
*
* @throws JbpmException in case no such token exists.
* @see #getToken(long)
* @see #loadTokenForUpdate(long)
* @see #getTokenForUpdate(long)
*/
public Token loadToken(long tokenId) {
return getGraphSession().loadToken(tokenId);
}
/**
* gets a token from the db.
*
* @return the token or null in case no such token exists.
* @see #loadToken(long)
* @see #loadTokenForUpdate(long)
* @see #getTokenForUpdate(long)
*/
public Token getToken(long tokenId) {
return getGraphSession().getToken(tokenId);
}
/**
* loads a token from the db and registers it for auto-save. The loaded token will be
* {@link #save(Token)}d automatically at the {@link #close()}. This is a convenience method
* in case you plan to do update operations on this token.
*
* @throws JbpmException in case no such token exists.
* @see #getToken(long)
* @see #loadToken(long)
* @see #getTokenForUpdate(long)
*/
public Token loadTokenForUpdate(long tokenId) {
Token token = getGraphSession().loadToken(tokenId);
addAutoSaveToken(token);
return token;
}
/**
* gets a token from the db and registers it for auto-save. The loaded token will be
* {@link #save(Token)}d automatically at the {@link #close()}. This is a convenience method
* in case you plan to do update operations on this token.
*
* @return the token or null in case no such token exists.
* @see #getToken(long)
* @see #loadToken(long)
* @see #loadTokenForUpdate(long)
*/
public Token getTokenForUpdate(long tokenId) {
Token token = getGraphSession().getToken(tokenId);
if (token != null) {
addAutoSaveToken(token);
}
return token;
}
/**
* loads a process instance from the db. Consider using
* {@link #loadProcessInstanceForUpdate(long)} if you plan to perform an update operation on
* the process instance.
*
* @throws JbpmException in case no such process instance exists.
* @see #getProcessInstance(long)
* @see #loadProcessInstanceForUpdate(long)
* @see #getProcessInstanceForUpdate(long)
*/
public ProcessInstance loadProcessInstance(long processInstanceId) {
return getGraphSession().loadProcessInstance(processInstanceId);
}
/**
* gets a process instance from the db. Consider using
* {@link #loadProcessInstanceForUpdate(long)} if you plan to perform an update operation on
* the process instance.
*
* @return the token or null in case no such token exists.
* @see #loadProcessInstance(long)
* @see #loadProcessInstanceForUpdate(long)
* @see #getProcessInstanceForUpdate(long)
*/
public ProcessInstance getProcessInstance(long processInstanceId) {
return getGraphSession().getProcessInstance(processInstanceId);
}
/**
* loads a process instances from the db and registers it for auto-save. The loaded process
* instance will be {@link #save(ProcessInstance)}d automatically at the {@link #close()}.
* This is a convenience method in case you plan to do update operations on this process
* instance.
*
* @throws JbpmException in case no such process instance exists.
* @see #loadProcessInstance(long)
* @see #getProcessInstance(long)
* @see #getProcessInstanceForUpdate(long)
*/
public ProcessInstance loadProcessInstanceForUpdate(long processInstanceId) {
ProcessInstance processInstance = getGraphSession().loadProcessInstance(processInstanceId);
addAutoSaveProcessInstance(processInstance);
return processInstance;
}
/**
* gets a process instances from the db and registers it for auto-save. The loaded process
* instance will be {@link #save(ProcessInstance)}d automatically at the {@link #close()}.
* This is a convenience method in case you plan to do update operations on this process
* instance.
*
* @return the token or null in case no such token exists.
* @see #loadProcessInstance(long)
* @see #getProcessInstance(long)
* @see #loadProcessInstanceForUpdate(long)
*/
public ProcessInstance getProcessInstanceForUpdate(long processInstanceId) {
ProcessInstance processInstance = getGraphSession().getProcessInstance(processInstanceId);
if (processInstance != null) {
addAutoSaveProcessInstance(processInstance);
}
return processInstance;
}
/**
* returns the process instance with the given key or null if no such instance exists.
*/
public ProcessInstance getProcessInstance(ProcessDefinition processDefinition, String key) {
return getGraphSession().getProcessInstance(processDefinition, key);
}
/**
* returns the process instance with the given key or throws an exception if no such instance
* exists.
*/
public ProcessInstance loadProcessInstance(ProcessDefinition processDefinition, String key) {
return getGraphSession().loadProcessInstance(processDefinition, key);
}
/**
* returns the process instance with the given key or null if no such instance exists. Upon
* close of this jbpmContext, the fetched process instance will be automatically saved.
*/
public ProcessInstance getProcessInstanceForUpdate(ProcessDefinition processDefinition,
String key) {
ProcessInstance processInstance = getGraphSession().getProcessInstance(processDefinition,
key);
if (processInstance != null) {
addAutoSaveProcessInstance(processInstance);
}
return processInstance;
}
/**
* returns the process instance with the given key or throws an exception if no such instance
* exists. Upon close of this jbpmContext, the fetched process instance will be automatically
* saved.
*/
public ProcessInstance loadProcessInstanceForUpdate(ProcessDefinition processDefinition,
String key) {
ProcessInstance processInstance = getGraphSession().loadProcessInstance(processDefinition,
key);
if (processInstance != null) {
addAutoSaveProcessInstance(processInstance);
}
return processInstance;
}
/**
* creates a new process instance for the latest version of the process definition with the
* given name.
*
* @throws JbpmException when no processDefinition with the given name is deployed.
*/
public ProcessInstance newProcessInstance(String processDefinitionName) {
ProcessDefinition processDefinition = getGraphSession().findLatestProcessDefinition(processDefinitionName);
return new ProcessInstance(processDefinition);
}
/**
* creates a new process instance for the latest version of the process definition with the
* given name and registers it for auto-save.
*
* @throws JbpmException when no processDefinition with the given name is deployed.
*/
public ProcessInstance newProcessInstanceForUpdate(String processDefinitionName) {
ProcessDefinition processDefinition = getGraphSession().findLatestProcessDefinition(processDefinitionName);
ProcessInstance processInstance = new ProcessInstance(processDefinition);
addAutoSaveProcessInstance(processInstance);
return processInstance;
}
/**
* saves the process instance.
*/
public void save(ProcessInstance processInstance) {
ensureOpen();
services.save(processInstance, this);
}
/**
* saves the process instance of the given token.
*/
public void save(Token token) {
save(token.getProcessInstance());
}
/**
* saves the process instance of the given task instance.
*/
public void save(TaskInstance taskInstance) {
save(taskInstance.getTaskMgmtInstance().getProcessInstance());
}
/**
* mark this transaction for rollback only in the persistence service. The {@link #close()}
* operation will then perform a rollback.
*/
public void setRollbackOnly() {
ensureOpen();
TxService txService = services.getTxService();
if (txService != null) {
txService.setRollbackOnly();
}
else {
throw new JbpmException("no transaction service configured");
}
}
// services //////////////////////////////////////////////////////////
/**
* gives access to the services and service factories.
*/
public Services getServices() {
return services;
}
public ServiceFactory getServiceFactory(String name) {
return services.getServiceFactory(name);
}
/**
* gives access to the object factory that builds the service factories.
*/
public ObjectFactory getObjectFactory() {
return objectFactory;
}
/** gives access to the configuration that created this context. */
public JbpmConfiguration getJbpmConfiguration() {
return (JbpmConfiguration) objectFactory.createObject(JbpmConfiguration.OBJECT_NAME);
}
// persistence methods //////////////////////////////////////////////////////
/**
* gets the hibernate session factory from the default configured persistence service.
*
* @return the hibernate session factory, or null
if a nonstandard persistence
* service is configured
*/
public SessionFactory getSessionFactory() {
PersistenceService persistenceService = getPersistenceService();
if (persistenceService instanceof DbPersistenceService) {
DbPersistenceService dbPersistenceService = (DbPersistenceService) persistenceService;
return dbPersistenceService.getSessionFactory();
}
return null;
}
/**
* sets the hibernate session factory into the default configured persistence service,
* overwriting the configured session factory (if there is one configured). if a nonstandard
* persistence service is configured, then this call has no effect.
*/
public void setSessionFactory(SessionFactory sessionFactory) {
PersistenceService persistenceService = getPersistenceService();
if (persistenceService instanceof DbPersistenceService) {
DbPersistenceService dbPersistenceService = (DbPersistenceService) persistenceService;
dbPersistenceService.setSessionFactory(sessionFactory);
}
}
/**
* gets the hibernate session from the default configured persistence service.
*
* @return the hibernate session, or null
if a nonstandard persistence service is
* configured.
*/
public Session getSession() {
PersistenceService persistenceService = getPersistenceService();
if (persistenceService instanceof DbPersistenceService) {
DbPersistenceService dbPersistenceService = (DbPersistenceService) persistenceService;
return dbPersistenceService.getSession();
}
return null;
}
/**
* sets the hibernate session into the default configured persistence service, preventing the
* creation of a session from the configured session factory (if there is one configured). if
* a nonstandard persistence service is configured, then this call has no effect.
*/
public void setSession(Session session) {
PersistenceService persistenceService = getPersistenceService();
if (persistenceService instanceof DbPersistenceService) {
DbPersistenceService dbPersistenceService = (DbPersistenceService) persistenceService;
dbPersistenceService.setSession(session);
}
}
/**
* gets the jdbc connection from the default configured persistence service.
*
* @return the jdbc connection, or null
if a nonstandard persistence service is
* configured.
*/
public Connection getConnection() {
PersistenceService persistenceService = getPersistenceService();
if (persistenceService instanceof DbPersistenceService) {
DbPersistenceService dbPersistenceService = (DbPersistenceService) persistenceService;
return dbPersistenceService.getConnection();
}
return null;
}
/**
* allows users to provide a jdbc connection to be used when the hibernate session is created.
* if a nonstandard persistence service is configured, then this call has no effect.
*/
public void setConnection(Connection connection) {
PersistenceService persistenceService = getPersistenceService();
if (persistenceService instanceof DbPersistenceService) {
DbPersistenceService dbPersistenceService = (DbPersistenceService) persistenceService;
dbPersistenceService.setConnection(connection);
}
}
// jbpm database access sessions
/**
* more variables related database access.
*/
public ContextSession getContextSession() {
PersistenceService persistenceService = getPersistenceService();
return persistenceService != null ? persistenceService.getContextSession() : null;
}
/**
* more logging related database access.
*/
public LoggingSession getLoggingSession() {
PersistenceService persistenceService = getPersistenceService();
return persistenceService != null ? persistenceService.getLoggingSession() : null;
}
/**
* more job related database access.
*/
public JobSession getJobSession() {
PersistenceService persistenceService = getPersistenceService();
return persistenceService != null ? persistenceService.getJobSession() : null;
}
/**
* more graph (process) related database access.
*/
public GraphSession getGraphSession() {
PersistenceService persistenceService = getPersistenceService();
return persistenceService != null ? persistenceService.getGraphSession() : null;
}
/**
* more task related database access.
*/
public TaskMgmtSession getTaskMgmtSession() {
PersistenceService persistenceService = getPersistenceService();
return persistenceService != null ? persistenceService.getTaskMgmtSession() : null;
}
// authentication methods ///////////////////////////////////////////////////
/**
* retrieves the current authenticated actor from the authentication service.
*/
public String getActorId() {
return services.getAuthenticationService().getActorId();
}
/**
* sets the currently authenticated actorId.
*/
public void setActorId(String actorId) {
ensureOpen();
AuthenticationService authService = services.getAuthenticationService();
if (authService != null) {
authService.setActorId(actorId);
}
}
public void addAutoSaveProcessInstance(ProcessInstance processInstance) {
ensureOpen();
if (autoSaveProcessInstances == null) {
autoSaveProcessInstances = new HashSet();
}
autoSaveProcessInstances.add(processInstance);
}
public void addAutoSaveToken(Token token) {
addAutoSaveProcessInstance(token.getProcessInstance());
}
public void addAutoSaveTaskInstance(TaskInstance taskInstance) {
addAutoSaveProcessInstance(taskInstance.getTaskMgmtInstance().getProcessInstance());
}
// private methods //////////////////////////////////////////////////////////
private PersistenceService getPersistenceService() {
ensureOpen();
return services.getPersistenceService();
}
public String toString() {
JbpmConfiguration configuration = getJbpmConfiguration();
if (configuration != null) {
String resourceName = configuration.getResourceName();
if (resourceName != null) {
return "JbpmContext(" + resourceName + ')';
}
}
return "JbpmContext@" + Integer.toHexString(hashCode());
}
}