Art of Conversation: Miscellaneous Topics – Part 4

Programmatically looking up Beans

As you may know, you can use Vorpal client to create client side application. I talked about using client side Vorpal here. For the most part, Vorpal client has the same programming model as its server counterpart.

Vorpal relies heavily on CDI for resources; this is not a problem if you’re on the server side, but on the client side you have to lookup the CDI instances yourself. The trick is this is to get a reference to either BeanManager or WeldContainer.

Which of those 2 objects you get depends largely on how you bootstrap CDI in the Java SE environment. See this for the various ways. Since BeanManager is standard Java EE API, we’ll use BeanManager.

One way that I’ve found that works is to get CDI to inject an instance of BeanManager by listening to the container starting up event. Then you can cache a reference of BeanManager in a singleton. The following shows how we go about doing this

@ApplicationScoped

public class MySingletons {

   @Inject private BeanManager bm;

   @Inject ComponentContext ctx;

  

   private static MySingletons instance = null;

  

   @PostConstruct private void init() {

      instance = this;

   }

   private void containerInitialized(

         @ObservesContainerInitialized ciEvt) { }

   public BeanManager getBeanManager() {

      return (bm);

   }

   public ComponentContext getComponentContext() {

      return (ctx);

   }

   public static MySingletons getInstance() {

      return (instance);

   }

}

During container startup we use MySingletons to listen to the container initializing and use this opportunity to hold a reference to BeanManager. Same with ComponentContext. Now wherever you need to access either BeanManager or ComponentContext, you can use the static method MySingletons.getInstance() .

Note: Vorpal client is suppose to be CDI implementation agnostic, but I’ve only ever tested it with Weld.

Client side conversation setup

When you’re working with conversation on the client side, you have make sure that you are not working with conversation artifacts from a previous processing cycle.

On the server, before Vorpal calls your message handler, it initializes the component context and populate it with the appropriate bindings and meta data that your message handler will need to process a message correctly. Server side is mostly reactive processing to incoming messages and Vorpal uses this behaviour to perform a lot of mundane task under the hood.

However on the client side, message processing is mostly proactive viz. you click on a button and your application uses Vorpal client to send out a message. Since there is no initializing the component context; you may actually be picking up artifacts from the previous processing cycle. What you have to do is to clear the component context before you perform your processing by calling ComponentContext.startProcessingCycle().

The following code shows you how you clear the component context on every button click

public void actionPerformed(ActionEvent aEvt) {

   String cmd = aEvt.getActionCommand();

   switch (cmd) {

      case “New Conversation”:

         ComponentContext compCtx = MySingletons

               .getInstance().getComponentContext();

         compCtx.startProcessingCycle();

         Conversation conv = lookup(Conversation.class

               , new NamedQualifier(“__conversation__”));

         ConversationContext convCtx = lookup(

               ConversationContext.class);

         conv.begin();

         ResponseContext respCtx =

               new ResponseContext(…);

                    

         compCtx.send(respCtx);

         break;

      …

   }

}

private <T> T lookup(Class<T> type

      , Annotation… qualifiers) {

   T instance = null;

   BeanManager bm = MySingletons.getInstance();

   Bean<T> bean = (Bean<T>)bm.resolve(

         bm.getBeans(type, qualifiers));

   if (null != bean) {

      CreationalContext<T> ctx =

            bm.createCreationalContext(bean);

      instance = bean.create(ctx);

   }

   return (instance);

}

The above shows how you can lookup an instance of Conversation and ConversationContext programmatically. I’ll leave the NamedQualifier class as an exercise for the reader. Hint: use AnnotationLiteral

If you’re just interested in just creating a new conversation but not about associating any states with it then you can manually add a ThreadID to ResponseContext like so:

case “ New Conversation”:

   ComponentContext compCtx = MySingletons

         .getInstance().getComponentContext();

   compCtx.startProcessingCycle();

   ResponseContext respCtx = new ResponseContext(…);

   respCtx.add(ThreadID.generate());

       …

   compCtx.send(respCtx);

   break;

which is a lot simpler. I’ve blog about this in my previously.

Warning: you should not use ComponentContext.startProcessingCycle() when you are developing server side components or bad things will happen.

Turning off conversation inheritance

Vorpal allows conversation states to be inherited viz. if you create a new conversation in the context of an existing conversation, then that new conversation will inherit all the states from the existing ConversationContext.

If you want to suppress the new conversation from inheriting the states, add a property call com.kenai.jabberwocky.framework.property.inheritConversationContext to the existing conversation’s ComponentContext and set the value to false. This will prevent new conversation from inheriting the existing conversation’s state.

//ConversationContext from an existing conversation

convCtx.setAttribute(

      FrameworkProperty.INHERIT_CONVERSATION_CONTEXT

      , false);

//Outgoing packet will not inherit conversation states

ResponseContext respCtx = new ResponseContext(…);

respCtx.add(ThreadID.generate());

   …

compCtx.send(respCtx);

The com.kenai.jabberwocky.framework.property.inheritConversationContext is not a permanent attribute as it is cleared after every processing cycle. So you will have to set it again on the next processing cycle if you wish to further suppress conversation inheritance.

The September 2012 bundles supports the latest conversation features. You can download them here. I’ve just uploaded a new bundle with bug fixes.

Till next time.

Advertisements
%d bloggers like this: