现在的位置: 首页 > 综合 > 正文

OSWorkflow代码结构,配置文件及初始化

2014年01月19日 ⁄ 综合 ⁄ 共 6721字 ⁄ 字号 评论关闭
文档的版权属于
http://zstzah.blog.bokee.net




osworkflow

的代码结构

首先来看看它的包的静态结构,


workflow
包中我们发现了很多内容,光从名字上来看,就很一目了然。我将对最初常用的几个包进行阅读,后续在用到更多的功能时,补充该文档。
该文档原始地址


最早主要会提到的是
basic

config

loader
这三个包中的部分类,这三个包对于
osworkflow
的初始化非常重要。其中也会提到
spi
中的几个类,对于持久化操作的封装将使用这个包内的东西。
1

 basic
这个包中有两个类,
BasicWorkflow

BasicWorkflowContext
。如下我们来看看这两个类的继承体系:下面首先是
workflow
控制流程对象的继承体系
 

再来看看
BasicWorkflowContext
的继承体系:
 
 
 
 
这个包其实从名字上来看非常的明了,也就是我们从使用
osworkflow
的角度来看,一个流程实例的创建,我们可以使用的基本对象是
BasicWorkflow
,而我们同时也使用的
BasicWorkflowContext
这个对象来完成保存流程请求的用户的基本功能。
2

 config
这个包完成的工作就像他的名字一样,基本的两个配置类在这个包中:
DefaultConfiguration

SpringConfiguration
。我们来看看这个包的基本结构:
 

DefaultConfiguration
这个类,完成了基本的配置文件的载入工作,包括
osworkflow.xml(
存放持久层配置以及流程工厂配置的文件
)
以及
workflows.xml(
存放流程模型资源的配置文件
)
的解析和映射。
我们来看看它的几个实例字段:
//
流程工厂类,通常被配置到
osworkflow.xml
文件中,在初始化的时候会去寻找是不是配置了别的工厂,如果配置了,将替换这个工厂的引用
    private AbstractWorkflowFactory factory = new URLWorkflowFactory();
 
//
持久化信息的
map
,从配置文件中读出来,存放到这个
map

    private Map persistenceArgs = new HashMap();
 
    //
完成持久化信息的各种工作的类全路径
private String persistenceClass;
 
//
这个引用本身是一个接口,它将在初始化发生的时候,赋予它的子类实现,这个接口在类中直接被实例化成
WorkflowStore
这接口的实现类。具体使用什么实现类将在配置文件中配置。
    private transient WorkflowStore store = null;
       //
这个是配置是否完成的标志字段,这个字段在
load
方法完成的时候,被设置为
true
    private boolean initialized;
 
SpringConfiguration
这个类为和
Spring
的整合提供了支持,目前还没有对
Spring
整合进行分析,在这里暂时不进行分析,将在以后补充。
3

 loader
这个包,这个包中有大量的
Descriptor
,这些个描述符对象,记录了一个流程实例的步骤、动作、状态、名称等信息。由于这个类图过分庞大,因此不在这里出图例。这个类中也有一些关键的流程模型加载的工厂类,完成流程模型信息的初始化。我们在实际的应用中,只使用到了
XMLWorkflowFactory
,那么我们的流程配置文件自然也就使用了
xml
格式,在
AbstractWorkflow
中,大量的调用到了这个类的接口,来获取模型对象。这个类的详细分析,将放到以后的文档中。这里只要明白这个类是保存里流程模型对象的工厂,也就对模型进行一些操作,比如删除和保存一个流程模型。
4

 spi
这个包里面的东西也很多,主要我们会提到的是记录流程实例状态的对象、持久化真正实现的方式。先来看看实例状态对象的类图:

SimpleWorkflowEntry
这个类,经常会用到,在流程启动和运行过程中,我们通常都使用这个类来标识流程实例的所对应的模型和实例状态。
5
、还有就是真正操作持久类的对象
Store

 
这里只把实际操作流程数据库的
jdbc
实现类图画出来。创建流程实例对象到数据库,操作流程实例相关的很多数据库数据。
 
 

osworkflow
的配置
在阅读
osworkflow
初始化之前有必要了解
osworkflwo
的一些基本配置。
首先,我们要知道
osworkflow
中需要配置的两个重要文件,这两个重要文件的配置是在使用
XMLWorkflowFactory
类来处理配置文件时一定要有的配置文件。
 
第一个


osworkflow.xml
文件,当然,你不可以随意指定这个文件的名称,而且你必须放到
classes
的根目录或者
META-INF
目录下,来看看这个部分的编码:
       //
使用默认文件名
 
       if (is == null) {
            try {
                is = classLoader.getResourceAsStream("osworkflow.xml");
            } catch (Exception e) {
            }
        }
        if (is == null) {
            try {
                is = classLoader.getResourceAsStream("/osworkflow.xml");
            } catch (Exception e) {
            }
        }
        if (is == null) {
            try {
                is = classLoader.getResourceAsStream("META-INF/osworkflow.xml");
            } catch (Exception e) {
            }
        }
        if (is == null) {
            try {
                is = classLoader.getResourceAsStream("/META-INF/osworkflow.xml");
            } catch (Exception e) {
            }
        }
 
该代码来自
DefaultConfiguration
中的
load(url)
方法中,当然在这个代码所在的方法中,
osworkflow.xml
文件是可以指定路径和文件名称的,主要是在调用
load
的上层
AstractWorkflow
中却没有传递任何文件路径和名称参数的接口,其实这个地方完全可以改成使用一个参数来确定文件的路径和名称的,传递
url

AstractWorkflow
中去。
来看看这个文件的格式样例:
 
 
<
osworkflow
>
<!--
<persistence class="com.opensymphony.workflow.spi.memory.MemoryWorkflowStore"/>
-->
<
persistence
class
=
"com.opensymphony.workflow.spi.jdbc.JDBCWorkflowStore"
>
  
<
property
key
=
"datasource"
value
=
"jdbc/osworkflow"
/>
  
<
property
key
=
"entry.sequence"
value
=
"
select isnull(max(ID),0)+1 from dbo.OS_WFENTRY"

/>
  
<
property
key
=
"step.sequence"
value
=
"select sum(c1) + 1 from (select 1 as tb, count(*)
as c1    from os_currentstep union
select 2 as tb, count(*) as c1 from os_historystep) as TabelaFinal"
/>
</
persistence
>
 
<
factory
class
=
"com.opensymphony.workflow.loader.XMLWorkflowFactory"
>
       
<
property
key
=
"resource"
value
=
"workflows.xml"
/>
       
<
property
key
=
"reload"
value
=
"true"
/>
   
</
factory
>
</
osworkflow
>
 
这个样例是使用
jdbc
来持久化流程实例的配置,
这里主要有两个关键结点:
<persistence
>

<
factory
>
 
1

<persistence
>
元素中配置了一个
class
属性,在这里,它是一个持久化实现类的配置,那么里面的子元素都将针对这个
class
的配置进行特殊的配置,我这里是使用了
JDCBWorkflowStore
对象,在使用这个对象的前提下,只对三个
<
property
>
元素配置进行说明,一个是
key
属性是
entry.sequence

step.sequence
的两个
<
property
>
元素,这两个元素主要是因为不同是数据库需要配置不同的实现方式,还有就是
datasource
的数据源元素。
以下分别对这三个元素进行配置说明:
key
值为
datasource

<
property
>
元素:这个元素的
value
属性配置的是一个
jndi
的数据源,我们一般需要在特定的容器中配置特定的
jndi
数据源,以下是
tomcat
的例子:
 
<Context path="/osworkflow" docBase="osworkflow"
debug="99" reloadable="true" crossContext="true" verbosity="DEBUG">
<!-- debug level is set to paranoid, to know what is happening,
turn it off once you do not need it -->
<Logger className="org.apache.catalina.logger.FileLogger"
prefix="OSWorkflow." suffix=".log" timestamp="true"/>
 
<Resource name=
"jdbc/osworkflow"

 auth="Container"
type="javax.sql.DataSource"/>
 
<ResourceParams name="jdbc/osworkflow">
<parameter>
<name>factory</name>
<value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
</parameter>
<parameter>
<name>maxActive</name>
<value>100</value>
</parameter>
<parameter>
<name>maxIdle</name>
<value>30</value>
</parameter>
<parameter>
<name>maxWait</name>
<value>10000</value>
</parameter>
<parameter>
<name>username</name>
<value>sa</value>
</parameter>
<parameter>
<name>password</name>
<value></value>
</parameter>
<parameter>
<name>driverClassName</name>
<value>net.sourceforge.jtds.jdbc.Driver</value>
</parameter>
<parameter>
<name>url</name>
<value>jdbc:jtds:sqlserver://localhost:1433/osworkflow</value>
</parameter>
</ResourceParams>
</Context>
 
在这里,我不对数据源的配置进行细节说明,这里就是有一个很重要的地方需要指出:看这段数据源配置的最初,
<
Resource
>
元素中
name
属性如果配置错误
(
随意指定名称
)
,那么程序在运行中将发生很多不可以理解的异常,系统会不停的打出数据源找不到的异常,然而我曾经花了很长的一段时间来寻找一个问题的原因,找遍了很多的代码也不能找到问题的原因,直到我后来去研读
PropertySet
开源项目的时候才发现,原来在这个开源架构的一个内部配置文件中,数据源已经被配置成
jdbc/DefaultDS

,因此上面这段配置最终会发生异常,因此如果不想让系统打印出数据源异常,这个数据源的配置务必配置成
jdbc/DefaultDS

,
或者修改
PropertySet
的配置文件,在示例代码中,我故意把数据源的配置保持在错误的状态,读者可以运行这个示例,看看控制台出现了什么错误。不过在接下来的部分,马上就会改回正确配置,以进行下一步的研究。
 
key
值为
entry.sequence

<
property
>
元素:在
osworkflow
中需要我们自己来配置,通常系统中会使用这个配置获取实例存放的数据
id
。这个值可以不配置,但它只提供了一种数据库的生成语句,它将使用
oracle
支持的一个
nextval
(’
序列号发生器名称
’)
,去获取。
key
值为
step.sequence

<
property
>
元素:同样,这里是用来获取当前所在的
step
的步骤
id
。同样,它也提供一个默认值,支持类似
oracle

db

序列号发生器。
还有其他的很多配置,如果不使用自己特定的物理表格和特别的实现,可以不提供配置。如下来看看部分源代码:
 
entrySequence = getInitProperty(props, "entry.sequence", "SELECT nextVal(’seq_os_wfentry’)");
stepSequence = getInitProperty(props, "step.sequence", "SELECT nextVal(’seq_os_currentsteps’)");
entryTable = getInitProperty(props, "entry.table", "OS_WFENTRY");
entryId = getInitProperty(props, "entry.id", "ID");
entryName = getInitProperty(props, "entry.name", "NAME");
entryState = getInitProperty(props, "entry.state", "STATE");
historyTable = getInitProperty(props, "history.table", "OS_HISTORYSTEP");
currentTable = getInitProperty(props, "current.table", "OS_CURRENTSTEP");
currentPrevTable = getInitProperty(props, "currentPrev.table", "OS_CURRENTSTEP_PREV");
historyPrevTable = getInitProperty(props, "historyPrev.table", "OS_HISTORYSTEP_PREV");
stepId = getInitProperty(props, "step.id", "ID");
stepEntryId = getInitProperty(props, "step.entryId", "ENTRY_ID");
stepStepId = getInitProperty(props, "step.stepId", "STEP_ID");
stepActionId = getInitProperty(props, "step.actionId", "ACTION_ID");
stepOwner = getInitProperty(props, "step.owner", "OWNER");
 stepCaller = getInitProperty(props, "step.caller", "CALLER");

抱歉!评论已关闭.