[JBoss jBPM] - Re: signaling to a forked sibling
by gnagy
> Is the subprocess in a certain state and can continue from there? Is the subprocess not even started?
Yes, the observer sub-process(es) are in a waiting state, doing nothing but waiting for all affected items to get past a certain state (mail delivered).
Initially i guess you could say that the observer sub-process has not started yet, because the wait state is the first state in that branch, so it is a technicality whether we first branch and then wait, or if we wait before the branch. However later in the process another mail notification is needed when another state completes on the observer side, with the same requirement to wait for all affected parties to be notified, so I decided to fork and wait for the first mailing as well to keep things similar.
A possible sequence of events: 1 observer, 2 parties
Branch
-Observer: wait for all parties to be notified
-Party1: send mail to party1
-Party2 send mail to party2
-Party1: mail could not be delivered, resend mail
-Party2: mail was delivered
-Party1: mail was delivered
-Observer comes out of wait state, goes to anotherimportantbusinessstep state
-Observer completes anotherimportantbusinessstep, goes to wait state because parties need notification
-Party1: send mail2 to party1
-Party2 send mail2 to party2
-Party2: mail2 was delivered
-Party1: mail2 was delivered
- Observer finishes wait state, goes into another business state
- somewhere near the end of the process branches join
- whole process completes
The reason to include such steps for the mailing is because our customer wants to track the physical mailing process (print document, take it to the post office, etc), so they are task notes in a "todo list". Same with most of the observer states, that are real world tasks that are tracked by the system.
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4176323#4176323
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4176323
17 years, 6 months
[JBoss jBPM] - Re: signaling to a forked sibling
by gnagy
Well, the reason we modeled the process like this, and I guess I wasn't clear about that in the original post, is that the observer and item "states" are a actually processes with multiple steps that need to be synchronized.
The item side represents sub-processes about postal mailing to certain parties, with states (mostly tasks to be performed by a human) like generating mail, mail sent, mail not received (loop back if threshold not exceeded, fail otherwise), mail received (notify observer side), etc, and the observer side can only continue from certain states when *all* involved parties have been notified.
I'm not sure how much I can tell you about our actual business process, but if it is useful to the community I can cook up some example test case to showcase how we implemented the fork, as the fork is really a generic node with an action handler to control the token propagation, setting branch-local variables (such as info about the mailed party) on the child tokens, etc...
So in light of all this would you still recommend against such approach? I'll have a look at making the observer wait states decision nodes, but I guess since the decision is basically stay there or continue, it is better to use State nodes somehow...
BTW we had a look at drools (for authentication), but since our domain objects are rather complex drools turned out to be rather cumbersome (it's really good at deciding on direct properties of an object (like foo.bar), but when we needed to make decisions on foo.bar[].baz.xul, it started to look a lot like java code, so we finally implemented the rules in java, but closely modeled after drools, i.e. through Identity.hasPermission(name, action, data).
Thanks,
Greg
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4176317#4176317
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4176317
17 years, 6 months
[JBoss jBPM] - Would like to use ProcessDefinition subclass for custom seri
by joe_jboss@freemansoft.com
We want to use custom serialization (externalizable) for ProcessDefinitions because there isn't any reason to serialize the the ProcessDefinitions when going in and out of network caches. We really just need to serialize the names of the ProcessDefiitions and then reattach with readReplace(). The problem is that the BPM will not let us swap in our own subclass of ProcessDefinition and it doesn't use interfaces or factories in this particular area. (It has nice configurable behavior in other places)
| Our code calls ProcessDefinition.parseXmlInputStream()
| That calls jpdlReader.readProcessDefinition()
| readProcessDefinition is hardwired to create instances of the ProcessDefinition class. It calls ProcessDefinition.crateNewProcessDefinition().
| createNewProcessDefinition() creates the instance and configures it in one method.
|
We thought about subclassing JpdlXmlReader to create our own ProcessDefinition (subclass) instances but the readProcessDefinition() method needs to be broken into two parts. The first part creates an instance and stores it in the processDefinition attribute on JpdlXmlReader. The second part of the broken up readProcessDefinition() method would do all the processing exactly as it does.
We tried post-process replacing ProcessDefinition instances with OurProcessDefinition instances but that is too late in the process. There are many objects in a ProcessDefinition that have back pointers to the ProcessDefinition that contains them.
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4176266#4176266
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4176266
17 years, 6 months
[JBoss jBPM] - at org.hibernate.engine.StatefulPersistenceContext.(Stateful
by ailenin
collection growing to 16000 and not garbage collected.
Collection Counts:
java.util.HashMap 16823 org/hibernate/engine/StatefulPersistenceContext.(org.hibernate.engine.SessionImplementor)
java.util.HashMap 16823 org/apache/commons/collections/SequencedHashMap.(int)
java.util.ArrayList 16708 org/hibernate/engine/ActionQueue.init()
StackTrace:
at org.hibernate.engine.StatefulPersistenceContext.(StatefulPersistenceContext.java:118)
at org.hibernate.impl.SessionImpl.(SessionImpl.java:209)
at org.hibernate.impl.SessionFactoryImpl.openSession(SessionFactoryImpl.java:473)
at org.hibernate.impl.SessionFactoryImpl.openSession(SessionFactoryImpl.java:497)
at org.hibernate.impl.SessionFactoryImpl.openSession(SessionFactoryImpl.java:505)
at org.jbpm.persistence.db.DbPersistenceService.getSession(DbPersistenceService.java:116)
at org.jbpm.persistence.db.DbPersistenceService.getGraphSession(DbPersistenceService.java:336)
at org.jbpm.JbpmContext.getGraphSession(JbpmContext.java:571)
Please advise any suggestions to resolve this
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4176262#4176262
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4176262
17 years, 6 months
[JBoss jBPM] - Re: signaling to a forked sibling
by kukeltje
yikes... hmm... I would solve it a completely different way I think. More datadriven.
Why not make I1,I2 and I3 variables. Have two states. O1 and O2, each with a decision under them. Each decision has two outcomes, one back to the state and one to a next state. Each time one of the variables get's updated, you signal both states which then go to the decision and each decision checks the values of the variables and decides which transition to take. These decisions can be in java, drools, script or....
One other solution is to just have two states with one outcome (go-further) and put the decisions AND signalling of states in drools. You can decide there which of the states to signal.
Hope I gave you some more info..... either way.... if you could (as you promised to do from now on ;-) ) make this in a unit test, please post it. We need more of these examples.
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4176235#4176235
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4176235
17 years, 6 months
[JBoss jBPM] - Re: Task timer and TaskInstance.dueDate field
by kukeltje
1: Sure, no problem... just model it that way
2: leaving the node but keeping the task and 'just' notify? Via Email? That is possible with a timer. Via a new task, leaving the node where to? A new tasknode? And what if the user finishes the task before someone else can react on this task? Do you want to cancel it then?
Remember that jBPM van have tasks that are not in the flow... you can create and start them when a timer goes off. And e.g. cancel them when a transition is taken on the original node.
Just to show you (and this is a one time effort by me ;-)) I've made an example of this which is even somewhat configurable.
These are all possible with jBPM *now* just think out of the box and model these things into your process. Or write some code (actionhandlers etc..) The thing is, escalation, or the way people want it, is so dependant on the case, it cannot to the fullest extend be part of the processlanguage.
The solution for the initial problem 'reported' is to give both the timer and the duedate (which is just for informing the original owner) the same date. but what need is a date for a reminder if when the duedate is reached
| package net.vankuijk.jbpm;
|
| import java.util.ArrayList;
| import java.util.Collection;
| import java.util.List;
| import java.util.Map;
|
| import org.apache.commons.logging.Log;
| import org.apache.commons.logging.LogFactory;
| import org.jbpm.db.AbstractDbTestCase;
| import org.jbpm.graph.def.ActionHandler;
| import org.jbpm.graph.def.Node;
| import org.jbpm.graph.def.ProcessDefinition;
| import org.jbpm.graph.exe.ExecutionContext;
| import org.jbpm.graph.exe.ProcessInstance;
| import org.jbpm.graph.exe.Token;
| import org.jbpm.graph.node.TaskNode;
| import org.jbpm.taskmgmt.def.Task;
| import org.jbpm.taskmgmt.exe.TaskInstance;
| import org.jbpm.taskmgmt.exe.TaskMgmtInstance;
|
| public class EscalationExampleTest extends AbstractDbTestCase {
|
| ArrayList ownerIDs;
| ArrayList escalatorIDs;
|
| List ownerTasks;
| List escalatorTasks;
|
| public void setUp() throws Exception {
| super.setUp();
|
| ownerIDs = new ArrayList();
| ownerIDs.add("owner");
|
| escalatorIDs = new ArrayList();
| escalatorIDs.add("escalator");
|
| }
|
| static String processDefinition = "<process-definition name='testEscalation'>"
| + " <swimlane name='ownerSwimlane'>"
| + " <assignment pooled-actors='owner' />"
| + " </swimlane>"
|
| + " <event type='node-leave'>"
| + " <action class='net.vankuijk.jbpm.EscalationExampleTest$CancelEscalationTask' />"
| + " </event>"
|
| + " <action name='createEscalationTask' class='net.vankuijk.jbpm.EscalationExampleTest$CreateEscalationTask'>"
| + " <escalationTaskNodeName>task escalated</escalationTaskNodeName>"
| + " </action>"
|
| + " <swimlane name='escalationSwimlane'>"
| + " <assignment pooled-actors='escalator' />"
| + " </swimlane>"
|
| + " <start-state>"
| + " <transition name='to_task' to='task' />"
| + " </start-state>"
|
| + " <task-node name='task'>"
| + " <task name='task 0' swimlane='ownerSwimlane'>"
| + " <timer duedate='5 seconds'>"
| + " <action ref-name='createEscalationTask' />"
| + " </timer>"
| + " </task>"
| + " <transition name='to_end' to='end' />"
| + " </task-node>"
|
| + " <task-node name='task escalated'>"
| + " <task name='escalated task 0' swimlane='escalationSwimlane' signalling='false'/>"
| + " </task-node>"
|
| + " <end-state name='end' />"
|
| + "</process-definition>";
|
| void deployProcessDefinition(String xml) {
| ProcessDefinition processDefinition = ProcessDefinition
| .parseXmlString(xml);
| jbpmContext.deployProcessDefinition(processDefinition);
| newTransaction();
| }
|
| public void testNormalFlow() {
|
| deployProcessDefinition(processDefinition);
|
| ProcessInstance processInstance = jbpmContext
| .newProcessInstanceForUpdate("testEscalation");
| processInstance.signal();
|
| processInstance = saveAndReload(processInstance);
|
| ownerTasks = jbpmContext.getGroupTaskList(ownerIDs);
| TaskInstance ownerTask = (TaskInstance) ownerTasks.get(0);
| ownerTask.end();
|
| assertEquals(0, processInstance.getTaskMgmtInstance()
| .getUnfinishedTasks(processInstance.getRootToken()).size());
|
| assertEquals(true, processInstance.hasEnded());
|
| }
|
| public void testEndingNormalTaskAfterEscalationCancelsEscalation() {
| deployProcessDefinition(processDefinition);
|
| ProcessInstance processInstance = jbpmContext
| .newProcessInstanceForUpdate("testEscalation");
| long piId = processInstance.getId();
| processInstance.signal();
|
| assertEquals(1, processInstance.getTaskMgmtInstance()
| .getTaskInstances().size());
|
| processInstance = saveAndReload(processInstance);
|
| ownerTasks = jbpmContext.getGroupTaskList(ownerIDs);
| assertEquals(1, ownerTasks.size());
|
| escalatorTasks = jbpmContext.getGroupTaskList(escalatorIDs);
| assertEquals(0, escalatorTasks.size());
|
| processJobs(10000);
|
| processInstance = jbpmContext.getProcessInstance(piId);
|
| assertEquals(2, processInstance.getTaskMgmtInstance()
| .getTaskInstances().size());
|
| escalatorTasks = jbpmContext.getGroupTaskList(escalatorIDs);
| assertEquals(1, escalatorTasks.size());
|
| ownerTasks = jbpmContext.getGroupTaskList(ownerIDs);
| TaskInstance ownerTask = (TaskInstance) ownerTasks.iterator().next();
| ownerTask.end();
|
| // processInstance = saveAndReload(processInstance);
|
| // Escalation task should be cancelled
| escalatorTasks = jbpmContext.getGroupTaskList(escalatorIDs);
| assertEquals(0, escalatorTasks.size());
|
| }
|
| public void testEscalationEnded_NormalTaskStays() {
| deployProcessDefinition(processDefinition);
|
| ProcessInstance processInstance = jbpmContext
| .newProcessInstanceForUpdate("testEscalation");
| long piId = processInstance.getId();
| processInstance.signal();
|
| assertEquals(1, processInstance.getTaskMgmtInstance()
| .getTaskInstances().size());
|
| processInstance = saveAndReload(processInstance);
|
| ownerTasks = jbpmContext.getGroupTaskList(ownerIDs);
| assertEquals(1, ownerTasks.size());
|
| escalatorTasks = jbpmContext.getGroupTaskList(escalatorIDs);
| assertEquals(0, escalatorTasks.size());
|
| processJobs(10000);
|
| processInstance = jbpmContext.getProcessInstance(piId);
|
| assertEquals(2, processInstance.getTaskMgmtInstance()
| .getTaskInstances().size());
|
| escalatorTasks = jbpmContext.getGroupTaskList(escalatorIDs);
| assertEquals(1, escalatorTasks.size());
|
| TaskInstance escalatorTask = (TaskInstance) escalatorTasks.iterator()
| .next();
| assertEquals("escalated task 0", escalatorTask.getName());
| escalatorTask.end();
|
| processInstance = saveAndReload(processInstance);
|
| // owner task should still be there... is it?
| ownerTasks = jbpmContext.getGroupTaskList(ownerIDs);
| assertEquals(1, ownerTasks.size());
|
| escalatorTasks = jbpmContext.getGroupTaskList(escalatorIDs);
| assertEquals(0, escalatorTasks.size());
|
| }
|
| public static class CreateEscalationTask implements ActionHandler {
| private static final long serialVersionUID = 1L;
|
| public String escalationTaskNodeName;
|
| public void execute(ExecutionContext executionContext) throws Exception {
|
|
| if ("".equals(escalationTaskNodeName) || escalationTaskNodeName == null) {
| log.warn("escalationTaskNodeName not specified");
| return;
| }
|
| Token token = executionContext.getToken();
| TaskMgmtInstance tmi = executionContext.getTaskMgmtInstance();
|
| Node node = executionContext.getProcessDefinition().getNode(
| escalationTaskNodeName);
| if (node != null) {
| TaskNode escalatedTaskNode = (TaskNode) node;
|
| // assuming 1 task in node... otherwise also use e.g. a param
| // like escalationTaskNodeName. Errorhandling for this not done yet
| Task escalateTask = (Task) escalatedTaskNode.getTasksMap()
| .values().iterator().next();
|
| Token childToken = new Token(token, token.getFullName()
| + "_child_" + token.getChildren().size());
|
| childToken.setNode(escalatedTaskNode);
|
| tmi.createTaskInstance(escalateTask, childToken);
| } else {
| log.warn("escalationTaskNode with name " + escalationTaskNodeName + " not found.");
| }
|
| }
| }
|
| public static class CancelEscalationTask implements ActionHandler {
| private static final long serialVersionUID = 1L;
|
| public void execute(ExecutionContext executionContext) throws Exception {
|
| // Assuming max one active childToken and max one unfinished task in
| // this childtoken
| Map activeChildren = executionContext.getToken()
| .getActiveChildren();
| if (!activeChildren.isEmpty()) {
| Token childToken = (Token) activeChildren.values().iterator()
| .next();
| Collection unfinishedTasks = executionContext
| .getTaskMgmtInstance().getUnfinishedTasks(childToken);
| if (!unfinishedTasks.isEmpty()) {
| ((TaskInstance) unfinishedTasks.iterator().next()).cancel();
| }
| }
|
| }
| }
|
| private static final Log log = LogFactory.getLog(EscalationExampleTest.class);
|
| }
|
|
Maybe someone wants to make a wiki page out of this....
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4176232#4176232
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4176232
17 years, 6 months