第四章 面向图形的编程
4.1. 介绍
本章可以看作是JBoss jBPM的表现。它给出了当前策略背后的思想和蓝图以及JBoss jBPM工程未来方向的完整概览。这个蓝图和传统的途径有很大的不同。
首先,我们相信很多流程语言。有很多不同的环境和不同的目的要求有他们自己指定的流程语言。
其次,面向图形编程是一种新的实现技术为所有的机遇图形的流程语言提供服务。
我们进步的最有利的地方在于他定义了所有类型的流程语言的一种基本技术。
当前软件开发依赖于各领域指定的语言。一个典型的Java开发者将使用相当一部分领域制定的语言。各种框架里面的工程中的XML文件可以被认为是特定领域语言。
图4.1. 基于图形语言的位置
用于工作流、BPM、流程编制和页面流的特定领域语言是基于有向图的执行。其他的诸如Hibernate映射文件,ioc-configuration就不是。 面向图形编程是所有基于执行图的特定领域语言的基础。
面向图形编程是一种非常简单的技术,它描述了在平面的面向对象编程语言之上图形如何被定义以和执行。
在4.5节,“应用领域”,我们见爱你个覆盖大部分常用的能被使用工作流、BPM、流程编制和页面流实现的流程语言。
4.1.1. 特定领域语言
每种流程语言都可以被认为是特定领域语言(DSL)。DSL透视图在流程语言如何与普通的OOP关联上给了开发者很好的洞察力。
这一节我们将单纯地集中注意力在编程环境上以有个印象。面向图形编程包含了连续整套的BPM产品,从API库到完整丰富的BPM套件产品。BPM套件产品是以业务流程为中心的完整的软件开发环境。在这种类型的产品中,用编程语言编写代码能够被尽量地避免。
特定领域语言的一个重要的方面是每种语言有一个特定的文法。该文法能够被表达为一个域模型。在java中,这些可以是类,方法,字段域,构造器...在jPDL中,可以是节点,转换,动作(Action)...在Rules中,可以是条件,concequence...
DSL的主要想法是,开发者用一种指定的语言创造东西。IDE是围绕一种语言的语法构建的。因此,可以有很多不同的编辑器来进行创作。比如jPDL了流程有一个图形的编辑器和一个XML源代码视图编辑器。同样的,也有不同的方法来存储相同的作品:比如,对于jPDL,可以是一个流程XML文件或是一个节点和转换对象图的序列化对象。其他的(理论上的)例子是java:你可以在系统中使用java类文件格式。当用户打开编辑器,源代码就产生好了。当用保存时,编译的类也同时被保存。
10年前,最大一部分的开发人员用在编写代码。现在随着特定领域语言的学习和使用,这一切改变了。这一趋势将持续下去,其结果是开发人员在同一个宿主平台上将在框架和编写软件之间有更大的选择余地。JBoss SEAM在这个方向上迈出了一大步。
这些语言中有些是基于图形执行的。比如:用于java工作流的jPDL,用于流程编制服务的BPEL,SEAM页面流…等等。面向图形编程是所有这些特定领域语言类型的公共基础。
以后,对于每种语言,开发人员将可以选择最适合他/她的编辑器。比如:核心程序员可能因为工作起来更快而喜欢在源文件格式下编辑Java代码。但缺乏经验的java程序员可能选择一个点击的编辑器来组合一个最终形成一个java类的功能。java源代码编辑可能显得更加复杂。
从其他方式来看这些特定领域语言可以从架构软件的角度。面向对象编程通过组合方法和数据来增加结构。面向关联编程 (AOP)增加了提取交错关联的方法。依赖注入(DI) 和反向控制 (IoC) 框架增加了图形对象的连线的简便性。 同样的基于图形的执行语言(这里介绍的)能通过围绕图行的执行架构你的部分软件项目的方式来有效的解决复杂性。
关于特定领域元的最初解释可以在Martin Fowler的bliki找到。但其背后更细致的阐述请看Martin关于Language Workbenches的论文。
4.1.2. 基于图形语言的特性
有很多的机遇图形的流程语言。在环境和侧重点上有很大的区别。例如,BPEL用来作为建立在企业服务总线(ESB)之上的基于XML的服务编制组件。而页面流流程语言则定也了在一个web应用中页面是如何导航的。这些是两种完全不同的环境。
尽管所有的这些都有区别,但你将发现在几乎每个流程语言中都有两个特性:支持等待状态和图形化表示。这一点没有一致性性,因为它的两个特性在普通的OOP编程语言(如Java)中不能得到充分支持。
面向图形编程是用面向对象编程语言实现这两个特性的一种技术。面向图形编程在面向对象编程的依赖性意味着所有具体的实现于面向图形编程之上的流程语言,必须用OOP开发。但这并不意味着流程语言本身暴露了底层OO的实现。比如:BPEL和OO编程没有任何关联,并且它能够在面向图形编程上实现。
4.1.2.1. 支持等待状态
像Java这样的强制性语言用来表达有一个系统执行的一系列指令。没有等待指令。强制性语言可以完美地描述诸如在服务器中的一个请求响应周期。系统连续地执行指令序列直到请求被处理并且响应结束。
但一个这样的请求往往是一个比想象中更大的一部分。比如:客户端提交了一个订单,该订单要被订单管理员验证。正式批准后,消息必须进入ERP系统。很多发到服务器的请求也是想象中一样大的一部分。
所以流程语言是用来描述更大场景的语言。我们这里必须区分的一个重要的区别是一个系统内部的执行和多个系统的协议。面向图表语言的实现技术仅仅用于在一台机器上执行的程序语言。
所以一个编制流程按照一个系统描述所有的场景。比如:当客户端提交订单时,一个流程开始。流程的下一步是订单管理员的批准。所以系统必须在订单管理员的任务列表中增加一个入口,并等待直到订单管理员提供请求输入。当输入被接受,流程继续执行。现在消息被发送到ERP系统,系统将再次等待直到响应发回。
所以,为了为一个系统描述全部的场景,我们需要一种机制来处理等待状态。
在大多数的应用领域,在等待状态期间执行必须被持久化。这就是为什么阻塞线程不够充分。聪明的Java程序员会想到Object.wait()和Object.notify()方法。这些将用来模拟等待状态但问题是线程不是持久化的。、
Continuations是一种使得线程(及上下文变量)可持久化的技术。这足够可以用来解决等待状态问题。但和我们在下节要讨论的一样,图形化表示在很多应用领域也一样重要。Countinuation是一种基于命令编程的技术,所以它不适合图形化表示。
所以支持等待状态的一个重要方面是执行需要被持续化。不同的应用领域可能有持久化这么一个执行的不同需求。对于大部分工作流、BPM和编排应用,执行需要被持久化到一个关系数据库中。典型的,一个流程执行中的状态转换将和数据库的一个转换相一致。
4.1.2.2. 图形化表示
软件开发的一些方面可以从基于图形的进步受益。业务流程管理是基于图形语言最明显的一个应用。在那个例子中,业务分析和开发人员的沟通把基于图形的业务流程图表作为通用语言进行改良。请看4.5.1节“业务流程管理(BPM)”
另一个可以从图形化表示受益的方面是页面流。在这种情况下,页面、导航和动作命令被展示并用图形化表示链接到一起。
在面向图表编程中,我们的目标是使用图表来代表一些格式的业务程序的执行。那与UML类图实例有明显的区别,UML类图用来表示OO数据结构的静态模型。
同时图形化表示可以被看作是OO编程的一个缺失的特性。没有一种好的方法能图形化地表示OO程序的执行。因此在OO程序和图形化视图之间没有直接的联系。
在面向图形的编程中,图形的描述是中心,而且它是像描述流程图的XML文件的一个实际的软件作品。由于图形化视图实质上是软件的一部分,因此它往往是同步的。从图形化需求到软件设计并不需要手册翻译。软件是围绕着图形构造的。
4.2. 面向图形编程
我们这里介绍的是基于图形的执行语言的一种实现技术。该技术是基于图形的runtime解释。其他的图形执行技术是基于消息队列和代码生成的。
本节将解释关于流程执行如何在OO编程语言上实现的策略。对于那些熟悉设计模式的人来说,这是命令模式和职责链模式的一种结合。
我们将尽量从最简单的模型开始,并一点点地扩展。
4.2.1. 图形化结构
首先,图形的结构由Node和Transition类来描绘。transition有一个方向,故节点(nodes)有离开和到达转换的行为。
Figure 4.2. Node and Transition classes
节点是一个命令,并有一个执行方法。Node的子类支持覆盖execute方法来实现那个节点类型的特定行为。
4.2.2. 执行
我们定义在图形结构上的执行模型看起来与有限状态机或UML状态图类似。实际上面向图形编程可以被用来实现那些类型的行为,但它还可以做得更多。
执行(亦即token)由叫做Executeion的类来描绘。执行有一个指向当前节点的引用。
Figure 4.3. The Execution class
转换可以通过take方法把执行从一个源节点传递到目标节点。
Figure 4.4. The Transition take method
当执行到达一个节点,那个节点就被执行。Node的execute方法同样负责传递执行。传递执行意味着一个节点可以传递抵达某个节点的执行越过一个即将离开的转换到下一个节点。
Figure 4.5. The Node execute method
当一个节点的execute方法不传递执行,它就成了等待状态。同样的,当一个新的执行被创建,它将被初始化在某个起始状态并等待一个事件。
事件是用来发给执行的,并触发执行开始移动。当事件发给一个当前节点要离开的转换相关的执行,该执行就会带起转换。然后执行将继续传递直到它进入另一个处于等待状态的节点。
Figure 4.6. The Execution event method
4.2.3. 流程语言
现在我们已经可以看到两种被支持的特性:等待状态和图形化表示。在等待状态期间,Execution只是指向图形中的一个节点。流程图和Execution两者都能被持久化:比如使用如Hibernate的O/R映射保存到数据库或序列化图形对象到一个文件中。同样的你可以看到图形中的节点和转换在图形化表示中有直接的关联。你也能看到一个图表/“业务程序定义”的节点和转向。因此,这也是一个与可视化表示的直接结合。 Also you can see that the nodes and transitions form a graph and hence there is a direct coupling with a graphical representation.
流程语言只不过是节点-实现的一个集合。 每个节点-实现与一个流程结构相一致。流程结构的准确的行为是通过覆盖execute方法来实现的。
这里我们展示一个具有4个流程结构的流程语言的例子:一个起始状态,一个决定,一个任务和结束状态。这个例子与jPDL流程语言无关。
Figure 4.7. An example process language
具体的节点对象现在可以用来在我们流程语言的示例中创建流程图了。
Figure 4.8. An example process
当为该流程创建了一个新的执行,我们把执行定位到起始状态开始。如果执行没有收到任何事件,那么执行将保持定位在起始状态。
Figure 4.9. A new execution
现在我们看看当一个事件被启动时会发生什么。在这个初始的情形,我们启动将与默认转换保持一致的默认事件。
这可以通过调用executeion对象的event方法完成。event方法将开始查找默认的离开转换并通过调用转换之上的take方法吧执行传递到转换,并把自身作为参数传递。
转换将传递执行到decision节点并调用execute方法。我们假设decision的execute实现履行计算功能并且决定通过发送‘yes’事件给执行来传递执行。那将导致执行结束‘yes’转换而继续并且执行将到达‘doubleCheck’任务。
什么假设doubleCheck(二次核对)的任务节点的执行实现增加了一个条目到核对者的任务列表并在以后不传递执行来等待核对者的输入。
现在,执行将仍旧定位在doubleCheck任务节点。所有的嵌套呼叫将在直到原始的event方法返回时开始返回。
Figure 4.10. An execution in the 'doubleCheck' wait state
4.2.4. Actions
在某些应用领域中,必须有一种方法来包含程序逻辑的执行而不用为它引进一个节点。比如在业务流程管理中这就是非常重要的一方面。业务分析管理图形化表示而开发人员负责使之执行。如果开发人员必须改变图表来包含业务分析员不感兴趣的技术细节,那将是难以接受的。
Action还是一个带有execute方法的命令。Action可以和事件绑定。
在执行的运行过程中有2个基本的事件由Node类启动:node-leave和node-enter。随着导致转换被带起的事件,这已经给了往图形的执行注入程序逻辑很大的自由。
Figure 4.11. Actions that are normally hidden from the graphical view
每个时间可以与一个actions列表相结合。随着事件的触发,所有的action都将被执行。
4.2.5. 代码示例
为了让人们学习到面向图形编程的规则,我们用少于130行的代码开发了这4个类。你可以阅读代码来获得一个认识或你可以进行改造并实现你自己的节点类型。
这是实例代码:
* Execution.java
* Node.java
* Transition.java
* Action.java
你也可以下载全部的(297KB)源代码项目并自己改造。它包含一个eclipse工程,你只要导入已有工程便可以使用。也有一系列的展示基本流程执行的测试,高级的图表执行概念在下一节介绍。
4.3. 高级面向图形编程扩展
前一节用最简单的形式介绍了普通的面向图形编程模型。本周将讨论基于图形语言的各种概念以及面向图形编程如何被使用或扩展以符合这些需求。
4.3.1. Process variables
4.3.1. 流程变量
流程变量保存一个流程执行的上下文数据。在一个保险索赔流程,“索赔总额”、“核准总额”和“拨付标志”就是很好的流程变量的例子。在很多情况下,它们与类的成员(域)相似。
面向图形编程能通过联合一个 与流程结合的键-值对集合,随着流程变量支持 简单地扩展,并发的执行路径和流程的组合将使事情变得有点复杂。万一在并发路径或子流程的情况下,范围规则将会定义流程变量的可见性。
工作流数据模式是一个关于各种范围的广泛的研究报告,这些范围可以应用于在子流程上下文和并发执行的流程变量。
4.3.2. 并发执行
假设你用基于图形的流程处理语言在为工作流程开发一个“sale”流程。在客户端提交订单之后,将有一系列的活动在为客户端付现金,同时也有一系列活动在为客户端运送商品项。正如你能想象的,付款活动和运送活动能够并行完成。
在这种情况下,一条执行路线将不足以跟踪整个流程状态。让我们一步步扩展面向图的编程模型并增加对并发执行的支持。
首先,我们对执行重新命名为一个执行路径,然后我们可以引进一个新的概念叫做流程执行(a process execution).流程执行描绘了一个流程的完整执行,并包含了很多执行路线。
执行路径可以被分级的排序。这意味着当一个流程执行被实例化的时候一个跟执行被创建。当这个根执行路径被分解到多个并发执行路径时,根就成了父亲,而新创建的执行路径则是根的所有的孩子。这样,一个join执行就变得相当易懂:一个join执行只要检查是否所以的兄弟执行路线已经全部指向了join节点。如果是这种情况,那么复制性路径可以回复执行,离开join节点。
尽管分层次的执行路径和join执行基于兄弟执行路径覆盖了该用例的一大部分,其他的并发行为应该在具体的环境中进行描述。比如当多条合并与一个分叉关联。在这种情形下,其他运行时数据和混合执行的组合是必须的。动作通常情况下都从图形视图中隐藏。
图 4.12. Actions that are normally hidden from the graphical view
执行的多条并发路径经常和多线程编程混淆在一起,尤其在工作流和BPM上下文中,他们有很大的不同。一个流程指定一个状态机。考虑一下,一个状态机通常总是处于稳定状态的,而状态转换是瞬时的。你可以通过查看状态转换引起的事件来解释执行的并发路径。并发执行意味着可以被处理的事件与两个并发的执行路径没有关联。现在,我们假设流程执行中的状态转换与一个数据库转换相关联,(as explained in Section 4.3.6, “Persistence and Transactions”),那么你可以看到多线程编程实际上没有被要求来支持执行的并发路径。
4.3.3. 流程的制作
流程创造可以包含一个子流程作为一个超流程(上级流程、父流程)的一部分。这个高级特性使得增加流程建模的抽取成为可能。对于业务分析来说,这个特性对于将模型分解为子模块的解决办法是很重要的。
主要的是路是超流程在图中有一个节点描绘了一个子流程的完整的执行。当一个执行进入超流程的子流程节点,有很多事情要考虑:
*首先,一个子流程的执行被创建。
*一些存储在超流程的流程变量的信息可以可选地从超流程的执行中注入到子流程执行。最为简单的方式是子流程节点被配置为:将带有从超流程的流程变量拷贝过来的一个变量集合复制到子流程变量中。
*子流程的开始节点必须只能有一个离开的转换。支持多个离开转换的流程语言必须有一种机制来从那些基于超流程变量的转换中选择一个转换。
*子流程的执行通过发送一个相当于它的开始状态的默认离开转换的事件来被启动。
在子流程进入一个等待状态后,超流程执行将被指向子流程节点而子流程执行将被指向某个等待状态。
当子流程执行完成,超流程执行可以继续。那是一下几个方面必须被考虑:
*流程变量信息必须从子流程执行被拷贝回来,放到超流程执行中。
*超流程执行将继续。典型的,流程语言允许在子流程节点只有一个离开转换。这样,超流程执行会在默认单独的离开转换上被传播。
*当一个子流程节点被允许多于一个离开转换时,必须引入一种机制开选择一个离开转换。这个选择可以给予子流程执行的变量,或是子流程的结束状态(一个典型的状态机可以有多个结束状态)。
未完成:bpel有一个未明确的子处理概念,没有明确指出...
4.3.4. 同步执行
4.3.5. 异步执行
4.3.6. 持久化与事务
4.3.7. 服务和环境
2008年10月28日星期二
jBPM用户指南-CH04
订阅:
博文评论 (Atom)







没有评论:
发表评论