Hi Harald.
Just a quick answer as I am in a hurry. By the way: Did you already think of maybe attending an training? I think a couple of things could get clearer there (see www.camunda.com/fox/training/camunda-bpm-basics/).
However - quick answers inline - hope that helps.
-----Ursprüngliche Nachricht-----
Von: camunda-...@googlegroups.com [mailto:camunda-...@googlegroups.com] Im Auftrag von Harald Wellmann
Gesendet: Donnerstag, 19. September 2013 17:54
An: camunda-...@googlegroups.com
Betreff: Fwd: [camunda-bpm-users] AW: User Tasks and Forms with JSF and CDI
Hi Bernd,
thanks for the JSF Task Form Guide, that answers most of my JSF related questions, but I'm still unsure about the CDI part.
I've been looking at bestellprozess-java-ee6 demo before, but I don't find it very helpful. I can't relate the process model to what I see in the UI; when I click a button, I don't see what I expect, and I don't know if my expectation is wrong, or my setup or the demo itself.
Besides, the @StartProcess and @CompleteTask annotations I was interested in don't occur in this demo.
I actually think it is more understandable code not using these annotations but the CDI beans directly.
Just to give you an idea how things that may seem trivial to you are a massive obstacle to new users, let's look at this expression:
#{camunda.taskForm.startTask(taskId, callbackUrl)}
1) I expect to find a bean with EL name "camunda".
Wrong! There is no such bean. The TaskForm bean is named "camunda.taskForm". I didn't know that EL names are allowed to contain dots, and I would have expected an EL exception.
Now you know :-)
2) I expect startTask() to start a task.
Wrong. By enabling the global CDI process event listener and logging all events, I can see that the user task is started when the predecessor task is completed. TaskForm.startTask() has no Javadoc, it delegates to BusinessProcess.startTask(), and somewhere in the Javadoc of that class, I see "@return the resumed task", which appears to be more accurate: An executing task is resumed by attaching the current conversation to it. If the task weren't started, we couldn't attach to it (and we wouldn't even have a taskId, I presume).
startTask starts a conversation and binds the task instance to it (to read/change process variables in that conversation - maybe in a wizzard with multiple pages) before the task is completed and this changes are written to the process engine. See http://stage.docs.camunda.org/real-life/how-to/#user-interface-jsf-task-forms-how-does-this-work
3) I expect taskId to be the Task ID.
Wrong!!! The User Task has an id attribute (<userTask id="kunde-umberaten" ...>), corresponding to the ID property in the Modeller UI. So anyone would expect Task.getId() to return this ID, and the same goes for all sorts of TaskFoo.doSomethingWithId() methods (e.g. TaskQuery.taskId()). It took me several hours of debugging to find out that the XML "id" correspond to "key" on the Java API, and that "id" on the Java API is an autogenerated UUID. Same problem with Process ID vs. Key.
Now this is utterly and fatally confusing. I don't think I want to know how this name clash came to be, and I fear it's too late to be changed, but then please do include a big red letter warning in the User Guide to spare other newbies discomfort and frustration....
the id in the BPMN XML is the "task key". the task id is the primary key of the task instance.
4) I'm not sure what a callbackUrl is supposed to be in this context.
If you mean a redirect URL, then why not call it "redirectUrl"? But in JSF, wouldn't it be more natural to use an outcome here, to hook into JSF navigation?
It simply redirects - true. Maybe redirectUrl might have been better.
In my own demo, I'd been trying hard to "start" a task from my controller bean by businessProcess.startTask("MyUserTask"), until I realized that I really needed an interface like startTaskByKey() which does not exist.
So I replaced BusinessProcess by ExtendedBusinessProcess, adding the missing API:
public class ExtendedBusinessProcess {
@Inject
private BusinessProcess process;
@Inject
private TaskService taskService;
public void attachToTaskByDefinitionKey(String taskName) {
String instanceId = process.getProcessInstanceId();
Task task =
taskService.createTaskQuery().processInstanceId(instanceId).taskDefinitionKey(taskName).singleResult();
process.setTask(task);
process.startTask(task.getId());
}
}
My demo is working now, but I'm still unsure in which layer to start/resume or complete user tasks:
- in the JSF view
- in the (JSF) controller bean
- in the service bean/EJB
You seem to favour the JSF view, I currently do it in the controller, and I feel it really should be in the service bean. Imagine an application with alternative UIs, e.g. a JSF web UI and an Eclipse RCP UI. All process logic is business logic and should be located in the service layer and not in the UI layer(s), or what do you think?
Controller is fine from my feeling. The view is more ashortcut to not be forced to have any controller for simple forms. If you have a controller - best do it there.
If you move logic to a service bean I would not use BusinessProcess - as I see conversations part of the UI - not the Service/Business Logic Layer.
Cheers,
Hi Harald,
thanks for taking the time and pointing out where you had trouble understanding how the CDI / JSF integration works. This kind of feedback can really help us improving things.
Cheers,
Daniel Meyer
Project Lead