Integrating CDI with Vorpal and the Cuckoo Bird Effect


Nest with Cuckoo bird’s egg

I first came across the insidious practices of the Cuckoo bird in Clifford Stoll’s book The Cuckoo’s Egg. The Cuckoo bird is a brood parasite. They never build any nests of their own; so when its time for them to lay their eggs, they lay their eggs in the nest of other species (of bird) whose egg resembles that of their own. Unawares, the “foster” bird will feed the Cuckoo’s nestling when they hatch. In the book Cuckoo’s Egg, a hacker used a similar method to trick the host computer to give him root access through movemail.

Fascinating stuff you say but what does this piece of trivia have to do with Vorpal? Vorpal uses a similar technique, though for benign reasons, to coax Glassfish application server into giving it what it wants – JavaEE resources (object lifecycle management, JPA, transaction, Stateless Session Bean, validation, etc). Vorpal achieve this firstly by masquerading as a Web Application and secondly by integrating with CDI. The first allows a Vorpal application to be deployed into Glassfish and the second allowed the Vorpal applications to consume container resources.

In this blog, I will show you how you can use Vorpal with CDI. Note that the Vorpal programming model that I describe here is still valid. CDI supports builds on this. This blog is not a CDI tutorial. I’ll just be listing what are the features that are supported by Vorpal. Those of you who are not familiar with CDI are encouraged to go through this tutorial before continuing.

Message Handler Lifecycle

When you are using Vorpal with CDI, all Vorpal message handler class must be annotated with either @RequestScoped or @ApplicationScoped. The semantics of these 2 annotations are similar to those in a Java EE 6 application. Vorpal also supports a third lifecycle annotation call @com.kenai.jabberwocky.framework.ConversationScoped. This annotation is conceptually similar to @javax.enterprise.context.ConversationScoped but supports XMPP conversation semantics. As conversation support is quite involved, I’ll explain this in my next blog. Vorpal does not support @SessionScoped.

Once you have annotated with any one of the 3 annotations listed, you can also use lifecycle methods like @PostConstruct and @PreDestroy.

Here is a simple example of an object using CDI

@RequestScoped @Message
@Body(“Hello {*name}”)
public class HandleMessage {
   private final String name;
   @PostConstruct void init() {
      //Do something
   }
}

As in the example above, the HandleMessage class is a request scoped object meaning that a new instance of HandleMessage will be created when there is a match and HandleMessage is selected for firing.

Note the asterisk before name in @Bind. This is a new matching feature and it denotes none or more. If you specify “Hello {name}“, then a match will include a String literal following “Hello ” in the body like “Hello Fred Flintstone“. However with an asterisk, @Body will  match “Hello ” as well. See my previous blog for matching and firing.

Resource Injection

Vorpal supports full CDI resource injection. Injection points include

Furthermore all Vorpal annotations, eg. @Body, @Message, @XmlElement, @Bind, etc. are CDI qualifiers if they are use on fields and method parameters. If you are annotating members and methods, then the @Inject annotation is optional. There are also some predefined injection types like ComponentManager, Conversation, ThreadID and ConversationContext.

@RequestScoped @Message
@Body(“Hello {*name}”)
public class HandleMessage {
   private final String name;
   @From private JID from;
   @Inject @To private JID to; //@Inject is optional
   @Inject ComponentManager mgr; //Predefined type injection
   //Constructor injection
   @Inject public HandleMessage(@Bind(“name”)String n) {
      name = ((null == n) || (n.trim().length() <= 0))? “Fred”: n;
   }
   @PostConstruct void init() {
      //Do something
   }
   //Method injection
   @Inject void setSubject(@Subject String subject) {
      —
}

From the example above

  • Notice the member injection. Since all Vorpal annotations are CDI qualifiers, the @Inject annotation is optional
  • Vorpal defines a set of injectable objects which I’ve listed above. You can inject any of these types without qualifiers; as there are no qualifiers, you have to annotate the member with @Inject
  • You can injected any valid CDI resources into constructor, member and method
  • setSubject() is an example of method injection

Capture and @Named

Vorpal works by matching incoming XMPP messages against message handlers. Captures are bound to members and parameters by the @Bind annotation. See example above. If you are using Vorpal with CDI, you can continue to use @Bind to bind capture values; if however you are a CDI purist, you can use @Named instead. Every capture export themselves as @Named. These @Named objects have a slightly different semantics to the regular JavaEE @Named objects in the following ways:

  1. Capture @Named are local to the class – viz. they are not visible outside of the class
  2. Capture @Named are bound to the ‘nearest’ capture – viz. members and methods injection capture @Named are bound to class level capture and a method parameters capture @Named are bound that method capture

Here is a simple example to illustrate the point

@RequestScoped @Message
@Body(“Hello {*name}”) @From(“{from}@jabber.org”)
public class HandleMessage {
   private final String name;
   //Member level capture, bound to class
   //’name’ is only visible in HandeMessage class
   @Inject @Named(“name“) private String name;
  
   //Method injection – also bound to class
   @Inject void setFrom(@Named(“from“) String from) {
      —
   //name is bound to capture in @To
   @To(“{name}@{__domain__}”)
   public String handleMessage(@Named(“name“)String to) {
      …
   //name is bound to this method’s @To
   @To(“info-{name}@{__domain__}”) @Subject(“{subject}”)
   public String handleInfo(@Named(“name“) String name
         , @Named(“subject“) String subject) {
      …
}

Firstly notice that the @Named member (String name) and the @Named method (setFrom) parameter injection are bound to @Body and @From from the class level. Furthermore @Named are bound to their nearest capture. So @Named(“name”) in handleMessage method will be bound to the @To annotation on that method and not to @Body. Similarly for handleInfo, its @Named(“name”) will be bound to its @To annotation. If my explanation is a little confusing, you can see the various @Named association above from their colours. Another simple way of deciding which capture @Named is bound to which capture is to place your finger on the @Name, eg. on @Named(“name”) on handleInfo, and move up. The first capture with the same name that you encounter will be bound to that @Named. In this case, the it will be @To(“info-{name}@{__domain__}”).

One other point is that message handler methods are not annotated with @Inject. In the above example handleMessage and handleInfo are message handler methods because they do not have @Inject. If these methods were annotated with @Inject, then they would be invoked when HandleMessage is instantiated.

JavaEE 6 Resources

Once a message handler are under CDI control, the message handler can access all of the JavaEE’s platform resources via injection. I’ll not go into defining JavaEE resources like JPA, Stateless Session Bean, etc. The following code shows how you use JPA from within a message handler.

@RequestScoped @Message
@Body(“Hello {*name}”) @From(“{from}@jabber.org”)
public class HandleMessage {
   //Injecting EntityManager
   @PesistenceContext EntityManager em;
   private final String name;
   @Inject @Named(“name“) private String name;
   …

The latest bundle of Vorpal and Jabberwocky container can be found here. As of this blog, the latest bundle (Merdeka 2011) contains Glassfish containers, NetBeans plugin, Vorpal framework JAR (if you are not using NetBeans) and demo code. There are 2 demo code; the first Eliza demonstrate conversation support; however I feel that this is NOT a very good example and I’ll update it in the next release. The second is query, which basically shows using JPA from within a message handler. The persistence unit points to the default customer database on Derby/JavaDB. Both of these are NetBeans project so they should compile and deploy with out problem if you are using NetBeans (7.0 and 7.0.1).

There is a bug in the Jabberwocky container which prevents 2 or more Vorpal applications to be deployed at the same time. I’ll hopefully fix this in the near future.

CDI support for Vorpal is enabled in the usual way by adding a file call beans.xml to WEB-INF directory.

I’ll talk about conversation support in my next blog.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: