Miles to go …

February 18, 2010

TOTD #124: Using CDI + JPA with JAX-RS and JAX-WS

Filed under: General — arungupta @ 10:36 am

This is a follow up blog to TOTD #120 and TOTD #123. These two blogs together have created a simple Java EE 6 application and showed the following features so far:

  • No-interface view for EJB
  • EJBs packaged in a WAR file
  • Optional "faces-config.xml" for Java Server Faces
  • FacesServlet registered using Servlet 3.0 programmatic registration APIs
  • Java Server Faces navigation rules using convention-over-configuration
  • Optional "web.xml" for Servlets 3.0
  • Add database access using Java Persistence API 2.0
  • Show type-safe Criteria API from JPA 2.0
  • Use Context & Dependency Injection for JSF managed beans
  • Add Ajax effects from Java Server Faces 2.0
  • Add Bean Validation to the JSF managed bean

GlassFish v3 is the Java EE 6 Reference Implementation and comes bundled with a complete SOAP Web services stack (Metro/JAX-WS) and a RESTful stack (JAX-RS/Jersey). This blog will update the previously created Maven project with:

  • A SOAP Web service using JAX-WS
  • A RESTful Web service using JAX-RS
  • Use Context & Dependency Injection with JAX-WS and JAX-RS
  • Query the database using JPA 2 based upon criteria from the Web service invocation

Lets get started!

  1. Use the Maven project from TOTD #123 and update the directory structure as follows:
    src
    src/main
    src/main/java
    src/main/java/org
    src/main/java/org/glassfish
    src/main/java/org/glassfish/samples
    src/main/java/org/glassfish/samples/ActorResource.java
    src/main/java/org/glassfish/samples/RESTApplication.java
    src/main/java/org/glassfish/samples/SakilaBean.java
    src/main/java/org/glassfish/samples/SimpleBean.java
    src/main/java/org/glassfish/samples/SimpleEJB.java
    src/main/java/org/glassfish/samples/SimpleServlet.java
    src/main/java/org/glassfish/samples/SOAPService.java
    src/main/resources
    src/main/webapp
    src/main/webapp/index.jsp
    src/main/webapp/index.xhtml
    src/main/webapp/sakila.xhtml
    src/main/webapp/show.xhtml
    src/main/webapp/WEB-INF
    src/main/webapp/WEB-INF/beans.xml
    src/main/webapp/WEB-INF/web.xml
    

    The changes are:

    • "ActorResource.java" is added for the RESTful representation of Actor table.
    • "SOAPSevice.java" is added to invoke the SOAP-based Web service.
    • "SakilaBean.java" is updated to query the database for an Actor identified by "id".
  2. The updated files are explained below.
    • A new method is added to SakilaBean.java as shown below:
      public Actor findActorById(int id) {
      EntityManager em = emf.createEntityManager();
      CriteriaBuilder cb = emf.getCriteriaBuilder();
      CriteriaQuery<Actor> criteria = cb.createQuery(Actor.class);
      // FROM clause
      Root<Actor> actor = criteria.from(Actor.class);
      // SELECT clause
      criteria.multiselect(actor.<Short>get("actorId"),
      actor.<String>get("firstName"),
      actor.<String>get("lastName"));
      // WHERE clause
      criteria.where(cb.equal(actor.<Short>get("actorId"), id));
      Query q = em.createQuery(criteria);
      ((org.eclipse.persistence.jpa.JpaQuery)q).getDatabaseQuery().dontMaintainCache();
      return (Actor)q.getResultList().get(0);
      }
      

      This method queries the database for an actor by his id and uses the typesafe Criteria API to achieve the purpose. The FROM, SELECT, and WHERE clause are highlighted in the code. A cast to EclipseLink specific class is required because of the bug #303205.

    • SOAPService.java
      package org.glassfish.samples;
      import javax.inject.Inject;
      import javax.jws.WebService;
      import sakila.Actor;
      @WebService
      public class SOAPService {
      @Inject SakilaBean bean;
      public String sayHello(int id) {
      Actor a = bean.findActorById(id);
      return "Hello " + a.getFirstName();
      }
      }
      

      The key points in the code are:

      • Standard JAX-WS annotations from "javax.jws.*" package are used to represent the Web service.
      • The Web service has only one method "sayHello" that concatenates the string "Hello" with the first name of "Actor" identified by "id".
      • No deployment descriptor modifications are required to publish this Web service.
      • "SakilaBean" is injected using @Inject annotation and used to query the database. This allows to encapsulate all the database details in one class and injected in a typesafe manner.
    • RESTApplication.java
      package org.glassfish.samples;
      import javax.ws.rs.ApplicationPath;
      import javax.ws.rs.core.Application;
      @ApplicationPath("/sakila")
      public class RESTApplication extends Application {
      }
      

      This is a marker class to inform Jersey of the root resource to be registered. By default, all classes with @Path and @Provider annotations are included. It also specifies the base path at which all resources are accessible.

      An alternative to this class is to specify the required information in "web.xml" as:

      <servlet>
           <servlet-name>Jersey Web Application</servlet-name>
           <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
      </servlet>
      <servlet-mapping>
           <servlet-name>Jersey Web Application</servlet-name>
           <url-pattern>/sakila/*</url-pattern>
      </servlet-mapping>
      

      So only one of RESTApplication.java or changes in "web.xml" are required.

    • ActorResource.java
      package org.glassfish.samples;
      import javax.enterprise.context.RequestScoped;
      import javax.inject.Inject;
      import javax.ws.rs.GET;
      import javax.ws.rs.Path;
      import javax.ws.rs.Produces;
      import javax.ws.rs.PathParam;
      import sakila.Actor;
      @Path("/actor/{id}")
      @RequestScoped
      public class ActorResource {
      @Inject SakilaBean sakila;
      @GET
      @Produces("application/json")
      public Actor getActor(@PathParam("id") int id) {
      return sakila.findActorById(id);
      }
      }
      

      The key points in the code are:

      • Standard JAX-RS annotations from "javax.ws.rs" package are used to represent the RESTful resource.
      • "getActor" method is invoked when the resource is accessed using HTTP GET.
      • The resource is accessible at "/actor/{id}" URL where "{id}" is mapped to the "id" parameter of "getActor" method.
      • SakilaBean is injected in a typesafe manner using @Inject annotation. This bean is then used to query the database using the "id" parameter.
      • "getActor" method produces JSON representation, as defined by the "@Produces" annotation. This is easily achieved by updating our Persistence Unit (PU) created in TOTD #122 and adding "@javax.xml.bind.annotation.XmlRootElement" as the class level annotation on "sakila.Actor" class. Make sure to install the updated PU to your local Maven repository.

Package and deploy the application as:

mvn clean package
./bin/asadmin deploy --force=true ~/samples/javaee6/simplewebapp/target/simplewebapp-1.0-SNAPSHOT.war

Now the SOAP web service is accessible at "http://localhost:8080/simplwebapp-1.0-SNAPSHOT/SOAPServiceService" and looks like:


Notice, the URL in your case may be different if the Web service class name was different. The default URL is "http://<HOST>:<PORT>/<CONTEXT ROOT><WEB SERVICE CLASS NAME>Service".

This Web service can be easily tested by using the in-built tester accessible at "http://localhost:8080/simplwebapp-1.0-SNAPSHOT/SOAPServiceService?tester" and looks like:

The WSDL describing the Web service can be seen by clicking on the "WSDL File" link. The Web service method can be invoked by entering a value ("id" of the Actor) in the text box and clicking on "sayHello" button. Here is a sample run:

Clicking on "Submit" invokes the Web service which then uses the injected "SakilaBean" to query the database using the parameter specified. The first name from the response from the database is then extracted, concatenated with the string "Hello" and returned as Web service response.

The RESTful resource is accessible at "http://localhost:8080/simplwebapp-1.0-SNAPSHOT/sakila/actor/5" and looks like:

As in the SOAP-based Web service, the "5" in the URL is mapped to a parameter in the "ActorResource.java", the injected "SakilaBean" is then used to query the database and returns the JSON representation. Specifying a different number in the URL will show the RESTful JSON representation for that particular actor.

More Java EE 6 features will be covered in subsequent blogs. Are you interested in any particular ones ?

Technorati: jaxws metro webservices jaxrs rest jersey glassfish v3 cdi jsr299 weld

Share and Enjoy:
  • Print
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • DZone
  • StumbleUpon
  • Technorati
  • Twitter
  • Slashdot
Related posts:
  1. TOTD #123: f:ajax, Bean Validation for JSF, CDI for JSF and JPA 2.0 Criteria API – all in one Java EE 6 sample application
  2. TOTD #99: Creating a Java EE 6 application using MySQL, JPA 2.0 and Servlet 3.0 with GlassFish Tools Bundle for Eclipse
  3. TOTD #151: Transactional Interceptors using CDI – Extensible Java EE 6
  4. TOTD #121: JDBC resource for MySQL and Oracle sample database in GlassFish v3
  5. TOTD #122: Creating a JPA Persistence Unit using NetBeans 6.8

3 Comments »

  1. [Trackback] This post was mentioned on Twitter by arungupta: New Blog: TOTD #124: Using CDI + JPA with JAX-RS and JAX-WS: This is a follow up blog to TOTD #120 and TOTD #123. … http://bit.ly/drMrTW

    Comment by uberVU - social comments — February 19, 2010 @ 8:55 pm

  2. Are the sources available as a ZIP? I don’t use Maven. Thanks!

    -NBW

    Comment by NBW — February 22, 2010 @ 2:42 pm

  3. NBW,

    All sources are posted on:

    http://blogs.sun.com/arungupta/entry/totd_120_deployment_descriptor_free

    http://blogs.sun.com/arungupta/entry/totd_123_f_ajax_bean

    and above blog. You’ll need Maven to run the project anyway. Will post the Maven project in next blog entry.

    Comment by Arun Gupta — February 23, 2010 @ 4:23 pm

RSS feed for comments on this post. TrackBack URL

Leave a comment

The views expressed on this blog are my own and do not necessarily reflect the views of Oracle.
Powered by WordPress