All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jbpm.db.GraphSession Maven / Gradle / Ivy

There is a newer version: 3.2.19.ayg
Show newest version
/*
 * 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.db;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.ObjectNotFoundException;
import org.hibernate.Session;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

import org.jbpm.JbpmContext;
import org.jbpm.JbpmException;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;
import org.jbpm.graph.node.ProcessState;
import org.jbpm.persistence.JbpmPersistenceException;

/**
 * graph-related database operations.
 */
public class GraphSession {

  private final Session session;
  /** @deprecated */
  private final JbpmSession jbpmSession;

  /** @deprecated use {@link #GraphSession(Session)} instead */
  public GraphSession(JbpmSession jbpmSession) {
    this.session = jbpmSession.getSession();
    this.jbpmSession = jbpmSession;
  }

  public GraphSession(Session session) {
    this.session = session;
    this.jbpmSession = null;
  }

  // process definitions //////////////////////////////////////////////////////

  /**
   * assigns a version number to the given process definition and then makes it persistent.
   */
  public void deployProcessDefinition(ProcessDefinition processDefinition) {
    // versioning applies to named process definitions only
    String processName = processDefinition.getName();
    if (processName == null) {
      throw new JbpmException("process definition has no name");
    }
    // find the current latest process definition
    ProcessDefinition previousLatestVersion = findLatestProcessDefinition(processName);
    // if there is a current latest process definition
    if (previousLatestVersion != null) {
      // take the next version number
      processDefinition.setVersion(previousLatestVersion.getVersion() + 1);
    }
    else {
      // start from 1
      processDefinition.setVersion(1);
    }
    saveProcessDefinition(processDefinition);
  }

  /**
   * saves the process definition. this method does not assign a version number.
   * 
   * @see #deployProcessDefinition(ProcessDefinition)
   */
  public void saveProcessDefinition(ProcessDefinition processDefinition) {
    try {
      session.save(processDefinition);
    }
    catch (HibernateException e) {
      handle(e);
      throw new JbpmPersistenceException("could not save " + processDefinition, e);
    }
  }

  /**
   * returns the persistent process definition with the given identifier, assuming the
   * definition exists. if the requested process definition does not exist in the database,
   * {@link ObjectNotFoundException} is thrown when the definition state is first accessed.
   */
  public ProcessDefinition loadProcessDefinition(long processDefinitionId) {
    try {
      return (ProcessDefinition) session.load(ProcessDefinition.class,
        new Long(processDefinitionId));
    }
    catch (HibernateException e) {
      handle(e);
      throw new JbpmPersistenceException("could not load process definition "
        + processDefinitionId, e);
    }
  }

  /**
   * returns the persistent process definition with the given identifier.
   * 
   * @return the referenced process definition, or null if there is no such
   * definition.
   */
  public ProcessDefinition getProcessDefinition(long processDefinitionId) {
    try {
      return (ProcessDefinition) session.get(ProcessDefinition.class,
        new Long(processDefinitionId));
    }
    catch (HibernateException e) {
      handle(e);
      throw new JbpmPersistenceException("could not get process definition "
        + processDefinitionId, e);
    }
  }

  /**
   * finds the process definition with the given name and version.
   */
  public ProcessDefinition findProcessDefinition(String name, int version) {
    try {
      return (ProcessDefinition) session.getNamedQuery("GraphSession.findProcessDefinitionByNameAndVersion")
        .setString("name", name)
        .setInteger("version", version)
        .uniqueResult();
    }
    catch (HibernateException e) {
      handle(e);
      throw new JbpmPersistenceException("could not find process definition by name '" + name
        + "' and version " + version, e);
    }
  }

  /**
   * queries the database for the latest version of a process definition with the given name.
   */
  public ProcessDefinition findLatestProcessDefinition(String name) {
    try {
      return (ProcessDefinition) session.getNamedQuery("GraphSession.findLatestProcessDefinitionQuery")
        .setString("name", name)
        .setMaxResults(1)
        .uniqueResult();
    }
    catch (HibernateException e) {
      handle(e);
      throw new JbpmPersistenceException("could not find process definition by name " + name, e);
    }
  }

  /**
   * queries the database for the latest version of each process definition. process definitions
   * are distinct by name.
   */
  public List findLatestProcessDefinitions() {
    try {
      List tuples = session.getNamedQuery("GraphSession.findLatestProcessDefinitions").list();
      if (tuples.isEmpty()) return Collections.EMPTY_LIST;

      List result = new ArrayList(tuples.size());
      for (Iterator i = tuples.iterator(); i.hasNext();) {
        Object[] tuple = (Object[]) i.next();
        String name = (String) tuple[0];
        Integer version = (Integer) tuple[1];
        result.add(findProcessDefinition(name, version.intValue()));
      }
      return result;
    }
    catch (HibernateException e) {
      handle(e);
      throw new JbpmPersistenceException("could not find latest process definitions", e);
    }
  }

  public List findProcessDefinitions(Collection processDefinitionIds) {
    try {
      return session.createCriteria(ProcessDefinition.class)
        .add(Restrictions.in("id", processDefinitionIds))
        .list();
    }
    catch (HibernateException e) {
      handle(e);
      throw new JbpmPersistenceException("could not find process definitions by identifiers "
        + processDefinitionIds, e);
    }
  }

  /**
   * queries the database for all process definitions, ordered by name (ascending), then by
   * version (descending).
   */
  public List findAllProcessDefinitions() {
    try {
      return session.getNamedQuery("GraphSession.findAllProcessDefinitions").list();
    }
    catch (HibernateException e) {
      handle(e);
      throw new JbpmPersistenceException("could not find all process definitions", e);
    }
  }

  /**
   * queries the database for all versions of process definitions with the given name, ordered
   * by version (descending).
   */
  public List findAllProcessDefinitionVersions(String name) {
    try {
      return session.getNamedQuery("GraphSession.findAllProcessDefinitionVersions")
        .setString("name", name)
        .list();
    }
    catch (HibernateException e) {
      handle(e);
      throw new JbpmPersistenceException("could not find all process definitions by name "
        + name, e);
    }
  }

  public void deleteProcessDefinition(long processDefinitionId) {
    deleteProcessDefinition(loadProcessDefinition(processDefinitionId));
  }

  public void deleteProcessDefinition(ProcessDefinition processDefinition) {
    try {
      // delete all instances of the given process
      List processInstances = session.createCriteria(ProcessInstance.class)
        .add(Restrictions.eq("processDefinition", processDefinition))
        .setProjection(Projections.id())
        .list();
      for (Iterator iter = processInstances.iterator(); iter.hasNext();) {
        Long id = (Long) iter.next();
        ProcessInstance processInstance = (ProcessInstance) session.get(ProcessInstance.class, id);
        if (processInstance != null) deleteProcessInstance(processInstance);
      }

      List referencingProcessStates = findReferencingProcessStates(processDefinition);
      for (Iterator i = referencingProcessStates.iterator(); i.hasNext();) {
        ProcessState processState = (ProcessState) i.next();
        processState.setSubProcessDefinition(null);
      }

      // then delete the process definition
      session.delete(processDefinition);
    }
    catch (HibernateException e) {
      handle(e);
      throw new JbpmPersistenceException("could not delete " + processDefinition, e);
    }
  }

  private List findReferencingProcessStates(ProcessDefinition subProcessDefinition) {
    return session.getNamedQuery("GraphSession.findReferencingProcessStates")
      .setEntity("subProcessDefinition", subProcessDefinition)
      .list();
  }

  // process instances ////////////////////////////////////////////////////////

  /**
   * @deprecated use {@link org.jbpm.JbpmContext#save(ProcessInstance)} instead.
   */
  public void saveProcessInstance(ProcessInstance processInstance) {
    JbpmContext.getCurrentJbpmContext().save(processInstance);
  }

  /**
   * returns the persistent process instance with the given identifier, assuming the instance
   * exists. if the requested process instance does not exist in the database,
   * {@link ObjectNotFoundException} is thrown when the instance state is first accessed.
   */
  public ProcessInstance loadProcessInstance(long processInstanceId) {
    try {
      return (ProcessInstance) session.load(ProcessInstance.class, new Long(processInstanceId));
    }
    catch (HibernateException e) {
      handle(e);
      throw new JbpmPersistenceException("could not load process instance "
        + processInstanceId, e);
    }
  }

  /**
   * returns the persistent process instance with the given identifier.
   * 
   * @return the referenced process instance, or null if there is no such instance
   */
  public ProcessInstance getProcessInstance(long processInstanceId) {
    try {
      return (ProcessInstance) session.get(ProcessInstance.class, new Long(processInstanceId));
    }
    catch (HibernateException e) {
      handle(e);
      throw new JbpmPersistenceException("could not get process instance "
        + processInstanceId, e);
    }
  }

  /**
   * returns the persistent token with the given identifier, assuming the token exists. if the
   * requested token does not exist in the database, {@link ObjectNotFoundException} is thrown
   * when the token state is first accessed.
   */
  public Token loadToken(long tokenId) {
    try {
      return (Token) session.load(Token.class, new Long(tokenId));
    }
    catch (HibernateException e) {
      handle(e);
      throw new JbpmPersistenceException("could not load token " + tokenId, e);
    }
  }

  /**
   * returns the persistent token with the given identifier.
   * 
   * @return the referenced token, or null if there is no such token.
   */
  public Token getToken(long tokenId) {
    try {
      return (Token) session.get(Token.class, new Long(tokenId));
    }
    catch (HibernateException e) {
      handle(e);
      throw new JbpmPersistenceException("could not get token " + tokenId, e);
    }
  }

  /**
   * obtains a pessimistic lock on the process instance with the given identifier.
   */
  public void lockProcessInstance(long processInstanceId) {
    try {
      session.load(ProcessInstance.class, new Long(processInstanceId), LockMode.UPGRADE);
    }
    catch (HibernateException e) {
      handle(e);
      throw new JbpmPersistenceException("could not lock process instance "
        + processInstanceId, e);
    }
  }

  /**
   * obtains a pessimistic lock on the given process instance.
   */
  public void lockProcessInstance(ProcessInstance processInstance) {
    try {
      session.lock(processInstance, LockMode.UPGRADE);
    }
    catch (HibernateException e) {
      handle(e);
      throw new JbpmPersistenceException("could not lock " + processInstance, e);
    }
  }

  /**
   * finds all instances of the given process definition.
   * 
   * @return a list of process instances ordered by start date, earliest first
   */
  public List findProcessInstances(long processDefinitionId) {
    try {
      return session.getNamedQuery("GraphSession.findAllProcessInstancesForDefinition")
        .setLong("processDefinitionId", processDefinitionId)
        .list();
    }
    catch (HibernateException e) {
      handle(e);
      throw new JbpmPersistenceException("could not find instances for process definition "
        + processDefinitionId, e);
    }
  }

  public void deleteProcessInstance(long processInstanceId) {
    deleteProcessInstance(loadProcessInstance(processInstanceId));
  }

  public void deleteProcessInstance(ProcessInstance processInstance) {
    deleteProcessInstance(processInstance, true, true);
  }

  public void deleteProcessInstance(ProcessInstance processInstance, boolean includeTasks,
    boolean includeJobs) {
    if (processInstance == null) {
      throw new IllegalArgumentException("processInstance cannot be null");
    }

    try {
      // delete outstanding jobs
      if (includeJobs) deleteJobs(processInstance);

      // delete logs
      deleteLogs(processInstance);

      // detach from superprocess token
      Token superProcessToken = processInstance.getSuperProcessToken();
      if (superProcessToken != null)
        detachFromSuperProcess(processInstance, superProcessToken);

      // delete subprocess instances
      deleteSubProcesses(processInstance);

      // delete tasks; since TaskLogs reference tasks, logs are deleted first
      if (includeTasks) deleteTasks(processInstance);

      // delete the process instance
      session.delete(processInstance);
    }
    catch (HibernateException e) {
      handle(e);
      throw new JbpmPersistenceException("could not delete " + processInstance, e);
    }
  }

  private void deleteJobs(ProcessInstance processInstance) {
    session.getNamedQuery("GraphSession.deleteJobsForProcessInstance")
      .setEntity("processInstance", processInstance)
      .executeUpdate();
  }

  private void deleteLogs(ProcessInstance processInstance) {
    List logs = session.getNamedQuery("GraphSession.findLogsForProcessInstance")
      .setEntity("processInstance", processInstance)
      .list();
    for (Iterator i = logs.iterator(); i.hasNext();) {
      session.delete(i.next());
    }
  }

  private void detachFromSuperProcess(ProcessInstance processInstance, Token superProcessToken) {
    processInstance.setSuperProcessToken(null);
    superProcessToken.setSubProcessInstance(null);
  }

  private void deleteSubProcesses(ProcessInstance processInstance) {
    List subProcessInstances = session.getNamedQuery("GraphSession.findSubProcessInstances")
      .setEntity("processInstance", processInstance)
      .list();

    for (Iterator i = subProcessInstances.iterator(); i.hasNext();) {
      ProcessInstance subProcessInstance = (ProcessInstance) i.next();
      deleteProcessInstance(subProcessInstance);
    }
  }

  private void deleteTasks(ProcessInstance processInstance) {
    List tasks = session.getNamedQuery("GraphSession.findTaskInstancesForProcessInstance")
      .setEntity("processInstance", processInstance)
      .list();
    for (Iterator i = tasks.iterator(); i.hasNext();) {
      session.delete(i.next());
    }
  }

  public static class AverageNodeTimeEntry {

    private long nodeId;
    private String nodeName;
    private int count;
    private long averageDuration;
    private long minDuration;
    private long maxDuration;

    public long getNodeId() {
      return nodeId;
    }

    public void setNodeId(final long nodeId) {
      this.nodeId = nodeId;
    }

    public String getNodeName() {
      return nodeName;
    }

    public void setNodeName(final String nodeName) {
      this.nodeName = nodeName;
    }

    public int getCount() {
      return count;
    }

    public void setCount(final int count) {
      this.count = count;
    }

    public long getAverageDuration() {
      return averageDuration;
    }

    public void setAverageDuration(final long averageDuration) {
      this.averageDuration = averageDuration;
    }

    public long getMinDuration() {
      return minDuration;
    }

    public void setMinDuration(final long minDuration) {
      this.minDuration = minDuration;
    }

    public long getMaxDuration() {
      return maxDuration;
    }

    public void setMaxDuration(final long maxDuration) {
      this.maxDuration = maxDuration;
    }
  }

  public List calculateAverageTimeByNode(long processDefinitionId, long minumumDurationMillis) {
    try {
      List tuples = session.getNamedQuery("GraphSession.calculateAverageTimeByNode")
        .setLong("processDefinitionId", processDefinitionId)
        .setDouble("minimumDuration", minumumDurationMillis)
        .list();
      if (tuples.isEmpty()) return Collections.EMPTY_LIST;

      List results = new ArrayList();
      for (Iterator i = tuples.iterator(); i.hasNext();) {
        Object[] values = (Object[]) i.next();

        AverageNodeTimeEntry entry = new AverageNodeTimeEntry();
        entry.setNodeId(((Number) values[0]).longValue());
        entry.setNodeName((String) values[1]);
        entry.setCount(((Number) values[2]).intValue());
        entry.setAverageDuration(((Number) values[3]).longValue());
        entry.setMinDuration(((Number) values[4]).longValue());
        entry.setMaxDuration(((Number) values[5]).longValue());

        results.add(entry);
      }
      return results;
    }
    catch (HibernateException e) {
      handle(e);
      throw new JbpmPersistenceException("could not calculate average time by node "
        + "for process definition " + processDefinitionId, e);
    }
  }

  public List findActiveNodesByProcessInstance(ProcessInstance processInstance) {
    try {
      return session.getNamedQuery("GraphSession.findActiveNodesByProcessInstance")
        .setEntity("processInstance", processInstance)
        .list();
    }
    catch (HibernateException e) {
      handle(e);
      throw new JbpmPersistenceException("could not find active nodes for "
        + processInstance, e);
    }
  }

  /**
   * returns the instance of the given process definition with the specified business key.
   * 
   * @return the referenced instance, or null if there is no such instance
   */
  public ProcessInstance getProcessInstance(ProcessDefinition processDefinition, String key) {
    try {
      return (ProcessInstance) session.getNamedQuery("GraphSession.findProcessInstanceByKey")
        .setEntity("processDefinition", processDefinition)
        .setString("key", key)
        .uniqueResult();
    }
    catch (HibernateException e) {
      handle(e);
      throw new JbpmPersistenceException("could not get process instance by key " + key, e);
    }
  }

  /**
   * returns the instance of the given process definition with the specified business key,
   * assuming the instance exists.
   * 
   * @throws JbpmPersistenceException if the referenced process instance does not exist
   */
  public ProcessInstance loadProcessInstance(ProcessDefinition processDefinition, String key) {
    ProcessInstance processInstance = getProcessInstance(processDefinition, key);
    if (processInstance == null) {
      throw new JbpmPersistenceException("could not load process instance by key " + key);
    }
    return processInstance;
  }

  private void handle(HibernateException exception) {
    // exception will be rethrown, no need to log here
    if (jbpmSession != null) jbpmSession.handleException();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy