cancel
Showing results for 
Search instead for 
Did you mean: 

Activiti + JSF

patobe
Champ in-the-making
Champ in-the-making
Is it possible to use JSF-based forms with the Activiti Engine?
6 REPLIES 6

patobe
Champ in-the-making
Champ in-the-making
I've done some testing on this subject by integrated Activiti with a JSF framework (Seam 2.2.1 CR1) and the vacation request definition. I wrote some  Seam components for deploying definitions, starting processes and working with tasks. The integration works and it is possible to deploy new definitions, start processes, view tasks etc. But it fails when working with tasks.

When a new process is started the task form can be rendered and submitted without any problem (with some custome code I store the submitted request parameters as process variables).

But when I try to load the task form for the first task in the vacation process I get an exception  … As far as I understand it is because the vacation process uses html forms with the $paramName notation and this can't be resolved by JSF.

Therefore I tried to replaced the form in the first task of the vacation request with a JSF based form with process variables reference like this #{variablesMap['employeeName']}. But when I get the form (taskService.getTaskForm(someTaskId)) I get a new exception "javax.el.PropertyNotFoundException: Cannot find property variablesMap".

After digging around in the Activiti source code I found that task forms are evaluated (parsed?) by org.activiti.engine.impl.scripting.ScriptingEngines. My question is if this parsing of forms is putting a limitation on what form types can be used by tasks?

My impression was that the Activity explorer required plain html forms but another "explorer" implementation could use just about any form type as long as the form request parameters are taken care of and stored as process variables and vice versa when displaying forms with stored process variables.

So my question remains: What kind of form types can be used when embedding the Activiti Engine (not using the Activity Explorer).

tombaeyens
Champ in-the-making
Champ in-the-making
Here's a section that I just added on trunk to the Userguide.  It will be in beta 2 release of October 1:

External rendering of forms

Above we showed the build-in task form rendering. But the API also allows for you to perform your own task form rendering outside of the Activiti Engine. These steps explain the hooks that you can use to render your task forms yourself.

You can just stick any form template resource inside the business archives that you deploy (in case you want to store them versioned with the process). It will be available as a resource in the deployment. You can use the String ProcessDefinition.getDeploymentId() and InputStream RepositoryService.getResourceAsStream(String deploymentId, String resourceName); to obtain the file that you included in the deployments. That could be your form template definition file.

Btw, you can use this capability of accessing the deployment resources beyond task forms for any other purposes as well.

The attribute <userTask activiti:form="…" is exposed by the API through String Task.getFormResourceKey(). You could for instance store a generic key in the form attribute and apply an algorithm or transformation to get to the actual template that needs to be used. This might be handy when you want to render different forms for different UI technologies like e.g. one form for usage in a web app of normal screen size, one form for mobile phone's small screens and maybe even a template for a IM form or an email form.

We would really appreciate those SEAM integration components.  Do you think you could contribute the code for that?  And/or a wiki page describing how you did it?

I know also Mimacom is working on JSF integration with Activiti. 
Christian, Micha, can you compare what you are cooking to what patobe did?

cstettler
Champ in-the-making
Champ in-the-making
At mimacom, we did a spike for an integration of the Activiti engine into a JSF-based Web application. We implemented the EL data binding between JSF and the process variables and connected the user tasks to JSF views based on the form resource key.

With help of the data binding, it is possible to refer to and update any process variable via EL used in the JSF view (e.g. #{process.user.name} would lookup the process variable value stored under "user" in the process variables map and then reads (or also writes, depending on the UI form element) the "title" property value).

For the view integration of the user tasks forms, we use the form resource key defined in the process model (using activit:form) to link to a JSF view, i.e. interpreting the form resource key as a view id that is mapped to a JSF view based on the standard JSF navigation rules.

The engine itself is integrated into the JSF application using Spring, i.e. using the ProcessEngineFactoryBean.

We basically faced two major issues: one was the EL API version conflict between Activiti and the JSF environment, the other one was related to the fact that process variables are always directly read from/written to the database when accessing them via the RuntimeService, so one gets a fresh copy of the process variables for every access. We solved this by introducing a kind of window-scoped process context that reads and keeps the process variables for the time a specific user task is worked on, and synces the process variables with the ones stored by the RuntimeService once the task gets completed. The custom EL resolver then works on the process variables stored in the process context. Once we have something like a "first level cache" for process variables inside a transaction, this custom process context will probably be obsolete.

I hope this sheds some light on the JSF integration possibilities.

Regards,
Christian

patobe
Champ in-the-making
Champ in-the-making
Thanks Tom for the info. I can certainly provide you with the Seam components and info about the integration as soon as I'm done (some more testing, clean-up and documentation).

Christian, can you share any of the code you have regarding the EL data binding between JSF and the process variables?  The way I implemented it in Seam is to outject the process variable map in a conversation context together with a custom activiti tag for displaying the task form. I think your approach with the El binding might be a more straight forward solution than mine.  It would be very interesting to look at your solution if possible.

Regards
/Patrick

cstettler
Champ in-the-making
Champ in-the-making
@Patrick: sorry, I'm not allowed to post the actual code here, but I can describe the approach a bit more in detail so you should be able to follow the same way on your own (assuming you like the approach ;-))

- we implemented a custom EL resolver that is able to resolve expressions like "process.foo" against the process variables ("process" is like a reserved word referring to the process variables map, "foo" is referring to the key in the process variables map)
- the custom EL resolver is installed when bootstrapping the JSF application (using the "el-resolver" configuration option in the faces-config.xml
- whenever a user starts working on a task, we read the current process variables into a window-scope context object (this is required as Activit returns a new copy of the process variable value for every lookup via the RuntimeService) (btw: the window-scope is actually realized with Spring an the Edoras WebUtils window scope implementation, which should make it into Spring 3.1)
- when the corresponding task form is displayed (it is a JSF view in our case), the custom EL resolver uses the mentioned window-scope context object to read the process variables from and also to write it back (e.g. if you use an expression like #{process.order.amount} on an JSF outputText field, the value entered by the user will be stored to the "amount" property of the bean which is stored under the name "order" in the process variables)
- once the user completes the task, the process variables from the window-scoped context are written back to the process instance using the RuntimeService

The same EL resolver could also be configured for the Activiti engine itself, which would allow similar expressions e.g. in resource assignment expression. We are also thinking about providing meta information on the process execution (e.g. which assignee completed which task) via the same mechanism.

I hope this helps. If you need more information, just let me know.

Regards,
Christian

patobe
Champ in-the-making
Champ in-the-making
Thank you for the info Christian! I will try your approach and see how it works.

Regards
/Patrick