Creating the REST client

Now that there is a service that provides a list of movie exhibitions available on the Theater module, we need to update the Store module to consume this API and display the retrieved information on the query page. Here's a graphical representation of this functionality:

Creating the REST client

The JAX-RS RI defines a client API for RESTful Web Services clients and the base class for this is com.sun.jersey.api.client.Client. This is the main class we're going to use to develop our client in the next section.

Configuring JAX-RS client libraries and optional package

Before starting the creation of the client, we need to add some Jersey libraries to the project classpath since they provide the client API and JSON classes that we're going to use:

  1. Open the Properties for Store window and go to the Java Build Path section.
  2. Click on the Libraries tab and click on Add External JARs….
  3. Browse to the WebLogic 12c installation directory and go to the modules folder at $MW_HOME/oracle_common/modules.
  4. Select files jersey.core-1.17.1.jar, jersey.json-1.17.1.jar, and jersey.client-1.17.1.jar and click on OK:
    Configuring JAX-RS client libraries and optional package
  5. Click on OK to close the Properties for Store window.

Also, we need to add references to TheaterBO to properly manipulate the response of our REST Web Service. As we did with StoreBO in the previous chapter, we need to add a reference to the project for design-time compilation, and some tags to the project's MANIFEST.MF file to link them at runtime. Let's do so:

  1. To add a project reference, right-click on the Store project and select Properties, then Java Build Path and finally Projects. Click on Add… and select the TheaterBO project.
  2. Now, open the Store's project MANIFEST.MF file inside WebContent/META-INF, add a reference to the Extension-List, and then add the package details. Here's how your file should look after this step:
    Manifest-Version: 1.0
    Class-Path: 
    Extension-List: storeBO theaterBO
    storeBO-Extension-Name: storeBO
    storeBO-Specification-Version: 1.0
    storeBO-Implementation-Version: 1.0.0
    theaterBO-Extension-Name: theaterBO
    theaterBO-Specification-Version: 1.0
    theaterBO-Implementation-Version: 1.0.0
    
  3. Save the file.

The Store project is now ready and you can start implementing the web service client.

Creating the web service consumer

Now that the Store project has the correct libraries, we can create the client that is going to consume the API exposed at http://localhost:7001/theater/api/exhibition/q. In order to achieve this, we must:

  1. Create a named bean that is going to act as a proxy between our SearchManager bean and the Theater API.
  2. Instantiate the JAX Client handler and retrieve an actual handler to call the remote methods, represented by a WebResource object.
  3. Define and code the proxy method that is going to receive a movie ID from SearchManager, build the query, and execute it.

So, in the Store project, create a new Java class named TheaterClient under the package com.packt.theater.client, decorate it with @Named and add a method to retrieve a JAX-RS handler:

private WebResource getClient() {
   final Client client = Client.create();
   return client.resource(ENDPOINT);
}

The endpoint referenced above is going to be retrieved from a deployment descriptor, web.xml, using CDI. Add these lines just after the class declaration:

@Resource(lookup="theaterServiceEndpoint")
private String ENDPOINT;

Now, open your web.xml file and add this block at the end of the web-app tag:

<env-entry>
   <env-entry-name>theaterServiceEndpoint</env-entry-name>
   <env-entry-type>java.lang.String</env-entry-type>
   <env-entry-value>http://localhost:7001/theater/api
   </env-entry-value>
</env-entry>

Note

As we will simulate just one Theater module when running the projects, there's no need to worry about finding out the right recipient for a request (which theater), so we won't have such a logic in our project, that is, we will use a fixed endpoint address. In a real-world scenario, we should have several entries here, each pointing to a different partner.

The last step is to create a method, getExhibitionByMovie, that receives a movie ID as parameter and returns a list of exhibitions, executing the call to the REST Web Service exposed by the Theater module. Here's how the final code of the TheaterClient class should look like:

@Named
public class TheaterClient {
   @Resource(lookup="theaterServiceEndpoint")
   private String ENDPOINT;

   private WebResource getClient() {
      final Client client = Client.create();
      return client.resource(ENDPOINT);
   }
   
   public List<Exhibition> getExhibitionByMovie(int movieId) {
      if (null == ENDPOINT) {
         return null;
      }
      
      final List<Exhibition> exhibition = (List<Exhibition>)getClient()
         .path("exhibition")
         .path("q")
         .queryParam("movie", String.valueOf(movieId))
         .accept(MediaType.APPLICATION_XML)
         .get(ClientResponse.class)
         .getEntity(new GenericType<List<Exhibition>>() {});
      
      return exhibition;
   }
}

Now, we must change the SearchManager bean to call the brand new client proxy and add variables to deal with this new data.

Updating the SearchManager bean

The SearchManager class already has methods that list theaters (getTheaters) and movies (getMovies), and now we need to update the bean to include a method that will call TheaterClient and receive a list of available exhibitions of the selected movie:

  1. Open class SearchManager and add two attributes, one to hold the list of exhibitions and another to hold the value of the selected entry from the exhibition drop-down menu (don't worry, it doesn't exist just yet, we're going to create it shortly), along with their respective getters and setters:
    private List<Exhibition> exhibitions;
    private int exhibition;
  2. Inject an instance of TheaterClient into it, marking it as transient to avoid problems later when serializing the instance of SearchManager:
    @Inject
    private transient TheaterClient theaterClient;
  3. Create a method that will handle any changes in the Movie drop-down menu, so every time you select a different movie, this method will be called and the list of exhibitions will be populated or refreshed:
    public void handleMovieChange() {
       if (movie != 0)
          exhibitions = newTheaterClient().getExhibitionByMovie(movie);
       else
          exhibitions = null;
    }

The complete class should look like this:

@Named("search")
@SessionScoped
public class SearchManager implements Serializable {
   private static final long serialVersionUID = 1L;

   @PersistenceContext(unitName="StoreBO")
   EntityManager em;

   @Inject
   private transient TheaterClient theaterClient;
   
   private List<Theater> theaters;
   private List<Movie> movies;
   private List<Exhibition> exhibitions;

   private int movie;
   private int theater;
   private int exhibition;

   // Change listener for Movie selectOneMenu
   public void handleMovieChange() {
      if (movie != 0) {
         exhibitions = theaterClient.getExhibitionByMovie(movie);
      } else {
         exhibitions = null;
      }
   }

   @SuppressWarnings("unchecked")
   public List<Theater> getTheaters() {
      if (theaters == null)
         theaters = em.createNamedQuery(Theater.findAll).
         getResultList();

      return theaters;
   }

   @SuppressWarnings("unchecked")
   public List<Movie> getMovies() {
      if (movies == null)
         movies = em.createNamedQuery(Movie.findAll).
         getResultList();

      return movies;
   }
}

// Other getters and setters omitted

Updating the query page

The web page that displays the search form needs to be updated with the exhibition dates retrieved from the Theater module. To accomplish this without refreshing the whole page, we will rely on some Ajax (Asynchronous JavaScript and XML) features provided by JavaServer Faces. This can be accomplished by firing an Ajax call when the user selects an entry from the Movies drop-down menu:

  1. Open the index.xhtml file and add a form named queryForm between tags p:fieldset and p:panelGrid—this is needed so that the Ajax engine can capture events:
       <p:fieldset legend="Basic Query">
          <h:form id="queryForm">
             <p:panelGrid columns="2">
             ...
             </p:panelGrid>
          </h:form>
  2. Add a p:ajax component inside the p:selectOneMenu tag that shows the movie list. This component needs to inform which method should be called (that is, the event listener), and which component must be updated upon event execution. The component should look like this:
    <p:selectOneMenu id="movie" value="#{search.movie}"style="width: 350px;">
       <f:selectItem itemLabel="Select one" itemValue="0" />
       <f:selectItems value="#{search.movies}" var="n"itemLabel="#{n.name}" itemValue="#{n.id}" />
       <p:ajax process="@this" update="exhibition"listener="#{search.handleMovieChange}" />
    </p:selectOneMenu>
  3. Add another p:selectOneMenu tag to list the exhibitions. It's very important to set the ID of this component to exhibition since it's the value configured in the Ajax event listener in the previous step:
    <h:outputLabel for="exhibition" value="Exhibition:" />
    <p:selectOneMenu id="exhibition"value="#{search.exhibition}" style="width: 350px;">
       <f:selectItem itemLabel="Select one" itemValue="0" />
       <f:selectItems value="#{search.exhibitions}" var="n"itemLabel="#{n.date}" itemValue="#{n.id}"/>
    </p:selectOneMenu>
  4. Save all files and redeploy (publish) the Store application.

The resulting page should look like this:

Updating the query page

The Exhibition drop-down menu is being populated by the results returned by the exhibition RESTful web service, hosted by the Theater application. Every time the movie list changes, a new call is made and the exhibition list is refreshed. For a real-world scenario, many considerations would need to be taken into account, such as latency, caching, security, and other strategies. Some of these strategies will be explored in the following chapters.

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

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