`

【转】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 ;
    }
  }
}

原文:http://www.cnblogs.com/wufengtinghai/archive/2011/07/17/2108551.html
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics