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)