In jBPM5, when you start a process, it executes all the nodes it can. If you don't have any wait-state, then the process will be completed when the session.startProcess() method returns.
There are 3 ways (somebody please correct me if I'm forgeting someone) to define wait-points:
- Asyncronous WorkItemHandlers in your Service Task Nodes:
When you define a Service Task in your process, you need to assign a handler for it. This handler could be synchronous or asynchronous. It will be synchronous only if you invoque workItemManager.completeWorkItem() inside handler's executeWorkItem() method. The only difference with asynchnornous handlers is that they don't complete the work item inside. They delegate this behaviour to an external mechanism.
When the process finds a Service Task Node, its executes the associated handler. If the handler conpletes the work item, the execution continues. If the handler doesn't complete the work item, the process reaches a wait-state (if there are no more parallel paths to continue with). When the process reaches a wait-state, it state is persisted (if you are using persistence, of course ).
Asynchronous work item handlers are good for (time) expensive calls to external systems. If you don't know how long the external sytem will take to respond, then you could use an asynchronous work item handler. The process will call the external system, everythng is going to be persisted and you can even dispose you ksession and stop the Thread that performed the startProcess() call. You still need to have a mechanism for continue the execution of the process when the external system ends. You will need at least the id of the ksession and the id of the work item to be able to restore you ksession ( JPAKnowledgeService.loadStatefulKnowledgeSession() ) and to complete the work item ( ksession.getWorkItemManager().completeWorkItem()). The completeWorkItem() method wil execute as many nodes as it can until it reaches a new wait-point or until the process finishes.
- Human Task Nodes: Human tasks are handled like asynchronous Work Items by jBPM5. jBPM5 already comes with a WorkItemHandler implementation for Human Tasks: WSHumanTaskHandler. This handler will communicate with a Task Service (also provided by jBPM5) and create a new Task in it. Then, it will wait for someone (using Human Client API) to complete/cancel the task.
- External Events: You can define external events handlers in your process using an intermediateCatchEvent. Then, from outside your process you can signal the event using ksession.signalEvent() method. If you combine a intermediateCatchEvent with a converging parallel gateway, you get a wait-state.
I have a set of simple tests that show some of the things I have mentioned here. You can download and try them from here:
- Asyncronous WorkItemHandlers in your Service Task Nodes:
Thanks for your reply!
Right now, i take the first methord. And by the way, i have to know the workItem ID, isn't it? But how to know?
i readed some examples, including your supply! i find that WorkItemManager.completeWorkItem() is used in the same testCase. In another testCase, how to get the workItem, or how to complete the workdItem?
WIth the second method, it takes C/S mode. When the jbpm is self-governed, it is userful, isn't it? But at this time, how to manage the transaction?
Looking forward to your reply!
Remember that you will need to make an external mechanism to hanlde the result of async calls. Inside the WorkItemHandler you can get the workItem Id. Two (of the probably infinite) options that you have are:
- Pass the id (along with the session Id) to the external system. The external system, when finishes, can use those values to perform a call to your system and complete the work item.
- Create a complete isolated mechanism for handling async calls to external systems. In this scenario, you could call the external system on your WorkItem Handler and then notify this third system (the isolated system I have mentioned before) that a new "task" is running. When the external system completes its work, it notifies this to the same third system. When a task is completed, the third system will notify your system about it.
If you want to start a process in one test and complete it in another, you will need to follow these steps:
- Your process must have a wait-state. If it doesn't the process will start and end in the startProcess() call.
- You need to enable persistence. When the process reaches the wait-state in the first test it will be persisted in the DB.
- The second test needs to know the session id generated in the first test. You can get this id from the session object created in the first test. You wil need to store it in a place reachable by the second test. If you want to keep it simple, just use a static variable.
- Whithin the first test, your process will eventually execute the Handler you have configured for your Work Item. This handler will need to store the workItem id somewhere (again, in a place reachable by test number 2)
- In the second test, using the session id stored in th efirst test, you need to retrieve the session from the database. The best way to do this is using JPAKnowledgeService.
- Once you have the session, you need to call session.getWorkItemManager().completeWorkItem() using the work item id previously saved.
Taking your advise, i store the session id and the work item id and can complete a process instance which has only one Huam Task. When my process has one more and the process instance reached the second Huam Task node, i can get an exception:
2011-04-18 10:59:17,773 ERROR [org.drools.persistence.SingleSessionCommandService] - Could not commit session
org.drools.WorkItemHandlerNotFoundException: Could not find work item handler for Human Task
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
What's the matter? How to deal?
I restore a session using JPAKnowledgeService.loadStatefulKnowledgeSession (copy/paste from org.jbpm.integration.console.CommandDelegate which looks like a workaround) and re-registering work item handlers using WorkItemManager.registerWorkItemHandler method. What I notice is; these handlers are invoked for any newly created process instance but they are not invoked for process instances created before re-storing the session. (Human Task handler - CommandBasedWSHumanTaskHandler works with no problem though). Do I need to do anything extra to associate existing process instances with the handlers?
I am testing this scenario by deploying a web application that uses jBPM to Glassfish, enabling persistence and stopping and starting the application server in between.
I want to implement the same wait-state but without using the database. I need everything to be in memory.
Currently, I have the following definition in the XML
<intermediateCatchEvent id="_5" name="_5" >
What I want to achieve is that the process waits for x minutes until some external event to complete the subsequent activities or end the process instance if the time elapses. How can i achieve this without JPA?