JWFDv0.96开源工作流引擎设计---XMLTO-数据库解析过程说明

     

        JWFDv0.96开源工作流引擎设计

                       

                        ---XMLTO数据库解析过程说明

 

 

 

  

 

 


注:这篇文章中所使用的“函数”就是指JAVA语言中的方法

 


 

作者 comsci   2011.4.25    四川。成都

 

 

 

 

 

 

简要说明:


 

  实际上用户通过JWFD 流程设计器设计出的流程图的结构一般是保存在 XML 格式的文件中的 (XML 文件结构请参考” JWFDv0.96 开源工作流引擎设计 - 流程图 XML 结构说明 .doc ) ,而流程引擎的运行和控制却是建立在对后台数据库的基本表结构的 SQL 操作基础上面的 ( 数据库结构请参考” JWFDv0.96 开源工作流引擎设计 - 数据库结构明 .doc ) ,因此从前端设计器 XML 到后台数据库基本表的数据解析和转换过程对于整个 JWFD 工作流系统的设计就显得尤为重要,所以我在初步完成了 JWFD 工作流系统设计文档的编写之后,发现这个环节必须补上,因此我将在这篇文档中,详细介绍 JWFD 工作流系统的 XML- 数据库解析过程 ( 包括代码实现 )


我尽量把整个设计思想和实现代码的结构都用很通俗的语言来讲述清楚,方便大家理解,如果经过自己的思考之后,还有不理解的地方,可以给我发邮件或者在JWFD 的论坛上面提问题,非常感谢 fireflow 的非也和 openjweb 的阿宝同志的大力支持,JWFD 也有自己的论坛板块 http://www.fireflow.org/forum-33-1.html ,如果大家对JWFD 有什么意见和建议,可以再这个论坛上面发帖,包括提交 BUG 报告,另外这篇文章中介绍的JWFD代码和程序均在这个地址下载 http://www.cnblogs.com/comsci/favorite/260690.html

 

 

 

 

 

 

 

设计与实现方法:

 

  采用基于JGRAPH 开源软件的流程图数据结构 XML 模型,通过调用 JGraphGXLCodec 类的流程图编码和解码方法,将设计器设计出来的流程图转换为GXL(XML)- 文件格式存储在本地硬盘 ( 服务器 ) 上面 ( 解释 :gxl 文件格式就是一种简单的图形 xml 文件存储格式 ), 然后通过调用 ParserGxl 类和 GxlToDatabase 类实现将XML 文件中存储的流程图数据转换到数据库中进行存储,以便实现下一步 JWFD 流程引擎对流程图数据的处理。

 


 

  JWFD 流程图 - 数据库转换的实现过程

 

上面的图例是JWFD 开源工作流系统里面的流程图 XML- 数据库转换的实现流程,而具体负责实现上述功能的代码是在 JWFD 的代码包里面的  org.jwfd.workflowDesigner.FLCLs.Gxl  的package 里面的下面三个类,如下


 

   org.jwfd.workflowDesigner.FLCLs.Gxl .GxlToDatabase.java

   org.jwfd.workflowDesigner.FLCLs.Gxl .JgraphGxlCodec.java

   org.jwfd.workflowDesigner.FLCLs.Gxl .ParserGxl.java

 

 

主要的实现方法用简单的语言来描述就是: 通过调用DOM( 一种 XML 解析工具包) 类中的函数对流程图文件的 XML 结构进行解析,对存储在 XML 文件里面的流程图的拓扑结构( 节点和连接线 ) 进行提取操作,然后把提取出来的流程图拓扑结构据通过数据库的 SQL 操作 insert update 等方式插入到已经建立好的 MYSQL 数据库的 JWFD 流程基本表中( JWFD 的流程基本表的表结构请参考  JWFDv0.96  开源工作流引擎设计 - 数据库结构说明 .doc   一文)

 


 

需要说明的是, XML 解析模块在JWFD 中主要是依靠 JGRAPH 开源软件的 XML 处理模块来实现的,JWFD 通过调用这个 XML 处理模块,然后加上 XML 数据整理和数据库操作方法来共同完成这一过程


在这篇文章中,我主要介绍ParserGxl类的实现过程和代码结构,因为只要理解这个类的结构,其它两个相关类的结构就可以很容易的理解了,这个ParserGxl类是主体结构,而其它两个类是附属功能模块

 

public   ParserGxl (String fe, String gid)  throws  Exception {}


 

这个类中的主函数  ParserGxl() 是一个DOM 类的变形函数,主要用于从流程图的 XML 文档中把流程图的节点,连接线,坐标等数据提取出来,如果大家需要改造流程图的定义 XML 文件格式,那么就需要对这个函数中的某些代码有所了解


 

 

现在我们来对具体的实现代码进行分析


 

File f =  new  File(fe) 这句代码的意义是通过参数 fe传递过来的文件名称建立一个文件类型的变量 f ,这个变量 f 就是后面 DOM 类用来读取 xml 文件的文件名称

 

 

DocumentBuilderFactory dbf = DocumentBuilderFactory. newInstance ();

这句代码的意义是建立一个 XML文档数据处理模型的实例  .newInstance 的意思就是在内存中创建一个 XML 数据模型的实例


 

DocumentBuilder db = dbf.newDocumentBuilder();

这句代码的意思是 实例化一个XML文档解析类

 

 

Document doc = db.parse(f);

这句代码的意思是 装载前面导入的XML文件


 

Element gxl = (Element) doc.getDocumentElement(); 

NodeList graph_list = gxl.getChildNodes();

 

 

这两句代码的作用是初始化需要解析的XML 文件,并获取该 XML 文件的第一个元素,并从第一个元素列表 list 开始解析这个 XML 数据

 

实际上,前面几句代码联合在一起就是一个初始化 XML数据处理类的代码段,这些代码段是统一在一起的,不能够分开使用,这点需要注意,特别是大家在复制这段代码的时候要注意 它们是一个整体,作用是初始化一个XML 数据模型实例,并为下面的提取 XML 数据元做准备

 

 

if  (graph_list.getLength() == 0) {   return ;}

这段代码的意思通过判断xml 数据列表的长度是否为 0 ,并执行返回命令

 

 

for  ( int  graph_index = 0; graph_index < graph_list.getLength(); graph_index++) {      

这个for循环的循环控制变量 graph_index XML 文件的数据段长度,从这个循环开始程序开始自动的提取 xml 文件的数据


Node graph_node = graph_list.item(graph_index);

定义一个Node 类型变量  并从 graph_list 数组 item 中提取 graph_node 元数据

 

 

if  (graph_node.getNodeName().equals( "graph" )) {}

这个IF 判断的用处是通过判断 xml 数据段的初始名称是否为 "graph" ,如果是则决定执行下面的操作 , getNodeName() 方法是用来程序读取XML 数据段节点名称的操作

 

 

Element graph_elem = (Element) graph_node;

定义一个 Element元素变量,并将 graph_node 变量类型强行转化为 Element 类型


 

NodeList list = graph_elem. getChildNodes ();

定义一个NodeList 变量 list  并将前面定义的 graph_elem 里面的子元素提取出来


 

for  ( int  i = 0; i < list.getLength(); i++) { }

这个FOR 循环把前面获得 xml 流程图的 LIST 数据列表的长度作为循环控制条件,循环体内部是读取 XML 流程节点和连接线数据的操作函数,读取这些数据并同步写入数据库的表中

 

 

注意,这个for 循环和前面另外一个 for 循环共同发挥作用,一起来做这个 XML 数据提取工作,因为 XML 数据结构是嵌套的,因此需要两个 FOR 循环来一起使用

 

 

 

 ================================================================= =====================


  if  (node.getAttributes() !=  null  && node.getNodeName() !=  null {

        String    type = node.getNodeName().toString().toLowerCase(); 

 

            if  (type.equals( "node" ))  {

    

            Node edgeid = node.getAttributes().getNamedItem( "id" );

           String id = edgeid.getNodeValue();

 

 

 

 这两个嵌套的if 判断语句是用来过滤需要提取的 XML 数据的标志头的,第一个 if 判断语句是过滤空数据的操作 , 就是属性和名称都为空 null 的数据就不进入下一步的提取操作,而非空的数据则需要进行 tostring()- 字符串转换操作并转化为小写 lowerCase()

 

 

第二个if 语句是判断 type 数据名称是否为 node- 节点 如果数据段标志为 node ,则我们就可以对这个 XML 数据段中包含的数据进行提取,这里主要提取两个标志中的数据,一个是节点的 id ,一个是连接边 edge id ,并在下面的 wis.into_node() 方法中把这两个关键 id 值写入到数据库的表结构中去

 


 

================================================================= =========================      

 

wis.into_node( getLabel (node),id,gid,getcondition(node) );


 

这句代码是这个类中所有代码的一个核心语句,意义就是把提取出来的XML 文件中的流程图节点的 id 和节点包含的条件控制参数数据一起写入数据库中,当然这个方法是引用另外一个类 GxlToDatabase 中的操作,该操作实际上是一个SQL 操作,具体的代码如下

 

 

  "insert into step_main(step_name,graph_id,step_id,cond) values

 ('"  +step_name + "','"  + gid +  "','"  + step_id +  "','"  + condition +  "')"

 

 

Insert语句中使用的数据库表名称  step_main JWFD 数据结构的节点主表,其表结构的详细说明请参考文档  JWFDv0.96 开源工作流引擎设计 - 数据库结构说明 .doc  


 

这个语句中的insert 插入操作仅仅涉及 step_main 表中的 step_name( 节点名称 ) 字段, graph_id (流程图 id )字段 ,step_id( 节点 id) 字段 ,cond (节点嵌入条件控制参数)字段,而这些字段中的具体数据就是用前面所描述的那些 JAVA 语句从 XML 数据文件中提取出来的,所以按照 insert 操作的顺序我们可以了解  getLabel(node) 是取节点名称的操作 ,id 是流程节点的 id gid 是流程图的 id,getcondition(node) 是取节点嵌入的条件控制参数的操作,这样的说明是否让大家对本语句所执行的操作和涉及到数据结构有比较清晰的理解了呢? 如果还有不清楚地地方,请给我 发邮件 或者在论坛上面发帖或者加我的QQ(784092877) ,我会尽量回答大家的问题 

 

 

接下来的这个IF 判断语句是继续前面的工作,不过这次是提取 XML 中的节点之间的连接线 edge 的数据,如果类型为 edge  则进行下面的提取操作

 


 

if  (type.equals( "edge" ))

 

 

================================================================= ======= =====================

 


 

  String from =  null ;

  String to =  null ;

  String edge =  null ;

  String prop =  null ;

  

  Node edgeid =  node.getAttributes().getNamedItem ( "id" );

  Node tmp =  node.getAttributes().getNamedItem ( "from" );

    Node tmp1 =  node.getAttributes().getNamedItem ( "to" );

  

  edge = edgeid. getNodeValue ();

  from = tmp. getNodeValue ();

  to = tmp1. getNodeValue ();

 


 

这段代码完成几个工作,前面四行定义四个字符串 (from,to,edge,prop) 变量,用于存储接下来要提取的 XML文件中的连接线数据 , 其中 from 用于存储节点连接线的起始端点, to 变量用于存储节点连接线的终止端点,两个节点之间的连接线就是通过起始端点和终止端点来定义的,另外加上一个 Edgeid 变量,这个变量作为连接边的唯一标志 id


 

而接下来的代码段中的粗体字所表示的代码就是本程序用于提取xml 文档中的数据的操作函数,这些操作代码来源于 JAVA XML 处理模块 dom , 大家可以找找专门介绍 DOM 数据处理的文章来看看,我在这里就不做详细介绍了

本段最后的三行代码就是利用getNodeValue() 函数把 XML 数据段中的流程图的边,边起始点,边终止点的具体数据提取出来,并存放在前面定义的字符串变量 edge,from,to 中,以便下一步的处理

 


 

================================================================= ======= =====================

 

  try  {

      wis.into_edge(edge, from, to, gid, getcondition(node));

 } catch  (Exception ex) {

    System. out .println( "创建edge异常:"  +ex);

  }


 

在理解前面一段的代码的意义之后,我们再来看看这段代码,这是一个 try-catch异常处理语句包围的功能执行语句 , 前面我们已经介绍过这种 wis 类中的一个函数  wis.into_node ,而这里的 wis.into_edge 的功能和这个 wis.into_node 的功能是对应的, into_node() 函数是系统在提取了xml 数据段中的节点相关数据之后,往数据库中写入这些数据的功能代码函数,而 into_edge() 函数却是系统在提取了XML 数据段中的节点连接边的相关数据之后,往数据库中写入这些节点连接边数据的功能代码函数,这个功能函数其实和前面介绍过的 into_node() 函数一样,是一个SQL 语句,具体代码如下

 

"insert into edge_control(edge_id,from_step,to_step,graph_id,prop) values 

('"  +edgeid +  "','"  + from + "','"  + to +  "','"  + gid +  "','"  + prop +  "')"

 

前面介绍过这种类似的SQL 操作,这里就再简略介绍下   

 

edge_control  是 JWFD 流程数据库结构中的一个基础表,这个基础表是系统用于存储流程图中连接边 edge 的一张表,其详细的数据结构请参考  JWFDv0.96 开源工作流引擎设计 - 数据库结构说明 .doc  

 

 

edge_control 数据表中写入的数据参数分别如下


 

Edge_id    两个节点间连接线段的唯一标识id 

From_step   连接线段的起始节点id

To_step     连接线段的终止节点id

Graph_id    该连接线段所在的流程图的id

Prop         该连接线所包含的嵌入式参数( 未使用 ) ,这里通过 getcondition(node) 函数来获得这个参数,实际上并未使用,这个参数是节点的嵌入数据,而不是连接边的嵌入数据


 

所有这些参数都已经通过前面的 XML数据提取操作保存在本类定义的字符串变量中了,这个 sql 操作就用这些字符串变量作为写入数据库中的实际数据变量

 

 

================================================================= =======================


 

到这里为止,系统提取XML 数据的功能代码  和写入数据库的操作代码 就基本介绍完了,这个类的剩下的函数的代码  都是同一结构的函数,其主要功能是提取 xml 数据段中的详细参数,比如说 getlabel 是提取 xml 数据段中的节点的名称 , 注意是名称而不是 id ,而 getcondition 是提取节点中嵌入的条件表达式参数, getBound 是提取节点在整个流程图的二维坐标的数据,这些功能代码的结构均来自 jgraph 的一个子项目  jgraphpad 的代码包中,我仅仅是做了下修改,具体的代码结构我就不做详细的介绍了

 

 

 

protected  String getcondition(Node node) {}

protected  String getLabel(Node node) { }

protected  Vector getBound(Node node) { }

 

 

 

只有一个地方需要注意下,如果大家要自定义这些函数,比如说根据系统的需要修改了XML 文件的自定义的变量,现在需要提取这些新的定义变量,仅仅需要修改这些函数的一行,就可以实现代码复用

 

 

if  (attr.getNodeName().equals( "attr" )

            && attr

            .getAttributes()

            .getNamedItem( "name" )

            .getNodeValue()

            .equals(

             "Condition" )) 

 


 

如果大家需要复用这段代码,只需要修改这段代码的最后一行的参数  这里是Condition ,而仅仅需要把这个 Condition 修改为你定义的 XML 的参数即可,而整个函数都可以立即复用,并不需要修改其他的部分,当然需要修改下函数的名称

 

 

================================================================= ======================


 

实际上,到目前为止,通过这里所介绍的代码,我们就完成了将通过流程设计器设计好的流程图的XML 文件转换并保存在后台的数据库中这一过程了,在实现这一个过程之后,我们就可以通过对数据库中的这些流程图数据进行 SQL 操作,来实现一个流程引擎的一系列功能了,流程引擎的底层操作 API 的结构和说明请参考下面的文档和代码

 

 

 

JWFDv0.96 开源工作流系统 - 二次开发 API 简易说明 .doc

JWFDv0.96 开源工作流引擎设计 - 流程图 XML 结构说明 .doc

JWFDv0.96 开源工作流引擎设计 - 自动运行控制器结构说明 .doc


 

 

 


你可能感兴趣的:(数据结构,数据库,xml,Graph,文档,工作流引擎)