Starting a CDI webapp from Maven with Weld-Servlet and Jetty Plugin

Posted by Antoine Sabot-Durand on Jul 10, 2012 | Comments

In Agorava framework we want to provide an easy way to launch our example applications. One of the easiest way is to provide a maven Goal that build the project and launch it with embedded Jetty servlet container. If you have read our previous post you already know that right now Agorava has only a CDI implementation. So when we created Socializer demo app we add to find a way to launch CDI container from Jetty Maven Plugin. This article is about how we did it.

Launching CDI from Servlet Api

The first problem to deal with is about launching CDI container from Servlet API. CDI is a Java EE 6 specification and thus comes in all Java EE container like JBoss, TomEE or Glassfish. However the specification doesn’t provide a standard way to launch CDI container outside Java EE. Each implementation brings its own solution (to be more precise OpenWebBeans and Weld bring a solution, Candi has no known way to be launch outside Resin). We decided to go with Weld because it’s the CDI RI and that it is the implementation on which Agorava was the more tested thru Glassfish and JBoss.

Adding maven dependecies

As we want to support Jetty but also full Java EE containers we added a profile in the pom.xml to keep the Java EE build clean. As this profile is supposed to build and run the project we call it run. We add the following dependencies in the pom.xml

<profile>
  <id>run</id>
    <dependencies>
        <dependency>
            <groupId>org.jboss.weld.servlet</groupId>
            <artifactId>weld-servlet</artifactId>
            <version>1.1.8.Final</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>2.1.3</version>
        </dependency>
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-impl</artifactId>
            <version>2.1.3</version>
        </dependency>
    </dependencies>
</profile>

Jsf dependencies are added because Socializer uses JSF and Jetty doesn’t provide thrm. The Jboss Weld Servlet is the important dependency here since it will provide bootstrapping for CDI thru servlet API. It also will bring transitively all the needed dependencies for Weld core and CDI API.

Adding Jetty Maven plugin

Now we can add the plugin to our new profile

<build>
    <plugins>
       <plugin>
          <groupId>org.mortbay.jetty</groupId>
          <artifactId>jetty-maven-plugin</artifactId>
          <version>8.1.3.v20120416</version>
       </plugin>
    </plugins>
</build>

This plugin allows to build a Maven project and launch Jetty directly from Maven with a simple mvn jetty:run command.

Boostraping CDI

To bootstrap CDI, we have 2 steps to perform :

Expose CDI bean manager thru JNDI

To do that we create a jetty-env.xml file in WEB-INF containing this

<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure id="webAppCtx" class="org.eclipse.jetty.webapp.WebAppContext">
    <New id="BeanManager" class="org.eclipse.jetty.plus.jndi.Resource">
        <Arg>
            <Ref id="webAppCtx"/>
        </Arg>
        <Arg>BeanManager</Arg>
        <Arg>
            <New class="javax.naming.Reference">
                <Arg>javax.enterprise.inject.spi.BeanManager</Arg>
                <Arg>org.jboss.weld.resources.ManagerObjectFactory</Arg>
                <Arg/>
            </New>
        </Arg>
    </New>
</Configure>

This file is a standard Jetty config file and is run by the container at boot time.

Adding Web.xml configuration

To achieve the bootstrapping we also need to add two entries to web.xml :

  • One to retrieve the BeanManager exposed in the file above and expose it to servlet API
  • One to launch the servlet listener that will boot CDI container

As we don’t want to pollute existing web.xml which works perfectly for Java EE 6 containers, we add a web.xml overriding file to add our entries. This file is declared in Jetty plugin configuration like this

<plugin>
    <groupId>org.mortbay.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>8.1.3.v20120416</version>
    <configuration>
        <webApp>
            <overrideDescriptor>src/main/webapp/WEB-INF/web-add.xml</overrideDescriptor>
        </webApp>
    </configuration>
</plugin>

The content of web-add.xml file is as follow

<web-app version="3.0" 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_3_0.xsd">

    <listener>
        <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
    </listener>

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

It’s content will override web.xml one (i.e web.xml will be interpreted before web-add.xml).

Last trick to allow injection in servlets

Weld Servlet will try to decorate some Jetty internal class to add the possibility of using @Inject inside servlets. This class is a Jetty system class and therefore is not visible from the web application. We have to tell Jetty classloader to expose this class to the web app in order to have Weld Servlet decorating it.
To allow this we create a jetty-context.xml file in WEB-INF

<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
    <Set name="serverClasses">
        <Array type="java.lang.String">
            <Item>-org.eclipse.jetty.servlet.ServletContextHandler.Decorator</Item>
        </Array>
    </Set>
</Configure>

Then we add it to Jetty Maven plugin configuration like this

<configuration>
    <webApp>
        <overrideDescriptor>src/main/webapp/WEB-INF/web-add.xml</overrideDescriptor>
    </webApp>
    <contextXml>src/main/webapp/WEB-INF/jetty-context.xml</contextXml>
</configuration>

Then we’re done

To sum up

Here is the complete run Profile in our pom.xml file

<profile>
    <id>run</id>
    <dependencies>
        <dependency>
            <groupId>org.jboss.weld.servlet</groupId>
            <artifactId>weld-servlet</artifactId>
            <version>1.1.8.Final</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>2.1.3</version>
        </dependency>
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-impl</artifactId>
            <version>2.1.3</version>
        </dependency>
    </dependencies>
    <build>
        <defaultGoal>clean jetty:run</defaultGoal>
        <plugins>
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>8.1.3.v20120416</version>
                <configuration>
                    <webApp>
                        <overrideDescriptor>src/main/webapp/WEB-INF/web-add.xml</overrideDescriptor>
                    </webApp>
                    <contextXml>src/main/webapp/WEB-INF/jetty-context.xml</contextXml>
                </configuration>
            </plugin>
        </plugins>
    </build>
</profile>

Don’t forget the 3 files above jetty-env.xml to define JNDI, web-add.xml to override web.xml with CDI servlet bootstrapping and JNDI and jetty-context.xml to expose the internal servlet implementation for Weld decorator.
With this Maven profile, we only have to enter mvn -Prun to build our web application and have it launched in Jetty to test it. Hard to make it simpler.

Check our code

Feel free to look at Socializer code and play with our API. Contribution are always welcome.

Meet Agorava, The Social Framework

Posted by Antoine Sabot-Durand on Jun 22, 2012 | Comments

Did you ever looked for a nice solution in java to authenticate your users with their Twitter, Facebook or LinkedIn account ? Have you ever looked for a nice way to post tweets or Facebook updates from your Java application? Do you need to read your timeline or perform a search on a Social Media services from Java EE web application? If you answered yes to one of these questions Agorava is (or will be soon) the right answer to your needs.
Agorava is the missing framework to deal with Social Media based on OAuth 1.0a and OAuth 2.0. It provides a way to authenticate on Social Media, use APIs and map JSON answers to Java pojo. It’ll have multiple implementations (like CDI, Java SE, JSR 330 supporting framework and others) to support your needs. Right now the only implementation is based on CDI but we’ll provide others in the coming months.

Agorava genesis

Agorava’s short history is important because it helps to understand the goals of our team. In March 2011 the project Seam Social was launched. This project was a collection of CDI beans and extension to support Social Network consuming. It lived inside Seam 3 project which was an ambitious JBoss project aimed to provide a rich ecosystem for Java EE 6 thru CDI extensions. For all kind of reasons we won’t develop here, Seam 3 project was stopped at the end of 2011 to create a new project around CDI ecosystem : Apache Deltaspike (merging Seam 3, Apache CODI and others initiatives).
In parallel of this event, a few people launched a JCP proposal on Social Media : Java Social JSR 357. Projects like Seam Social or DaliCore were main influencers for this proposal. This proposal was voted down for all kind of reasons, but mainly because there wasn’t a real proof of concept (an implementation) behind it.
So the conjunction of these 2 stories brought us to create a new project : start from Seam Social code to provide an implementation for Java Social with the goal to go back to JCP in the future. This project is also a experiment to answer the problem and challenges in creating a standard API for Social Media API for Java platform. Thus Agorava is born

But most Social Media already have their own APIs. So why do we reinvent the wheel?

Yes it’s true, but these social APIs are almost always in Javascript only and if it