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)