I have had my share of LazyInitializationExceptions in developing my web application. The issue stems from loading the objects in one JbpmContext and then attempting to do something with them in another JbpmContext. For example, if you make an RMI call to retrieve all of the TaskInstances for a given actorId, and then make another RMI call to end a TaskInstance along a specified transition, the second call will fail with a LazyInitializationException because the JbpmContext (and, more importantly, the underlying Hibernate Session) associated with the TaskInstance proxy was closed.
Still trying to iron out the best way to deal with this (see my earlier post on Long Transactions). I prefer calling JbpmContext.getSession().lock() on my objects prior to accessing their lazy properties, but the lock operation does not cascade to all of the associations. That might still be okay for you, depending on what it is you are doing. Another option is JbpmContext.getSession().refresh(), but that is dangerous as it does not perform a version check (you might get a lost update).
Are you opening and closing the JbpmContext in each RMI call? What kinds of operations are you exposing? What kinds of arguments are you passing back and forth?
I think we are exactly on the same page ;-)
I'm doing the RMI through a Stateless EJB bean at the moment. I took this approach versus Stateful as I may want to expose these as webservices at some point in the future.
As far as LazyInitializationExceptions, what you said regarding calling a transistion without the TaskInstance is exactly what I'm running into.
As of this writing, I'm making a serializable DTO to capture all that nessary information first before sending it over RMI to avoid this exception. I'm still determining what I may need, but so far this is the template I'm working on:
long id = tasks.get(0).getId(); String name = tasks.get(0).getName(); String desc = tasks.get(0).getDescription(); java.util.Date duedate = tasks.get(0).getDueDate(); Date startdate = tasks.get(0).getStart(); int priority = tasks.get(0).getPriority(); String assignedto = tasks.get(0).getActorId(); String processdef = tasks.get(0).getToken().getProcessInstance().getProcessDefinition().getName();
The RMI api is client-centric, as in the person logging in will be the actor. A seperate 'manager' api will probably be used, but for now I just need something to work for a user to handle the human-intervention task nodes.
The methods I'm looking to expose include:
*Logged in user's awaiting tasks.
*Logged in user's pool(s) and the pool(s) awaiting tasks (pull assignment).
*Replicate the webapp's taskFormParameter and extend it for working on the actual task (I saw someone working on an XForms implementation of extending, although I haven't seen if it's open source -- my use case is for Eclipse RCP but will have no eclipsisms in this DTO). Use the taskId from the awaiting tasks list to get the 'taskFormParameter'.
*Submitting the completed taskFormParameter to signal the next step in the workflow.
As you can see, I'm not trying to over-complicate anything ;-)
That ought to work, and when defining an API it's a good idea to insulate yourself from changes to the jBPM object model, which is what the DTO accomplishes. I assume that you will load the TaskInstance using the "id" property of the DTO, set the variables, and then call end() to transition the task? One thing to watch out for:
1. User A loads the TaskInstance and gets a DTO with id=1 and version=1
2. User B loads the same TaskInstance and gets a DTO with id=1 and version=1
3. User B alters the DTO and makes a call to an update method. The TaskInstance is re-loaded (version=1), modified, and saved. The version is now 2.
4. User A alters the DTO and makes a call to an update method. The TaskInstance is re-loaded (version=2), modified, and saved. The version is now 3, and User B's changes may have been overwritten.
But I don't know of a better solution than yours. The only thing I would recommend is storing the task instance version (if that property exists/is exposed) so that you can do an explicit manual version check before updating. Then again, lost updates may not be an issue if all you are doing is adding associated objects (comments, variables, etc.). The lost update problem is an issue only if two users are modifying the same data (such as the value of the same process instance variable) or if one user adds a variable and another tries to remove the same variable. And if you are transitioning at the end of every update then you should get an error on the second update anyway, which would roll back User A's changes.
I am just getting started with trying to connect to JBPM with RMI,
can you get me a easy sample of your code for a basic connection.
Our first task is to remotely start a task, but mainly I need the actual RMI code, as its not astrong point of mine (yet)