This seems like a good additional feature. We have currently indeed no direct support for guarded transitions (I assume this is the thing you want). So if you would like this capability, I suggest you add this feature request in JIRA and make a reference to this forum thread.
In the meantime, you can already emulate this behaviour with the use of process variables. You can maintain a list of strings representing the enabled transitions. This list can be manipulated and checked by action handlers on node-enter and node-leave events, when a timer expires, etc...
+1 on this.
This feature is exactly what I'd need in the project I'm currently working on.
Most preferably something like this:
- conditions (implemented by Java code and or BSH scripts) that can be dynamically added/removed to transitions both in code and in the proc. def.
- a getter that returns true if all the conditions are met on a given transition
Keep in mind that this introduces a kind of fuzzy state (or tri-state if you like). e.g. The task is completed, the user has selected a transition, nothing can be performed anymore on that task/token but it still is in that state. So if you visualize it, some attention should be payed to this special case....!!!
Ronald, I agree that the interaction with tasks is a key place where care needs to be taken, and this was part of my motivation for raising the issue; if isSignalling is true for a task, but the nominated transition is not valid (either it is disabled or its precondition is false), then should the task end but not signal, or should these conditions be checked before the task_end even is fired and the end call be aborted. I'm inclined to have teh task end, but not signal since I think the right place to insert such changes is in Token.signal
There's also the issue of how to handle this 'failure' - is throwing an exception sufficient/desirable and/or should there be associated events that are fired.
I once raised the idea that every nodetype should be "conditional" instead of having a special node for that purpose. If you implement a conditionhandler, this could be used when signal() is called (as this tries to get a default transition, which is now always the first transition).
See http://www.jboss.com/index.html?module=bb&op=viewtopic&t=70238 (and forget about the aop bit :-))
In a recent consulting, I found the need to attach conditions to transitions going out of task nodes. A sample scenario is easy to imagine: you buy an air ticket and the airline gives you the option to cancel it until some days before the plane departs. When this line is crossed, all you can do is check in. So you would attach a condition to the cancel transition that checks whether the current date is after the cancel deadline.
In order for this to be useful, two premises must hold:
a) The UI should be aware of conditions and don't even show disabled transitions. Getting an error message after taking a given transition just doesn't make sense to users.
b) Ronald's point: at least one transition must stand alive. A token placed in a node with all outgoing transitions transitions is effectively in deadlock, which implies that the process is badly designed.
I think we should allow conditions in all transitions, but jBPM should think of them only as assertions. Just like in JDK 1.4+, the developer should be able to turn them on (throwing an exception) and off (silently ignoring, possibly with a log entry).
The application using jBPM should be responsible for giving truly meaningful semantics to conditioned transitions, as in the scenario portrayed above.
i created a feature request for this http://www.jboss.com/index.html?module=bb&op=viewtopic&p=3910206#3910206
i don't think that validation should have the focus here (of course it must be possible to have jbpm throw an exception when an unavailable transition is being taken)
the focus should be on the implementation of the methods:
So that the user interface knows how to avoid offering buttons that the user is not allowed to push.
should we introduce 2 levels token and task instance ?
At the consultancy I've just finished they've been using the CPAN Perl workflow framework (see http://search.cpan.org/~cwinters/Workflow-0.17/lib/Workflow.pm) which, while very simple, implements this well. In fact, it has two parts, conditions and validators. Conditions are used to determine whether a transition is available, and validators are used to check whether the inputs supplied to the transition are valid. In the context of JBPM, I think that conditions are the important aspect.
Having each of Token.getAvailableTransitions()/TaskInstance.getAvailableTransitions() calling the transition guards with an appropriate context seems right.
However I disagree with Alex that there should always be at least one available transition since the guards may, for example, be time-dependent or otherwise have their status depend on external state. Naturally a UI might need to periodically call getAvailableTransitions() to check whether there had been a change. Taking his example, you may not be able to cancel the ticket less than 24 hrs before departure, but again you may not be able to check in great than 12 hrs before departure, which would leave a 12 hr window where the process is effectively stalled, but not actually deadlocked.
If you ordered and everything is processed, wouldn't you be in another state where you have just one transition 'cancel'?
Part of the functionality descibed here can already be achieved. I introduced a real state (kind of a milestone) which is explicitly in the model. There is a timer there which checks the value of a certain viariable. If it is not there it repeats this until a certain date/time is reached. One optimization could be that you can attach a kind of listener to a variable that triggers this instead of polling. This makes sure the process is in an explicit state. The transition is taken but waiting for an event to occur. Personally, I've struggled a lot with this, should we create more and more complex nodes or stay at a certain level of simplicity. My gut feeling says the latter is better.
But please... prove me wrong ;-)
How does TaskInstance.getAvailableTransitions() differ from Token.getAvailableTransitions()? If I remember correctly, if the task instance is allowed to signal, then its transitions correspond exactly to those of the token. Otherwise, none is available. Broadly speaking, would that be the behavior of TaskInstance.getAvailableTransitions(), or am I missing something?
I imagine the 12-hr window corresponds to a desperate user that is shocked to find there's nothing he can do, which still feels like a badly designed process to me. I agree that there might be situations where this is unavoidable, tough.
This leads to the conclusion that a deadlocked process is undistinguishable from a temporarily stalled one, under the light of a pessimistic analysis. Well, we still have unit tests.
Is what you modeled a sort of state in-between nodes, similar to a place (sometimes confusingly referred to as condition) in a Petri net?
Maybe the guard is on status of the taskinstance itself. It could be possible that taskinstances may not end unless a special guard condition is fullfilled.
There is a little statemachine behind taskinstance itself, and maybe you want to put guards on various transitions these states as well (e.g. start(), end())... I know there is a fine line between business rules (the validation) and the tasks, but it would be interesting that ending a task could be prevented (or at least check if it can be ended).
I agree w/ lawless. You can't force a task node to have at least one transition be available, as this does not translate well to the real world.
It would be up to the programmer to ensure that such a possibility is handled correctly -- lawless mentioned periodic polling of the transition conditions, but, also, using proper merge conditions where parallel paths are involved.