Bug 975005 - Incorrect execution of fork/join after async node
Summary: Incorrect execution of fork/join after async node
Keywords:
Status: CLOSED UPSTREAM
Alias: None
Product: JBoss Enterprise SOA Platform 5
Classification: JBoss
Component: JBPM - standalone, JBPM - within SOA
Version: 5.3.1
Hardware: Unspecified
OS: Unspecified
high
high
Target Milestone: GA
: ---
Assignee: Nobody
QA Contact:
URL:
Whiteboard:
Depends On:
Blocks: 986007
TreeView+ depends on / blocked
 
Reported: 2013-06-17 11:10 UTC by Martin Weiler
Modified: 2025-02-10 03:27 UTC (History)
3 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed: 2025-02-10 03:27:57 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)


Links
System ID Private Priority Status Summary Last Updated
Red Hat Issue Tracker JBPM-4030 0 Major Resolved Incorrect execution of fork/join after async node 2014-03-05 16:52:27 UTC

Description Martin Weiler 2013-06-17 11:10:56 UTC
Description of problem:
Platform issue for JBPM-4030

Comment 1 JBoss JIRA Server 2013-06-17 15:20:49 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.

Comment 2 JBoss JIRA Server 2013-06-18 14:24:39 UTC
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}

Comment 3 JBoss JIRA Server 2013-06-24 19:47:26 UTC
Marco Rietveld <marco.rietveld> made a comment on jira JBPM-4030

Martin, this is fantastic work! Thanks very much.

Comment 4 JBoss JIRA Server 2013-06-25 09:35:01 UTC
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.

Comment 5 JBoss JIRA Server 2013-06-25 14:53:29 UTC
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.

Comment 6 JBoss JIRA Server 2013-06-28 09:14:53 UTC
Marco Rietveld <marco.rietveld> updated the status of jira JBPM-4030 to Resolved

Comment 10 Red Hat Bugzilla 2025-02-10 03:27:57 UTC
This product has been discontinued or is no longer tracked in Red Hat Bugzilla.


Note You need to log in before you can comment on or make changes to this bug.