org.jbpm.JbpmContext.java Source code

Java tutorial

Introduction

Here is the source code for org.jbpm.JbpmContext.java

Source

/*
 * 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.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.authentication.DefaultAuthenticationService;
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.
 * 
 * <p>Obtain JbpmContext's via {@link org.jbpm.JbpmConfiguration#createJbpmContext()}
 * and put it in a try-finally block like this:
 * </p>
 * 
 * <pre>
 * 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();
 * }
 * </pre>
 * 
 * <p>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, ...
 * </p>
 * 
 * <p>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.  
 * </p>
 * 
 * <p>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.   
 * </p>
 * 
 * <p>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)}.
 * </p>
 * 
 * <p>All the <code>...ForUpdate(...)</code> methods will automatically save the loaded 
 * objects at <code>jbpmContext.close();</code>
 * </p>
 */
public class JbpmContext implements Serializable {

    private static final long serialVersionUID = 1L;

    public static final String DEFAULT_JBPM_CONTEXT_NAME = "default.jbpm.context";

    static ThreadLocal currentContextsStack = new ThreadLocal();

    /**
     * resets static members for test isolation.
     */
    static void reset() {
        currentContextsStack = new ThreadLocal();
    }

    ObjectFactory objectFactory = null;
    Services services = null;
    List autoSaveProcessInstances = null;
    JbpmConfiguration jbpmConfiguration = null;

    /**
     * normally, JbpmContext object are created via a {@link JbpmConfiguration}.
     */
    public JbpmContext(Services services, ObjectFactory objectFactory) {
        log.debug("creating " + toString());
        this.services = services;
        this.objectFactory = objectFactory;
    }

    /**
     * make sure you close your JbpmContext in a finally block.
     */
    public void close() {
        log.debug("closing jbpmContext " + toString());
        try {
            if (services != null) {
                try {
                    autoSave();
                } finally {
                    services.close();
                }
            }
        } finally {
            if (jbpmConfiguration != null) {
                jbpmConfiguration.jbpmContextClosed(this);
            }
        }
    }

    /**
     * obtains the current JbpmContext from a thread local.
     * The current JbpmContexts are maintained in a stack so 
     * that you can do nested context operations for 
     * different jbpm configurations.
     * @deprecated method moved to {@link JbpmConfiguration}.
     */
    public static JbpmContext getCurrentJbpmContext() {
        JbpmContext currentJbpmContext = null;
        JbpmConfiguration currentJbpmConfiguration = JbpmConfiguration.getCurrentJbpmConfiguration();
        if (currentJbpmConfiguration != null) {
            currentJbpmContext = currentJbpmConfiguration.getCurrentJbpmContext();
        }
        return currentJbpmContext;
    }

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

    /**
     * get 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) {
        if (services != null) {
            services.save(processInstance, this);
        }
    }

    /**
     * saves the complete process instance for this token.
     */
    public void save(Token token) {
        save(token.getProcessInstance());
    }

    /**
     * saves the complete process instance for this 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() {
        TxService txService = (services != null ? services.getTxService() : null);
        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 containing the configuration 
     * for creating the service factories.
     */
    public ObjectFactory getObjectFactory() {
        return objectFactory;
    }

    // persistence methods //////////////////////////////////////////////////////

    /**
     * gets the hibernate session factory from the default configured persistence 
     * service.  
     * @throws ClassCastException if another persistence service is configured then the default.
     */
    public SessionFactory getSessionFactory() {
        DbPersistenceService persistenceService = (DbPersistenceService) getPersistenceService();
        if (persistenceService == null)
            return null;
        return persistenceService.getSessionFactory();
    }

    /**
     * sets the hibernate session factory into the default configured persistence 
     * service, overwriting the configured session factory (if there is one configured).
     * @throws ClassCastException if another persistence service is configured then the default.
     */
    public void setSessionFactory(SessionFactory sessionFactory) {
        DbPersistenceService persistenceService = (DbPersistenceService) getPersistenceService();
        if (persistenceService == null)
            return;
        persistenceService.setSessionFactory(sessionFactory);
    }

    /**
     * gets the hibernate session from the default configured persistence 
     * service.  
     * @throws ClassCastException if another persistence service is configured then the default.
     */
    public Session getSession() {
        DbPersistenceService persistenceService = (DbPersistenceService) getPersistenceService();
        if (persistenceService == null)
            return null;
        return persistenceService.getSession();
    }

    /**
     * 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).
     * @throws ClassCastException if another persistence service is configured then the default.
     */
    public void setSession(Session session) {
        DbPersistenceService persistenceService = (DbPersistenceService) getPersistenceService();
        if (persistenceService == null)
            return;
        persistenceService.setSession(session);
    }

    /**
     * gets the jdbc connection from the default configured persistence service.
     * @throws ClassCastException if another persistence service is configured then the default.
     */
    public Connection getConnection() {
        DbPersistenceService persistenceService = (DbPersistenceService) getPersistenceService();
        if (persistenceService == null)
            return null;
        return persistenceService.getConnection();
    }

    /**
     * allows users to provide a jdbc connection to be used when the hibernate 
     * session is created.
     * @throws ClassCastException if another persistence service is configured then the default.
     */
    public void setConnection(Connection connection) {
        DbPersistenceService persistenceService = (DbPersistenceService) getPersistenceService();
        if (persistenceService == null)
            return;
        persistenceService.setConnection(connection);
    }

    // jbpm database access sessions

    /**
     * more variables related database access.
     */
    public ContextSession getContextSession() {
        PersistenceService persistenceService = getPersistenceService();
        if (persistenceService == null)
            return null;
        return persistenceService.getContextSession();
    }

    /**
     * more logging related database access.
     */
    public LoggingSession getLoggingSession() {
        PersistenceService persistenceService = getPersistenceService();
        if (persistenceService == null)
            return null;
        return (persistenceService != null ? persistenceService.getLoggingSession() : null);
    }

    /**
     * more job related database access.
     */
    public JobSession getJobSession() {
        PersistenceService persistenceService = getPersistenceService();
        if (persistenceService == null)
            return null;
        return (persistenceService != null ? persistenceService.getJobSession() : null);
    }

    /**
     * more graph (process) related database access.
     */
    public GraphSession getGraphSession() {
        PersistenceService persistenceService = getPersistenceService();
        if (persistenceService == null)
            return null;
        return (persistenceService != null ? persistenceService.getGraphSession() : null);
    }

    /**
     * more task related database access.
     */
    public TaskMgmtSession getTaskMgmtSession() {
        PersistenceService persistenceService = getPersistenceService();
        if (persistenceService == null)
            return null;
        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.
     * @throws ClassCastException if another authentication service is configured then the default.
     */
    public void setActorId(String actorId) {
        DefaultAuthenticationService authenticationService = (DefaultAuthenticationService) services
                .getAuthenticationService();
        DefaultAuthenticationService defaultAuthenticationService = (DefaultAuthenticationService) authenticationService;
        defaultAuthenticationService.setActorId(actorId);
    }

    // private methods //////////////////////////////////////////////////////////

    void addAutoSaveProcessInstance(ProcessInstance processInstance) {
        if (autoSaveProcessInstances == null)
            autoSaveProcessInstances = new ArrayList();
        autoSaveProcessInstances.add(processInstance);
    }

    void addAutoSaveToken(Token token) {
        addAutoSaveProcessInstance(token.getProcessInstance());
    }

    void addAutoSaveTaskInstance(TaskInstance taskInstance) {
        addAutoSaveProcessInstance(taskInstance.getTaskMgmtInstance().getProcessInstance());
    }

    void autoSave() {
        if (autoSaveProcessInstances != null) {
            Iterator iter = autoSaveProcessInstances.iterator();
            while (iter.hasNext()) {
                ProcessInstance processInstance = (ProcessInstance) iter.next();
                save(processInstance);
                iter.remove();
            }
        }
    }

    PersistenceService getPersistenceService() {
        if (services == null)
            return null;
        return services.getPersistenceService();
    }

    public JbpmConfiguration getJbpmConfiguration() {
        return jbpmConfiguration;
    }

    private static Log log = LogFactory.getLog(JbpmContext.class);
}