您的位置:首页 > 产品设计 > 产品经理

JBPM深入解析之变量设计

2011-07-17 08:15 417 查看
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;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐