??xml version="1.0" encoding="utf-8" standalone="yes"?>
ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(
"<process-definition>" +
" <start-state>" +
" <transition to='s' />" +
" </start-state>" +
" <state name='s'>" +
" <transition to='end' />" +
" </state>" +
" <end-state name='end' />" +
"</process-definition>"
);
ProcessInstance processInstance =new ProcessInstance(processDefinition);
Token token = processInstance.getRootToken();
assertSame(processDefinition.getStartState(), token.getNode());
token.signal();
assertSame(processDefinition.getNode("s"), token.getNode());
token.signal();
assertSame(processDefinition.getNode("end"), token.getNode());
}
首先Q我们定义个程模板QProcessDefinitionQ,是上面代码的ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(….);q段Q在括号中是jbpm定义的流E,其中包括三个环节Q分别是starts-state、state和end-state。parseXmlStringQ)Ҏ的主要功能是解析q段xml语言q回个流E模板对象(processDefinitionQ?br />
接着Q通过程实例c(ProcessInstanceQ来实例化个程实例Q通过传进来的程模板对象创徏ProcessInstance processInstance =new ProcessInstance(processDefinition)。我们来看看new ProcessInstance(processDefinition)到底做了什么,通过查看ProcessInstance的源代码Q可以看到其中主要的一D|
public ProcessInstance( ProcessDefinition processDefinition ) {
//略去其他代码
this.processDefinition = processDefinition; //流E模板对象付l流E实?br />
this.rootToken = new Token(this); //创徏跟o?br />
//略去其他代码
}
我们l箋跟进Tokenq个c?br />
public Token(ProcessInstance processInstance) {
//主要一句如?br />
this.node = processInstance.getProcessDefinition().getStartState();
}
q样实C令牌l定到开始节炏V至此,一个流E实例就创徏h了,q且该流E实例走C开始节点,即o牌所处的位置?br />
我们接着往下走token.signal()
public void signal() {
signal(node.getDefaultLeavingTransition(), new ExecutionContext(this));
//q里的getDefaultLeavingTransition()如果有多条\径,则去W一条\?br />
}
void signal(Transition transition, ExecutionContext executionContext) {
//省略其他代码
node.leave(executionContext, transition);
//省略其他代码
}
q里的node是刚才令牌所在的开始节点,我们来看看jbpm是如何将令牌从开始节点移C个节点的?br />
public void leave(ExecutionContext executionContext, Transition transition) {
Token token = executionContext.getToken();
token.setNode(this);//此时令牌q在开始节?br />
executionContext.setTransition(transition);
//略去部分代码
executionContext.setTransitionSource(this);
transition.take(executionContext);//实现令牌的{U?br />
}
我们来看看transition.take(..)Ҏ做了什?br />
public void take(ExecutionContext executionContext) {
//略去部分代码
to.enter(executionContext);//d开始节点,q入C个节?br />
}
大家可能会有点疑问,q个to节点是什么是否初始化的?其实在signal时有句node.getDefaultLeavingTransition()Q这句返回Transition对象Q该对象已l初始化了to节点的对象。我们在跟进to.enter(..)
public void enter(ExecutionContext executionContext) {
Token token = executionContext.getToken();
token.setNode(this);//此时令牌到了名字ؓ“s”的state节点
token.setNodeEnter(new Date());
executionContext.setTransition(null);
executionContext.setTransitionSource(null);
execute(executionContext);
}
在这D代码中的注释这句,真正实现了o牌从开始节点到下个节点了?br />
xQjbpm工作引擎的内部工作原理׃l完了,其实q就是工作流引擎最核心的部分了Q就是如何从一个环节{Ud另一个环节。或怽会说“q么单,我马上就可以写一?#8221;Q其实不Ӟ上面我们所用的例子是十分简单的例子Q其实在工作联盟规范中q有其他复杂的节Ҏ型,如splitQjoinQsubflow{。不q幸q的是这些复杂的节点模型jbpm都ؓ我们提供了他自己的默认的实现Q这些节Ҏ型都在org.jbpm.graph.node包下。jbpm引擎中很好的抽象了节Ҏ型Nodec,大部分的复杂节点模型都承自NodeQ我们也可以定制自己的节点,只要实现Nodecȝexecute()Ҏ卛_方便的实现。其实从上面分析的代码可以看出,NodecM要的逻辑处理是在leave()、enter()和execute()三个ҎQ大家可以看下ProcessStateQjoinQforkq些节点模型是如何实现的?br />
以上单介l了jbpm引擎内核的工作原理,如有不对的地方还望指正?br />
操作pȝQ?/span>window xp sp2
SVN的版本:1.5Q?/span>http://www.collab.net/downloads/subversion/Q?/span>
TortoiseSVN的版本:1.5Q?/span>http://sourceforge.net/projects/tortoisesvn/Q?/span>
SVN服务器端安装配置
1?nbsp;安装SVN服务器端
A、到svn的官方网下蝲svn服务器端软g到本圎ͼ然后安装Q按提示一步一步安装完成?/span>1.5版本默认的会?/span>svnd?/span>window的服务的选项Q勾选上卛_随操作系l的启动而启?/span>svn的服务。?/span>1.5以前的版本则需要手动添加的window的服务中Q用window?/span>sc命oQ至?/span>sc命o如何用读者可以查?/span>sc的帮助?/span>
B、安装完后打开window的服务管理器Q将svn的服务启动,全名?/span>Svnversion Server。打开命o行运行命?/span>svnadmin --versionQ可以看?/span>svn安装的版本信息,xsvn的安装完成?/span>
C、安?/span>svn客户端端软gTortoiseSVNQ按步骤安装下来卛_?/span>
2?/span>SVN服务器端的配|?/span>
W一点只介绍?/span>svn的安装,要让其能够用,我们q需要些配置Q像版本库的建立Q用L讉K权限{?/span>
A、创建版本库?/span>
打开命o行执?/span>svnadmin create pathQ其?/span>path表示你要建立的版本库的存放\?此\径也是svn在window的服务上注册是指向的路径Q笔者的路径?/span>D:\svn_repositoryQ即svnadmin create D:\svn_repository。运行该命o后,可以发现?/span>D:\svn_repository的目录下Q创Z些文件和文g夹,x创徏版本库成功?/span>
B、配|用L讉K权限?/span>
在刚才的目录下有个文件夹confQ?/span>svn的配|文件就在此目录中。打开该文件夹下的svnserver.conf文gQ我们可以看?/span>svn的配|信息的一些属性,q里行前凡是?/span>#的都表示被注释掉了,你可以把#L让该行的属性生效,或者自己在最后添加新的行来生?/span>svn的属性?/span>
在这我们兛_的属性说明如下:
anon-access = read 表示匿名的用户可以什么样的方式访问版本库Q有none?/span>read?/span>write三个值可选,文g中ؓread说明匿名用户可以只读的方式访问版本库?/span>
auth-access = write 表示验证通过的用户具有什么权限,?/span>none?/span>read?/span>write三个值可选,文g中ؓwrite表示可写Q当然也可读了?/span>
password-db = passwd 表示用户的密码存攄地方?/span>
authz-db = authz 表示版本库中讉K路径的规则,卌只能讉K哪个目录下的文gQ其他目录下的文件无法访问?/span>
现在我们?/span>auth-access?/span>password-db?/span>authz-db三个属性的前面?/span>#LQ其生效,注意三个属性前不能有空根{?/span>
然后我们~辑passwd?/span>authzq两个文件的信息?/span>
a、在passwd文g中的[users]下添加能讉K版本库的用户名和密码Q如该文件中的事例。我们添?/span>admin = admin
b、在authz文g中,[groups]下可以配|组信息Q即几个h加入C个组中?/span>[/foo/bar]下添加h员的规则表示谁可讉K/foo/bar路径下的信息。我们在[/foo/bar]下添?/span>
[/]
admin = rw
xQ我们配|了admin的̎P该̎号具有根目录下的所有文件的d操作权限?/span>
3、创建我们的目
?/span>D:"test下新?/span>project文g夹,?/span>project下新?/span>trunkQ?/span>tagsQ?/span>branches三个文g夹,打开命o行,目录{?/span>D:\test下,q行svn import –m addproject --username admin --password admin --config-dir /project svn://localhost回R昄如下Q?/span>
Adding project
Adding project/trunk
Adding project/branches
Adding project/tags
Committed revision 1.
表示我们的项?/span>project创徏成功?/span>
q里说明?/span>trunk?/span>tags?/span>branches三个文g夹的作用Q?/span>
trunkQ表C开发时版本存放的目录,卛_开发阶D늚代码都提交到该目录上?/span>
branchesQ表C发布的版本存放的目录,即项目上U时发布的稳定版本存攑֜该目录中?/span>
tagsQ表C标{֭攄目录?/span>
在这需要说明下分三个目录的原因Q如果项目分Z期、二期、三期等Q那么一期上U时的稳定版本就应该在一期完成时代?/span>copy?/span>branches上,q样二期开发的代码对一期的代码没有影响Q如新增的模块就不会部v到生产环境上。?/span>branches上的E_的版本就是发布到生环境上的代码Q如果用户用的q程中发现有bugQ则只要?/span>branches上修改该bugQ修改完bug后再~译branches上最新的代码发布到生产环境即可?/span>tags的作用是在branches上修改的bug的代码合q到trank上时创徏个版本标识,以后branches上修改的bug代码再合q到trunk上时׃tags?/span>version?/span>branches最新的version合ƈ?/span>trunkQ以保证前期修改?/span>bug代码不会在合q?/span>
x我们可以?/span>svn来管理我们的代码了?/span>