CS639 Programming Assignment 3:  REST Web Service Clients

Due Monday, April 29, in one partner’s pa3 directory (other partner has README pointing to solution)

Featuring

·         Writing Java Client code for REST Web services

·         Programming with the Jersey client library for REST Web services

·         Using REST Web services implemented in the supplied JAX-RS/Jersey orderService project

·         Programming with JAXB to bridge between POJOs and XML, even (slowly) changing XML

·         or Programming with DOM to handle XML that changes from week to week

·         Pair programming: get a partner! (not required)

Write a Java client, not a web app itself, that interacts with the user to find out what coffee order they want, just one item for simplicity. Then it posts the order to orderService. After this, it asks the user if they would like to check the order status, and does so when the user agrees. If the order is not yet ready, the program asks the user again if they would like to check the status, and so on, until the order is ready or the user quits.  That’s the general idea, but prompted user input is not easily automated with our tools, so we’ll use an even more user-unfriendly UI as follows.

 

The user can find out the coffee options as follows:

 

java TakeOrder1 help

For your coffee-drinking pleasure, we offer:

Choice of location: TAKEAWAY, IN_STORE

Choice of drink: ESPRESSO, LATTE, CAPPUCCINO, FLAT_WHITE

Choice of size: SMALL, MEDIUM, LARGE

Choice of milk: WHOLE, SKIM, SEMI, NONE

Please order as follows (for example) java TakeOrder1 location=TAKEAWAY drink=LATTE size=LARGE milk=SKIM

 

Then the user runs the program again to place an order, for just one item, as follows (the options can be in any order). The program checks the status every 2 seconds and prints out the result:

 

java TakeOrder1 location=TAKEAWAY drink=LATTE size=LARGE milk=SKIM      

order placed sucessfully (order number 12)

order status is PREPARING

order status is PREPARING

order status is PREPARING

 

We will copy in target “restPoke” from orderService’s build.xml into this project’s build.xml to be able to make the oldest unready order ready. In the case that another process on the system does “ant restPoke” (that makes this order ready) 5 seconds later, the output would look like this:

 

java TakeOrder1 location=TAKEAWAY drink=LATTE size=LARGE milk=SKIM      

order placed sucessfully (order number 12)

order status is PREPARING

order status is PREPARING

order status is PREPARING

order status is READY

order status is READY

 

The initial version of this program, TakeOrder1.java, assumes OrderService.xsd never changes, and simply builds in the choices, like this, or something like this:

String[] location = {"TAKEAWAY", “IN_STORE” };

String[] milk = { “WHOLE”, “SKIM”, “SEMI”, “NONE” };

String[] size = {...};

String[] drink = {...}; 

 

These arrays are used to display the help information and check the user arguments on an order. For flexibility, you can create a Map<String, String[]> to hold all the option info keyed by option name.  The user choices should all be checked with one method that can handle all four cases, e.g., by taking parameters "location" (the option name) and "TAKEAWAY" or  (mistakenly) “TAKEOUT” or whatever the user entered, and returning true or false.  Then use DOM or JAXB to generate the XML for the POST.  See Test2.java of firstRest for how to handle DOM data for REST easily.

 

Dynamic Choices feature. The final version, TakeOrder2.java, should do its UI the same way as TakeOrder1, but it no longer has the built-in arrays for location, etc. Instead, it reads the server-provided OrderService.xsd and uses whatever location, milk, size, and drink options are currently in use in it, so the management can put in special drinks for a holiday period, for example.  Your program should even be able to handle a new item child element of item such as choice of "topping" of "COCOA" or "SPRINKLES". 

 

Further, for TakeOrder2, if the project is done by a pair, isolate the HTTP actions in a ClientService class that offers the actions in application terms, such as the following for placing an order.

 

public OrderRepresentation placeOrder(OrderRepresentation order, URI orderUri)

  throws MalformedOrderException, ServiceFailureException // HTTP 400, 500 errors

or

public Document placeOrder(Document order, URI orderUri)

  throws MalformedOrderException, ServiceFailureException // HTTP 400, 500 errors

 

The first form is appropriate if you are using an OrderRepresentation POJO (with JAXB annotation, but cleaned of any server-side-specific code) to set up orders, and the second form is appropriate if you are using DOM Documents to build orders. Note the HTTP failures (400 and 500, anyway) have been turned into application-defined exceptions. There is code in EndToEndTest.java of orderService that can be a start for this.

 

Admin Tool

Also write a small Java program AdminTool.java to offer the two admin actions:

java AdminTool poke

and

java AdminTool init

The first does a POST to /poke and the second does a DELETE to /order of orderService, to delete all the orders in the server.  To show it’s possible, write these simple actions using only the JDK URL classes, specifically by using a HttpURLConnection object, which can be obtained from a URL object by calling url.openConnection() and casting the result to HttpURLConnection, call it connection.  On the connection object, call setDoOutput(true), then call setRequestMethod for POST/DELETE and setRequestProperty to set “Content-Type” to “text/xml”. Get the connection’s OutputStream, and flush it, to finish the message for sending (no content is needed here.). Get the connection’s ResponseCode to see if the action was successful.  Finally, call disconnect on the connection.

 

Designing a Better orderService

The fact that we needed to process the XSD to make a decent client is a black eye for the service. Design an extension to orderService (with new resource types) that allows a simple client to find out about the various options using resources (“everything is a resource”).  Give the new URI template(s) you propose. Note that URI templates can have more than one parameter, as in the example from the Java EE6 Tutorial: @Path("/{eventId}/{inviteId}"). Here the server code can separately pick up the two Ids. These Ids may be Strings. You may use any of the actions defined in the big table of collection/element REST actions at the start of the class 18.

 

Getting Started

You should have firstRest and orderService up and running on your development system from hw3. Note that orderService does have some client code in EndToEndTest that could be useful.  But don’t develop this app within the orderService project!  Leave the orderService project alone for now, except as your orderService provider. Of course you can change its POJOs (add size HUGE for example), to change the XSD it serves out, in order to properly test your dynamic choices feature.  Start a new project “pa3” from a copy of firstRest, including the Test2.java that was added, which shows off Jersey’s ability to serialize and parse DOM-to/from-XML and POJOs-to/from XML, useful for the client code.  You have the choice of using DOM or POJOs on the client side to represent orders. Note that pa3 only needs client code, so it doesn’t need to be a Dynamic Web Project.

 

Implementing the Dynamic Choice feature. Here is one way to tackle the dynamic choices feature. Use XPath on the XSD XML to find Nodes with related <choice> elements. For each Node, find the related name ("location") and options ("TAKEAWAY", ...),, so you end up with same information you had in TakeOrder1. Again, generate the XML with DOM or JAXB. 

 

For the JAXB-generated orders case, you need to regenerate the POJOs each time the XSD changes. This is not difficult: just copy the gen-pojos-from-schema target and the top-level lib directory from orderService into this project, and get the POJOs to be generated right into the cs639.ordering.representations package.  Don’t try to fully automate the execution of this regeneration. Just catch any exceptions that occur because of new options being there at JAXB-use time and give a decent error message explaining the need for the regeneration.

 

Final test for dynamic choice feature: after normal testing, orderService starts serving out an XSD with an additional option. The grading script does ant order-help2 to see the new option, then runs TakeOrder2 to order with the new option, to see order submission with the new option or at least the detection of the change by TakeOrder2. Then the script does ant gen-pojos-from-schema in case that target exists and is useful, and then tries again on the new order.

Files for Grading:

In directory pa3

README: pointer to solution, any notes for grading
memo.txt: authors’ names, provide a guide to your sources with one sentence descriptions of source files, listed by packages Attribute any help you have received from the web or other sources. Give your extended orderService design.
build.xml: this should be based on the client parts of the build.xmls for firstRest and orderService. Specifically, it doesn’t need a “deploy” target since it is only client code. Deliver targets “restPoke” and “restAdd” from orderService, “adminPoke“ for AdminTools’ poke, “adminInit” for AdminTool’s init, “order-help1” for TakeOrder1’s help, “order-help2” for TakeOrder2’s help,  “order1” for submitting one order via your TakeOrder1 client, “order2” for submitting one order via your TakeOrder2 client, and optionally “gen-pojos-from-schema” all using TOMCAT_URL for portability. Maintain the usual targets: “init”, “build”, “clean”.

Java Sources: under pa3/src
Expected Packages Please follow these names as much as possible.

cs639.ordering.client: TakeOrder*, helpers if any, ClientService

cs639.ordering.admin: AdminTool

cs639.ordering.representations: POJOs annotated by JAXB (only if you use JAXB)