Showing posts with label j2ee. Show all posts
Showing posts with label j2ee. Show all posts

Friday, October 26, 2007

jboss seam and jbpm async nodes

In a jboss seam project i wanted to use async nodes in a jbpm workflow. You can add "async=true" to any node in you jbpm process definition. This makes the workflow continue in the background so your user interface does not have to wait for the complete workflow to complete.

I accomplished this by starting the JbpmThreadServlet by adding in the web.xml:


<!-- Jpbpm Thread listener which will do async continuations & Timer -->

<servlet>
<servlet-name>JbpmThreadsServlet</servlet-name>
<servlet-class>org.jbpm.web.JbpmThreadsServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>JbpmThreadsServlet</servlet-name>
<url-pattern>/jbpmthreads</url-pattern>
</servlet-mapping>



When your web application starts, jbpm will spawn off a thread that will continue your workflow. This thread is also being used for sending out email notifications of task nodes.

A problem that rises here is that your action handlers don't have access to the seam contexts. To solve this problem I made a abstract action handler which will startup the seam lifecycle from a such an actionHandler if it does not exist. This code comes from the seam 2.0.0 framework which actually support this. I haven't tried it out still.

The code for the actionHandler is:



import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.contexts.Lifecycle;
import org.jboss.seam.core.BusinessProcess;
import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.taskmgmt.exe.TaskInstance;

public abstract class SeamContextualActionHandler implements ActionHandler {

abstract public void executeInSeam(ExecutionContext context)
throws Exception;

public void execute(final ExecutionContext context) throws Exception {

try {
if (Contexts.isEventContextActive()
|| Contexts.isApplicationContextActive()) //not sure about the second bit (only needed at init time!)
{

} else {
Lifecycle.beginCall();
try {
initProcessAndTask(context);
executeInSeam(context);
} finally {
Lifecycle.endCall();
}
}
} catch (RuntimeException re) {
throw re;
} catch (Exception e) {
throw new RuntimeException(e);
}
}

private static void initProcessAndTask(ExecutionContext context) {
BusinessProcess businessProcess = BusinessProcess.instance();
businessProcess.setProcessId(context.getProcessInstance().getId());
TaskInstance taskInstance = context.getTaskInstance();
if (taskInstance != null) {
businessProcess.setTaskId(taskInstance.getId());
}
}

}





Your actionHandlers should extend this class and implement the executeInSeam() method instead of the execute method from the ActionHandler interface.

Friday, October 19, 2007

Jboss Seam Jaas authentication and jbpm Actors

The Identity component in Seam is a pretty handy thing. You can authenticate users by providing your own Authentication method or you can use JAAS. At my company we prefer JAAS. However there is a catch. When you also use jbpm, you should be able to populate the Actor component. But because we use JAAS there is no direct way to execute some custom code.

Fortunatly the seam developers provide a event model. Several components can emit events which our code can Listen on. It is very simple. You can simply add the @Observer annotation to a method with the correct event.

Now for populating the Actor component, we are going to write a Observer that listens to the "org.jboss.seam.postAuthenticate" event. You can read about these events in the seam documentation.

The next problem is that the JAAS API completely sucks. It is easy to find out if the users is in a specific role, but finding all the roles a user has is not possible. Fortunatly i found some code on the seam forums from a clever guy that allows me to do it. The drawback is that you make your code container specific. But for the moment being it serves me well.

So my authentication handler looks like this now:


import java.util.Enumeration;
import java.util.Iterator;

import javax.security.auth.Subject;

import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Observer;
import org.jboss.seam.core.Actor;
import org.jboss.seam.log.Log;
import org.jboss.seam.security.Identity;
import org.jboss.security.SimpleGroup;
import org.jboss.security.SimplePrincipal;

@Name("postAuthenticationHandler")
public class PostAuthenticationHandler {

@Logger
Log log;

@In
Identity identity;

@In
Actor actor;

@SuppressWarnings("unchecked")
@Observer("org.jboss.seam.postAuthenticate")
public void doPostAuthenticate() {
log.info("Entering doPostAuthenticate...");
actor.setId(identity.getUsername());
Subject subject = identity.getSubject();

Iterator principleItr = subject.getPrincipals().iterator();
while (principleItr.hasNext()) {
Object principle = principleItr.next();
if (principle instanceof SimpleGroup) {
SimpleGroup simpleGroup = (SimpleGroup) principle;
Enumeration simpleGroupMembers = simpleGroup.members();
while (simpleGroupMembers.hasMoreElements()) {
Object o = simpleGroupMembers.nextElement();
SimplePrincipal aPrincipal = (SimplePrincipal) o;
log.info ("User " + identity.getUsername() + " is a member of group " + aPrincipal.getName());
actor.getGroupActorIds().add(aPrincipal.getName());
}
}
}
}
}


So first we inject the Actor/Identity components. Also notice the @Observer annotation which causes this method to be invoked when the postAuthenticate event is raised.

In the method itself we will get the JAAS subject from the identity component. This Subject class is some kind of container which contains all authentication specific attributes for this users called Principals. Now we can iterate over these Principals and extract the roles from it and insert them into the Actor component. As you see we cast the principle to a SimpleGroup which is a jboss specific implementation. So deploying this code on something other than jboss or even on another version of jboss than version 4.0.5.GA will break this code. But i found no other way to get to this information otherwise.

Tuesday, October 2, 2007

jboss seam and jbpm in a message driven bean hell

Hi all,


Last friday i was struggling with the bijection stuff of jboss seam. Bijection allows you to inject and outject variables to the several contexts jboss seam offers.

What i am trying to do is to create a jbpm process from a message driven bean and 'outject' some variables to the business context. I want to inject these same variables in a action handler when the business process enters a node. But things go wrong here. Actually things go already wrong when creating the jbpm process. I found a bugreport on the jboss bug tracking system that creating a jbpm process within a message driven bean does not work, so i suspect saving these variables to it has also something to do with it.

My code is very simple:

@CreateProcess(definition="inkless")
public void onMessage(Message m){
//some Message Parsing goes here
}
But i get lots of transaction related exeptions here. I found the following jira issue:
http://jira.jboss.org/jira/browse/JBSEAM-798 and related forum thread at http://www.jboss.com/index.html?module=bb&op=viewtopic&t=101047


I think my next step will be to check out jboss seam 2.0.0 CR1.

Wednesday, September 12, 2007

Could not enlist in transaction on entering meta-aware object!

This errormessage provided by the Jboss j2ee server gave me a major headance. In a project we are using 2 datasources:

  • an oracle datasource being used by iBatis DAO layer
  • a postgresql datasource being used by JPA DAO layer
After invoking both DAO layers I got this nice SystemException by the JTA transactionmanager.

Investigation showed me ( a few hours later ) that the oracle datasource is not XA by default. You have to configure it to use the XADataSource. You can find a example in the jboss distribution in docs/examples/jca/oracle-xa-ds.xml