LAB-5542: Project Jersey: Building RESTful Web Services in Java

Expected Duration: 120 minutes

Exercise 3: Consuming RESTful Web Services using Jersey Client API (15 minutes)

 

In this exercise we will see how to consume a RESTful web service using the Jersey Client API. We will see how easily we can send requests to a service and get back a response.

We will create a Java Swing Application, which will consume the jerseyservice we created in the previous exercise. Using this application we will be able to list the system properties, and update/add/delete a particular property.

In the previous exercise we have seen how to create a RESTful Web Service using maven. To show how you can use Jersey without Maven, in this exercise we will download the required Jersey jars manually and use them in an ant-based project.


Steps to Follow

 

Step 1: Creating a Client Project

In order to save some time, the lab provides a pre-built skeleton application, which already contains all of the UI components. The only thing we will be adding during this lab is the business logic. We will start by opening this pre-built project and walking through its structure a bit.

  1. From the NetBeans IDE, open jerseyclient project located in <lab_root>/restwebservice/exercises/exercise3.
  2. What got opened is a simple ant-based project implementing a Swing UI.

    The com.mycompany.jerseyclient package has three classes:
    • MainWindow - Implements the main window of the application containing a list box for listing all the properties and buttons to perform operations on the properties.
    • EditPropWindow - Implements a dialog window used to display/gather user input for a particular property.
    • DataProvider - A simple class containing methods that should perform the actual operations of retrieving, updating and deleting the properties - the UI components delegate to these methods - so this class is the only one we will need to touch.

    All these classes are reasonably documented, so you can browse through their code to find out more.

  3. Let's run the application to get a better idea of how it looks like by right-clicking on "jerseyclient" in the Projects tab and clicking on Run.
  4. The main window will appear. To get list of all properties, the main window calls DataProvider.getPropertyNames() method, which currently always returns hard-coded values - property1, property2 and property3. The same call is made when you click on Refresh button.
  5. Click on New button - the EditPropWindow dialog will appear. You can enter some name and value. Upon clicking OK, a call to DataProvider.setPropertyValue() is made passing the property name and value you entered. Currently this method does nothing. The application also does a refresh (by calling DataProvider.getPropertyNames() to update the list box content).
  6. Select a property from the list and click on Edit button. The same dialog will appear but this time the property name field is read-only. To get the current value of the selected property, the application calls DataProvider.getPropertyValue() passing the property name. This method currently always returns "dummy". Once user changes the value in the dialog and clicks OK, the application calls DataProvider.setPropertyValue() and does a refresh.
  7. Select a property from the list and click Delete. Application asks if you are sure - after clicking OK it calls DataProvider.deleteProperty() (which currently does nothing) and does a refresh.
  8. Exit the application by closing the main window.

Step 2: Adding the Required Libraries to the Classpath

Before we start properly implementing methods of the DataProvider class, we need to make sure we have the required Jersey jar files on the classpath. Every release of Jersey provides a snapshot of the dependencies page showing which libraries you need to depend on when using certain features of Jersey. For developers not using maven, it provides links for downloading the JAR files directly.

We will use the Jersey Client API. To unmarshall the data from XML we will use JAXB (similarly to using it in jerseyservice for marshalling to XML/JSON). As a result, we will need the following jar files for this exercise:

  • jersey-bundle-*.jar - core Jersey classes
  • jsr311-api-*.jar - JAX-RS API
  • jaxb-api-2.1.jar - (needed for JDK5 only) JAXB API
  • jaxb-impl-2.1.10.jar - (needed for JDK5 only) implementation of JAXB API
  • activation-*.jar - (needed for JDK5 only) JAXB dependency
  • stax-api-*.jar - (needed for JDK5 only) JAXB dependency
  • wstx-asl-*.jar - (needed for JDK5 only) JAXB dependency

For your convenience, the needed files can be found in lib directory under the root of jerseyclient project.

Let's add them to the classpath of our project:
  1. Right-click on the Libraries node under the jerseyclient project and choose "Add JAR/Folder..."
  2. In the Add JAR/Folder dialog browse to <lab_root>/restwebservice/exercises/exercise3/jerseyclient/lib directory, select all jars in it and click OK.

    NOTE: As mentioned above, only jersey-bundle and jsr311-api jars are needed when running on JDK6. Please add all jars as suggested in case you are not sure which version of JDK you are running on.

Step 3: Implementing DataProvider Methods

Now we can finally get to the main topic of this exercise. We will use the Jersey Client API to properly implement methods of the DataProvider class.

  1. Open the DataProvider class for editing by double-clicking on it in the Projects tab.
  2. Jersey Client API defines WebResource class that makes it easy to invoke operations on web resources (such as PropertiesResource we developed in the previous exercise). Let's declare a static variable of type WebResource we will use to access the properties resource:
        private static WebResource propsResource = Client.create().resource(
                "http://localhost:8080/jerseyservice/webresources/properties");
    
  3. Now, before we start implementing the individual methods, let's copy the PropertyBean class from the jerseyservice project we developed in the previous exercise by right-clicking on it in the Projects tab, choosing Copy from the pop-up menu and then right-clicking on com.mycompany.jerseyclient package, choosing Paste->Refactor Copy and clicking Refactor in the Copy Class dialog.

    We will use this class for representing a single property. Since it is a JAXB bean, Jersey will be able to automatically unmarshall XML in server responses into its instances.

  4. Get back to the DataProvider class and replace getPropertyNames() method implementation with the following:
            List<PropertyBean> properties = propsResource.accept("application/xml")
                    .get(new GenericType<List<PropertyBean>>() {});
    
            String[] propNames = new String[properties.size()];
            int i = 0;
            for (PropertyBean property : properties) {
                propNames[i] = property.getName();
                i++;
            }
            return propNames;
    
    The call to the REST service is on the first line of this code. We are using the accept() method of WebResource class to indicate what media types our client accepts and then issue an HTTP GET request by calling get() method on the resource. We are indicating what type the response should be unmarshalled into by passing an instance of GenericType representing List<PropertyBean>. This ensures Jersey will try to process the server response using an appropriate reader (in this case JAXB) to construct a result of the requested type - so we can assign the returned result directly to a variable of List<PropertyBean>. The rest of the code is just constructing an array of property names from the list of property beans.
  5. Besides the get() method, WebResource defines methods corresponding to the remaining HTTP methods - most importantly put() and delete(). We can get to a particular sub-resource by calling path() method on a resource. So now it should be straightforward how to implement the remaining methods of DataProvider. Replace the deleteProperty() implementation with the following:
            propsResource.path(propertyName).delete();
    
  6. Replacing getPropertyValue() should also be straightforward:
            PropertyBean property = propsResource.path(propertyName)
                    .accept("application/xml").get(PropertyBean.class);
            return property.getValue();
    
  7. And finally the code for setPropertyValue() method:
            propsResource.path(propertyName).put(propertyValue);
    
  8. The whole class should look as follows:
    package com.mycompany.jerseyclient;
    
    import com.sun.jersey.api.client.Client;
    import com.sun.jersey.api.client.GenericType;
    import com.sun.jersey.api.client.WebResource;
    import java.util.List;
    
    /** Class that handles all the communication with the RESTful web service
     * for manipulating remote system properties.
     */
    public class DataProvider {
        private static WebResource propsResource = Client.create().resource(
                "http://localhost:8080/jerseyservice/webresources/properties");
    
        /** Sets the property of a given name to a given value.
         *
         * @param propertyName Name of the property to set or create.
         * @param propertyValue A new value of the property.
         */
        public static void setPropertyValue(String propertyName, String propertyValue) {
            propsResource.path(propertyName).put(propertyValue);
        }
    
        /** Retrieves the value of a given property.
         *
         * @param propertyName Name of the property to retrieve the value of.
         * @return value of the property.
         */
        public static String getPropertyValue(String propertyName) {
            PropertyBean property = propsResource.path(propertyName)
                    .accept("application/xml").get(PropertyBean.class);
            return property.getValue();
        }
    
        /** Deletes the property of a given name.
         *
         * @param propertyName Name of the property to delete.
         */
        public static void deleteProperty(String propertyName) {
            propsResource.path(propertyName).delete();
        }
    
        /** Retrieves names of all properties.
         *
         * @return array of names of the properties.
         */
        public static String[] getPropertyNames() {
            List<PropertyBean> properties = propsResource.accept("application/xml")
                    .get(new GenericType<List<PropertyBean>>() {});
    
            String[] propNames = new String[properties.size()];
            int i = 0;
            for (PropertyBean property : properties) {
                propNames[i] = property.getName();
                i++;
            }
            return propNames;
        }
    }
    
  9. Now we are done - run the application.
    TROUBLESHOOTING: If the application does not work, check if GlassFish V2 is running and that jerseyservice application has been deployed.
  10. Add a new property named "aaa". After clicking OK in the property dialog, you should see the property added in the list.
  11. Try changing the value of the property by selecting it and clicking Edit. The next time you select the property and click Edit you should see the new value.
  12. Delete the property by clicking Delete. After confirming, observe the property is no longer in the list.
  13. You can play by modifying the properties from the web browser and from the Swing client simultaneously.
    NOTE: Don't modify or delete any of the existing properties. Play only with the ones you added.

This concludes the third exercise.


Summary

 

In this exercise, you saw how the Jersey Client API could be used to consume a RESTful Web Service. You have seen how to:

  1. Get a handle to a web resource.
  2. Build request to a web resource using the path() method.
  3. Send HTTP requests using the get() , put() and delete() methods.
  4. Specify the mime-type in which you want to get the response to a request, using the accept() method.

 

Back to top
To summary