September 2nd, 2017

Web services in Java SE, Part 3: Creating RESTful Web services

Core Java, Java Language, Learn Java, Libraries and Frameworks, others, Programing, by admin.

Part 2 of this four-part series on Java SE Web services showed how to use the JAX-WS API to develop SOAP-based Web services. JAX-WS also supports RESTful-based Web services, which this article shows how to develop. It first defines and then builds and runs a library Web service, and next defines, builds, and runs a simple client that accesses this service.

Defining a library web service

The library Web service, which I’ve named Library, manages a library of books with their authors. It consists of a main Library class along with supporting Book and Author classes.

Exploring the Library class

The Library class manages the four HTTP operations (DELETE, GET, POST, and PUT) that are the hallmark of a RESTful Web service and which, in this example, handle requests to delete a specific book (identified via its ISBN) or all books, get a specific book (identified via its ISBN) or the ISBNs of all books, insert a new book, or update an existing book. Listing 1 presents this class’s source code.

Listing 1. Library’s endpoint class

import java.beans.XMLDecoder;
import java.beans.XMLEncoder; import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringReader; import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set; import javax.annotation.Resource; import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.stream.StreamSource; import javax.xml.ws.BindingType;
import javax.xml.ws.Endpoint;
import javax.xml.ws.Provider;
import javax.xml.ws.ServiceMode;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.WebServiceProvider; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.http.HTTPBinding;
import javax.xml.ws.http.HTTPException; import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory; import org.w3c.dom.NodeList; @WebServiceProvider
@ServiceMode(value = javax.xml.ws.Service.Mode.MESSAGE)
@BindingType(value = HTTPBinding.HTTP_BINDING)
public class Library implements Provider
{ private final static String LIBFILE = "library.ser"; @Resource private WebServiceContext wsContext; private Map library; Library() { try { library = deserialize(); } catch (IOException ioe) { library = new HashMap<>(); } } @Override public Source invoke(Source request) { if (wsContext == null) throw new RuntimeException("dependency injection failed on wsContext"); MessageContext msgContext = wsContext.getMessageContext(); switch ((String) msgContext.get(MessageContext.HTTP_REQUEST_METHOD)) { case "DELETE": return doDelete(msgContext); case "GET" : return doGet(msgContext); case "POST" : return doPost(msgContext, request); case "PUT" : return doPut(msgContext, request); default : throw new HTTPException(405); } } private Source doDelete(MessageContext msgContext) { try { String qs = (String) msgContext.get(MessageContext.QUERY_STRING); if (qs == null) { library.clear(); serialize(); StringBuilder xml = new StringBuilder(""); xml.append("all books deleted"); return new StreamSource(new StringReader(xml.toString())); } else { String[] pair = qs.split("="); if (!pair[0].equalsIgnoreCase("isbn")) throw new HTTPException(400); String isbn = pair[1].trim(); library.remove(isbn); serialize(); StringBuilder xml = new StringBuilder(""); xml.append("book deleted"); return new StreamSource(new StringReader(xml.toString())); } } catch (IOException ioe) { throw new HTTPException(500); } } private Source doGet(MessageContext msgContext) { String qs = (String) msgContext.get(MessageContext.QUERY_STRING); if (qs == null) { Set keys = library.keySet(); Iterator iter = keys.iterator(); StringBuilder xml = new StringBuilder(""); xml.append(""); while (iter.hasNext()) xml.append("" + iter.next() + ""); xml.append(""); return new StreamSource(new StringReader(xml.toString())); } else { String[] pair = qs.split("="); if (!pair[0].equalsIgnoreCase("isbn")) throw new HTTPException(400); String isbn = pair[1].trim(); Book book = library.get(isbn); if (book == null) throw new HTTPException(404); StringBuilder xml = new StringBuilder(""); xml.append(""); xml.append("" + book.getTitle() + ""); for (Author author: book.getAuthors()) xml.append("" + author.getName() + ""); xml.append("" + book.getPublisher() + ""); xml.append(""); return new StreamSource(new StringReader(xml.toString())); } } private Source doPost(MessageContext msgContext, Source source) { try { DOMResult dom = new DOMResult(); Transformer t = TransformerFactory.newInstance().newTransformer(); t.transform(source, dom); XPathFactory xpf = XPathFactory.newInstance(); XPath xp = xpf.newXPath(); NodeList books = (NodeList) xp.evaluate("/book", dom.getNode(), XPathConstants.NODESET); String isbn = xp.evaluate("@isbn", books.item(0)); if (library.containsKey(isbn)) throw new HTTPException(400); String pubYear = xp.evaluate("@pubyear", books.item(0)); String title = xp.evaluate("title", books.item(0)).trim(); String publisher = xp.evaluate("publisher", books.item(0)).trim(); NodeList authors = (NodeList) xp.evaluate("author", books.item(0), XPathConstants.NODESET); List auths = new ArrayList<>(); for (int i = 0; i < authors.getLength(); i++) auths.add(new Author(authors.item(i).getFirstChild() .getNodeValue().trim())); Book book = new Book(isbn, title, publisher, pubYear, auths); library.put(isbn, book); serialize(); } catch (IOException | TransformerException e) { throw new HTTPException(500); } catch (XPathExpressionException xpee) { throw new HTTPException(400); } StringBuilder xml = new StringBuilder(""); xml.append("book inserted"); return new StreamSource(new StringReader(xml.toString())); } private Source doPut(MessageContext msgContext, Source source) { try { DOMResult dom = new DOMResult(); Transformer t = TransformerFactory.newInstance().newTransformer(); t.transform(source, dom); XPathFactory xpf = XPathFactory.newInstance(); XPath xp = xpf.newXPath(); NodeList books = (NodeList) xp.evaluate("/book", dom.getNode(), XPathConstants.NODESET); String isbn = xp.evaluate("@isbn", books.item(0)); if (!library.containsKey(isbn)) throw new HTTPException(400); String pubYear = xp.evaluate("@pubyear", books.item(0)); String title = xp.evaluate("title", books.item(0)).trim(); String publisher = xp.evaluate("publisher", books.item(0)).trim(); NodeList authors = (NodeList) xp.evaluate("author", books.item(0), XPathConstants.NODESET); List auths = new ArrayList<>(); for (int i = 0; i < authors.getLength(); i++) auths.add(new Author(authors.item(i).getFirstChild() .getNodeValue().trim())); Book book = new Book(isbn, title, publisher, pubYear, auths); library.put(isbn, book); serialize(); } catch (IOException | TransformerException e) { throw new HTTPException(500); } catch (XPathExpressionException xpee) { throw new HTTPException(400); } StringBuilder xml = new StringBuilder(""); xml.append("book updated"); return new StreamSource(new StringReader(xml.toString())); } private Map deserialize() throws IOException { try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(LIBFILE)); XMLDecoder xmld = new XMLDecoder(bis)) { @SuppressWarnings("unchecked") Map result = (Map) xmld.readObject(); return result; } } private void serialize() throws IOException { try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(LIBFILE)); XMLEncoder xmle = new XMLEncoder(bos)) { xmle.writeObject(library); } } public static void main(String[] args) { Endpoint.publish("http://localhost:9902/library", new Library()); }
}

Listing 1 relies on various Java XML APIs such as DOM and XPath. If you’re unfamiliar with these APIs, you might want to check out my Java XML and JSON book (advertised at the end of this post).

Back Top

Leave a Reply