风人园

弱水三千,只取一瓢,便能解渴;佛法无边,奉行一法,便能得益。
随笔 - 99, 文章 - 181, 评论 - 56, 引用 - 0
数据加载中……

jBPM--Node Type

Nodetype task-node

A task node represents one or more tasks that are to be performed by humans. So when execution arrives in a task node, task instances will be created in the task lists of the workflow participants. After that, the node will behave as a wait state. So when the users perform their task, the task completion will trigger the resuming of the execution. In other words, that leads to a new signal being called on the token.
任务节点:一个或多个可以人为执行的任务。所以当执行到任务节点,任务实例将由工作流参与者的任务列表创建。之后,这个节点会表现为等待状态。当用户执行他们的任务,任务完成将会触发执行继续。还句话说,在token上会调用一个新的signal

Nodetype state

A state is a bare-bones wait state. The difference with a task node is that no task instances will be created in any task list. This can be usefull if the process should wait for an external system. E.g. upon entry of the node (via an action on the node-enter event), a message could be sent to the external system. After that, the process will go into a wait state. When the external system send a response message, this can lead to a token.signal(), which triggers resuming of the process execution.

Nodetype decision

Actually there are 2 ways to model a decision. The distinction between the two is based on *who* is making the decision. Should the decision made by the process (read: specified in the process definition). Or should an external entity provide the result of the decision.

When the decision is to be taken by the process, a decision node should be used. There are basically 2 ways to specify the decision criteria. Simplest is by adding condition elements on the transitions. Conditions are beanshell script expressions that return a boolean. At runtime the decision node will loop over its leaving transitions (in the order as specified in the xml), and evaluate each condition. The first transition for which the conditions resolves to 'true' will be taken. Alternatively, an implementation of the DecisionHandler can be specified. Then the decision is calculated in a java class and the selected leaving transition is returned by the decide-method of the DecisionHandler implementation.

When the decision is taken by an external party (meaning: not part of the process definition), you should use multiple transitions leaving a state or wait state node. Then the leaving transition can be provided in the external trigger that resumes execution after the wait state is finished. E.g. Token.signal(String transitionName) and TaskInstance.end(String transitionName).

Nodetype fork

A fork splits one path of execution into multiple concurrent paths of execution. The default fork behaviour is to create a child token for each transition that leaves the fork, creating a parent-child relation between the token that arrives in the fork.

Nodetype join

The default join assumes that all tokens that arrive in the join are children of the same parent. This situation is created when using the fork as mentioned above and when all tokens created by a fork arrive in the same join. A join will end every token that enters the join. Then the join will examine the parent-child relation of the token that enters the join. When all sibling tokens have arrived in the join, the parent token will be propagated over the (unique!) leaving transition. When there are still sibling tokens active, the join will behave as a wait state.

Nodetype node

The type node serves the situation where you want to write your own code in a node. The nodetype node expects one subelement action. The action is executed when the execution arrives in the node. The code you write in the actionhandler can do anything you want but it is also responsible for propagating the execution.

This node can be used if you want to use a JavaAPI to implement some functional logic that is important for the business analyst. By using a node, the node is visible in the graphical representation of the process. For comparison, actions --covered next-- will allow you to add code that is invisible in the graphical representation of the process, in case that logic is not important for the business analyst.

posted @ 2007-01-25 09:32 风人园 阅读(713) | 评论 (0)编辑 收藏

jBPM之名词解释

JbpmConfiguration:configuration of one jBPM instance.
JbpmContext:is used to surround persistent operations to processes.
ProcessDefinition
ProcessInstance:is one execution of a ProcessDefinition. To create a new process execution of a process definition, just use the ProcessInstance(ProcessDefinition).
ContextInstance:maintains all the key-variable pairs for a process instance
TaskMgmtSession:
                                 
findTaskInstances(java.lang.String actorId) 
                                  get the tasllist for a given actor.(根据角色得到此角色的任务列表)
                                 loadTaskInstance(long taskInstanceId) 
                                  get the task instance for a given task instance-id.(根据实例ID获得任务实例)
TaskInstance:   
                                 
end() marks this task as done.
                                 end(java.lang.String transitionName) 
                                  marks this task as done and specifies the name of a transition leaving the task-node for the case that the completion of this task instances triggers a signal on the token.

posted @ 2007-01-19 12:47 风人园 阅读(582) | 评论 (1)编辑 收藏

jBPM之Custom node behaviour

在流程中会涉及到很多的分支结构,下面就用代码说明
public class AmountUpdate implements ActionHandler {
  
public void execute(ExecutionContext ctx) throws Exception {
    
// business logic
    Float erpAmount = get amount from erp-system;
    Float processAmount 
= (Float) ctx.getContextInstance().getVariable("amount");
    
float result = erpAmount.floatValue() + processAmount.floatValue();
    update erp
-system with the result;
    
    
// graph execution propagation
    if (result > 5000{
      ctx.leaveNode(ctx, 
"big amounts");
    }
 else {
      ctx.leaveNode(ctx, 
"small amounts");
    }

  }

}
leaveNode(java.lang.String transitionName)
          leave this node over the given transition.
通过ctx的 leaveNode方法,来确定下一个node,这样就可以通过代码动态控制流程。

posted @ 2007-01-18 14:18 风人园 阅读(513) | 评论 (0)编辑 收藏

jBPM之swimlane

 

swimlane一般是为了task准备的,任务总是要分配到某个人头上的。如果在流程定义文件中任务没有指定对应的泳道如:,那么就需要在程序代码中分配相关的处理人taskInstance.setActorId("jeffen")。如果程序都是这样来搞那其实是很麻烦的,而且分配代码分散到各个地方,很容易出错。于是引进了泳道,我们可以在流程定义文件中统一指定swimlane和处理人的关系、task和swimlane的关系,只需要维护这一个文件就好了,(有点像struts的配置文件)如下:

< swimlane name = " banker " >
        
< assignment expression = " user(jeffen) " />
</ swimlane >
......

< task name = " bank "   swimlane = " banker " >

这样就将任务实例和处理人松耦合了,对于多任务对应相同的处理人,这种方式的好处显而易见。

当然还可以在程序中动态指定处理人,如上taskInstance.setActorId("jeffen"),也可以通过泳道实例swimlaneInstance.setActorId("jeffen")指定。

posted @ 2007-01-18 11:56 风人园 阅读(2391) | 评论 (2)编辑 收藏

jBPM之JbpmContext

The three most common persistence operations are:

  • Deploying a process
  • Starting a new execution of a process
  • Continuing an execution

First deploying a process definition. Typically, this will be done directly from the graphical process designer or from the deployprocess ant task. But here you can see how this is done programmatically:

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
  ProcessDefinition processDefinition = ...;
  jbpmContext.deployProcessDefinition(processDefinition);
} finally {
  jbpmContext.close();
}

For the creation of a new process execution, we need to specify of which process definition this execution will be an instance. The most common way to specify this is to refer to the name of the process and let jBPM find the latest version of that process in the database:

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
  String processName = ...;
  ProcessInstance processInstance = 
      jbpmContext.newProcessInstance(processName);
} finally {
  jbpmContext.close();
}

For continuing a process execution, we need to fetch the process instance, the token or the taskInstance from the database, invoke some methods on the POJO jBPM objects and afterwards save the updates made to the processInstance into the database again.

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
  long processInstanceId = ...;
  ProcessInstance processInstance = 
      jbpmContext.loadProcessInstance(processInstanceId);
  processInstance.signal();
  jbpmContext.save(processInstance);
} finally {
  jbpmContext.close();
}

Note that if you use the xxxForUpdate methods in the JbpmContext, an explicit invocation of the jbpmContext.save is not necessary any more because it will then occur automatically during the close of the jbpmContext. E.g. suppose we want to inform jBPM about a taskInstance that has been completed. Note that task instance completion can trigger execution to continue so the processInstance related to the taskInstance must be saved. The most convenient way to do this is to use the loadTaskInstanceForUpdate method:

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
  long taskInstanceId = ...;
  TaskInstance taskInstance = 
      jbpmContext.loadTaskInstanceForUpdate(taskInstanceId);
  taskInstance.end();
} finally {
  jbpmContext.close();
}

posted @ 2007-01-18 11:39 风人园 阅读(1811) | 评论 (0)编辑 收藏

jBPM之hello world

参考
http://www.blogjava.net/chengang/archive/2006/07/13/57986.html

下面是根据官方开发向导及自己的经验写的

开发向导上提供的helloworld例子,这个流程是单向的,没有任何的分支,且没有自定义actionHandler,使用的是默认的handler
public void testHelloWorldProcess() {
  // This method shows a process definition and one execution// of the process definition.  The process definition has // 3 nodes: an unnamed start-state, a state 's' and an // end-state named 'end'.// The next line parses a piece of xml text into a// ProcessDefinition.  A ProcessDefinition is the formal // description of a process represented as a java object.
  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>"
  );
  
  // The next line creates one execution of the process definition.// After construction, the process execution has one main path// of execution (=the root token) that is positioned in the// start-state.
  ProcessInstance processInstance = 
      new ProcessInstance(processDefinition);
  
  // After construction, the process execution has one main path// of execution (=the root token).
  Token token = processInstance.getRootToken();
  
  // Also after construction, the main path of execution is positioned// in the start-state of the process definition.
  assertSame(processDefinition.getStartState(), token.getNode());
  
  // Let's start the process execution, leaving the start-state // over its default transition.
  token.signal();
  // The signal method will block until the process execution // enters a wait state.// The process execution will have entered the first wait state// in state 's'. So the main path of execution is now // positioned in state 's'
  assertSame(processDefinition.getNode("s"), token.getNode());

  // Let's send another signal.  This will resume execution by // leaving the state 's' over its default transition.
  token.signal();
  // Now the signal method returned because the process instance // has arrived in the end-state.
  
  assertSame(processDefinition.getNode("end"), token.getNode());
}

更详细的例子可以看参考,里面有很详细的操作说明。




下面是根据参考例子测试时出现的一些问题及说明。
一、关于数据库,首先要修改数据库连接,然后创建数据库,里面的表格jBPM提供相应的API去创建。
public void testDeployProcessDefinition() throws FileNotFoundException 
        
// 从 jbpm.cfg.xml 取得 jbpm 的配置 
        JbpmConfiguration config = JbpmConfiguration.getInstance();
        config.dropSchema();//删除数据表结构
        config.createSchema();//创建数据表结构
        
// 创建一个 jbpm 容器 
        JbpmContext jbpmContext = config.createJbpmContext(); 
        
// 由 processdefinition.xml 生成相对应的流程定义类 ProcessDefinition 
        InputStream is = new FileInputStream("processes/simple/processdefinition.xml"); 
        ProcessDefinition processDefinition 
= ProcessDefinition.parseXmlInputStream(is); 
        
        
// 利用容器的方法将流程定义数据部署到数据库上 
        jbpmContext.deployProcessDefinition(processDefinition); 
        
// 关闭 jbpmContext 
        jbpmContext.close(); 
    }

这个是根据流程配置文件最后生成的数据库信息的测试方法,刚开始我还有一个疑问,数据库和数据表是系统自动创建还
是要手动创建,数据库是要手动创建的,数据表可以自动创建的



posted @ 2007-01-18 10:55 风人园 阅读(1001) | 评论 (0)编辑 收藏

Struts 2.0 起步

参考 http://www.blogjava.net/max/category/16130.html

1、添加struts2的jar包,struts2-core-2.x.x.jar, struts2-api-2.x.x.jar (struts2-all-2.x.x.jar即可,其他的struts2的插件包已经包含在里面)。
   如添加其他的插件包,可能会出现文件重复,具体可以看异常信息。
   或者不要加all包,而使用插件包,可以减小包的大小。
2、修改web.xml

 1 <? xml version="1.0" encoding="UTF-8" ?>
 2 < web-app  version ="2.4"  
 3  xmlns ="http://java.sun.com/xml/ns/j2ee"  
 4  xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"  
 5  xsi:schemaLocation ="http://java.sun.com/xml/ns/j2ee 
 6  http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" >
 7   < display-name > Struts2 Hello World! </ display-name >   
 8
 9     < filter >
10          < filter-name > Struts2 </ filter-name >
11          < filter-class >
12             org.apache.struts2.dispatcher.FilterDispatcher
13          </ filter-class >
14      </ filter >
15      < filter-mapping >   
16          < filter-name > Struts2 </ filter-name >   
17          < url-pattern > /* </ url-pattern >   
18      </ filter-mapping >   
19 </ web-app >
20


3、在classpath下添加struts.properties文件,内容如下
struts.devMode = true
struts.enable.DynamicMethodInvocation = false

4、在classpath下添加struts.xml,这个是对应struts1.x里面的struts-config.xml

 1 <! DOCTYPE struts PUBLIC
 2         "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
 3         "http://struts.apache.org/dtds/struts-2.0.dtd" >
 4 < struts >
 5      < package  name ="example"  extends ="struts-default" >
 6          < action  name ="hello"  class ="com.ivo.struts2.HelloWorld"  method ="aliasAction" >
 7              < result > /hello.jsp </ result >
 8          </ action >
 9          < action  name ="Login"  class ="com.ivo.struts2.Login" >
10        < result > /hello.jsp </ result >
11    </ action >
12    < action  name ="LoginX"  class ="com.ivo.struts2.LoginX" >
13        < result > /hello.jsp </ result >
14    </ action >
15      </ package >
16 </ struts >


注意,struts2的两个相关文件需要放在classpath下

posted @ 2006-12-29 10:09 风人园 阅读(523) | 评论 (0)编辑 收藏

Rome使用入门

Rome的两种使用方法
所需jar包的下载 here,在这里可以找到与rome相关的所有文件

1、只使用rome
   
package com.ivo.rss;

import java.io.IOException;
import java.net.URL;
import java.util.Iterator;

import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.XmlReader;
public class Feed {
    public static void main(String[] args) throws Exception {

       
        SyndFeedInput input = new SyndFeedInput();
        //System.out.println(warmedFeed);
        SyndFeed feed = input.build(new XmlReader(new URL("
http://rss.news.yahoo.com/rss/topstories ")));

        // Iterate through feed items, adding a footer each item
        Iterator entryIter = feed.getEntries().iterator();
        while (entryIter.hasNext()) {
            SyndEntry entry = (SyndEntry) entryIter.next();
            System.out.println(entry.getPublishedDate());
            System.out.println(entry.getTitle());
            //System.out.println(entry.getDescription());
            //System.out.println(entry.getAuthor());
            System.out.println(entry.getLink());
           
        }
    }

}

2、使用rome+rome fetcher

package com.ivo.rss;

import java.net.URL;
import java.util.List;

import com.sun.syndication.feed.synd.SyndContent;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.fetcher.FeedFetcher;
import com.sun.syndication.fetcher.impl.FeedFetcherCache;
import com.sun.syndication.fetcher.impl.HashMapFeedInfoCache;
import com.sun.syndication.fetcher.impl.HttpURLFeedFetcher;

public class RssReader {

    public static void main(String[] args) throws Exception {
        FeedFetcherCache feedInfoCache = HashMapFeedInfoCache.getInstance();
        FeedFetcher feedFetcher = new HttpURLFeedFetcher(feedInfoCache);
        SyndFeed feed = feedFetcher.retrieveFeed(new URL(
                "
http://feeds.feedburner.com/jscud "));
        List entryList = feed.getEntries();
        for (int i = 0; i < entryList.size(); i++) {
            SyndEntry entry = (SyndEntry) entryList.get(i);
            System.out.println("Published Date: "+entry.getPublishedDate());
            System.out.println("Title: "+entry.getTitle());
            System.out.println("Link: "+entry.getLink());
            //System.out.println(entry.getDescription());
            SyndContent sc = entry.getDescription();
            System.out.println("Description: "+sc.getValue());
            System.out.println("------------------------------");
        }
    }
}

上面是使用了缓存的,也就是说更新才读取,如果每次都读取,则修改对应行为:

FeedFetcher feedFetcher = new HttpURLFeedFetcher();

posted @ 2006-07-07 14:20 风人园 阅读(1316) | 评论 (3)编辑 收藏

仅列出标题
共10页: First 上一页 2 3 4 5 6 7 8 9 10