Convesations with Vorpal

In my last blog, I talk about using Vorpal with CDI. As you probably know, one of the responsibilities of CDI is to manage the lifecycle of Java objects within a web application for example. All the examples shown from that blog were request scoped.

In this blog, I’ll talk about using conversation with CDI. I’ve talked abit about conversation support here. I’ll expand on those concepts with regards to CDI.

How to Hold A Conversation

Every XMPP <message> packet that has the <thread> element is capable of supporting conversation in Vorpal.  See this if you are not familiar with conversation. Let look at how to use conversation by way of the shopping cart use case. 

We have a shopping client that will send items that we wish to purchase to cart@some_XMPP_domain.org. The items are carried in a separate XML element (uri:items) in a <message> packet. On receiving such a message, our shopping cart service will see if a conversation has been initiated; if not, the service will start a conversation. It will also create a ShoppngCart object and save that in the ConversationContext

The following class shows how this is done:

@ConversationScoped
@Message
@To(“cart@{__domain__}”)
public class ShoppingCartHandler {
   @Inject @Named(“__conversation__”) Conversation conv;
   @Inject ThreadID threadId;
   @Inject ConversationContext ctx;

   @XmlElement(“uri:items”, parameter=”{item}”)
   private List<Object> shopping(@Bind(“{item}”) Items items) {
      ShoppingCart cart;
      if (conv.isTransient()) {
         //Starts the conversation
         conv.begin();
         //Create the shopping cart
         ctx.setAttribute(“shopping-cart”, new ShoppingCart());
      }
      cart = (ShoppingCart)ctx.getAttribute(“shopping-cart”);
      // Save items into cart – not shown
   }
}

So to support conversation, annotate the class with with one of these annotations

  • javax.enterprise.context.RequestScoped
  • com.kenai.jabberwocky.framework.ConversationScoped, not javax.enterprise.context.ConversationScoped
  • javax.enterprise.context.ApplicationScoped – the use of this annotation this is not recommended. Will explain later

Secondly inject one of these into the message handler

  • Conversation – this allows us to start and terminate a conversation. Furthermore, when you are injecting Conversation, you must qualify it with @Named(“__conversation__”). This is to avoid confusing the container into injecting the default JSF conversation. The usage of this class is exactly the same as JSF.
  • ThreadID – this will give you the thread id from <thread> element in your message
  • ConversationContext – this is very similar to HttpSession. It allows data pertaining to the conversation to be saved like our ShoppingCart object; also all message handles/objects in a session will have access to the same ConversationContext thereby facilitating data sharing.

When ShoppingCartHandler.shopping() fires (see this on method resolution), we first checks to see if the conversation is transient; if it is, then we start the conversation, creates a new instance of ShoppingCart object and save that in our ConversationContext. ConversationContext are persistent and is bound to that conversation once its started.

Starting a conversation cause all classes that are annotated with ConversationScoped to be persisted in that conversation context. When a conversation ends, all these cached objects will be cleared. RequestScoped objects created under a conversation are not persisted. Conversations do not need to be started in a ConversationScoped object; you can call Conversation.start() from within a RequestScoped or an ApplicationScoped message handler. In fact you can have a ‘conversation’ from all RequestScoped objects. ApplicationScoped objects are never cleared when a conversation ends.

Vorpal can also be used without CDI. In that case if you have started a conversation, then all message handlers fired during the conversation will be persisted and will only be released when the conversation ends.

Now let’s look at how we handle checkout:

@RequestScoped
@Message
@To(“cart@{__domain__}”)
public class CheckoutHandler {
   @Inject @Named(PredefinedBindings.CONVERSATION) Conversation conv;
   @Inject ConversationContext ctx;

   @Body(“checkout {*ignore}”)
   public String checkout() {
      ShoppingCart cart;
      if (conv.isTransient())
         return (“You have not done any shopping!”);
     
      cart = (ShoppingCart)ctx.getAttribute(“shopping-cart”);
      //Perform checkout
         …
      //Terminate the conversation – free all objects
      conv.end();
         …
   }

}

To perform a checkout, all you have to do is send a message with ‘checkout‘ as the first word in the message’s body; this will cause CheckoutHandler.checkout() to be fired. We first check if a conversation has been started, sending an appropriate message back to the client if not. We then get the ShoppingCart object from ConversationContext and perform the checkout. Finally we end the conversation by calling Conversation.end(). This will free ConversationContext and also all ConversationScoped object created during this conversation.

Attributes Reinjection

If you are familiar with CDI, once injection have been performed on persistent object like SessionScoped or even ApplicationScoped objects, their members are no longer reinjected. Persistent objects in Vorpal are reinjected whenever they fire. Lets look at a simple example

@ConversationScoped
@Message
@XmlElement(“uri:items”, parameter=”{items}”)
public class ModifyShoppingCart {
   @Inject @Body String body;
   @Inject @Named(PredefinedBindings.CONVERSATION) Conversation conv;
   …

}

In the above message handler, a new instance of ModifyShoppingCart cart will be created if a conversation is not started. So when we create a new instance of ModifyShoppingCart, we will inject the message’s body into body. If however a conversation have been started, then an instance of ModifyShoppingCart will be created and save in the conversation’s context; and it is this instance that will be reused for that particular conversation, if it fires again, until we terminate the conversation.

Unlike the default CDI injection semantics, whenever we reuse a message handler object from a conversation context, all injected attributes pertaining to the incoming message will be refreshed; for example, in ModifyShoppingCart, we are injecting the message body into body member. So whenever ModifyShoppingCart is fired again under the same conversation, body member will be injected with the latest value in <body> from the incoming message. This is also the reason why its a bad idea to have ApplicationScoped objects are message handles.

If you wish to try out conversation support, get the latest build from here. Let me know what you think. Till next time

Advertisements

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.

%d bloggers like this: