Bug 975005
Summary: | Incorrect execution of fork/join after async node | ||
---|---|---|---|
Product: | [JBoss] JBoss Enterprise SOA Platform 5 | Reporter: | Martin Weiler <mweiler> |
Component: | JBPM - standalone, JBPM - within SOA | Assignee: | Nobody <nobody> |
Status: | VERIFIED --- | QA Contact: | |
Severity: | high | Docs Contact: | |
Priority: | high | ||
Version: | 5.3.1 | CC: | nwallace, rwagner, soa-p-jira, yann.perey |
Target Milestone: | GA | ||
Target Release: | --- | ||
Hardware: | Unspecified | ||
OS: | Unspecified | ||
Whiteboard: | |||
Fixed In Version: | Doc Type: | Bug Fix | |
Doc Text: | Story Points: | --- | |
Clone Of: | Environment: | ||
Last Closed: | Type: | Bug | |
Regression: | --- | Mount Type: | --- |
Documentation: | --- | CRM: | |
Verified Versions: | Category: | --- | |
oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |
Cloudforms Team: | --- | Target Upstream Version: | |
Embargoed: | |||
Bug Depends On: | |||
Bug Blocks: | 986007 |
Description
Martin Weiler
2013-06-17 11:10:56 UTC
Martin Weiler <mweiler> made a comment on jira JBPM-4030 Attaching a test process to reproduce the issue. Note that the end state is reached twice, and that inside the fork/join the parent/child token relationship is empty. Martin Weiler <mweiler> made a comment on jira JBPM-4030 Proposal to fix this issue: {code} diff --git a/core/src/main/java/org/jbpm/graph/node/Join.java b/core/src/main/java/org/jbpm/graph/node/Join.java index bcff33a..9260e89 100644 --- a/core/src/main/java/org/jbpm/graph/node/Join.java +++ b/core/src/main/java/org/jbpm/graph/node/Join.java @@ -129,6 +129,10 @@ public class Join extends Node { } Token parentToken = arrivingToken.getParent(); + // JBPM-4030 refresh parent token if necessary + if(parentToken.getChildren().size()==0) { + executionContext.getJbpmContext().getSession().refresh(parentToken); + } boolean reactivateParent; // if this is a discriminator if (isDiscriminator) { @@ -173,7 +177,10 @@ public class Join extends Node { childToken.setAbleToReactivateParent(false); } // unlock parent token - parentToken.unlock(parentToken.getNode().toString()); + // JBPM-4030 check if parentToken can be unlocked + if(parentToken.isLocked() && parentToken.getLockOwner().equals(parentToken.getNode().toString())) { + parentToken.unlock(parentToken.getNode().toString()); + } // leave the join node leave(new ExecutionContext(parentToken)); } {code} Marco Rietveld <marco.rietveld> made a comment on jira JBPM-4030 Martin, this is fantastic work! Thanks very much. Marco Rietveld <marco.rietveld> made a comment on jira JBPM-4030 This is a note to myself for future reference: One of the main causes of this problem is the following code in the Fork class: {code:java} // phase two: create child token for each selected transition Map childTokens = new HashMap(); for (Iterator iter = transitionNames.iterator(); iter.hasNext();) { String transitionName = (String) iter.next(); Token childToken = createForkedToken(token, transitionName); childTokens.put(transitionName, childToken); } {code} Specifically, the {code:java}Map childTokens = new HashMap();{code} line is a lot more dangerous than it looks. *Why?* Because jBPM 3 uses the Hibernate 3 2nd level cache, which means that many of the objects referred to in the code, are actually hibernate-proxies of the actual objects. You'll notice that the method {{createForkedToken()}} is called, and your suspicion that creates the parent-child token relationship will be correct -- but only partially. *Here's what happens:* {{createdForkedToken()}} eventually calls the {{Token(Token parent, String name)}} constructor. And that constructor contains the following code: {code:java} this.parent = parent; parent.addChild(this); {code} Great! *NO..* Why? Because the parent object referred to here is the _actual_ object, not the hibernate-proxied Token object. That means that when we return to the original {{execute(...)}} in the {{Fork}} class, the hibernate-proxied (parent) Token object will still have *no* children! Blech.. And we return to why {{Map childTokens = new HashMap();}} is so dangerous. It should simply be this: {code:java}Map childTokens = token.getChildren();{code}. That way, we add the children to the hibernate-proxied Token object map. If you've been paying attention, you'll notice that we're now adding this (parent-child) relationship twice: once in the {{Fork.execute(...)}} method (with the above line), and once in the {{createForkedToken(...)}} method. This is okay for 2 reasons: # We're adding the same relationship: in both cases, the key is the transition name, and the value is the (same) child token reference. # Technically, we're adding this relationship to 2 different maps: the first map is from the hibernate-proxied parent Token, and the second map is from the (real) parent Token object. Marco Rietveld <marco.rietveld> made a comment on jira JBPM-4030 Wow, there's an even simpler solution: simply initalize the {{Token.children}} (Map) field with a {{new HashMap()}} value so that the hibernate-proxied object also contains that field. LOL. |