JBPM深入解析之变量设计

在流程的流转的过程中,很多时候我们需要根据不同的实际情况传入一些初始化数据,以便完成我们个性化的业务需求;同时很多时候我们需要在不同的节点之间共享一些业务数据,特别是一些节点要以前一节点的输出作为输入等;变量对于流程引擎来说很重要,可以说没有变量,那么我们就不能运行时动态的设置和传入一些数据,这将极大的限制流程的灵活性!
      变量类型
       全局变量,所有的节点都可以获取并设置该变量的值
       局部变量,只在该节点及其子节点可以获取并设置该变量的值
      变量的传入
       在流程定义中进行变量的定义

<?xml version="1.0" encoding="UTF-8"?>

<process name="EndMultiple" xmlns="http://jbpm.org/4.4/jpdl">

<start g="16,96,48,48">
    <transition to="get return code" name=""/>
  </start>

<state g="96,94,111,52" name="get return code">
    <transition g="151,60:-36,11" name="200" to="ok"/>
    <transition g=":-16,-27" name="400" to="bad request"/>
    <transition g="151,183:-33,-32" name="500" to="internal server error"/>
  </state>

<end g="238,37,48,48" name="ok"/>
  <end g="238,98,48,48" name="bad request"/>
  <end g="240,160,48,48" name="internal server error"/>
  
  <variable    name="msg" init-expr="jbpm" type="string">      
  </variable>
  
      <null></null>
</variable>

</process>

在启动流程流程实例的时候传入全局变量

    Map<String, Object> variables = new HashMap<String, Object>();
    variables.put("category", "big");
    variables.put("dollars", 100000);
    Execution execution = executionService.startProcessInstanceByKey("TaskVariables", variables);

在唤醒那些可外部唤醒类型的节点时候传入局部变量

    variables = new HashMap<String, Object>();
    variables.put("category", "small");
    variables.put("lires", 923874893);
    taskService.completeTask(taskId, variables)

在任务存在的情况下,可以在任务等待外部唤醒时进行局部变量的设置

    variables = new HashMap<String, Object>();
    variables.put("category", "small");
    variables.put("lires", 923874893);    
    taskService.setVariables(taskId, variables);

在任何时候都可以通过执行服务传入设置全局变量

    variables = new HashMap<String, Object>();
    variables.put("category", "small");
    variables.put("lires", 923874893);    
    executionService.setVariable(execution.getId(),variables)
    variables = new HashMap<String, Object>();
    variables.put("category", "small");
    variables.put("lires", 923874893);    
    executionService.signalExecutionById(execution.getId(),variables);

变量架构设计


      TypeSet、DefaultTypeSet
      TypeSet定义了流程引擎中通过变量类型和matcher两种方式查找变量类型的接口;DefaultTypeSet对TypeSet的接口进行了实现,并定义了一个List<TypeMapping>来装载所有的变量类型的映射变量实例。
      TypeSet

package org.jbpm.pvm.internal.type;

/**
 * @author Tom Baeyens
 */
public interface TypeSet {

Type findTypeByMatch(String key, Object value);
  Type findTypeByName(String typeName);

}

DefaultTypeSet

package org.jbpm.pvm.internal.type;

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

/**
 * @author Tom Baeyens
 */
public class DefaultTypeSet implements TypeSet, Serializable {

private static final long serialVersionUID = 1L;

protected List<TypeMapping> typeMappings;

public Type findTypeByMatch(String key, Object value) {
    if (typeMappings!=null) {
      for (TypeMapping typeMapping: typeMappings) {
        if (typeMapping.matches(key, value)) {
          return typeMapping.getType();
        }
      }
    }
    
    return null;
  }

public Type findTypeByName(String typeName) {
    if ( (typeMappings!=null)
           && (typeName!=null)
       ) {
      for (TypeMapping typeMapping: typeMappings) {
        Type type = typeMapping.getType();
        if (typeName.equals(type.getName())) {
          return type;
        }
      }
    }
    return null;
  }

public void addTypeMapping(TypeMapping typeMapping) {
    if (typeMappings==null) {
      typeMappings = new ArrayList<TypeMapping>();
    }
    typeMappings.add(typeMapping);
  }
}

TypeSet的初始化     在配置文件中配置流程引擎中需要使用的变量的类型

Jbpm.defaut.cfg.xml引入变量类型配置的文件路径

<process-engine-context>
 
    <repository-service />
    <repository-cache />
    <execution-service />
    <history-service />
    <management-service />
    <identity-service />
    <task-service />

<object class="org.jbpm.pvm.internal.id.DatabaseDbidGenerator">
      <field name="commandService"><ref object="newTxRequiredCommandService" /></field>
    </object>

<object class="org.jbpm.pvm.internal.id.DatabaseIdComposer" init="eager" />
   
    <object class="org.jbpm.pvm.internal.el.JbpmElFactoryImpl" />
    <!--定义变量配置文件的路径-->
    <types resource="jbpm.variable.types.xml" />

<address-resolver />

</process-engine-context>

Jbpm.variable.types.xml定义了变量的类型、使用的转换器等信息

<types>

<!-- types stored in a native column -->
  <type name="string" class="java.lang.String" variable-class="org.jbpm.pvm.internal.type.variable.StringVariable" />
  <type name="long"   class="java.lang.Long" variable-class="org.jbpm.pvm.internal.type.variable.LongVariable" />
  <type name="double" class="java.lang.Double" variable-class="org.jbpm.pvm.internal.type.variable.DoubleVariable" />

<!-- types converted to a string -->
  <type name="date"    class="java.util.Date" converter="org.jbpm.pvm.internal.type.converter.DateToStringConverter" variable-class="org.jbpm.pvm.internal.type.variable.StringVariable" />
  <type name="boolean" class="java.lang.Boolean" converter="org.jbpm.pvm.internal.type.converter.BooleanToStringConverter" variable-class="org.jbpm.pvm.internal.type.variable.StringVariable" />
  <type name="char"    class="java.lang.Character" converter="org.jbpm.pvm.internal.type.converter.CharacterToStringConverter" variable-class="org.jbpm.pvm.internal.type.variable.StringVariable" />

<!-- types converted to a long -->
  <type name="byte"    class="java.lang.Byte" converter="org.jbpm.pvm.internal.type.converter.ByteToLongConverter" variable-class="org.jbpm.pvm.internal.type.variable.LongVariable" />
  <type name="short"   class="java.lang.Short" converter="org.jbpm.pvm.internal.type.converter.ShortToLongConverter" variable-class="org.jbpm.pvm.internal.type.variable.LongVariable" />
  <type name="integer" class="java.lang.Integer" converter="org.jbpm.pvm.internal.type.converter.IntegerToLongConverter" variable-class="org.jbpm.pvm.internal.type.variable.LongVariable" />

<!-- types converted to a double -->
  <type name="float" class="java.lang.Float" converter="org.jbpm.pvm.internal.type.converter.FloatToDoubleConverter" variable-class="org.jbpm.pvm.internal.type.variable.DoubleVariable" />

<!-- byte[] and char[] -->
  <type name="byte[]" class="[B" variable-class="org.jbpm.pvm.internal.type.variable.BlobVariable" />
  <type name="char[]" class="[C" variable-class="org.jbpm.pvm.internal.type.variable.TextVariable" />

<type name="hibernate-long-id"   class="hibernatable" id-type="long" variable-class="org.jbpm.pvm.internal.type.variable.HibernateLongVariable" />
  <type name="hibernate-string-id" class="hibernatable" id-type="string" variable-class="org.jbpm.pvm.internal.type.variable.HibernateStringVariable" />

<type name="serializable" class="serializable" converter="org.jbpm.pvm.internal.type.converter.SerializableToBytesConverter" variable-class="org.jbpm.pvm.internal.type.variable.BlobVariable" />

<!-- TODO: add ejb3 entity bean support -->
  <!-- TODO: add JCR activity support -->
  <!-- TODO: add collection support -->
  
</types>

TypesBinding解析jbpm.variable.types.xml中的变量类型定义

public class TypesBinding extends WireDescriptorBinding {

public TypesBinding() {
    super("types");
  }

public Object parse(Element element, Parse parse, Parser parser) {
    StreamInput streamSource = null;
    //查找type文件    
    if (element.hasAttribute("file")) {
      String fileName = element.getAttribute("file");
      File file = new File(fileName);
      if (file.exists() && file.isFile()) {
        streamSource = new FileStreamInput(file);
        parser.importStream(streamSource, element, parse);
      } else {
        parse.addProblem("file "+fileName+" isn't a file", element);
      }
    }

if (element.hasAttribute("resource")) {
      String resource = element.getAttribute("resource");
      ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
      streamSource = new ResourceStreamInput(resource, classLoader);
      parser.importStream(streamSource, element, parse);
    }

if (element.hasAttribute("url")) {
      String urlText = element.getAttribute("url");
      try {
        URL url = new URL(urlText);
        streamSource = new UrlStreamInput(url);
        parser.importStream(streamSource, element, parse);
      } catch (Exception e) {
        parse.addProblem("couldn't open url "+urlText, e);
      }
    }

TypesDescriptor typesDescriptor = new TypesDescriptor();

List<Element> typeElements = XmlUtil.elements(element, "type");
    for (Element typeElement: typeElements) {
      TypeMapping typeMapping = parseTypeMapping(typeElement, parse, parser);
      typesDescriptor.addTypeMapping(typeMapping);
    }
    return typesDescriptor;
  }

protected TypeMapping parseTypeMapping(Element element, Parse parse, Parser parser) {
    TypeMapping typeMapping = new TypeMapping();
    Type type = new Type();
    typeMapping.setType(type);

// type name
    //类型名称
    if (element.hasAttribute("name")) {
      type.setName(element.getAttribute("name"));
    }

String hibernateSessionFactoryName = XmlUtil.attribute(element, "hibernate-session-factory");

// first we get the matcher
    Matcher matcher = null;
    if (element.hasAttribute("class")) {
      String className = element.getAttribute("class");

// if type="serializable"
      if ("serializable".equals(className)) {
        matcher = new SerializableMatcher();

// if type="hibernatable"
      } else if ("hibernatable".equals(className)) {
        if (element.hasAttribute("id-type")) {
          String idType = element.getAttribute("id-type");
          if ("long".equalsIgnoreCase(idType)) {
            matcher = new HibernateLongIdMatcher(hibernateSessionFactoryName);
          } else if ("string".equalsIgnoreCase(idType)) {
            matcher = new HibernateStringIdMatcher(hibernateSessionFactoryName);
          } else {
            parse.addProblem("id-type was not 'long' or 'string': "+idType, element);
          }
        } else {
          parse.addProblem("id-type is required in a persistable type", element);
        }

// otherwise, we expect type="some.java.ClassName"
      } else {
        matcher = new ClassNameMatcher(className);
      }

} else {
      // look for the matcher element
      Element matcherElement = XmlUtil.element(element, "matcher");
      Element matcherObjectElement = XmlUtil.element(matcherElement);
      if (matcherObjectElement!=null) {
        try {
          Descriptor descriptor = (Descriptor) parser.parseElement(matcherObjectElement, parse);
          matcher = (Matcher) WireContext.create(descriptor);
        } catch (ClassCastException e) {
          parse.addProblem("matcher is not a "+Matcher.class.getName()+": "+(matcher!=null ? matcher.getClass().getName() : "null"), element);
        }
      } else {
        parse.addProblem("no matcher specified in "+XmlUtil.toString(element), element);
      }
    }

typeMapping.setMatcher(matcher);

// parsing the converter
    Converter converter = null;
    if (element.hasAttribute("converter")) {
      String converterClassName = element.getAttribute("converter");
      try {
        Class<?> converterClass = ReflectUtil.classForName(converterClassName);
        converter = (Converter) converterClass.newInstance();
      } catch (Exception e) {
        parse.addProblem("couldn't instantiate converter "+converterClassName, element);
      }
    } else {
      // look for the matcher element
      Element converterElement = XmlUtil.element(element, "converter");
      Element converterObjectElement = XmlUtil.element(converterElement);
      if (converterObjectElement!=null) {
        try {
          converter = (Converter) parser.parseElement(converterObjectElement, parse);
        } catch (ClassCastException e) {
          parse.addProblem("converter is not a "+Converter.class.getName()+": "+(converter!=null ? converter.getClass().getName() : "null"), element);
        }
      }
    }

type.setConverter(converter);

// parsing the variable class

Class<?> variableClass = null;
    if (element.hasAttribute("variable-class")) {
      String variableClassName = element.getAttribute("variable-class");
      try {
        variableClass = ReflectUtil.classForName(variableClassName);
      } catch (Exception e) {
        parse.addProblem("couldn't instantiate variable-class "+variableClassName, e);
      }
    } else {
      parse.addProblem("variable-class is required on a type: "+XmlUtil.toString(element), element);
    }

type.setVariableClass(variableClass);

return typeMapping;
  }
}

TypeDescriptor用于运行时生成DefaultTypeSet

public class TypesDescriptor extends AbstractDescriptor {

private static final long serialVersionUID = 1L;
  
  DefaultTypeSet defaultTypeSet = new DefaultTypeSet();
  
  public Object construct(WireContext wireContext) {
    return defaultTypeSet;
  }
  
  public Class< ? > getType(WireDefinition wireDefinition) {
    return DefaultTypeSet.class;
  }

public void addTypeMapping(TypeMapping typeMapping) {
    defaultTypeSet.addTypeMapping(typeMapping);
  }
  
  public DefaultTypeSet getDefaultTypeSet() {
    return defaultTypeSet;
  }
}

TypeMapping作为映射器,负责承载变量的类型和matcher

public class TypeMapping implements Serializable {

Matcher matcher;
  Type type;

private static final long serialVersionUID = 1L;
  
  public boolean matches(String name, Object value) {
    return matcher.matches(name, value);
  }
  
  public String toString() {
    return "("+matcher+"-->"+type+")";
  }
  
  public void setMatcher(Matcher matcher) {
    this.matcher = matcher;
  }
  public Type getType() {
    return type;
  }
  public void setType(Type type) {
    this.type = type;
  }
  public Matcher getMatcher() {
    return matcher;
  }
}

Matcher,递归查询给定变量的类型以及所有的基类中是否有与该Matcher对应的类的变量类型相同的。

public class ClassNameMatcher implements Matcher {

private static final long serialVersionUID = 1L;
  
  String className = null;
  
  public ClassNameMatcher(String className) {
    this.className = className;
  }
  
  public String toString() {
    return className;
  }

public boolean matches(String name, Object value) {
    if (value==null) {
      return true;
    }
    
    Class<?> valueClass = value.getClass();
    
    while (valueClass!=null) {
      if (className.equals(value.getClass().getName())) {
        return true;
      } else {
        Class<?>[] interfaces = valueClass.getInterfaces();
        for (int i=0; i<interfaces.length; i++) {
          if (className.equals(interfaces[i].getName())) {
            return true;
          }
        }
        valueClass = valueClass.getSuperclass();
      }
    }
    return false;
  }
}

Type 定义变量类型的名称、转换器和对应的Variable

public class Type implements Serializable {

private static final long serialVersionUID = 1L;
  
  protected String name;
  protected Converter converter;
  protected Class<?> variableClass;

public String toString() {
    if (name!=null) {
      return name;
    }
    StringBuilder text = new StringBuilder();
    if (converter!=null) {
      text.append(converter.toString());
      text.append("-->");
    }
    if (variableClass!=null) {
      text.append(variableClass.getSimpleName());
    } else {
      text.append("undefined");
    }
    return text.toString();
  }
  
  public Converter getConverter() {
    return converter;
  }
  public void setConverter(Converter converter) {
    this.converter = converter;
  }
  public Class< ? > getVariableClass() {
    return variableClass;
  }
  public void setVariableClass(Class< ? > variableClass) {
    this.variableClass = variableClass;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
}

Converter,负责变量运行时的表现形式和持久化形式进行转化

public class SerializableToBytesConverter implements Converter {

private static final long serialVersionUID = 1L;
  
  public boolean supports(Object value, ScopeInstanceImpl scopeInstance, Variable variable) {
    if (value==null) return true;
    return Serializable.class.isAssignableFrom(value.getClass());
  }

public Object convert(Object o, ScopeInstanceImpl scopeInstance, Variable variable) {
    byte[] bytes = null;
    try {
      ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
      ObjectOutputStream oos = new ObjectOutputStream(baos);
      oos.writeObject(o);
      oos.flush();
      bytes = baos.toByteArray();

Transaction transaction = EnvironmentImpl.getFromCurrent(Transaction.class, false);
      if (transaction!=null) {
        transaction.registerDeserializedObject(new DeserializedObject(o, scopeInstance, (BlobVariable) variable));
      }
      
    } catch (IOException e) {
      throw new JbpmException("couldn't serialize '"+o+"'", e);
    }
    
    return bytes;
  }

public Object revert(Object o, ScopeInstanceImpl scopeInstance, Variable variable) {
    byte[] bytes = (byte[]) o;
    try {
      ByteArrayInputStream bais = new ByteArrayInputStream(bytes);

ObjectInputStream ois = null;
     
      ois = new DeploymentObjectInputStream(bais, scopeInstance.getExecution().getProcessDefinition().getDeploymentId());
      
      Object object = ois.readObject();
      
      Transaction transaction = EnvironmentImpl.getFromCurrent(Transaction.class, false);
      if (transaction!=null) {
        transaction.registerDeserializedObject(new DeserializedObject(object, scopeInstance, (BlobVariable) variable));
      }
      
      return object;

} catch (Exception e) {
      throw new JbpmException("couldn't deserialize object", e);
    }
  }
}

Variable,定义具体的变量以及一些持久化需要的属性

public class StringVariable extends Variable {
  
  private static final long serialVersionUID = 1L;
  
  protected String string = null;

public boolean isStorable(Object value) {
    if (value==null) return true;
    return (String.class==value.getClass());
  }

public Object getObject() {
    return string;
  }

public void setObject(Object value) {
    this.string = (String) value;
    if (value!=null) {
      this.textValue = string;
    } else {
      this.textValue = null;
    }
  }
}

JBPM深入解析之变量设计相关推荐

  1. Tomcat 架构原理解析到架构设计借鉴

    ‍ 点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 Tomcat 架构原理解析到架构设计借鉴 Tomcat 发展这 ...

  2. jQuery技术内幕:深入解析jQuery架构设计与实现原理1

    jQuery技术内幕:深入解析jQuery架构设计与实现原理 高 云 著 图书在版编目(CIP)数据 jQuery技术内幕:深入解析jQuery架构设计与实现原理 / 高云著. -北京:机械工业出版社 ...

  3. Hadoop技术内幕:深入解析MapReduce架构设计与实现原理

    <Hadoop技术内幕:深入解析MapReduce架构设计与实现原理> 基本信息 作者: 董西成 丛书名: 大数据技术丛书 出版社:机械工业出版社 ISBN:9787111422266 上 ...

  4. jQuery技术内幕:深入解析jQuery架构设计与实现原理

    为什么80%的码农都做不了架构师?>>>    jQuery技术内幕:深入解析jQuery架构设计与实现原理 本书由阿里巴巴资深前端开发工程师撰写,从源代码角度全面而系统地解读了jQ ...

  5. mysql jdbc 绑定变量_jdbc测试mysql数据库sql预解析(绑定变量)

    jdbc测试mysql数据库sql预解析(绑定变量) 用习惯了oracle,学习mysql,想测试一下mysql绑定变量的效果.以前看网上介绍大部份都说mysql没有sql共享池的概念,所以也不存在s ...

  6. 解析php变量,php使用parse_str实现查询字符串解析到变量中的方法

    本文实例讲述了php使用parse_str实现查询字符串解析到变量中的方法.分享给大家供大家参考,具体如下: parse_str()函数可实现把字符串解析到变量中,这意味着实现了字符串与变量之间的一种 ...

  7. 中等职业学校计算机课程标准,全市中等职业学校信息技术课程标准内涵解析与教学设计培训会议成功举办...

    为深入贯彻落实教育部关于做好公共基础课新课标培训的要求,进一步提升信息技术课程教师教学能力水平,7月9日,由市职业教育研究院组织的全市中等职业学校信息技术课程标准内涵解析与教学设计培训会议在淄博信息工 ...

  8. 电力信息采集的通用型通信规约解析系统研究与设计

    电力信息采集的通用型通信规约解析系统研究与设计 蒋湘涛 http://xueshu.baidu.com/s?wd=paperuri%3A%28a61890f7723743df132caf246fd0a ...

  9. Hadoop技术内幕:深入解析MapReduce架构设计与实现原理 (大数据技术丛书) - 电子书下载(高清版PDF格式+EPUB格式)...

    Hadoop技术内幕:深入解析MapReduce架构设计与实现原理 (大数据技术丛书)-董西成著 在线阅读                   百度网盘下载(ihhy) 书名:Hadoop技术内幕:深 ...

最新文章

  1. C#中对POP3邮件解码
  2. 从Visual Studio里抓取抽象语法树(AST)
  3. 四轴飞行器实践教程(内部资料)
  4. Dubbo 集成 ZooKeeper 注册中心实现服务调用
  5. SpringBoot中扩展SpringMVC
  6. 华为nova6升级鸿蒙os,华为公布升级计划:鸿蒙OS系统开始推送,覆盖百款机型
  7. DIV CSS 网页兼容全搞定 (IE6 IE7 IE8 IE9 火狐 谷歌)
  8. Dev cpp出现段错误的原因之一
  9. html菜鸟教程选项卡,jQuery EasyUI 布局插件 – Tabs 标签页/选项卡 | 菜鸟教程
  10. 部署 - 前端部署https服务,并配置安全证书
  11. TyperError: excepted str,byte or os.PathLike object, not io.TextIOWrapper
  12. STM32F103 flash地址与数据存入时高低位的关系
  13. 爱荷华大学计算机科学专业,2015 U.S News计算机科学专业排名(不知道有没有伙伴在找)...
  14. 支付宝AR红包引出Python中的PIL小试
  15. int类型数组和bool类型数组互相转换
  16. javax.servlet.ServletException: Could not resolve view with name ‘***‘ in servlet
  17. linux weblogic 内存溢出,weblogic10内存溢出解决方法
  18. Cisco(62)——PBR策略路由案例
  19. CIA3 NOI接站(tarjan缩环+Floyd传递闭包+可相交最小路径覆盖)
  20. hadoop_hdfs命令

热门文章

  1. 知方可补不足~SQL2008中的发布与订阅模式~续
  2. Awesome Projects (汇聚全球所有
  3. 一张图看Windows Store有多混乱 微软现在开始整治
  4. 2017上半年软考 第七章 重要知识点
  5. 【5】python核心编程 第八章-条件和循环
  6. Cocos2d-x项目移植到WP8系列之二:开篇
  7. android关于设置list_item高度问题
  8. 使用Eclipse+PyDev+EclipseHtmlEditor搭建Django开发环境
  9. 2019年企业新增长 从雇佣“机器人员工”开始
  10. java B2B2C springmvc mybatis电子商务平台源码-Consul服务发现原理...