Chapter 34

Working with RESTful Web Services

In the nineties the Web became widely used, and newly created web applications were consumed by millions of people around the world. At the same time lots of legacy applications were available for use only within corporate walls. They were written in a variety of programming languages and deployed on a plethora of types of hardware. There was a need to expose corporate data to wider audiences, which resulted in the creation of the standard interface for consuming data over the Web.

The SOAP Web Services

The first standard for publishing and consuming web services was the XML-based Simple Object Access Protocol (SOAP). Web clients would form HTTP requests and receive responses using the SOAP syntax.

The difference between traditional JSP/Servlet/JSF web applications and web services is that the latter offer just the data and have no interest in what the client’s UI will look like. For example, an insurance company could offer information about its products, or a mutual fund could expose its data as a web service returning XML documents. Clients didn’t need to know that this insurance company was running its applications using a server from Sun Microsystems or that the mutual fund was running its on mainframe computers from IBM. The clients needed to know the directory of services available from this particular organization and the address of the endpoint to connect to in order to consume this service.

The directory of services could be published with the XML-based Web Services Description Language (WSDL), which is pretty verbose. In the Java world, SOAP messages could be processed by means of JAX-WS without the need for a directory of services.

Even though SOAP web services are verbose, they are still widely used as a simple means of integration with the software produced by third parties. Some SOAP services are publicly available. For example, the web page www.webservicex.net offers descriptions and WSDL locations of such information and services as weather forecasts, US address verification, currency converters, and stock quotes. You can integrate these into your application, but providing a user interface for them remains your responsibility.

The RESTful Web Services

As opposed to SOAP, REST is not a protocol, but a lighter-than-SOAP means of building web services, or, to be precise, REST is an architectural style Dr. Roy Fielding identified the REST principles in his PhD dissertation. A web service built on REST principles is called a RESTful web service.

Java EE 6 specification includes the JAX-RS API for creating RESTful web services. Several Java application servers already implement JAX-RS. I’ll continue using GlassFish v3, which comes with the JAX-RS implementation known as Jersey, and you won’t need to download any additional libraries to run the sample code from this lesson. Other popular open-source JAX-RS implementations are Apache Wink and JBoss RESTEasy.

REST stands for representational state of transfer. REST defines a set of constraints that an application must comply to, and web resources that the user may need to work with.

A resource is anything that you can access with a hyperlink. Each resource has a uniform resource identifier (URI), such as http://localhost:8080/StockServer or www.dice.com/yakovsresume.pdf. These URIs represent the state of a stock server and Yakov’s résumé, respectively.

REST resources have to support standard stateless requests. But if a typical web application uses only the HTTP methods GET for reading the resource and POST for updating it, in the RESTful world you can also use PUT for resource creation or updates and DELETE for resource removal. Web application developers often freely use both GET and POST for reading data, but REST is stricter about this.

The RESTful Stock Server

In this section I’ll redesign the familiar stock server example using REST. The representation of the resources (in this case stocks) can vary and is determined by media type.

With Java EE 6, creating a RESTful application is pretty straightforward — create a POJO and annotate it. For example, annotating a Java bean with @XmlRootElement can bring into action the JAXB framework for processing XML, which will turn the bean into an XML document before sending it to the web client. Listing 34-1 shows a Java bean called Stock annotated with @XmlRootElement.

download.eps

Listing 34-1: Root class Stock

import javax.xml.bind.annotation.XmlRootElement;
 
@XmlRootElement
public class Stock {
    private String symbol;
    private Double price;
    private String currency;
    private String country;
 
    public Stock() {
    }
 
    public Stock(String symbol,Double price, String currency, String country) {
        this.symbol = symbol;
        this.price = price;
        this.currency = currency;
        this.country = country;
    }
 
    public String getSymbol() {
        return symbol;
    }
 
    public void setSymbol(String symbol) {
        this.symbol = symbol;
    }
 
    public Double getPrice() {
        return price;
    }
 
    public void setPrice(Double price) {
        this.price = price;
    }
 
    public String getCurrency() {
        return currency;
    }
 
    public void setCurrency(String currency) {
        this.currency = currency;
    }
 
    public String getCountry() {
        return country;
    }
 
    public void setCountry(String country) {
        this.country = country;
    }
}

Here’s an example of how a RESTful service (Listing 34-2) may return the representation of a particular stock that’s identified by the URI http://localhost:8080/Lesson34/resources/stock/IBM:

<stock>
  <country>US</country>
  <currency>USD</currency>
  <price>43.12</price>
  <symbol>IBM</symbol>
</stock>

From the standpoint of RESTful Web service, the preceding XML code fragment is more important than the Java code in Listing 34-1. The latter is an implementation detail. It’s the actual representation expressed here in XML that really matters.

Just to reiterate the concept of resources and URIs, the stock MSFT is considered another resource and can be represented by the URI http://localhost:8080/Lesson34/resources/stock/MSFT. The class StockResource is a POJO, but if you’d like to turn it into an EJB, just annotate it with the @Stateless annotation.

The class StockResource is heavily sprinkled with annotations. First comes the annotation @Path, which can be used with either a class or a method. JAX-RS maps client’s requests to class methods. If more than one annotation $Path are used in a class, their values are going to be concatenated for finding the matching method.

In our example in Listing 34-2, during the client’s request the class-level @Path("/stock") results in the routing of each request containing /stock in its URI to the class StockResource. Then the matching process continues, and if there is a stock symbol after the word stock, (e.g., /stock/MSFT), the method-level @Path("{symbol}")will map the getStock() method for processing. The @PathParam("symbol") will inject the stock symbol included in the URI into the symb argument of the method getStock().

The addStock() method in Listing 34-2 is annotated to consume the form data and is called when the Add button in the web client (see Figure 34-1) is clicked. The @FormParam annotation injects the values entered in the HTML form into the method addStock(). If the web client isn’t using a form but instead is using an HTTP GET request with parameters, you have to use the annotation @QueryParam instead of @FormParam.

download.eps

Listing 34-2: REST resource StockResource

import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
 
@Path("/stock")
public class StockResource {
    
    @Produces({"application/xml", "application/json"})
    @Path("{symbol}")
    @GET
    public Stock getStock(@PathParam("symbol") String symb) {
 
        Stock stock = StockService.getStock(symb);
 
        if (stock == null) {
            return new Stock("NOT FOUND", 0.0, "--", "--");
        }
 
        return stock;
    }
 
    @POST
    @Consumes("application/x-www-form-urlencoded")
    public Response addStock(@FormParam("symbol") String symb,
                             @FormParam("currency") String currency,
                             @FormParam("price") String price,
                             @FormParam("country") String country) {
 
        if (StockService.getStock(symb) != null)
            return Response.status(Response.Status.BAD_REQUEST).
                    entity("Stock " + symb + 
                    " already exists").type("text/plain").build();
 
        double priceToUse;
        try {
            priceToUse = new Double(price);
        }
        catch (NumberFormatException e) {
            priceToUse = 0.0;
        }
 
        StockService.addStock(new Stock(symb, priceToUse, 
                                                  currency, country));
 
        return Response.ok().build();
    }
}

One of the methods in StockResource is marked with a @GET annotation and the other one with @POST. You’ve guessed it right — they will automatically be invoked to process the corresponding HTTP requests. The MIME types specified in the annotation @Produces mean that the method getStock() can produce the data in either XML format or JSON format. In REST terminology, you can say that the StockResource resource supports two representations — JSON and XML. JSON stands for JavaScript Object Notation; it can be used as a lighter alternative to XML.

JSON is popular with web clients written in JavaScript (see Listing 34-5 for the sample code). There are JSON parsers for programming languages other than JavaScript languages, including Java. Here’s an example of the data in JSON format, which clearly requires less overhead to represent the object Stock than XML does:

"stock": {
  "country": "US",
  "currency": "USD",
  "price": 43.12,
  "symbol": "IBM"
}
note.ai

The public community domain www.geonames.org enables you to search for geographical and statistical information about countries, cities, et cetera. This website uses RESTful web services for the most part. To compare how the same data is represented in XML and in JSON, visit this web page: www.geonames.org/export/ws-overview.html.

The class StockResource is using the helper class StockService, shown in Listing 34-3. For simplicity, this class has two hard-coded stocks, but in the real world it would be connected to one of the financial data feeds. This class uses static initializer, which calls the method generateStocks() on the first reference to StockService.

download.eps

Listing 34-3: StockService class

import java.util.HashMap;
import java.util.Map;
 
public class StockService {
    public static void addStock(Stock stock) {
        stocks.put(stock.getSymbol(), stock);
    }
 
    public static void removeStock(String symbol) {
        stocks.remove(symbol);
    }
 
    public static Stock getStock(String symbol) {
        return stocks.get(symbol);
    }
 
    private static Map<String, Stock> stocks = new HashMap<String, Stock>();
 
    static {
        generateStocks();
    }
 
    private static void generateStocks() {
        addStock(new Stock("IBM", 43.12, "USD", "US"));
        addStock(new Stock("APPL", 320.0, "USD", "US"));
     }
}

The web.xml file from Listing 34-4 is configured to redirect all HTTP requests that contain the pattern /resource to com.sun.jersey.spi.container.servlet.ServletContainer, the Jersey implementation class.

download.eps

Listing 34-4: web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
  http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
 
    <servlet>
        <servlet-name>Rest</servlet-name>
        <servlet-class>
           com.sun.jersey.spi.container.servlet.ServletContainer
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Rest</servlet-name>
        <url-pattern>/resources/*</url-pattern>
    </servlet-mapping>
</web-app>

Next comes the thin web client written in HTML and JavaScript, which is not covered in this book. I’ll just highlight the relevant code fragments to explain the client/server communication in the stock server example. Listing 34-5 shows the index.html file, which includes the popular JavaScript library JQuery (see the reference in the <head> section).

download.eps

Listing 34-5: Thin web client index.html

<!DOCTYPE html>
<html>
 
<head>
    <title>Rest + JSON</title>
    <link rel="stylesheet" type="text/css" href="css/main.css"/>
 
    <script src="http://code.jquery.com/jquery-1.4.4.js">
    </script>
</head>
 
<body>
 
<p class="title">Find Stock</p>
 
<form id="get-stock" action="javascript:alert('submit')">
    <input id="get-stock-symbol" type="text"/>
    <input class="button" type="submit" value="Find"/>
</form>
 
<div class="result">
<table>
    <tr>
        <td>Symbol</td>
        <td id="symbol"></td>
    </tr>
    <tr>
        <td>Price</td>
        <td id="price"></td>
    </tr>
    <tr>
        <td>Currency</td>
        <td id="currency"></td>
    </tr>
    <tr>
        <td>Country</td>
        <td id="country"></td>
    </tr>
</table>
</div>
 
<p class="title">Add new Stock</p>
 
<div id="add-stock-flash-message" class="flash-message">
</div>
 
<form id="add-stock" action="javascript:alert('submit')">
    <fieldset>
        <ol>
            <li>
                <label for="add-stock-symbol">Symbol</label>
                <input id="add-stock-symbol" name="symbol" type="text"/>
            </li>
            <li>
                <label for="add-stock-currency">Currency</label>
                <input id="add-stock-currency" name="currency" type="text"/>
            </li>
            <li>
                <label for="add-stock-price">Price</label>
                <input id="add-stock-price" name="price" type="text"/>
            </li>
            <li>
                <label for="add-stock-country">Country</label>
                <input id="add-stock-country" name="country" type="text"/>
            </li>
            <li>
                <input class="button" type="submit" value="Add"/>
            </li>
        </ol>
    </fieldset>
</form>
 
<script>
    $('.result').hide();
    $('#add-stock-flash-message').hide();
 
    $("#get-stock").submit(function() {
        $.getJSON('resources/stock/' + $("#get-stock-symbol").val(),   
      function(data) {
 
            $('.result').fadeOut(500, function(){
                $('#symbol').html(data.symbol);
                $('#price').html(data.price);
                $('#currency').html(data.currency);
                $('#country').html(data.country);
 
                $('.result').fadeIn(500)
            });
        });
 
        return false;
    });
 
    $("#add-stock").submit(function() {
 
        $.ajax({
            type: "POST",
            url: 'resources/stock',
            data: $("#add-stock").serialize(),
 
            success: function() {
                $("#add-stock-flash-message").show().html(
                          "Stock was added").fadeOut(5000);
            },
 
            error: function(request, textStatus, errorThrown) {
                if (textStatus == 'error') {
                    $("#add-stock-flash-message")
                      .show().html(request.responseText).fadeOut(5000);
                }
                else {
                    $("#add-stock-flash-message")
                      .show().html("Server error").fadeOut(5000);
                }
            }
        });
 
        return false;
    });
</script>
 
</body>
</html>

This HTML/JavaScript client can be invoked in such a way as to request a resource represented either as JSON or as XML. To get the data in JSON format, simply direct your web browser to http://localhost:8080/Lesson34/index.html. When you press the Find button on the form shown in Figure 34-1, the code in index.html calls the function getJSON(), which creates the pattern resources/stock , concatenates the entered stock symbol, and sends the request to the server. In the following JQuery code fragment get-stock is the ID of the top HTML form being submitted to the server:

$("#get-stock").submit(function() {
        $.getJSON('resources/stock/' + $("#get-stock-symbol").val(),   
      function(data) {
...
});

The function getJSON() has requested the resource Stock in JSON format. Even though the Java bean Stock has been annotated with @XmlRootElement, JAXB can represent it not only as XML, but also as JSON.

To test the XML branch, enter a URL containing the pattern /resources that was used in the web.xml file from Listing 34-4. For example, the URL http://localhost:8080/Lesson34/resources/stock/IBM will return this REST resource as XML, as shown in Figure 34-2.

In this use case the code from the file index.html is not being used, and the request is redirected to the function getStock() of StockResource. The function getStock() is capable of producing both JSON and XML, but this time it produces plain web browser’s code that knows how to consume XML only, and so JAX-RS picked up the XML format as a common denominator.

Try It

Your assignment is to make the code shown in the listings work. You’ll need to create an Eclipse project and copy to the proper places the code samples from the accompanying DVD (Listings 34-1 to 34-5). Then you’ll need to deploy this project in GlassFish and run it.

Lesson Requirements

You should have Java and GlassFish v3 server installed.

note.ai

You can download the code and resources for this Try It from the book’s web page atwww.wrox.com. You can find them in the Lesson34 folder in the download.

Hints

Eclipse IDE for Java EE Developers has a template for the creation of REST resources. Right-click the project name, select New, and then select RESTful Web Service From Pattern (Java EE 6). Eclipse will create for you an annotated class similar to the one from Listing 34-2, which you can edit to meet your application’s requirements.

Step-by-Step

1. Create a dynamic web project called Lesson34 in Eclipse. Then create a package called com.practicaljava.lesson34.

2. Copy the classes Stock, StockResource, and StockService from the DVD into this package.

3. Copy the file web.xml shown in Listing 34-4 to the directory WebContent/WEB-INF.

4. Create the folder WebContent/css and copy to it the file main.css from the DVD — this will add some colors to the client’s UI.

5. Deploy the project Lesson34 under GlassFish — right-click the server name, select Add and Remove, and in the pop-up window move Lesson34 from the left box to the right one by clicking Add. Then click Finish.

6. Open a web browser and go to http://localhost:8080/Lesson34/, which will open the file index.html from Listing 34-5. You’ll see something similar to Figure 34-1.

7. Enter IBM in the search field and click Find. The pricing information (hard-coded) about this stock will be displayed as in Figure 34-3.

8. Test the Add New Stock functionality by filling out the form shown in Figure 34-3 and clicking Add. This will make a POST request to the RESTful service, which will be mapped to the method addStock() of StockResource from Listing 34-2. After the new stock has been added you can search for it by entering its name in the search field and clicking Find.

cd.ai

Please select Lesson 34 on the DVD with the print book, or watch online at www.wrox.com/go/fainjava to view the video that accompanies this lesson.

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

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