JBPM深入解析之变量设计

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

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值