Note: This bug is displayed in read-only format because the product is no longer active in Red Hat Bugzilla.

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 - standaloneAssignee: David Le Sage <dlesage>
Status: CLOSED NEXTRELEASE QA Contact:
Severity: urgent Docs Contact:
Priority: urgent    
Version: 4.3 CP04 ER1CC: 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 Flags
bpm_orchestration1.tar.bz2
none
mbaluch_process.xml none

Description Martin Vecera 2010-03-24 09:33:35 UTC
Date of First Response: 2010-04-08 01:47:49
project_key: SOA

See the linked issue.

Comment 1 Martin Vecera 2010-03-24 09:34:41 UTC
Link: Added: This issue depends JBPM-2834


Comment 2 Martin Vecera 2010-03-30 17:09:41 UTC
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.

Comment 3 Alejandro Guizar 2010-04-08 05:47:49 UTC
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.

Comment 4 Alejandro Guizar 2010-05-25 23:23:01 UTC
Link: Added: This issue is related to SOA-1979


Comment 6 Alejandro Guizar 2010-05-28 04:32:07 UTC
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?

Comment 7 Martin Vecera 2010-06-07 15:13:46 UTC
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?

Comment 8 Alejandro Guizar 2010-08-12 20:11:18 UTC
> 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.

Comment 9 Martin Vecera 2011-01-27 12:58:27 UTC
The corresponding issue is already resolved for some time. When do we expect this to be consumed by SOA-P?

Comment 10 Martin Vecera 2011-01-31 14:12:56 UTC
The issue is still present. Attached a reproducer quickstart. 

Comment 11 Martin Vecera 2011-01-31 14:12:56 UTC
Attachment: Added: bpm_orchestration1.tar.bz2


Comment 12 Martin Vecera 2011-01-31 14:14:07 UTC
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)


Comment 13 Kevin Conner 2011-01-31 15:44:51 UTC
Not sure how you come to the conclusion that this is ESB, can you elaborate?

Comment 14 John Graham 2011-01-31 15:50:44 UTC
Link: Added: This issue Cloned to SOA-2858


Comment 15 Kevin Conner 2011-01-31 16:34:12 UTC
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.

Comment 16 Alejandro Guizar 2011-01-31 19:09:06 UTC
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.

Comment 17 Kevin Conner 2011-02-01 09:42:40 UTC
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?

Comment 18 Alejandro Guizar 2011-02-01 23:21:21 UTC
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).

Comment 19 Kevin Conner 2011-02-02 12:08:58 UTC
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?

Comment 20 Alejandro Guizar 2011-02-03 12:01:59 UTC
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.

Comment 21 Dana Mison 2011-02-25 01:45:56 UTC
Labels: Removed: rn-done-resolved 


Comment 22 Anne-Louise Tangring 2011-03-08 17:02:58 UTC
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.

Comment 23 (please assign to mrietvel@redhat.com) 2011-05-11 12:27:10 UTC
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."



Comment 24 (please assign to mrietvel@redhat.com) 2011-05-11 14:19:55 UTC
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.



Comment 25 Kevin Conner 2011-05-12 08:50:35 UTC
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)


Comment 26 Martin Vecera 2011-05-12 09:40:30 UTC
Link: Added: This issue relates to JBQA-4680


Comment 27 (please assign to mrietvel@redhat.com) 2011-05-19 07:51:15 UTC
Link: Added: This issue is related to JBIDE-8956


Comment 28 (please assign to mrietvel@redhat.com) 2011-05-20 12:55:10 UTC
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). 

Comment 29 (please assign to mrietvel@redhat.com) 2011-05-20 13:04:34 UTC
Oops, I meant the JpdlXmlReader class. (couldn't edit previous comment??)

Comment 30 (please assign to mrietvel@redhat.com) 2011-05-20 13:05:58 UTC
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.)

Comment 31 (please assign to mrietvel@redhat.com) 2011-05-20 14:30:31 UTC
Link: Added: This issue Cloned from JBPM-3213


Comment 32 Anne-Louise Tangring 2011-07-11 20:11:17 UTC
This needs to be verified as fixed.

Comment 33 Martin Vecera 2011-08-09 13:08:35 UTC
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

Comment 34 Martin Vecera 2011-08-09 13:09:24 UTC
The last update was run with SOA 5.2 ER1

Comment 35 (please assign to mrietvel@redhat.com) 2011-08-09 15:08:31 UTC
Hi Martin, 

Would you mind attaching the process definition that generated the exception/stack shown above? 

Thanks!

Comment 36 Marek Baluch 2011-08-22 14:09:27 UTC
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

Comment 37 (please assign to mrietvel@redhat.com) 2011-08-25 11:31:47 UTC
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. 

Comment 38 Marek Baluch 2011-08-29 11:23:56 UTC
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).

Comment 39 Marek Baluch 2011-08-29 11:24:47 UTC
Attached process definition file to the comment above. (Marek Baluch 29/Aug/11 7:23 AM)

Comment 40 Marek Baluch 2011-08-29 11:24:47 UTC
Attachment: Added: mbaluch_process.xml


Comment 41 (please assign to mrietvel@redhat.com) 2011-08-30 11:07:51 UTC
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. 


Comment 42 (please assign to mrietvel@redhat.com) 2011-08-30 13:14:39 UTC
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}

Comment 43 (please assign to mrietvel@redhat.com) 2011-09-26 14:57:41 UTC
Release Notes Text: Added: See my comment from 30/Aug/11 7:07 AM


Comment 44 David Le Sage 2011-09-27 22:19:34 UTC
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.


Comment 45 Martin Vecera 2011-11-15 08:08:44 UTC
Verified.