Exposing RESTful Services through JAX-RS

At this point we need to create a Stateless Session Bean (EJB) that will query exhibition data through the JPA entities and return such information. Before getting into it, let's take a quick look at the types of beans supported by Java EE 6 and their definitions:

  • Stateless: This is the same definition we find for EJB 2.x—components that aren't supposed to keep information between calls. The container keeps a bean pool, and any bean instance can serve an incoming request, being very lightweight to keep and having good scalability due to its ability to serve multiple clients.
  • Stateful: When multiple interactions between system and user is needed, this kind of bean keeps consistent state through the conversation. As it holds data from a specific user, more instances have to be created to serve more users. Under heavy loads, it can degrade performance.
  • Message-driven: The focus of this kind of bean is asynchronous processing—instead of calling its methods, we bound it to a JMS Queue or JMS Topic and publish messages to it, so it behaves like an event listener, the event being a JMS message.
  • Singleton: New on EJB 3.1, the name is pretty clear about what this kind of functionality this bean offers. By default, all methods of this type of bean are thread-safe (synchronized) and transactional. You can tune this behavior with annotations Lock and AccessTimeout, or even disable the container's control with annotation ConcurrencyManagement with value BEAN.

Note

Another new feature related to beans is the no-interface view, which improves the local client view concept of EJB 3.0. Now, we don't have to create a separate interface to expose the methods of a bean—the public methods of a Session Bean are automatically exposed as its local business interface, making development easier. To use it, you either explicitly decorate your bean with @LocalBean or leave it without any interface-related decoration (@LocalBean, @Local, and @Remote) to implicitly use the no-interface strategy.

Let's get back to our code and create the stateless bean that is going to be exposed as a web service:

  1. Create a Java class named ExhibitionBean.java under the package com.packt.theater.services.
  2. Decorate the class with the Stateless annotation.
  3. Add a reference to the persistence context through the PersistenceContext annotation:
       @PersistenceContext(unitName = "TheaterBO")
       private EntityManager em;

The session bean is now capable of interacting with the database through the persistence context we have declared and we can simply write Java methods to retrieve JPA objects, using named queries, for example. In the next section we're going to expose this stateless session bean as a RESTful service and how to write a REST client that will call this service from the Store application.

Coding the API

We're going to expose three basic functionalities as part of the RESTful API for the Theater application: list all exhibitions, list one exhibition, and retrieve an exhibition by movie. To support such operations, let's look at what must be done to the ExhibitionBean class:

  1. Decorate the class declaration with a java.ws.rs.Path annotation. This annotation specifies the relative path for a resource or method that is going to be exposed through REST:
    @Stateless
    @Path("/exhibition")
    public class ExhibitionBean {
    ...
  2. Create a Java method that is going to execute the named query that returns all exhibitions. This method of the API returns XML or JSON objects and that's what the decoration @Produces defines. We also use an HTTP verb, @GET, since this operation will not have any side-effect (it will not change any entity state on the server side):
    @GET
    @Produces({ MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON })
    public List<Exhibition> getAllExhibitions() {
       @SuppressWarnings("unchecked")
       List<Exhibition> result = em.createNamedQuery("Exhibition.findAll")
          .getResultList();
    
          if (result.size() > 0)
             return result;
          else 
             throw new WebApplicationException(Response.Status.NO_CONTENT);
    }

    Note

    Notice that this method does not define a @Path tag, so it will be used as the default method for the class—a request to the base path, http://<server>:<port>/theater/api/exhibition, will be handled by this method.

  3. Add another Java method that will receive an exhibition ID and return information about a single object. To consume a parameter JAX-RS uses the annotation PathParam and since this parameter will be part of the URL we need to use the Path annotation to differentiate from the default path of the service:
    @GET
    @Path("{id}")
    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
    public Exhibition getExhibition(@PathParam("id") int id) {
       try {
          Exhibition entity = (Exhibition) em
             .createNamedQuery("Exhibition.findById")
             .setParameter("id", id)
             .getSingleResult();
          return entity;
       } catch (NoResultException nre) {
          throw new WebApplicationException(Response.Status.NOT_FOUND);
       }
    }

    Note

    The following is how a request to this method must be done: http://<server>:<port>/theater/api/exhibition/{id}.

  4. And now add the most important method of this service that will receive a movie ID and return a list of available exhibitions for that movie. In order to provide such functionality we will add another path for the method, /q, and pass the movie ID as a URL parameter that can be read through the annotation QueryParam of JAX-RS. The complete method is shown as follows:
    @GET
    @Path("/q")
    @Produces({ MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON })
    public List<Exhibition> getAllExhibitionsByMovie(@QueryParam("movie") int movieId) {
          if (movieId > 0) {
             Query query = em.createNamedQuery(Exhibition.findByMovie);
             query.setParameter("movieId", movieId);
    
             @SuppressWarnings("unchecked")
             List<Exhibition> result = query.getResultList();
    
             if (result.size() > 0)
                return result;
             else 
                throw new WebApplicationException(Response.Status.NOT_FOUND);
          }
          else 
              throw new WebApplicationException(Response.Status.BAD_REQUEST);

    Tip

    Note that if a request is made to http://<server>:<port>/theater/api/exhibition/q without a parameter or with a parameter but no value, a BAD REQUEST error code (HTTP 400) will be returned. Remember that HTTP status codes are heavily used for RESTful web services since they are a standard and have meaningful descriptions.

  5. To deploy the application, open the Servers view accessing the menu Window, then navigate to Show View | Servers.
  6. Right-click on the server name and click on the Add and Remove… entry from the context menu.
  7. Select the Theater project from the Available list and click on Add >.
  8. Click on the Finish button.

Testing the web service

After the successful deployment, test the application accessing the following URLs from a browser:

  • http://localhost:7001/theater/api/exhibition/
    Testing the web service

  • http://localhost:7001/theater/api/exhibition/4
    Testing the web service

  • http://localhost:7001/theater/api/exhibition/q?movie=5
    Testing the web service

To complete the testing, we can call the service API from a command-line utility such as cURL, setting the accept HTTP header to application/json, which will change the web service's response, as shown in the following screenshot:

Testing the web service

Tip

To force a RESTful service support only one media type (only JSON or only XML, for example), you can modify the Produces annotation and set the appropriate media type. Actually the supported media types are listed in the Java docs of Jersey API at https://jersey.java.net/apidocs/latest/jersey/index.html.

You can check the RESTful APIs exposed by an application accessing the autogenerated Web Application Description Language (WADL) file at the API's root URL to get information about it. For the module we just coded, that address would be http://localhost:7001/theater/api/application.wadl:

Testing the web service

The application.wadl file is generated by Jersey and contains all the basic information about the service such as operations, supported media types for each operation, HTTP verbs, and input/output data.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.137.67