The road so far….

May 17, 2011

Integrating Apache OpenWebbeans with other frameworks

Filed under: java — Tags: — Rahul Sharma @ 9:02 pm

In my last post “Apache OWB CDI: from standalone to webapp I added a servlet over my existing RandomService. In this post I would like to expose a web-service over the same. I would update the source in the same project which was used for creating the servlet in my previous blog. For exposing the WS I would use jax-ws with Metro. Now Metro is  a third party framework, my intention here is to see how JEE6 CDI integrates with other frameworks.

So let us start , I first created the RandomWebService based on jaxws. The web-service requires an instance of RandomService which should be retrieved from the context. I could not use the @inject annotation here as two independent frameworks involved viz Apache OWB for context and Metro for WS with no defined specs of cross talk.  I created a method getService() where I would like to somehow make these two talk to each other and  retrieve the bean from the context.

@WebService(name = "RandomWebService", targetNamespace = "http://localhost:8080/jee6-sample-integration")
public class RandomWebService {
    @WebMethod
    public String performAction(int arg1, int arg2, int arg3) {
        RandomService service = getService();
        return service.perform(arg1, arg2, arg3);
    }

    private RandomService getService() {
       // TODO: get service using CDI
        return null;
    }}

I also updated my web.xml to include the WSServlet and the WSServletContextListener( I assume here that the required libs are deployed in Tomcat).

<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <display-name>jee6 Sample integration</display-name>
    <description>jee6 Sample integration</description>
    <listener>
        <listener-class>org.apache.webbeans.servlet.WebBeansConfigurationListener</listener-class>
    </listener>
    <listener>
        <listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>jax-ws</servlet-name>
        <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet>
        <servlet-name>randomServlet</servlet-name>
        <servlet-class>info.jee6.RandomServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>jax-ws</servlet-name>
        <url-pattern>/RandomWebService</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>randomServlet</servlet-name>
        <url-pattern>/RandomServlet</url-pattern>
    </servlet-mapping>
</web-app>

As shown in the web.xml, my web-service is getting loaded by WSServletContextListener and the JEE6 context is loaded  by WebBeansConfigurationListener. Both are there in the app but do not talk with each-other.

Now according to specs the BeanManager instance should be available via JNDI lookup under the name java:comp/BeanManager. Thus I created a factory  class for the RandomService and used the JNDI lookup for the BeanManager.

class JNDIBeanManager {
    private BeanManager beanManager;

    static JNDIBeanManager getInstance() {
        try {
            BeanManager manager = InitialContext.doLookup("java:comp/BeanManager");
            JNDIBeanManager jndiManager = new JNDIBeanManager();
            jndiManager.beanManager = manager;
            return jndiManager;
        } catch (NamingException e) {
            throw new RuntimeException(e);
        }
    }

    <T> T getBean(Class<T> type) {
        Bean<T> bean = (Bean<T>) beanManager.resolve(beanManager.getBeans(type));
        CreationalContext<T> creationalContext = beanManager.createCreationalContext(bean);
        return (T) beanManager.getReference(bean, type, creationalContext);
    }
}

Now I used this JNDIBeanManager in my getService() method.

private RandomService getService() {
        RandomService service = JNDIBeanManager.getInstance().getBean(RandomService.class);
        return service;
    }

I created the war and deployed in Tomcat. Things were running the servlet was responding and the web-service was also there. I made a SOAP call to the webservice but the call gave back a long stack trace of exception stating that the JNDI look-up has failed. Some more googling was required and I had to look into Weld documentation to realize that the JNDI directory in Tomcat is readonly. I ran the following steps that were described for Weld but applied to Apache OpenWebBeans as well.

Under Tomcat the specs did not applied quite well and I was required to expose the BeanManager. In order to expose the BeanManager I created a context.xml file in webapp/META-INF.

<Context>
    <Resource name="IntegrationBeanManager" auth="Container"
        type="javax.enterprise.inject.spi.BeanManager" factory="org.apache.webbeans.container.ManagerObjectFactory" />
</Context>

After this the BeanManager will be available under the following name java:comp/env/IntegrationBeanManager. In order to use retrieve the BeanManager under the same name I need to update my web.xml with the following configuration :

........
<resource-env-ref>
        <resource-env-ref-name>IntegrationBeanManager</resource-env-ref-name>
        <resource-env-ref-type>javax.enterprise.inject.spi.BeanManager</resource-env-ref-type>
    </resource-env-ref>
.....

After I do this the BeanManager is available to my application but under a different name than used earlier. I need to update the lookup name in the JNDIManager class. Now my webservice finds the context and retrieves the required  bean from the context.

Using the JNDI lookup mechanism I can use the context in any other framework but it does not look a clean approach. This resembles more of a workaround rather a solution. I guess frameworks should start considering the CDI and enable the support of the same.

Advertisements

1 Comment »

  1. Hi!

    Good post! You might try Apache MyFaces CODIs BeanManagerProvider for getting the BeanManager. This also works if no JNDI is available 😉

    LieGrue,
    strub

    Comment by struberg — May 18, 2011 @ 6:17 am


RSS feed for comments on this post. TrackBack URI

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: