Enabling JSF 2.2 and CDI 1.2 on Tomcat 8

Featured

Getting servers up and running can be quite a hassle. In my experience, choosing a full fledged JEE Server, without the needed support ends up usually in plenty of frustration. Maybe as an exercise in simplicity, or maybe out of frustration, I want to show how easy and clean it is to get a base Tomcat installation (no TomEE) to work with CDI and JSF.

Base Tomcat basically is just a Servlet Container with support for Servlets and JSP. No included JEE Features like CDI, JSF. Tomcat also provides only a read-only JNDI context under java:comp/env, and will require manually registering the Bean Manager SPI.

You can read more on this topic directly under the Weld Documentation.

Choosing the Implementations (dependencies)

Because Tomcat Doesn’t come with CDI or JSF baked into it, we will have to choose ourselves which implementation we are going to include. Well, kind of like that, never could agree with others, and I have the chance to choose latest versions independent of support offered by the vendor of the server.

However we are not completely on our own in choosing the implementation. We still need to validate that the implementations will work with Tomcat. That also means choosing which version of Tomcat to use.

Tomcat

As of writing Tomcat 8 is out, and includes support for the Servlet API 3.1 Specification (JSR-340). This is what I am going to employ as my servlet container. I could have chosen Jetty as well.

Below shows the Maven dependency you can use to be able to compile your code. We note that the actual implementation libraries come shipped with Tomcat, so we will tag this dependency with a “provided” scope. This will make sure that the libraries will not be packaged as part of the war, and allow us to use the server-side libraries.

<dependency>
  <!-- Provided by Tomcat, but needed for compilation -->
  <groupId>javax</groupId>
  <artifactId>javaee-web-api</artifactId>
  <version>7.0</version>
  <scope>provided</scope>
</dependency>

Note however that with this javaee-web-api inclusion we included probably too much. To avoid errors after deploying, you might narrow down the compile time libraries a little better for the libraries that will be available server side.

CDI

The latest specification is CDI 1.2 (JSR-346). Because the Reference Implementation used is that of Weld, I thought it to be convenient to use Weld as well. A quick check in the Weld Documentation confirms that there is support for Tomcat 7 and Tomcat 8.

To be able to compile against the specification, we only need to include a dependency for the API.

<dependency>
  <groupId>javax.enterprise</groupId>
  <artifactId>cdi-api</artifactId>
  <version>1.2</version>
  <scope>provided</scope>
</dependency>

Note that these libraries are just compile time libraries, and are supplied using more specific vendor implementations. Because these API’s will not be used at run-time, we supplied the “provided” scope. This will make it only available during compile phase,and will not be deployed as part of the war.

But now because we do not have any server side implementation chosen yet, we still need to somehow include the Weld libraries. These Weld libraries are just the implementation of the dependency container, and are not required for compilation.

<dependency>
  <!--
    JBoss/Weld Refrence Implementation for
    CDI on a Servlet Container
  -->
  <groupId>org.jboss.weld.servlet</groupId>
  <artifactId>weld-servlet</artifactId>
  <version>2.2.6.Final</version>
  <scope>runtime</scope>
</dependency>

Because we do not need it at the compile phase, as we compiled against the more lightweight API, we tag the scope as “runtime”, making it only included as part of the war deployment, but not as a compilation target. If it were a fully Java EE 7 compliant server, we would simply not have included this dependency.

JSF

The story for Java Server Faces (JSF) goes a similar route. The latest specification is JSF 2.2 (JSR-344). The reference implementation is Oracle’s Mojarra. JSF 2.2 is also the standard for Java EE 7 (JSR-342). So choices made.

To compile against the API use below Maven dependency.

<dependency>
  <groupId>javax.faces</groupId>
  <artifactId>javax.faces-api</artifactId>
  <version>2.2</version>
  <scope>provided</scope>
</dependency>

Again we set it to “provided” to avoid distributing the API on the server as part of the war. Now to be able to run it, we still need to include the libraries in the war for server side deployment.

<dependency>
  <!-- This is the Mojarra Implementation of JSF -->
  <groupId>org.glassfish</groupId>
  <artifactId>javax.faces</artifactId>
  <version>2.2.8-02</version>
  <scope>runtime</scope>
</dependency>

Again, for a fully Java EE 7 compliant server, we would simply not have included this dependency.

With these dependencies added to your web project, you might be able to compile everything, but you won’t be able to do much yet, and might see exceptions. We still need to configure things further to enable CDI and JSF.

Configuration

The following is the list of configuration files that require attention:

  • WEB-INF/web.xml
  • WEB-INF/beans.xml
  • META-INF/context.xml

WEB-INF/web.xml — add in the JSF Servlet (Faces Servlet), and bootstrap Weld

<?xml version="1.0" encoding="UTF-8"?>
<web-app
  xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  version="3.1"
  >
  <session-config>
    <session-timeout>30</session-timeout>
  </session-config>
  <resource-env-ref>
    <!-- Enable Weld CDI, also needs META-INF/context.xml entry -->
    <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>
  <context-param>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <param-value>Development</param-value>
  </context-param>
  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>/faces/*</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>faces/index.xhtml</welcome-file>
  </welcome-file-list>
</web-app>

WEB-INF/beans.xml, to enable CDI (the existence of an empty file is usually enough)

<?xml version="1.0" encoding="UTF-8"?>
<beans
  xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
  bean-discovery-mode="annotated"
  >
</beans>

META-INF/context.xml, to setup the Weld BeanManager as a Resource at startup as JNDI cannot be modified at runtime for self-registry.

<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/tomcat-test">
  <Resource
    name="BeanManager"
    auth="Container"
    type="javax.enterprise.inject.spi.BeanManager"
    factory="org.jboss.weld.resources.ManagerObjectFactory"
    />
</Context>

With these things added in you should be able to fire up your server and deploy. Still might not be able to do much without some actual code and webpages added.

Sample WebApp

With just two files, we can showcase CDI and JSF.

index.xhtml (src/main/webapp)

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
  xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://xmlns.jcp.org/jsf/html"
  >
  <h:head>
    <title>Facelet Title</title>
  </h:head>
  <h:body>
    Hello from ${me.name}
  </h:body>
</html>

Me.java (src/main/java)

import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class Me implements Serializable {
  private String name;

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  @PostConstruct
  public void init() {
    name = "Jo Desmet";
  }
}

In above code lies a riddle … what is the purpose of a @PostConstruct lifecycle event listener on an init() method, if I can directly create a Constructor? Hint – what is not available in a constructor that is available in the init()?

Read the follow-up article as well: Adding in Jersey to Tomcat 8

Also you can find some of the source code in GitHub: GitHub: jdesmet/zakee-web

Adding in Jersey to Tomcat 8

Selecting the new dependencies

With my previous posting, we want to probably first Up the versions used in some of our dependencies. Particularly Weld has become easier to use, as it doesn’t need much of the previous boots trapping.

Note that I will definitely assume that we are going to deploy on Tomcat 8 as the title suggests, otherwise we will just run into troubles. Example for using CDI 1.2, we require at least EL 3.0, which is available only in Tomcat 8, not Tomcat 7.

So what shall we upgrade?

  • javax.enterprise/cdi-api: 1.2
  • org.jboss.weld.servlet/weld-servlet: 2.3.2.Final
  • org.glassfish/javax.faces: 2.2.12
  • If you are using PrimeFaces, org.primefaces/primefaces: 5.3

With Jersey, supposedly things will register automatically with the newer versions setup of CDI, and at least Servlets 3.0

Then to adding JAX-RS support using Jersey, we will add-in:

  • Jersey Container: org.glassfish.jersey.containers:jersey-containerservlet:2.22.1

Round-up with the new POM

<dependency>
  <groupId>javax.ws.rs</a></groupId>
  <artifactId>javax.ws.rs</a>-api</artifactId>
  <version>2.0.1</version>
  <!-- There is somewhere a bug in the Jersey     -->
  <!-- distribution ... for now I need to include -->
  <!-- this api as compile (or default). -->
  <!--scope>provided</scope-->
</dependency>
<dependency>
  <groupId>org.glassfish.jersey.containers</groupId>
  <artifactId>jersey-container-servlet</artifactId>
  <version>2.22.1</version>
</dependency>
<!-- Required only when you are using JAX-RS Client -->
<dependency>
  <groupId>org.glassfish.jersey.core</groupId>
  <artifactId>jersey-client</artifactId>
  <version>2.22.1</version>
</dependency>
<!-- Required to bind Weld and Jersey -->
<!-- https://jersey.java.net/documentation/latest/cdi.support.html -->
<!-- Causes CdI @Inject to work, but Jersey @Context -->
<!-- injection to fail -->
<!--dependency>
  <groupId>org.glassfish.jersey.ext.cdi</groupId>
  <artifactId>jersey-cdi1x</artifactId>
  <version>2.22.1</version>
</dependency-->
<dependency>
  <groupId>org.netbeans.html</groupId>
  <artifactId>net.java.html.json</artifactId>
  <version>1.2.3</version>
  <scope>compile</scope>
</dependency>

Template on GitHub – Zakee-web

To make it all easy on one, I have created a project on GitHub. It has the following features:

  • Setup to start Tomcat8 from the Command line using maven and Cargo.
  • Works with Netbeans out of the box, and in Eclipse if handled as a Maven project
  • Runs and debugs in Eclipse

Feel free to Clone:

https://github.com/jdesmet/zakee-web

 

Why python is a hot mess

Right now Python is a real hot commodity programming language. Look around you: anyone doing big data, data analytics, statistics, most likely they are going to be using either Python or R. Understandably so, as Python provides the syntactical sugar and library support you would need.

However, be in my shoes, and provide support by providing customized analytical libraries, domain specific data aggregation and sourcing, code specific to the business and company you are working for, you will have a though time adjusting. If you are anyway like me, you are poor at memorizing methods, libraries, etc. This personal flaw of me, however, never hindered me: when writing code in Java, I had very good support by IDE’s. I know, editing source code, nothing can beat vi, but in providing context sensitive code support, nothing beats something like NetBeans or Eclipse.

So you will say, “fine, you have the same thing for Python …”. Yeah, there is, but IDE’s have a hard time providing hints for the extended operator syntax python has. See, for me to understand what I can do with a HashMap, I simply type a period, indicating my intent to call a method on an object, and here comes help! JavaDoc – guys have to get a medal for setting this up!

Then the next thing – I do want to limit myself writing optimized code in Java, and then use a more REPL or scripting style language like Python or others to leverage the potential of both sides. However … base python, just doesn’t over the integration with Java I want … and Jython just doesn’t appear to gain the traction I would like it to get.

So not a Java vs Python, I really see the potential of both. What is your experience? Really interested about something like Java in Jupyter, or calling Java from Python the right way.

Convert between primitive array, boxed array, and List

I just found the neatest thing that allow us to reduce boilerplate code in copying a native array into a boxed version of it. Before we had to revert to Apache or Google libraries… But now here comes Java 8 to the rescue.

int[] ints = ...
Integer[] boxedInts = 
  IntStream.of(ints)
  .boxed()
  .toArray(Integer[]::new);
int[] unboxed = 
  Stream.of(boxedInts)
  .mapToInt(Integer::valueOf)
  .toArray();
List<Integer> list = 
  IntStream.of(ints)
  .boxed()
  .collect(Collectors.toList());

And there are a couple of other combinations you can build from those given.