JBPM引擎设计(1)

本文主要探讨了JBPM引擎中的命令模式应用,该模式用于管理命令执行,优化接口处理。内容涉及Task处理的Command实现,如getTaskCmd,以及CommandService接口的重要角色。通过获取ProcessEnginee单例对象,我们可以执行JBPM流程引擎的各种操作。CommandService在TaskServiceImp和ProcessEnginee的execute接口中扮演关键角色。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、命令模式在Jbpm的使用,有助于管理各命令的执行,也方便方便接口处理,如下:

protected int getJobCount() {
    return processEngine.execute(new Command<Integer>() {
      private static final long serialVersionUID = 1L;


      public Integer execute(Environment environment) {
        org.hibernate.Session session = environment.get(org.hibernate.Session.class);
        return (Integer) session.createCriteria("org.jbpm.pvm.internal.job.JobImpl")
          .add(Restrictions.gt("retries", 0))
          .setProjection(Projections.rowCount())
          .uniqueResult();
      }
    });
  }


2、JBPM中类的调用关系,(主要在命令模式处理业务dao的过程)如下:

以上类图只在Task处理做解释,实际上包含业务处理的所有操作(DAO)都为一个Command,如上面的getTaskCmd,其实现如下:


package org.jbpm.pvm.internal.cmd;

import org.jbpm.api.JbpmException;
import org.jbpm.api.cmd.Environment;
import org.jbpm.api.task.Task;
import org.jbpm.pvm.internal.session.DbSession;
import org.jbpm.pvm.internal.task.TaskImpl;

/**
 * @author Alejandro Guizar
 */
public class GetTaskCmd extends AbstractCommand<Task> {

  private static final long serialVersionUID = 1L;
  
  protected String taskId;
  
  public GetTaskCmd(String taskId) {
    if (taskId==null) {
      throw new JbpmException("taskId is null");
    }
    this.taskId = taskId;
  }

  public Task execute(Environment environment) throws Exception {
    DbSession dbSession = environment.get(DbSession.class);
    return dbSession.get(TaskImpl.class, Long.parseLong(taskId));
  }
}

而以上处理中的DbSession就是hibernate的Session接口,这是在enviroment中注入的:


package org.jbpm.pvm.internal.hibernate;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.hibernate.metadata.ClassMetadata;

import org.jbpm.api.Execution;
import org.jbpm.api.JbpmException;
import org.jbpm.api.history.HistoryComment;
import org.jbpm.api.task.Task;
import org.jbpm.internal.log.Log;
import org.jbpm.pvm.internal.client.ClientExecution;
import org.jbpm.pvm.internal.env.EnvironmentImpl;
import org.jbpm.pvm.internal.history.model.HistoryCommentImpl;
import org.jbpm.pvm.internal.history.model.HistoryProcessInstanceImpl;
import org.jbpm.pvm.internal.id.DbidGenerator;
import org.jbpm.pvm.internal.job.JobImpl;
import org.jbpm.pvm.internal.job.StartProcessTimer;
import org.jbpm.pvm.internal.model.ExecutionImpl;
import org.jbpm.pvm.internal.query.DeploymentQueryImpl;
import org.jbpm.pvm.internal.query.HistoryActivityInstanceQueryImpl;
import org.jbpm.pvm.internal.query.HistoryDetailQueryImpl;
import org.jbpm.pvm.internal.query.HistoryProcessInstanceQueryImpl;
import org.jbpm.pvm.internal.query.JobQueryImpl;
import org.jbpm.pvm.internal.query.ProcessInstanceQueryImpl;
import org.jbpm.pvm.internal.query.TaskQueryImpl;
import org.jbpm.pvm.internal.session.DbSession;
import org.jbpm.pvm.internal.task.TaskImpl;
import org.jbpm.pvm.internal.util.Clock;
import org.jbpm.pvm.internal.util.CollectionUtil;

/**
 * @author Tom Baeyens
 */
public class DbSessionImpl implements DbSession {

  private static Log log = Log.getLog(DbSessionImpl.class.getName());

  protected Session session;

  public void close() {
    session.close();
  }

  public <T> T get(Class<T> entityClass, Object primaryKey) {
    return entityClass.cast(session.get(entityClass, (Serializable) primaryKey));
  }

  public void flush() {
    session.flush();
  }

  public void forceVersionUpdate(Object entity) {
    session.lock(entity, LockMode.FORCE);
  }

  public void lockPessimistically(Object entity) {
    session.lock(entity, LockMode.UPGRADE);
  }

  public void save(Object entity) {
    session.save(entity);
  }

  public void update(Object entity) {
    session.update(entity);
  }

  public void merge(Object entity) {
    session.merge(entity);
  }

  public void delete(Object entity) {
    session.delete(entity);
  }

  public Session getSession() {
    return session;
  }

  public void setSession(Session session) {
    this.session = session;
  }

  public void deleteProcessDefinitionHistory(String processDefinitionId) {
    List<?> historyProcessInstances = session.createCriteria(HistoryProcessInstanceImpl.class)
      .add(Restrictions.eq("processDefinitionId", processDefinitionId))
      .list();

    for (Object hpi : historyProcessInstances) {
      session.delete(hpi);
    }
  }

  public boolean isHistoryEnabled() {
    ClassMetadata historyHibernateMetadata = session.getSessionFactory()
      .getClassMetadata(HistoryProcessInstanceImpl.class);
    return historyHibernateMetadata != null;
  }

  // process execution queries ////////////////////////////////////////////////

  public ClientExecution findExecutionById(String executionId) {
    // query definition can be found at the bottom of resource jbpm.execution.hbm.xml
    return (ClientExecution) session.getNamedQuery("findExecutionById")
      .setString("id", executionId)
      .setMaxResults(1)
      .uniqueResult();
  }

  public ClientExecution findProcessInstanceById(String processInstanceId) {
    // query definition can be found at the bottom of resource jbpm.execution.hbm.xml
    return (ClientExecution) session.getNamedQuery("findProcessInstanceById")
      .setString("processInstanceId", processInstanceId)
      .setMaxResults(1)
      .uniqueResult();
  }

  public ClientExecution findProcessInstanceByIdIgnoreSuspended(String processInstanceId) {
    // query definition can be found at the bottom of resource jbpm.execution.hbm.xml
    return (ClientExecution) session.getNamedQuery("findProcessInstanceByIdIgnoreSuspended")
      .setString("processInstanceId", processInstanceId)
      .setMaxResults(1)
      .uniqueResult();
  }

  public List<String> findProcessInstanceIds(String processDefinitionId) {
    // query definition can be found at the bottom of resource jbpm.execution.hbm.xml
    List<?> processInstanceIds = session.getNamedQuery("findProcessInstanceIds")
      .setString("processDefinitionId", processDefinitionId)
      .list();
    return CollectionUtil.checkList(processInstanceIds, String.class);
  }

  public void deleteProcessInstance(String processInstanceId) {
    deleteProcessInstance(processInstanceId, true);
  }

  public void deleteProcessInstance(String processInstanceId, boolean deleteHistory) {
    if (processInstanceId == null) {
      throw new JbpmException("processInstanceId is null");
    }

    // if history should be deleted
    if (deleteHistory && (isHistoryEnabled())) {
      // try to get the history
      HistoryProcessInstanceImpl historyProcessInstance = findHistoryProcessInstanceById(processInstanceId);

      // if there is a history process instance in the db
      if (historyProcessInstance != null) {
        if (log.isDebugEnabled()) {
          log.debug("deleting history process instance " + processInstanceId);
        }
        session.delete(historyProcessInstance);
      }
    }

    ExecutionImpl processInstance = (ExecutionImpl) findProcessInstanceByIdIgnoreSuspended(processInstanceId);
    if (processInstance != null) {
      deleteSubProcesses(processInstance, deleteHistory);

      // delete remaining tasks for this process instance
      List<TaskImpl> tasks = findTasks(processInstanceId);
      for (TaskImpl task : tasks) {
        session.delete(task);
      }

      // delete remaining jobs for this process instance
      JobImpl currentJob = EnvironmentImpl.getFromCurrent(JobImpl.class, false);
      List<JobImpl> jobs = findJobs(processInstanceId);
      for (JobImpl job : jobs) {
        if (job != currentJob) {
          session.delete(job);
        }
      }

      if (log.isDebugEnabled()) {
        log.debug("Deleting process instance " + processInstanceId);
      }
      session.delete(processInstance);
    }
    else {
      throw new JbpmException("Can't delete processInstance " + processInstanceId
        + ": no processInstance found for the given id");
    }
  }

  private void deleteSubProcesses(ExecutionImpl execution, boolean deleteHistory) {
    ExecutionImpl subProcessInstance = execution.getSubProcessInstance();
    if (subProcessInstance != null) {
      subProcessInstance.setSuperProcessExecution(null);
      execution.setSubProcessInstance(null);
      deleteProcessInstance(subProcessInstance.getId(), deleteHistory);
    }
    Collection<ExecutionImpl> childExecutions = execution.getExecutions();
    if (childExecutions != null) {
      for (ExecutionImpl childExecution : childExecutions) {
        deleteSubProcesses(childExecution, deleteHistory);
      }
    }
  }

  public HistoryProcessInstanceImpl findHistoryProcessInstanceById(String processInstanceId) {
    return (HistoryProcessInstanceImpl) session.createCriteria(HistoryProcessInstanceImpl.class)
      .add(Restrictions.eq("processInstanceId", processInstanceId))
      .uniqueResult();
  }

  List<TaskImpl> findTasks(String processInstanceId) {
    List<?> tasks = session.createCriteria(TaskImpl.class)
      .createAlias("processInstance", "pi")
      .add(Restrictions.eq("pi.id", processInstanceId))
      .list();
    return CollectionUtil.checkList(tasks, TaskImpl.class);
  }

  List<JobImpl> findJobs(String processInstanceId) {
    List<?> jobs = session.createCriteria(JobImpl.class)
      .createAlias("processInstance", "pi")
      .add(Restrictions.eq("pi.id", processInstanceId))
      .list();
    return CollectionUtil.checkList(jobs, JobImpl.class);
  }

  public void cascadeExecutionSuspend(ExecutionImpl execution) {
    // cascade suspend to jobs
    List<?> jobs = session.createCriteria(JobImpl.class)
      .add(Restrictions.eq("execution", execution))
      .add(Restrictions.ne("state", JobImpl.STATE_SUSPENDED))
      .list();
    for (JobImpl job : CollectionUtil.checkList(jobs, JobImpl.class)) {
      job.suspend();
    }

    // cascade suspend to tasks
    List<?> tasks = session.createCriteria(TaskImpl.class)
      .add(Restrictions.eq("execution", execution))
      .add(Restrictions.ne("state", Task.STATE_SUSPENDED))
      .list();
    for (TaskImpl task : CollectionUtil.checkList(tasks, TaskImpl.class)) {
      task.suspend();
    }
  }

  public void cascadeExecutionResume(ExecutionImpl execution) {
    // cascade resume to jobs
    List<?> jobs = session.createCriteria(JobImpl.class)
      .add(Restrictions.eq("execution", execution))
      .add(Restrictions.eq("state", JobImpl.STATE_SUSPENDED))
      .list();
    for (JobImpl job : CollectionUtil.checkList(jobs, JobImpl.class)) {
      job.resume();
    }

    // cascade resume to tasks
    List<?> tasks = session.createCriteria(TaskImpl.class)
      .add(Restrictions.eq("execution", execution))
      .add(Restrictions.eq("state", Task.STATE_SUSPENDED))
      .list();
    for (TaskImpl task : CollectionUtil.checkList(tasks, TaskImpl.class)) {
      task.resume();
    }
  }

  public TaskImpl createTask() {
    TaskImpl task = newTask();
    task.setCreateTime(Clock.getTime());
    return task;
  }

  protected TaskImpl newTask() {
    TaskImpl task = new TaskImpl();
    long dbid = EnvironmentImpl.getFromCurrent(DbidGenerator.class).getNextId();
    task.setDbid(dbid);
    task.setNew(true);
    return task;
  }

  public TaskImpl findTaskByDbid(long taskDbid) {
    return (TaskImpl) session.get(TaskImpl.class, taskDbid);
  }

  public TaskImpl findTaskByExecution(Execution execution) {
    return (TaskImpl) session.createCriteria(TaskImpl.class)
      .add(Restrictions.eq("execution", execution))
      .uniqueResult();
  }

  public JobImpl findFirstAcquirableJob() {
    return (JobImpl) session.getNamedQuery("findFirstAcquirableJob")
      .setTimestamp("now", Clock.getTime())
      .setMaxResults(1)
      .uniqueResult();
  }

  public List<JobImpl> findExclusiveJobs(Execution processInstance) {
    List<?> exclusiveJobs = session.getNamedQuery("findExclusiveJobs")
      .setTimestamp("now", Clock.getTime())
      .setEntity("processInstance", processInstance)
      .list();
    return CollectionUtil.checkList(exclusiveJobs, JobImpl.class);
  }

  public JobImpl findFirstDueJob() {
    return (JobImpl) session.getNamedQuery("findFirstDueJob")
      .setMaxResults(1)
      .uniqueResult();
  }

  public List<StartProcessTimer> findStartProcessTimers(String processDefinitionName) {
    List<?> timers = session.createCriteria(StartProcessTimer.class)
      .add(Restrictions.eq("signalName", processDefinitionName))
      .list();
    return CollectionUtil.checkList(timers, StartProcessTimer.class);
  }

  public ProcessInstanceQueryImpl createProcessInstanceQuery() {
    return new ProcessInstanceQueryImpl();
  }

  public TaskQueryImpl createTaskQuery() {
    return new TaskQueryImpl();
  }

  public HistoryProcessInstanceQueryImpl createHistoryProcessInstanceQuery() {
    return new HistoryProcessInstanceQueryImpl();
  }

  public HistoryActivityInstanceQueryImpl createHistoryActivityInstanceQuery() {
    return new HistoryActivityInstanceQueryImpl();
  }

  public HistoryDetailQueryImpl createHistoryDetailQuery() {
    return new HistoryDetailQueryImpl();
  }

  public JobQueryImpl createJobQuery() {
    return new JobQueryImpl();
  }

  public DeploymentQueryImpl createDeploymentQuery() {
    return new DeploymentQueryImpl();
  }

  public List<HistoryComment> findCommentsByTaskId(String taskId) {
    List<?> comments = session.createCriteria(HistoryCommentImpl.class)
      .createAlias("historyTask", "task")
      .add(Restrictions.eq("task.dbid", Long.parseLong(taskId)))
      .addOrder(Order.asc("historyTaskIndex"))
      .list();
    return CollectionUtil.checkList(comments, HistoryComment.class);
  }
}
也就是说,底层还是通过session操作数据库的。


3、关于上图中的CommandService是一个接口:

public interface CommandService {
  
  String NAME_TX_REQUIRED_COMMAND_SERVICE = "txRequiredCommandService";
  String NAME_NEW_TX_REQUIRED_COMMAND_SERVICE = "newTxRequiredCommandService";

  /**
   * @throws JbpmException if command throws an exception.
   */
  <T> T execute(Command<T> command);
}

实际调用的类是AbstractServiceImpl依赖这个CommandService,如下:

public class AbstractServiceImpl {
  
  protected CommandService commandService;

  public CommandService getCommandService() {
    return commandService;
  }

  public void setCommandService(CommandService commandService) {
    this.commandService = commandService;
  }
}

AbstractServiceImpl几个子类对于实际操作的几个接口:


4、我们在使用JBPM流程引擎时,先获取单例的ProcessEnginee对象,用这个可以

 RepositoryService getRepositoryService();


  /** the {@link ExecutionService execution service} that provides access
   * to the runtime executions repository. */ 
  ExecutionService getExecutionService();


  /** the {@link HistoryService history service} that provides access
   * to the history executions repository. */ 
  HistoryService getHistoryService();


  /** the {@link TaskService task service} that exposes the 
   * runtime human task lists. */ 
  TaskService getTaskService();


  /** the {@link IdentityService identity service} that exposes the 
   * user and group operations management operations. */ 
  IdentityService getIdentityService();


  /** the {@link ManagementService management service} that exposes the 
   * management operations to operators that have to keep the jBPM system 
   * up and running. */ 
  ManagementService getManagementService();

也就是几个服务接口,我们应用层就是操作者几个接口进行流程控制。


6、以上关键部分就是CommandService是具体对象:

比如TaskServiceImp中依赖的CommandService就是:

processEngineWireContext.get()在上层获取

比如ProcessEniginee中还有一个execute(Command<T>)接口中的Command就是这里获取

userCommandService = (CommandService) processEngineWireContext.get(CommandService.NAME_TX_REQUIRED_COMMAND_SERVICE);



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值