Friday, June 28, 2013

Java REST WebService development examples - Jersey, Google Protocol Buffer, Tomcat combination

An overview:

RESTful architecture is the most popular form of Internet software architecture. It is clearly structured, standards-compliant, easy to understand, easy to expand, so the site is being used more and more.
Google Protocol Buffer (referred Protobuf) is a mixed-language Google's internal data standards, is a lightweight and efficient structured data storage format that can be used to structure data serialization, or serialized. It is very suitable for data storage or RPCdata exchange format. Can be used for communication protocols, data storage and other areas of language-independent, platform-independent, scalable serial data format structure. Currently provides + +, Java, Python three languages ​​of the API.
tomcat Servlet container to the market share of the first and well-known, so this paper spoke of how to use Jersey, Google PB, Tomcat these three magic weapons development REST-style WEB service.

Two environmental structures

jersey version: jersey-archive-1.2-SNAPSHOT 
Google PB Version: protobuf-2.3.0 
tomcat: tomcat6.0 
Eclipse: 3.5.1 + tomcat plug in: http://www.eclipsetotale.com/tomcatPlugin.html 

Three projects since lib

sm-3.1.jar 
jersey-server-1.2-SNAPSHOT.jar 
jackson-core-asl-1.1.1.jar 
jersey-spring-1.2-SNAPSHOT.jar 
jersey-client-1.2-SNAPSHOT.jar 
jettison-1.1.jar 
jersey-core-1.2-SNAPSHOT.jar 
jsr311-api-1.1.1.jar 
jersey-json-1.2-SNAPSHOT.jar 
protobuf-java-2.3.0.jar 
Please jersey of the package and the package to find the pb the lib 
Four hands 
4.1 Create a tomcat project in Eclipse,
The Eclipse workspace for the D :/ workspace: 

addressbook.proto pb comes with the phone message definition file 
compile.bat build scripts to write their own message 
protoc.exe pb compiler command-line tool 
ContactClient.java access REST service's client-side code 
CreatePerson.java generate Person PB write their own structure, and there is D: root directory gadget category 
AddressBookResource REST Service Core Resource Class 
HelloResource.java Hello world Resource Class 
AddressBookStore.java wrote a phonebook storage class server segment to D :/ addressBooks.txt to store files 
AddressBookProtos.java addressbook.proto been compiled PB command-line tool to generate java class 
ProtobufMessageBodyReader.java server sends Request input streams into PB structures Provider class for the user to wear on a byte-stream into the PB structure 
ProtobufMessageBodyWriter.java server into the PB institutions output stream Provider class for the PB structure into a byte stream output to the user
4.3 Code: 

  1. addressbook.proto
  2.   
  3. package demo;
  4.   
  5. option java_package = "sample.pb";
  6. option java_outer_classname = "AddressBookProtos";
  7.   
  8. message Person {
  9. required string name = 1;
  10. required int32 id = 2;
  11. optional string email = 3;
  12.   
  13.    enum PhoneType {
  14. MOBILE = 0;
  15. HOME = 1;
  16. WORK = 2;
  17. }
  18.   
  19. message PhoneNumber {
  20. required string number = 1;
  21. optional PhoneType type = 2 [default = HOME];
  22. }
  23.   
  24. repeated PhoneNumber phone = 4;
  25. }
  26.   
  27. message AddressBook {
  28. repeated Person person = 1;
  29. }

--------------------------------------
compile.bat 
protoc-I = D :/ workspace / jerseydemo / src - java_out = D :/ workspace / jerseydemo / src D :/ workspace / jerseydemo / src / demo / pb / addressbook.proto
--------------------------------------
ContactClient.java 

  1. package sample.hello.client;
  2.   
  3. import java.io.File;
  4. import java.io.FileInputStream;
  5. import java.io.IOException;
  6. import java.io.InputStream;
  7. import java.io.OutputStream;
  8. import java.net.HttpURLConnection;
  9. import java.net.URL;
  10. import java.util.List;
  11.   
  12. import sample.pb.AddressBookProtos.Person;
  13. import sample.pb.AddressBookProtos.Person.PhoneNumber;
  14.   
  15. public   class ContactClient {
  16.       
  17.      public   static   void main (String [] args) throws IOException {
  18. String url1 = "http://localhost:8080/jerseydemo/rest/addressbook/";
  19. putContacts (url1, "hery");
  20. String url2 = "http://localhost:8080/jerseydemo/rest/addressbook/hery";
  21. getContacts (url2);
  22. }
  23.      public   static   void putContacts (String url, String name) throws IOException {
  24. File file = new File ("D :/" + name + ". Per");
  25. Person p = Person.parseFrom (new FileInputStream (file));
  26.          byte [] content = p.toByteArray ();
  27.           
  28. URL target = new URL (url);
  29. HttpURLConnection conn = (HttpURLConnection) target.openConnection ();
  30. conn.setDoOutput (true);
  31. conn.setDoInput (true);
  32. conn.setRequestMethod ("PUT");
  33. conn.setRequestProperty ("Content-Type", "application / x-protobuf");
  34. conn.setRequestProperty ("Accept", "application / x-protobuf; q = 0.5");
  35.           
  36. conn.setRequestProperty ("Content-Length", Integer.toString (content.length));
  37.              / / Set stream mode to decrease memory usage   
  38. conn.setFixedLengthStreamingMode (content.length);
  39. OutputStream out = conn.getOutputStream ();
  40. out.write (content);
  41. out.flush ();
  42. out.close ();
  43. conn.connect ();
  44.          / / Check response code   
  45.          int code = conn.getResponseCode ();
  46.          boolean success = (code> = 200) && (code <300 span="">
  47. System.out.println ("put person:" + name + "" + (success? "Successful!": "Failed!"));
  48. }
  49.      public   static   void getContacts (String url) throws IOException {
  50. URL target = new URL (url);
  51. HttpURLConnection conn = (HttpURLConnection) target.openConnection ();
  52. conn.setDoOutput (true);
  53. conn.setDoInput (true);
  54. conn.setRequestMethod ("GET");
  55. conn.setRequestProperty ("Content-Type", "application / x-protobuf");
  56. conn.setRequestProperty ("Accept", "application / x-protobuf");
  57. conn.connect ();
  58.          / / Check response code   
  59.          int code = conn.getResponseCode ();
  60.          boolean success = (code> = 200) && (code <300 span="">
  61. InputStream in = success? Conn.getInputStream (): conn.getErrorStream ();
  62.                   
  63.          int size = conn.getContentLength ();
  64.           
  65.          byte [] response = new   byte [size];
  66.          int curr = 0, read = 0;
  67.           
  68.          while (curr
  69. read = in.read (response, curr, size - curr);
  70.              if (read <= 0) break;
  71. curr + = read;
  72. }
  73.           
  74. Person p = Person.parseFrom (response);
  75. System.out.println ("id:" + p.getId ());
  76. System.out.println ("name:" + p.getName ());
  77. System.out.println ("email:" + p.getEmail ());
  78. List pl = p.getPhoneList ();
  79.          for (PhoneNumber pn: pl) {
  80. System.out.println ("number:" + pn.getNumber () + "type:" + pn.getType (). Name ());
  81. }
  82. }
  83. }
CreatePerson.java 

  1. package sample.hello.client;
  2.   
  3. import java.io.BufferedReader;
  4. import java.io.FileOutputStream;
  5. import java.io.IOException;
  6. import java.io.InputStreamReader;
  7. import java.io.PrintStream;
  8.   
  9. import sample.pb.AddressBookProtos.Person;
  10.   
  11.   
  12.   
  13. public   class CreatePerson {
  14.      / / This function fills in a Person message based on user input.   
  15.        static Person create (BufferedReader stdin,
  16. PrintStream stdout) throws IOException {
  17. Person.Builder person = Person.newBuilder ();
  18.   
  19. stdout.print ("Enter person ID:");
  20. person.setId (Integer.valueOf (stdin.readLine ()));
  21.   
  22. stdout.print ("Enter name:");
  23. person.setName (stdin.readLine ());
  24.   
  25. stdout.print ("Enter email address (blank for none):");
  26. String email = stdin.readLine ();
  27.          if (email.length ()> 0) {
  28. person.setEmail (email);
  29. }
  30.   
  31.          while (true) {
  32. stdout.print ("Enter a phone number (or leave blank to finish):");
  33. String number = stdin.readLine ();
  34.            if (number.length () == 0) {
  35.              break;
  36. }
  37.   
  38. Person.PhoneNumber.Builder phoneNumber =
  39. Person.PhoneNumber.newBuilder (). SetNumber (number);
  40.   
  41. stdout.print ("Is this a mobile, home, or work phone?");
  42. String type = stdin.readLine ();
  43.            if (type.equals ("mobile")) {
  44. phoneNumber.setType (Person.PhoneType.MOBILE);
  45. Else   if (type.equals ("home")) {
  46. phoneNumber.setType (Person.PhoneType.HOME);
  47. Else   if (type.equals ("work")) {
  48. phoneNumber.setType (Person.PhoneType.WORK);
  49. Else {
  50. stdout.println ("Unknown phone type. Using default.");
  51. }
  52.   
  53. person.addPhone (phoneNumber);
  54. }
  55.   
  56.          return person.build ();
  57. }
  58.   
  59.        / / Main function: Reads the entire address book from a file,   
  60.        / / Adds one person based on user input, then writes it back out to the same   
  61.        / / File.   
  62.        public   static   void main (String [] args) throws Exception {
  63.          
  64. Person p = create (new BufferedReader (new InputStreamReader (System.in)),
  65. System.out);
  66.   
  67.          / / Write the new address book back to disk.   
  68. FileOutputStream output = new FileOutputStream ("D :/" + p.getName () + ". Per");
  69. p.writeTo (output);
  70. output.close ();
  71. }
  72. }
AddressBookResource.java 

  1. package sample.hello.resources;
  2.   
  3. import javax.ws.rs.GET;
  4. import javax.ws.rs.PUT;
  5. import javax.ws.rs.Path;
  6. import javax.ws.rs.PathParam;
  7. import javax.ws.rs.core.Response;
  8.   
  9. import sample.hello.util.AddressBookStore;
  10. import sample.pb.AddressBookProtos.Person;
  11.   
  12.   
  13.   
  14. @ Path ("/ addressbook")
  15. public   class AddressBookResource {
  16.      @ PUT     
  17.      public Response putPerson (Person person) {
  18. AddressBookStore.store (person);
  19.          return Response.ok (). build ();
  20. }
  21.       
  22.      @ GET     
  23.      @ Path ("/ {name}")
  24.      public Response getPerson (@ PathParam ("name") String name) {
  25. Person p = AddressBookStore.getPerson (name);
  26.          return Response.ok (p, "application / x-protobuf"). build ();
  27. }
  28. }
AddressBookStore.java 
  1. package sample.hello.util;
  2.   
  3. import java.io.File;
  4. import java.io.FileInputStream;
  5. import java.io.FileNotFoundException;
  6. import java.io.FileOutputStream;
  7. import java.io.IOException;
  8.   
  9. import sample.pb.AddressBookProtos.AddressBook;
  10. import sample.pb.AddressBookProtos.Person;
  11.   
  12. public   class AddressBookStore {
  13.      static AddressBook addressBook = null;
  14.      static {
  15.          try {
  16. addressBook =
  17. AddressBook.parseFrom (new FileInputStream ("D :/ addressBooks.txt"));
  18. Catch (FileNotFoundException e) {
  19.               
  20. e.printStackTrace ();
  21. Catch (IOException e) {
  22. e.printStackTrace ();
  23. }
  24. }
  25.       
  26.      public   static Person getPerson (String name) {
  27.          for (Person person: addressBook.getPersonList ()) {
  28.              if (person.getName (). equals (name)) {
  29.                  return person;
  30. }
  31. }
  32.          return   null;
  33. }
  34.       
  35.      public   static   void store (Person p) {
  36. AddressBook.Builder addressBookBuilder = AddressBook.newBuilder ();
  37.           try {
  38. String fileName = "D :/ addressBooks.txt";
  39. File file = new File (fileName);
  40.              if (! file.exists ()) {
  41. file.createNewFile ();
  42. }
  43. addressBookBuilder.mergeFrom (new FileInputStream (fileName));
  44. addressBookBuilder.addPerson (p);
  45. addressBookBuilder.build (). writeTo (new FileOutputStream (fileName));
  46. Catch (FileNotFoundException e) {
  47. e.printStackTrace ();
  48. Catch (IOException e) {
  49. e.printStackTrace ();
  50. }
  51. }
AddressBookProtos.java automatically generated slightly 
ProtobufMessageBodyReader.java 
  1. package sample.pb;
  2.   
  3. import java.io.ByteArrayOutputStream;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.lang.annotation.Annotation;
  7. import java.lang.reflect.Type;
  8. import javax.ws.rs.Consumes;
  9. import javax.ws.rs.WebApplicationException;
  10. import javax.ws.rs.core.MediaType;
  11. import javax.ws.rs.core.MultivaluedMap;
  12. import javax.ws.rs.ext.MessageBodyReader;
  13. import javax.ws.rs.ext.Provider;
  14.   
  15. import sample.pb.AddressBookProtos.Person;
  16.   
  17.   
  18. @ Provider     
  19. @ Consumes ("application / x-protobuf")
  20. public   class ProtobufMessageBodyReader implements MessageBodyReader {
  21.      @ Override     
  22.      public   boolean isReadable (Class type, Type genericType, Annotation [] annotations,
  23. MediaType mediaType) {
  24.          return mediaType.toString (). equals ("application / x-protobuf");
  25. }
  26.   
  27.      @ Override     
  28.      public Object readFrom (Class type, Type genericType,
  29. Annotation [] annotations, MediaType mediaType,
  30. MultivaluedMap httpHeaders, InputStream inputStream)
  31.              throws IOException, WebApplicationException {
  32. ByteArrayOutputStream baos = new ByteArrayOutputStream ();
  33.          byte [] buffer = new   byte [4096];
  34.          int read;
  35.          long total = 0L;
  36.          do {
  37. read = inputStream.read (buffer, 0, buffer.length);
  38.              if (read> 0) {
  39. baos.write (buffer, 0, read);
  40. total + = read;
  41. }
  42. While (read> 0);
  43.   
  44.          return Person.parseFrom (baos.toByteArray ());
  45. }
  46. }
ProtobufMessageBodyWriter.java 
  1. package sample.pb;
  2.   
  3. import java.io.IOException;
  4. import java.io.OutputStream;
  5. import java.lang.annotation.Annotation;
  6. import java.lang.reflect.Type;
  7. import java.util.Map;
  8. import java.util.WeakHashMap;
  9.   
  10. import javax.ws.rs.Produces;
  11. import javax.ws.rs.WebApplicationException;
  12. import javax.ws.rs.core.MediaType;
  13. import javax.ws.rs.core.MultivaluedMap;
  14. import javax.ws.rs.ext.MessageBodyWriter;
  15. import javax.ws.rs.ext.Provider;
  16.   
  17. import sample.pb.AddressBookProtos.Person;
  18.   
  19. @ Provider     
  20. @ Produces ("application / x-protobuf")
  21. public   class ProtobufMessageBodyWriter implements MessageBodyWriter {
  22.      / ** A cache to save the cost of duplicated call (getSize, writeTo) to one object. * /     
  23.      private Map byte []> buffer = new WeakHashMap byte []>
 ();
  •       
  •      @ Override     
  •      public   boolean isWriteable (Class type, Type genericType, Annotation [] annotations,
  • MediaType mediaType) {
  •          / / It will handle all model classes   
  •          return mediaType.toString (). equals ("application / x-protobuf");
  • }
  •       
  •      @ Override     
  •      public   long getSize (Object message, Class type, Type genericType,
  • Annotation [] annotations, MediaType mediaType) {
  • Person p = (Person) message;
  •          byte [] bytes = p.toByteArray ();
  • buffer.put (message, bytes);
  •          return bytes.length;
  • }
  •   
  •      @ Override     
  •      public   void writeTo (Object message, Class type, Type genericType,
  • Annotation [] annotations, MediaType mediaType,
  • MultivaluedMap httpHeaders, OutputStream entityStream)
  •              throws IOException, WebApplicationException {
  • entityStream.write (buffer.remove (message));
  • }
  • }
  • web.xml 
    1.  Xml   version = "1.0"   encoding = "UTF-8"?>     
    2.   
    3.    xmlns = "http://java.sun.com/xml/ns/javaee"   xmlns: xsi = "http://www.w3.org/2001/XMLSchema-instance"     
    4.      xsi: schemaLocation = "http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"     
    5.      version = "2.5">     
    6.           
    7.           ServletAdaptor </ servlet-name>     
    8.           com.sun.jersey.server.impl.container.servlet.ServletAdaptor </ servlet-class>     
    9.           1 </ load-on-startup>     
    10.      </ Servlet>     
    11.   
    12.           
    13.           ServletAdaptor </ servlet-name>     
    14.           / rest / * </ url-pattern>     
    15.      </ Servlet-mapping>     
    16.   
    17. </ Web-app>     

    Five testing process: 
    5.1

    Set the web application's context name is: 
    / Jerseydemo 
    The root for the web application 
    / Context 
    Using Eclipse tomcat plugin menu
    In% TOMACT_HOME% \ conf \ Catalina \ localhost generate documents: 
    jerseydemo.xml 
    Reads as follows: 
     
    5.2 Running CreatePerson generate Person and written to disk: 
    View D: root directory, discover new generation hery.per file.

    5.3 Start tomcat (I was on the point under the Eclipse kitten)
    5.4 Run ContactClient, perform the following results
    his shows that we uploaded successfully, and can query by name. 
    D root directory, while generating a file addressBooks.txt, this is the place to keep the phonebook server segment.

    Six complete engineering package file



    Modify the downloaded three files named
    jerseydemo.part1.rar
    jerseydemo.part2.rar
    jerseydemo.part3.rar
    Then extract