OK, here is the JoinAsync class. Instead of using a join when you have asychronous logic going on, use a standard node that calls this in its action and asynchronous logic should work.
Yes, it is a bit of a hack because it essentially reloads the parentToken for analysis and then throws it away, but hey, it gets the job done. | /** | * | */ | package com.whatever.jbpm; | | import java.rmi.RemoteException; | import java.util.Collection; | import java.util.Iterator; | | import org.apache.commons.logging.Log; | import org.apache.commons.logging.LogFactory; | import org.dom4j.Element; | import org.jbpm.graph.action.Script; | import org.jbpm.graph.def.Node; | import org.jbpm.graph.exe.ExecutionContext; | import org.jbpm.graph.exe.Token; | import org.jbpm.jpdl.xml.JpdlXmlReader; | import org.jbpm.jpdl.xml.Parsable; | import org.jbpm.graph.def.ActionHandler; | import org.jbpm.db.JbpmSession; | import org.jbpm.db.JbpmSessionFactory; | | //public class JoinAsync extends Node implements Parsable { | | public class JoinAsync implements ActionHandler { | | private static final long serialVersionUID = 1L; | | /** | * specifies if this joinhandler is a discriminator. a descriminator | * reactivates the parent when the first concurrent token enters the join. | */ | private boolean isDiscriminator = false; | | /** | * a fixed set of concurrent tokens. | */ | private Collection tokenNames = null; | | /** | * a script that calculates concurrent tokens at runtime. | */ | private Script script = null; | | /** | * reactivate the parent if the n-th token arrives in the join. | */ | private int nOutOfM = -1; | | private static final JbpmSessionFactory jbpmSessionFactory = JbpmSessionFactory.buildJbpmSessionFactory(); | | public void read(Element element, JpdlXmlReader jpdlReader) { | } | | public void execute(ExecutionContext executionContext) { | Token token = executionContext.getToken(); | | // if this token is not able to reactivate the parent, | // we don't need to check anything | if (token.isAbleToReactivateParent()) { | | // the token arrived in the join and can only reactivate | // the parent once | token.setAbleToReactivateParent(false); | | Node joinNode = token.getNode(); | | Token parentToken = token.getParent(); | Token originalParentToken = parentToken; | | if (parentToken != null) { | | /* ========================================================== */ | | // The parent token must be reloaded from the database for | // asynchronous behaviour to work properly | log.debug("need to reload parent token from database"); | JbpmSession jbpmSession = null; | try { | jbpmSession = jbpmSessionFactory.openJbpmSession(); | | // Get the parent token from the database | log.debug("about to reload parent token from database"); | parentToken = jbpmSession.getGraphSession().loadToken(parentToken.getId()); | log.debug("reloaded parent token from database!"); | // Need to load the children before closing the session | Iterator iter = parentToken.getChildren().values().iterator(); | while (iter.hasNext()) { | Token t = (Token) iter.next(); | // Need to set the flag on this token since it isn't committed yet | if (t.getId() == token.getId()) { | t.setAbleToReactivateParent(false); | } | } | log.debug("reloaded parent token's children from database!"); | | } catch (Exception ex) { | System.out.println("error: " + ex.toString()); | } finally { | if (jbpmSession != null) { | jbpmSession.close(); | } | } | | /* ========================================================== */ | | boolean reactivateParent = true; | | // if this is a discriminator | if (isDiscriminator) { | // reactivate the parent when the first token arrives in the | // join. this must be the first token arriving because otherwise | // the isAbleToReactivateParent() of this token should have been | // false | // above. | reactivateParent = true; | | // if a fixed set of tokenNames is specified at design time... | } | else if (tokenNames != null) { | // check reactivation on the basis of those tokenNames | reactivateParent = mustParentBeReactivated(parentToken, tokenNames.iterator()); | | // if a script is specified | } | else if (script != null) { | | // check if the script returns a collection or a boolean | Object result = script.eval(token); | // if the result is a collection | if (result instanceof Collection) { | // it must be a collection of tokenNames | Collection runtimeTokenNames = (Collection) result; | reactivateParent = mustParentBeReactivated(parentToken, runtimeTokenNames.iterator()); | | // if it's a boolean... | } | else if (result instanceof Boolean) { | // the boolean specifies if the parent needs to be reactivated | reactivateParent = ((Boolean) result).booleanValue(); | } | | // if a nOutOfM is specified | } | else if (nOutOfM != -1) { | | int n = 0; | // wheck how many tokens already arrived in the join | Iterator iter = parentToken.getChildren().values().iterator(); | while (iter.hasNext()) { | Token concurrentToken = (Token) iter.next(); | if (joinNode == concurrentToken.getNode()) { | n++; | } | } | if (n < nOutOfM) { | reactivateParent = false; | } | | // if no configuration is specified.. | } | else { | // the default behaviour is to check all concurrent tokens and | // reactivate | // the parent if the last token arrives in the join | reactivateParent = mustParentBeReactivated(parentToken, parentToken.getChildren().keySet() | .iterator()); | } | | /* ========================================================== */ | | // Reset the parent token back to the one on the open session | parentToken = originalParentToken; | | /* ========================================================== */ | | // if the parent token needs to be reactivated from this join node | if (reactivateParent) { | | // write to all child tokens that the parent is already reactivated | Iterator iter = parentToken.getChildren().values().iterator(); | while (iter.hasNext()) { | ((Token) iter.next()).setAbleToReactivateParent(false); | } | | // write to all child tokens that the parent is already reactivated | ExecutionContext parentContext = new ExecutionContext(parentToken); | joinNode.leave(parentContext); | } | } | } | } | | public boolean mustParentBeReactivated(Token parentToken, Iterator childTokenNameIterator) { | boolean reactivateParent = true; | while ((childTokenNameIterator.hasNext()) && (reactivateParent)) { | String concurrentTokenName = (String) childTokenNameIterator.next(); | | Token concurrentToken = parentToken.getChild(concurrentTokenName); | | if (concurrentToken.isAbleToReactivateParent()) { | log.debug("==================================================="); | log.debug("==================================================="); | log.debug("join will not yet reactivate parent: found concurrent token '" + concurrentToken + "'"); | log.debug("==================================================="); | log.debug("==================================================="); | reactivateParent = false; | } | } | if (reactivateParent) { | log.debug("==================================================="); | log.debug("==================================================="); | log.debug("all tokens have reached join. allowing passage"); | log.debug("==================================================="); | log.debug("==================================================="); | } | return reactivateParent; | } | | public Script getScript() { | return script; | } | | public void setScript(Script script) { | this.script = script; | } | | public Collection getTokenNames() { | return tokenNames; | } | | public void setTokenNames(Collection tokenNames) { | this.tokenNames = tokenNames; | } | | public boolean isDiscriminator() { | return isDiscriminator; | } | | public void setDiscriminator(boolean isDiscriminator) { | this.isDiscriminator = isDiscriminator; | } | | public int getNOutOfM() { | return nOutOfM; | } | | public void setNOutOfM(int nOutOfM) { | this.nOutOfM = nOutOfM; | } | | private static final Log log = LogFactory.getLog(JoinAsync.class); | } | View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=3911813#3911813 Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=3911813 ------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Do you grep through log files for problems? Stop! Download the new AJAX search engine that makes searching your log files as easy as surfing the web. DOWNLOAD SPLUNK! http://ads.osdn.com/?ad_id=7637&alloc_id=16865&op=click _______________________________________________ JBoss-user mailing list JBoss-user@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jboss-user