-
1. Re: fork and join childeren
salaboy21 Nov 13, 2008 10:49 AM (in response to tbee)First of all, great ASCII graphic!!
Hmm... you have an wierd situation...
The behaviour is like the documentation said...
So.. show us your process definition and your code that signal this process..
because there is something missing sure....
Greetings! -
2. Re: fork and join childeren
tbee Nov 13, 2008 10:54 AM (in response to tbee)"salaboy21" wrote:
First of all, great ASCII graphic!!
Ah well ;-)
I'm building up unit test to slow work jbpm into my application. This is the one where I'm trying out parallel flows. I have written the output as comment next to the println's./** */ @Test public void test() { // Declare a process with a fork // S // | // F // / \ // s1 s2 // \ / // J // | // E ProcessDefinition lProcessDefinition = ProcessDefinition.parseXmlString( "<process-definition>" + " <start-state name=\"start\">" + " <transition to=\"fork1\"></transition>" + " </start-state>" + " <fork name=\"fork1\">" + " <transition to=\"state1\"></transition>" + " <transition to=\"state2\"></transition>" + " </fork>" + " <state name=\"state1\">" + " <transition to=\"join1\"></transition>" + " </state>" + " <state name=\"state2\">" + " <transition to=\"join1\"></transition>" + " </state>" + " <join name=\"join1\">" + " <transition to=\"end\"></transition>" + " </join>" + " <end-state name=\"end\"></end-state>" + "</process-definition>" ); // Start a process ProcessInstance lProcessInstance = new ProcessInstance(lProcessDefinition); // Get the token Token lToken = lProcessInstance.getRootToken(); System.out.println(lToken.getNode() + "/" + lToken.getChildren()); // start if (lToken.getChildren() != null) System.out.println( " -" + ((Token)lToken.getChildren().get(lToken.getChildren().keySet().iterator().next())).getNode() ); // Goto the next lToken.signal(); System.out.println(lToken.getNode() + "/" + lToken.getChildren()); // fork1 if (lToken.getChildren() != null) System.out.println( " -" + ((Token)lToken.getChildren().get(lToken.getChildren().keySet().iterator().next())).getNode() ); // Goto the next lToken.signal(); System.out.println(lToken.getNode() + "/" + lToken.getChildren()); // state1 if (lToken.getChildren() != null) System.out.println( " -" + ((Token)lToken.getChildren().get(lToken.getChildren().keySet().iterator().next())).getNode() ); //Goto the next lToken.signal(); System.out.println(lToken.getNode() + "/" + lToken.getChildren()); // join1 if (lToken.getChildren() != null) System.out.println( " -" + ((Token)lToken.getChildren().get(lToken.getChildren().keySet().iterator().next())).getNode() ); //Goto the next lToken.signal(); System.out.println(lToken.getNode() + "/" + lToken.getChildren()); // end if (lToken.getChildren() != null) System.out.println( " -" + ((Token)lToken.getChildren().get(lToken.getChildren().keySet().iterator().next())).getNode() ); }
-
3. Re: fork and join childeren
salaboy21 Nov 13, 2008 11:02 AM (in response to tbee)At first sight..
I think you have a concept problem..
Remember that signal method will execute your process until the processInstance reach a wait state...
And the process is behaving well!!
If you look you very nice graph and follow the signals you will see...
1) the first signal will go out from the start node
2) in this step you have two child tokens waiting in the S1 and S2
3) the next signal (the second one) signal the S1 child token and it moves to join...(the parent token is still in the fork node)
4) the next signal (the third one) will signal S2 and then beacuse S1 and S2 are both in the join node your output will be end
Its that clear? -
4. Re: fork and join childeren
tbee Nov 13, 2008 11:22 AM (in response to tbee)"salaboy21" wrote:
I think you have a concept problem..
Its that clear?
It is good that I'm the one with the problem, that is probably the easiest to fix.
So, my main problem is with the magical token swapping. I get the token once. The root. The parent. How come it suddenly becomes child token 1 and 2? How would one write this code correctly? -
5. Re: fork and join childeren
salaboy21 Nov 13, 2008 11:26 AM (in response to tbee)The code is in some way correct.. you need to understand the behaviour only....
The two child tokens are created and propagated in the fork node, and the parent token stay in the fork node..
In your code you can look for child tokens in the root token and then signal them and not always signal the parent. Just to clear the concepts...
Because when you signal the root token.. it propagate the signal to the child tokens.. -
6. Re: fork and join childeren
tbee Nov 13, 2008 12:37 PM (in response to tbee)"salaboy21" wrote:
The code is in some way correct.. you need to understand the behaviour only....
The two child tokens are created and propagated in the fork node, and the parent token stay in the fork node..
In your code you can look for child tokens in the root token and then signal them and not always signal the parent. Just to clear the concepts...
Because when you signal the root token.. it propagate the signal to the child tokens..
Ok. So. Ah... I get the initial root token. It moves to the fork and at that time two child tokens are spawned. These become its childeren.R / \ C1 C2
So if I do a R.getNode() I actually get the node of C1, because R is in de join and holding for its childeren. Then C1 moves to the join. With another R.getNode() I then should get the node of C2. But that does not match, because I never have a token that has "state2".
So I'll see what happens if I refetch the root token every time. -
7. Re: fork and join childeren
tbee Nov 13, 2008 12:49 PM (in response to tbee)"tbeernot" wrote:
So I'll see what happens if I refetch the root token every time.
No, the behavior is identical.
So.
Back to the documentation: "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."
1. The token is in start.
2. I do a signal and then the token arrives at the fork. At that time it does not know what to do, they may be transitions with conditions.
3. When another signal is done on the token in the fork, THEN it will determine what transitions to follow and thus childeren can be created.
It still is THE token that arrived in the fork, so after the second signal there should be 2 childeren. Let's verify...
No. If I print the getNode and the getChilderen.size of the same token, it does not match. There is only one child. And the childeren appear at the wrong time.
StartState(start)/null
Fork(fork1)/1
State(state1)/1
Is there a good documentation? This is very confusing. -
8. Re: fork and join childeren
salaboy21 Nov 13, 2008 1:44 PM (in response to tbee)No NO NO!.. LOL
1. The token is in start.
2. I do a signal and then the token arrives at the fork. At that time it does not know what to do, they may be transitions with conditions.
3. When another signal is done on the token in the fork, THEN it will determine what transitions to follow and thus childeren can be created.
the second (2) point is wrong.. when the process enter to de fork node It know how many transition have.. so it create all the child token.. (If you don't belive me.. see the ForkNode.java class)
The fork node is not a wait state.. so if you signal the start-state, the process will continue passing thru the fork node until reach the S1 and S2 nodes...
So do this test:
1) signal de root token
2) look for childrens.. at this time with only one signal.. you must have 2 children.
3) then you can signal one of the child tokens and you see that the root token still in the fork node and the child token go to join node
4) then signal the other token and you will see that the root token moves to the end and the child token like the other move to join node...
Can you do that test and post your code? -
9. Re: fork and join childeren
tbee Nov 13, 2008 1:54 PM (in response to tbee)"salaboy21" wrote:
The fork node is not a wait state.. so if you signal the start-state, the process will continue passing thru the fork node until reach the S1 and S2 nodes...
So do this test:
1) signal de root token
2) look for childrens.. at this time with only one signal.. you must have 2 children.
3) then you can signal one of the child tokens and you see that the root token still in the fork node and the child token go to join node
4) then signal the other token and you will see that the root token moves to the end and the child token like the other move to join node...
Can you do that test and post your code?
Sure!public void test() { // Declare a process with a fork // S // | // F // / \ // s1 s2 // \ / // J // | // E ProcessDefinition lProcessDefinition = ProcessDefinition.parseXmlString( "<process-definition>" + " <start-state name=\"start\">" + " <transition to=\"fork1\"></transition>" + " </start-state>" + " <fork name=\"fork1\">" + " <transition to=\"state1\"></transition>" + " <transition to=\"state2\"></transition>" + " </fork>" + " <state name=\"state1\">" + " <transition to=\"join1\"></transition>" + " </state>" + " <state name=\"state2\">" + " <transition to=\"join1\"></transition>" + " </state>" + " <join name=\"join1\">" + " <transition to=\"end\"></transition>" + " </join>" + " <end-state name=\"end\"></end-state>" + "</process-definition>" ); // Start a process ProcessInstance lProcessInstance = new ProcessInstance(lProcessDefinition); // Get the token: we're in the start node Token lToken = lProcessInstance.getRootToken(); System.out.println("1: " + lToken.getNode()); // First signal: goto the fork lToken.signal(); // this should mean that this token gets two childeren System.out.println("2a: " + lToken.getChildren().size()); // this token should still be in the fork System.out.println("2b: " + lToken.getNode()); // this token should still be in the fork System.out.println("2c: " + lToken.getChildren()); Token lChild1 = (Token)lToken.getChildren().values().iterator().next(); //Token lChild2 = (Token)lToken.getChildren().values().iterator().next(); // the childeren should be in state1 and state2 System.out.println("2d: " + lChild1.getNode() ); //System.out.println("2e: " + lChild2.getNode() ); }
I commented out lines because I do not have two childeren:
1: StartState(start)
2a: 1
2b: Fork(fork1)
2c: {1=Token(/1)}
2d: State(state1) -
10. Re: fork and join childeren
salaboy21 Nov 13, 2008 2:19 PM (in response to tbee)Ok, you are right.. there is something with your process definition and at first sight i don't find this error...
So when I test it in my IDE i find the problem very quickly:
This is your problem:"<process-definition>" + " <start-state name=\"start\">" + " <transition to=\"fork1\"></transition>" + " </start-state>" + " <fork name=\"fork1\">" + " <transition to=\"state1\" name=\"2\"></transition>" + " <transition to=\"state2\" name=\"1\"></transition>" + " </fork>" + " <state name=\"state1\">" + " <transition to=\"join1\"></transition>" + " </state>" + " <state name=\"state2\">" + " <transition to=\"join1\"></transition>" + " </state>" + " <join name=\"join1\">" + " <transition to=\"end\"></transition>" + " </join>" + " <end-state name=\"end\"></end-state>" + "</process-definition>"
If you look it carefully, you will find that I add the name attribute in the transitions..
This confuse jBPM because have to with null or empty names...
If you correct that you see the right behaviour..
Hope it helps... -
11. Re: fork and join childeren
tbee Nov 13, 2008 2:26 PM (in response to tbee)"salaboy21" wrote:
If you look it carefully, you will find that I add the name attribute in the transitions..
Ah. Now indeed the behavior is more logical. Thanks! I'll experiment some more now and see if I get the concept now.
Thanks again! -
12. Re: fork and join childeren
kukeltje Nov 13, 2008 2:48 PM (in response to tbee)What is best in these cases is to make a real unittest and do asserts on what node you think the token is in, how many tokens are there etc..... Not using system.out or whatever. Using asserts, you can make clear to everyone in a declared way what you expect, without using natural language.
-
13. Re: fork and join childeren
tbee Nov 13, 2008 4:31 PM (in response to tbee)"kukeltje" wrote:
What is best in these cases is to make a real unittest and do asserts on what node you think the token is in, how many tokens are there etc..... Not using system.out or whatever. Using asserts, you can make clear to everyone in a declared way what you expect, without using natural language.
He he, naturally. In fact I was creating a unit test. But before I can assert something, I need to see it first... Are there really two tokens? Yes... Ok, assert.
And the two tokens weren't there. -
14. Re: fork and join childeren
kukeltje Nov 13, 2008 8:01 PM (in response to tbee)But before I can assert something, I need to see it first... Are there really two tokens? Yes... Ok, assert.
I disagree. You can assert ANYTHING, e.g. assert that you expect one token. The test fails because there are more tokens. Assert that the token is in a certain state: it succeeds or fails and the real value is always printed.... I initially did it as you mention, but starting with assertions is way easier and more understandable for others if something goes wrong.