Bug 779640 (SOA-2010)
| Summary: | Conditional transition cannot be considered as a default one | ||||||||
|---|---|---|---|---|---|---|---|---|---|
| Product: | [JBoss] JBoss Enterprise SOA Platform 4 | Reporter: | Martin Vecera <mvecera> | ||||||
| Component: | Documentation, JBPM - within SOA, JBPM - standalone | Assignee: | David Le Sage <dlesage> | ||||||
| Status: | CLOSED NEXTRELEASE | QA Contact: | |||||||
| Severity: | urgent | Docs Contact: | |||||||
| Priority: | urgent | ||||||||
| Version: | 4.3 CP04 ER1 | CC: | alex.guizar, kevin.conner, mbaluch, mvecera | ||||||
| Target Milestone: | --- | ||||||||
| Target Release: | --- | ||||||||
| Hardware: | Unspecified | ||||||||
| OS: | Unspecified | ||||||||
| URL: | http://jira.jboss.org/jira/browse/SOA-2010 | ||||||||
| Whiteboard: | |||||||||
| Fixed In Version: | Doc Type: | Bug Fix | |||||||
| Doc Text: | Story Points: | --- | |||||||
| Clone Of: | |||||||||
| : | 779641 (view as bug list) | Environment: |
SOA-P 4.3.CP03 ER1
|
||||||
| Last Closed: | 2011-11-15 08:08:44 UTC | 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: | |||||||||
| Attachments: |
|
||||||||
|
Description
Martin Vecera
2010-03-24 09:33:35 UTC
Link: Added: This issue depends JBPM-2834 Some things were not clear so I'd like to denote that this issue should fire a code change. The documentation seems logical to me. JBPM-2834 resolved as follows: * amended Node.getDefaultLeavingTransition to return the first transition if there is no unconditional transition * edited the decision.element section of the jpdl chapter for clarity. This edit should be merged into the product documentation. Link: Added: This issue is related to SOA-1979 Anne-Louise, this is not just about documentation. Given the date of my last comment the fix should have already been picked up into CP04, although I can't be sure. Martin, can you check if the changes were taken, and set the fix version appropriately? QE should not set Fix Version/s. This is a task for developers once they know their fix is in. Together with Fix Version/s the issue is usually set to Resolved. QE then verifies and closes it. What prevents this issue to follow this standard approach? > What prevents this issue to follow this standard approach? The procedure you describe appears to be new practice, at least to me. I used to resolve SOA issues once the JBPM counterpart was done and then they got reopened saying that someone from the platform should resolve instead. Go figure. Anyway, this issue is resolved. It does not appear in the triage page https://docspace.corp.redhat.com/docs/DOC-39103 so I cannot possibly know whether this issue fits the plans for the next SOA release. I am setting the fix version to 5.1.0 because it has the nearest release date. Edit as appropriate. The corresponding issue is already resolved for some time. When do we expect this to be consumed by SOA-P? The issue is still present. Attached a reproducer quickstart. Attachment: Added: bpm_orchestration1.tar.bz2 It seems that the issue is in ESB codebase: 2011-01-31 14:50:20,182 DEBUG [org.jboss.soa.esb.services.jbpm.integration.job.ExecuteJobCommand] (WorkManager(2)-8) exception while executing ExecuteActionJob(2,Action(ESB_ASYNC_SIGNAL_ACTION)) org.jbpm.JbpmException: condition '#(AAA == null)' guarding Transition(Node(node1)->Node(node2) not met at org.jbpm.graph.def.Transition.take(Transition.java:133) at org.jbpm.graph.def.Node.leave(Node.java:450) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:197) at org.jbpm.graph.def.Node_$$_javassist_148.leave(Node_$$_javassist_148.java) at org.jbpm.graph.exe.Token.signal(Token.java:210) at org.jbpm.graph.exe.Token.signal(Token.java:144) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:197) at org.jbpm.graph.exe.Token_$$_javassist_80.signal(Token_$$_javassist_80.java) at org.jbpm.command.SignalCommand.execute(SignalCommand.java:89) at org.jboss.soa.esb.services.jbpm.cmd.AsyncProcessSignal$AsyncSignalAction.execute(AsyncProcessSignal.java:300) at org.jbpm.graph.def.Action.execute(Action.java:117) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:197) at org.jbpm.graph.def.Action_$$_javassist_100.execute(Action_$$_javassist_100.java) at org.jbpm.graph.def.GraphElement.executeActionImpl(GraphElement.java:300) at org.jbpm.graph.def.GraphElement.executeAction(GraphElement.java:274) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:197) at org.jbpm.graph.def.Node_$$_javassist_148.executeAction(Node_$$_javassist_148.java) at org.jbpm.job.ExecuteActionJob.execute(ExecuteActionJob.java:30) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:197) at org.jbpm.job.Job_$$_javassist_152.execute(Job_$$_javassist_152.java) at org.jboss.soa.esb.services.jbpm.integration.job.ExecuteJobCommand.executeJob(ExecuteJobCommand.java:124) at org.jboss.soa.esb.services.jbpm.integration.job.ExecuteJobCommand.execute(ExecuteJobCommand.java:92) at org.jboss.soa.esb.services.jbpm.integration.command.AbstractMessageListener.onMessage(AbstractMessageListener.java:66) at org.jboss.soa.esb.services.jbpm.integration.command.JobListener.onMessage(JobListener.java:16) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.jboss.internal.soa.esb.dependencies.JCAInflowAdapter$1.invoke(JCAInflowAdapter.java:276) at org.jboss.soa.esb.listeners.jca.EndpointProxy.delivery(EndpointProxy.java:258) at org.jboss.soa.esb.listeners.jca.EndpointProxy.invoke(EndpointProxy.java:150) at $Proxy322.onMessage(Unknown Source) at org.jboss.resource.adapter.jms.inflow.JmsServerSession.onMessage(JmsServerSession.java:179) at org.jboss.jms.client.container.ClientConsumer.callOnMessageStatic(ClientConsumer.java:160) at org.jboss.jms.client.container.SessionAspect.handleRun(SessionAspect.java:831) at org.jboss.aop.advice.org.jboss.jms.client.container.SessionAspect_z_handleRun_1173212452.invoke(SessionAspect_z_handleRun_1173212452.java) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) at org.jboss.jms.client.container.ClosedInterceptor.invoke(ClosedInterceptor.java:172) at org.jboss.aop.advice.PerInstanceInterceptor.invoke(PerInstanceInterceptor.java:86) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) at org.jboss.jms.client.delegate.ClientSessionDelegate.run(ClientSessionDelegate.java) at org.jboss.jms.client.JBossSession.run(JBossSession.java:199) at org.jboss.resource.adapter.jms.inflow.JmsServerSession.run(JmsServerSession.java:236) at org.jboss.resource.work.WorkWrapper.execute(WorkWrapper.java:205) at org.jboss.util.threadpool.BasicTaskWrapper.run(BasicTaskWrapper.java:260) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:619) 2011-01-31 14:50:20,182 DEBUG [org.jboss.soa.esb.services.jbpm.integration.command.JobListener] (WorkManager(2)-8) Executed command org.jboss.soa.esb.services.jbpm.integration.job.ExecuteJobCommand@6c0d9a61 2011-01-31 14:50:20,190 DEBUG [org.jbpm.persistence.jta.JtaDbPersistenceService] (WorkManager(2)-8) marking external transaction for rollback 2011-01-31 14:50:20,195 DEBUG [org.jboss.soa.esb.services.jbpm.integration.command.JobListener] (WorkManager(2)-9) Processing message delegator->JBossMessage[5310389535178755]:PERSISTENT, deliveryId=1 2011-01-31 14:50:20,195 DEBUG [org.jboss.soa.esb.services.jbpm.integration.command.JobListener] (WorkManager(2)-9) getting job id from jms message... 2011-01-31 14:50:20,195 DEBUG [org.jboss.soa.esb.services.jbpm.integration.command.JobListener] (WorkManager(2)-9) retrieved jobId '2' via jms message 2011-01-31 14:50:20,195 DEBUG [org.jboss.soa.esb.services.jbpm.integration.command.JobListener] (WorkManager(2)-9) Extracted command org.jboss.soa.esb.services.jbpm.integration.job.ExecuteJobCommand@5dbf973 2011-01-31 14:50:20,195 DEBUG [org.jboss.cache.interceptors.InvalidationInterceptor] (WorkManager(2)-8) Caught a rollback. Clearing modification in txMods 2011-01-31 14:50:20,199 DEBUG [org.jboss.soa.esb.services.jbpm.integration.job.ExecuteJobCommand] (WorkManager(2)-9) Rescheduling job 2 2011-01-31 14:50:20,199 DEBUG [org.jboss.soa.esb.services.jbpm.integration.msg.JmsMessageService] (WorkManager(2)-9) Sending job 2 2011-01-31 14:50:20,199 DEBUG [org.jboss.soa.esb.services.jbpm.integration.msg.JmsMessageService] (WorkManager(2)-9) Creating connection 2011-01-31 14:50:20,199 DEBUG [org.jboss.soa.esb.services.jbpm.integration.msg.JmsMessageService] (WorkManager(2)-9) Creating session 2011-01-31 14:50:20,201 DEBUG [org.jboss.soa.esb.services.jbpm.integration.msg.JmsMessageService] (WorkManager(2)-9) Sent job 2 2011-01-31 14:50:20,201 DEBUG [org.jboss.soa.esb.services.jbpm.integration.command.JobListener] (WorkManager(2)-9) Executed command org.jboss.soa.esb.services.jbpm.integration.job.ExecuteJobCommand@5dbf973 2011-01-31 14:50:20,211 DEBUG [org.jboss.messaging.core.impl.OrderingGroupMonitor] (WorkManager(2)-9) message doesn't have group prop, fine by me 2011-01-31 14:50:20,212 DEBUG [org.jboss.soa.esb.services.jbpm.integration.command.JobListener] (WorkManager(2)-10) Processing message delegator->JBossMessage[5310389535539204]:PERSISTENT, deliveryId=2 2011-01-31 14:50:20,212 DEBUG [org.jboss.soa.esb.services.jbpm.integration.command.JobListener] (WorkManager(2)-10) getting job id from jms message... 2011-01-31 14:50:20,212 DEBUG [org.jboss.soa.esb.services.jbpm.integration.command.JobListener] (WorkManager(2)-10) retrieved jobId '2' via jms message 2011-01-31 14:50:20,212 DEBUG [org.jboss.soa.esb.services.jbpm.integration.command.JobListener] (WorkManager(2)-10) Extracted command org.jboss.soa.esb.services.jbpm.integration.job.ExecuteJobCommand@508e4439 2011-01-31 14:50:20,216 DEBUG [org.jboss.soa.esb.services.jbpm.integration.job.ExecuteJobCommand] (WorkManager(2)-10) executing ExecuteActionJob(2,Action(ESB_ASYNC_SIGNAL_ACTION)) 2011-01-31 14:50:20,219 DEBUG [org.jboss.soa.esb.services.jbpm.cmd.AsyncProcessSignal] (WorkManager(2)-10) Unlocking token id 1 from process instance 1 2011-01-31 14:50:20,219 DEBUG [org.jbpm.graph.exe.Token] (WorkManager(2)-10) 'ESB_ASYNC_SIGNAL_ACTION' unlocked Token(1) 2011-01-31 14:50:20,219 DEBUG [org.jboss.soa.esb.services.jbpm.cmd.AsyncProcessSignal] (WorkManager(2)-10) Signaling task 1 from process instance 1 2011-01-31 14:50:20,223 DEBUG [org.jbpm.context.exe.VariableContainer] (WorkManager(2)-10) Token(1) initializes 'theBody' to Service 1 Start It Up 2011-01-31 14:50:20,224 DEBUG [org.jbpm.graph.def.GraphElement] (WorkManager(2)-10) Token(1) fires event 'before-signal' on Node(node1) 2011-01-31 14:50:20,226 DEBUG [org.jbpm.graph.def.GraphElement] (WorkManager(2)-10) Token(1) fires event 'node-leave' on Node(node1) Not sure how you come to the conclusion that this is ESB, can you elaborate? Link: Added: This issue Cloned to SOA-2858 The original fix only applies to nodes of type Decision, but this is not the case with this process definition. The method invocations are token.signal() token.signal(node.getDefaultLeavingTransition(), context) node.leave(context, transition) <--- This is of type Node transition.take(context) With isConditionEnforced still being true for the default transition. Rather than a bug in ESB or jBPM, the problem is in the quickstart itself. Try replacing the parenthesis in expression {{#(AAA == null)}} with braces: {{#\{AAA == null\}}}. The former expression, while valid, simply returns the literal string "#(AAA == null)", which {{Boolean.valueOf(String)}} converts to false.
A default transition appears to be chosen unconditionally by the node (look for a null or take the first). There doesn't appear to be any attempt to evaluate the transitions to see whether the guards are satisfied, requiring that the first always evaluate to true.
Changing the guard to #{AAA != null}, even with a second transition having a #{AAA == null} condition, result in the same error.
Is this really intentional?
bq. A default transition appears to be chosen unconditionally by the node (look for a null or take the first). There doesn't appear to be any attempt to evaluate the transitions to see whether the guards are satisfied, requiring that the first always evaluate to true.
Right, no such attempt is made because that is the role of the decision node. Turning every other node into a decision node overnight would be a significant departure from the existing behavior.
bq. Changing the guard to #{AAA != null}, even with a second transition having a #{AAA == null} condition, result in the same error.
In this particular scenario, if the second transition had no guard condition, it would be selected instead of the first. Using a guarded transition as the default is a last-resort measure that did not even exist until JBPM-2834 requested it.
Perhaps JBPM-2834 should have been rejected. Previously, Node.getDefaultLeavingTransition() returned null if there was no unconditional transition. This outcome seemed adequate to me: the guard condition prevents a transition from being taken freely. The default transition ought to grant unrestricted pass.
Anyway, what is the meaning of the sample process? There is only one outgoing transition from node1, and it is guarded. What is supposed to happen if the condition is not satisfied? Currently, the process instance would be stuck (bad design?) unless condition enforcement was disabled (why is there a condition?) or the variable changed (yet this is an automatic node, not a wait state).
I can't speak as to the intent of the process definition, I suspect QE are just testing process definitions that are allowable and may be tried by customers. All I am doing is identifying the current issue, pointing out inconsistencies and raising questions, i.e. - why have conditional transitions if they are never evaluated during Token.signal, i.e. why allow them for non Decision nodes? - why allow unevaluated conditional transitions to succeed with Decision but not with other nodes? (fix for JBPM-2834) At best we have an inconsistency that we need to make sure is documented appropriately so that customers are also made aware of the difference in behaviour between evaluation of Decision nodes and others. As for the transitions, why would you not want to provide multiple leaving transitions with guards? If they cover all the exit scenarios then why would it be an issue? True, there are inconsistencies which need to be addressed. When transition conditions were introduced they were allowed only if leaving from a decision node. Users later requested to allow conditions on any transition to model guard conditions, as in UML activity diagrams. When told non-decision nodes were just going to throw an exception if the condition evaluated to false, they said that was fine. They wanted the condition to be available to their UIs for filtering out unavailable actions. {{Transition.getCondition()}} is the answer to their requirement.
In JBPM-2834 it was not considered that returning a guarded transition from {{Node.getDefaultLeavingTransition()}} could later cause an exception if the condition was false. Allowing said method to evaluate the conditions if no unguarded transition exists would extend the usefulness of guard conditions beyond the basic scenario outlined in the previous paragraph.
So far so good, but even this alternative does not address the problem posed by a node whose leaving transitions were all guarded.
{{Node.getDefaultLeavingTransition()}} would return the first transition that evaluated to true. Nonetheless, what if all conditions were false? The token would have to take the first (guarded) transition anyway, as in the JBPM-2984 fix, and further disable condition enforcement. Not good.
Labels: Removed: rn-done-resolved We plan on picking up the same version of jBPM as in SOA 5.2. This issue is not fixed in that version, so it will be moved to Future. Just to clarify something: Martin's comment and stacktrace on 31/Jan/11 9:14 AM is an example of the functionality that Alejandro describes on 03/Feb/11 7:01 AM: "When told non-decision nodes were just going to throw an exception if the condition evaluated to false, they said that was fine." There are two problems here, one of which Alejandro already summarized (see comment 03/Feb/11 7:01 AM): # Users requested that conditions be used for transitions on nodes. Introducing this feature basically caused SOA-2010. (this is explained in 03/Feb/11 7:01 AM) # What's not helping is that Node and Decision have exactly the same behavior with regards to the default transition, even though the documentation says otherwise. a. Node behavior does not correspond to the documentation, while Decision behavior does. To some extent, Node behavior is not fully documented. ---- In short, the discrepancies can be summed up as follows: ||Documentation||Code|| |_common node elements_| | |default transition for a Node is first transition |default transition for a Node is first unconditional transition, otherwise first conditional| |_transition_ | | |use conditions on transitions *only* with decisions |conditions on transitions used in decisions *and* nodes (default transition)| |_condition_ | | |if no conditions are true, first/default transition is used \\ (no mention of conditional or unconditional) |default transition is first unconditional transition, otherwise first conditional \\ | ---- I've been looking at the following: http://docs.redhat.com/docs/en-US/JBoss_Enterprise_SOA_Platform/5/html/JBPM_Reference_Guide/common.node.elements.html http://docs.redhat.com/docs/en-US/JBoss_Enterprise_SOA_Platform/5/html/JBPM_Reference_Guide/decision.element.html http://docs.redhat.com/docs/en-US/JBoss_Enterprise_SOA_Platform/5/html/JBPM_Reference_Guide/transition.element.html http://docs.redhat.com/docs/en-US/JBoss_Enterprise_SOA_Platform/5/html/JBPM_Reference_Guide/condition.element.html With regards to handling transitions, the documentation says the following (copy/pasted from above links): common node elements: - The first transition that is specified is called the default transition. - The default transition is taken when the node is left without specifying a transition. decision: - The decision node ... selects the first transition whose condition is true. - In case no condition is met, the default transition is taken. - The default transition is the first unconditional transition if there is one, or else the first conditional transition. - Transitions are considered in document order. transition: - Use these condition attributes (or child elements) in decision nodes or to calculate the available transitions on a token at run-time. condition: - A decision takes the first transition (as ordered in the processdefinition.xml file) for which the expression resolves to true. - If none of the conditions resolve to true, the default leaving transition (the first one) will be taken. There are two discrepancies that need to be addressed with this issue
- jPDL allows for guarded transitions to be specified on non-decision nodes but makes no attempt to evaluate them
- the execution of the 'default transition' is different in decision nodes as it will ignore guards if there is no default.
I suspect that the real fix is to tighten up the parsing of the jPDL so that it does not allow guarded transitions for anything other than a decision node, i.e. make the parsing enforce the intentions in the codebase. This would also provide answers to my earlier questions, namely
* why have conditional transitions if they are never evaluated during Token.signal, i.e. why allow them for non Decision nodes?
* why allow unevaluated conditional transitions to succeed with Decision but not with other nodes? (fix for JBPM-2834)
Link: Added: This issue relates to JBQA-4680 Link: Added: This issue is related to JBIDE-8956 The code and tests for this issue have been written and committed to the jbpm-3.2-soa branch. The solution that Kevin and I discussed and agreed upon is the following: - conditions on transitions are only valid if used on transitions leaving decision nodes. This means that the parser will reject (throw an exception) when parsing a process definition where a condition is used on a transition that leaves a node that is _not_ a decision. The code in question here is in the JpdlXmlParser class. The jboss tooling in eclipse has also been modified to reflect his (see JBIDE-8956). Oops, I meant the JpdlXmlReader class. (couldn't edit previous comment??) Oops, and yes, the documentation has also been made more explicit (sentences added in all relevant sections which explicitly state: only conditions on transitions in decsions, etc.) Link: Added: This issue Cloned from JBPM-3213 This needs to be verified as fixed. A condition that is not met causes an exception which restarts the whole process instance.
2011-08-09 15:04:35,797 DEBUG [org.jboss.soa.esb.services.jbpm.integration.job.ExecuteJobCommand] (WorkManager(2)-37) exception while executing ExecuteActionJob(13,Action(ESB_
org.jbpm.JbpmException: condition '#{theBody == 'aaaaaBadBodyNode'}' guarding Transition(useBadBody2) not met
at org.jbpm.graph.def.Transition.take(Transition.java:133)
at org.jbpm.graph.def.Node.leave(Node.java:450)
at org.jbpm.graph.exe.ExecutionContext.leaveNode(ExecutionContext.java:138)
at org.jbpm.graph.node.Decision.execute(Decision.java:153)
at org.jbpm.graph.def.Node.enter(Node.java:381)
....
2011-08-09 15:04:35,803 ERROR [org.jboss.soa.esb.services.jbpm.integration.job.ExecuteJobCommand] (WorkManager(2)-38) Job retry count exceeded for job 13
The last update was run with SOA 5.2 ER1 Hi Martin, Would you mind attaching the process definition that generated the exception/stack shown above? Thanks! the process definition which produced the stack-trace above can be found here: https://svn.devel.redhat.com/repos/jboss-soa/trunk/qa/tests/quickstarts/bpm_decision My suspicion is that the test above (stack trace {{M. Vecera, 09/Aug/11 9:08 AM}}) is incorrect:
{code}
org.jbpm.JbpmException: condition '#{theBody == 'aaaaaBadBodyNode'}' guarding Transition(useBadBody2) not met
at org.jbpm.graph.def.Transition.take(Transition.java:133)
at org.jbpm.graph.def.Node.leave(Node.java:450)
{code}
The stack trace indicates that the condition was on a transition leaving a _node_, which is no longer allowed.
----
After looking at the current code and the original purpose of the code -- and talking with Kevin, I decided on the following resolution:
- *Conditions are _only_ allowed on transitions leaving decisions*.
However, the current code implements a fairly complex situation -- and is also not always consistent with regards to this type of logic (conditions on transitions, a.k.a. "guarded transitions.) Therefore, the actual fix consisted of the following:
- Leave the actual implementation code (Transition, Decision, Node, etc.) as it was in order to ensure backwards compatibility.
- Change the documentation in order to _clearly_ declare that guarded transitions are _only_ allowed out of decisions.
- Modify the jPDL/jBPM 3 eclipse tool so that it also enforced this logic (JBIDE-8956).
This means that there might be some nontrivial cases in which guarded transitions _are_ allowed out of nodes that are not decisions. Changing this in the implementation would have had too many effects for existing uses.
Hi Marco, I reviewed your comment and I disagree. IMHO the process definition is OK. Guarded conditions are defined only on Decision nodes. The exception stack above (stack trace M. Vecera, 09/Aug/11 9:08 AM) is correct and will be produced during the evaluation of the "checkBody" decision node. In our test we send a message with a body string e.g. "Invalid". When this body arrives in the decision node then both guarded transitions will evaluate as false. Now as stated in the documentation: http://documentation-stage.bne.redhat.com/docs/en-US/JBoss_Enterprise_SOA_Platform/5/html/JBPM_Reference_Guide/decision.element.html "Every transition may have a guard condition. The decision node examines the leaving transitions having a condition, and selects the first transition whose condition is true. In case no condition is met, the default transition is taken. The default transition is the first unconditional transition if there is one, or else the first conditional transition. Transitions are considered in document order." Based on the above the first conditional transition must be chosen because all our conditional transitions evaluate to false and we don't define an unconditional transition. The first transition which will indeed be chosen: {code} <transition name="toScript1" to="script1"> <condition expression="#{theBody == 'execScript1'}"/> </transition> {code} The problem is that the condition of the transition will be checked once more in the Transition class and will evaluate as false. Therefor we can see the exception stack. IMHO the condition of the transition should not be checked anymore (by setting it's conditionEnforced attribute to false). Attached process definition file to the comment above. (Marek Baluch 29/Aug/11 7:23 AM) Attachment: Added: mbaluch_process.xml Apologies Marek, I don't think I was fully awake last week.. :/ Your comment is totally correct! ---- I talked to Marek about the issue and we ended up deciding on the following: - the documentation is _not_ complete or clear enough about behavior with regards to transitions/conditions/decisions. -- I'll be fixing this. - The current behaviour -- throwing an exception when _all_ guarded transitions have conditions that evaluate to _false_ -- is correct. -- Users might have processes in which decisions can only be left via 1 or more guarded transitions. -- In this case they _expect_ that one of the guarded transitions will always be viable. Throwing an exception when none of the guarded transitions are viable informs them that the process isn't correct. Added the following to the documentation for the decision jbpl element:
{quote}
Every transition may have a guard condition. The decision node examines the leaving transitions having a condition, and selects the first transition whose condition is true.
In case no condition is met, the default transition is taken. The default transition is the first unconditional transition if there is one, or else the first conditional transition. Transitions are considered in document order.
If only conditional ("guarded") transitions are available, and none of the conditions on the transitions evaluate to true, an exception will be thrown.
{quote}
Release Notes Text: Added: See my comment from 30/Aug/11 7:07 AM Release Notes Docs Status: Added: Documented as Resolved Issue Writer: Added: dlesage Release Notes Text: Removed: See my comment from 30/Aug/11 7:07 AM Added: https://issues.jboss.org/browse/SOA-2010 The software was erratic in terms of support for transitions. It has been changed so that, if no condition is met, the default transition is taken. (The default transition is the first unconditional transition if there is one, or else the first conditional transition.) If only conditional ("guarded") transitions are available, and none of the conditions on the transitions evaluate to true, an exception will be thrown. Throwing an exception when none of the guarded transitions are viable informs the user that the process is incorrect. Verified. |