CS 639 Class 22
Handout: firstRest2 on front, orderService on back
Last class notes: see cleaned up explanation of JAXB annotations for orderService.
Recall last time that we have ant targets to use JAXB for conversion of XSD to/from POJOs. The additional JAXB tool support code is in basedir/lib, not deployed to tomcat. This is using JAXB outside of Jersey. We are of course also using JAXB when we use Jersey with POJOs.
Let’s look at the slick setup generated by JAXB from our schema, OrderService.xsd, located in the gen-src directory of the orderService project.
They are all in one package (specified in the XJC command in build.xml) with package-info to set the NS for all classes, and elementFormDefault. So OrderRepresentation (POJO name from XSD type name) gets the advantage of this setup, and has no NS markup itself. OrderRepresentation.java has
@XmlAccessorType(XmlAccessType.FIELD)
So that fields will be one-one with child elements. Then only the fields for the required child elements are given @XmlElement markup:
@XmlElement(required = true)
We see a new annotation of the class:
@XmlType(name
= "orderRepresentation", propOrder = {
"id",
"item",
"location",
"cost",
"status"
})
This tells JAXB what order to generate child elements in. At runtime, JAXB only has .class files to look at for serialization, and it turns out that reflection does not reliably report on the order of the fields, so this annotation is needed to bridge that gap. This also explains the “laxness” we discussed last time, that JAXB will accept XML with out of order child elements. So this annotation is important, and really should be in our orderService POJOs.
Mysteriously, there is no @XMLRootElement in gen-src’s OrderRepresentation or Item, although order and item are global elements in the OrderService.xsd. This is explained by reading the spec and finding there are two ways to specify root elements, the @XMLRootElement we used before and by having an ObjectFactory.java with class annotation @XmlRegistry and a createOrder method with @XmlElementDecl annotation, and this more obscure way is used here. We can easily convert to @XMLRootElement.
Back to Vogel’s JAX-RS
tutorial, Sec. 5. nicely set up, example of GET to collection URI
(re design problem in pa3)
Available in firstRest2, linked to class web page under Resources.
Packages
resources: ToDoResource,
ToDosResource
dao: TodoDao: uses
HashMap<String, Todo> to store Todos
model: Todo, with minimal
JAXB markup, just @XmlRootElement on the class.
These packages can be
corresponded to the three well-known web app layers:
·
Presentation: top
layer, where new requests come in: resources
·
Service: heart of
app, where business code resides: pretty trivial here, also in resources
·
Data access: dao
This leaves model, with the
POJO, separate from the layers, and this is right. The Todo POJO carries data
across the layers.
More on these layers when we
analyze orderService later in this class.
Note: no namespace in use
here, simplifying the JAXB needs. If we want to add a namespace, we can
annotate the child elements as in OrderRepresentation, or set up package
annotations.
His Todo service looks like
this:
GET
/todos ßGET
to collection URI
GET
/todos/count
POST
/todos
GET
/todos/{id]
PUT
/todos/{id}
DELETE
/todos/{id}
Vogel’s GET /todos returns
List<Todo> to JAX-RS. Here’s the XML:
This is printed in the
tutorial, from a browser:
<?xml
version="1.0" encoding="UTF-8"
standalone="yes"?>
<todoes>
<todo><id>3</id><summary>Blabla</summary>
</todo>
<todo><description>Read complete http://www.vogella.de</description>
<id>2</id><summary>Do
something</summary>
</todo>
<todo><description>Read
http://www.vogella.de/articles/REST/article.html</description>
<id>1</id><summary>Learn
REST</summary>
</todo>
</todoes>
Interestingly, it spells the
plural of todo with an e, different from the URI segment. It has some
pluralization algorithm of its own to go from “todo” to its plural. There is no
JAXB markup to guide it here.
Note that in the big table of
class 18, we saw in GET for collection URI:
List the URIs and perhaps other details of
the collection's members
So another option would be
List<URI>, but JAXB won’t serialize this type, or List<String>
without additional work (providing message handlers.)
JAXB will serialize
List<POJO> for any JAXB POJO, so we could set up a POJO for a URI and
send that List off.
But for our purposes, sending
List<Todo> for the collection-URI GET fits with our URI-free responses.
// Return the list of todos to the user
in the browser
@GET
@Produces(MediaType.TEXT_XML)
public List<Todo>
getTodosBrowser() {
List<Todo> todos = new
ArrayList<Todo>();
todos.addAll(
TodoDao.instance.getModel().values() );
return todos;
}
So List<POJO> gets
serialized, using funny plural of todo to contain the list, because there is no
markup to specify that element name.
On the client side: set up a
service object of type WebResource, as before, and, for above display
// Get the Todos
System.out.println(service.path("rest").path("todos").accept(
MediaType.TEXT_XML).get(String.class));
The implementation of the
whole REST API could be all in TodosResource, but instead it’s split up into
two source files to show the power of subresources to handle hierarchy in URIs.
/todos/{id}
<---->
<--->
TodosResource: main resource
for handling collection of Todos
TodoResource: a subresource
handling a single Todo
For now, just accept this as
an explanation for why there are two java files in resources. This service could easily be implemented all
in TodosResource, as follows:
TodosResource has
@Path(“/todos”) on the class:
the root resource, starts with / (not allowed in subresources)
sets first part of URI for
the class
@GET on a method, to handle
GET /todos
@GET
@Path(“count”) on a method, to handle GET /todos /count
@POST on a method, to handlle
POST /todos
Following orderService, we
could handle GET /todos/1234 here too:
@GET
@Path(“{todo}”)
To handle GET /todos/1234
And similarly for the others.
Instead, there’s a handoff
from here into the subresource---look at later
Another trick in this
firstRest2 example: Form handling
REST services are so
simple we can use them from HTML
Consider a HTML form in the
top-level directory of the web app called “todo_form.html” and make it
(simplified and corrected) as follows:
...
<form action="rest/todos"
method="POST">
<input name="id"
/><br/>
<input name="summary"
/><br/>
Description:
<TEXTAREA NAME="description"
COLS=40 ROWS=6></TEXTAREA><br/>
<input type="submit"
value="Submit" />
</form>
The resulting POST to the local
URL rest/todos with params id=6, summary=new+entry, description=new+idea,
brings it to the following in TodosResource.java:
@POST
@Produces(MediaType.TEXT_HTML)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) <--form data coming in
public void newTodo(
@FormParam("id")
String id, <--and particular params
@FormParam("summary")
String summary,
@FormParam("description")
String description,
@Context
HttpServletResponse servletResponse
<-- for redirect
) throws
IOException {
Todo
todo = new Todo(id,summary);
if
(description!=null){
todo.setDescription(description);
}
TodoDao.instance.getModel().put(id,
todo);
URI
uri = uriInfo.getAbsolutePathBuilder().path(id).build();
Response.created(uri).build();
servletResponse.sendRedirect("../create_todo.html");
}
Then Jersey can give us the
params with @FormParam(“id”) annotation of a method parameter as we process the
POST, and also the servlet response object for a redirect. The create_todo.html
is in the top-level directory, .. to /rest.
To check your addition,
browse to /firstRest/rest/todos and get a new list.
See the new project posting
at the end of the class web page, with links for the project and for the form
and the list of Todos, from the deployed project at sf08.cs.umb.edu:11600/firstRest2/.
Headers, Cookies can be picked up similarly—see
Javadocs
orderService Software Architecture, Pull
technology vs. notifications
So far we have been concentrating
on orderServices REST services, since that’s what is important to clients, and
also JAXB, which is more generally useful than just this one app.
Now look at it as a decent
REST service implemention, and get ready for pa4, which expands it to handle
payment and flexible options.
C:\CS\CS639\ORDERSERVICE\SRC
├───functionaltest
│ ...
├───main
│ └───java
│ └───com
│ └───restbucks
│ └───ordering
│ ├───activities
│ ├───domain
│ ├───repositories
│ ├───representations
│ └───resources
└───test
...
unit tests
orderService packages
resources:
where the @GET, @POST, etc., handlers
are for each resource. Minimal REST-related code is here. The methods call into the main app code to do
whatever the app is meant to do.
representations:
where OrderRepresentation is, and any other POJO needed just for external
communication.
domain:
where Order is, also Item, used by both Order and OrderRepresentation, and the
enums for all the options. These are the
POJOs used by the app internals in activities and repositories.
activities:
the heart of the app. Implementations of the actions this app wants to do for
each incoming request. Also known as the
“business layer” or “service layer”
repositories:
code for accessing database tables or similar holders of long-term state for
the app. Also known as the Data Access layer, or DAO layer, for data access
objects.
Web apps (including orderService)
generally have three layers:
·
Presentation
layer: here resources: interacting with a user or external agents
·
Business/Service
layer: here activities: the heart of the app, doing what it knows how to do
·
Data Access
layer, here repositories: arranging long-term storage for app data
What is a layer here?
In a layered system, the code
in a higher layer calls methods in the next layer down, or in its own layer,
but never calls up to the layer above it.
Here resources methods call activities methods, and activities methods
call repositories methods, which just do their thing saving or retrieving data
and return. Then the activities method
returns to the resources method.
That leaves domain as not
being a layer. That is correct: domain
objects circulate in the system, carrying data.
After all, the data needs to flow from the network down into the
long-term storage when an order is created, and back up when order status is
asked for.
Note that the calls go down
the layers even in the case that the data is coming up the layers. Consider a GET for order status.
1.
It first shows up
as a call into resources at the @GET method in OrderResource.
2.
This resources
method calls into activities to get status by id.
3.
This activities
method calls into repositories to get the data from long-term storage
4.
The data is
returned from repositories to activities in an Order object.
5.
Then it is
converted into an OrderRepresentation object and returned from activities to resources
6.
Then in
resources, the GET method of OrderResource sends it off as XML.
Pull Web Interactions
Note that the user has to ask
over and over for status to be sure to find out immediately if their order is
ready. It would be nice if the system
contacted the user when the order became ready.
But HTTP is client-request driven, otherwise known as Pull technology.
Although the server’s web address is known to the client, and the server
accepts new requests any time, the client does not have the same capability.
The server gets to send to the client at the end of each client request, but
once it closes that connection, it has lost contact.
In the case that the server
must get back to the user at some “random” time, email is one option. That’s
because the user has a relationship with another server, and checks it now and
then, or has an email agent that periodically checks and signals new email. It
is strightforward to add email capability to web apps, something like adding
database access (covered in CS636).
Of course HTTP is not the only
protocol on the network. It is possible to have a TCP connection open for
longer times, say hours, and keep a conversation going between two ends. But in
practice, it’s hard to engineer this approach, because the network has
interruptions, and then you have to resynchronize the conversation. It’s better
to live within the restrictions of HTTP.
Having only Pull Requests makes call-down layering
possible
The fact that REST follows
HTTP Pull protocols makes the layering possible and practical. If the system had to notify the client when
the coffee order was ready, that would be an up-call: the change of state would
happen in the repository level, and then the repository would have to call up
to the user-communications level. But
that doesn’t happen.
The orderService package structure is reusable,
“natural” for web services apps, even web apps
So we see that this layered
software organization is not just for this particular app, but can be used for
any REST server. Or any web services
server, for that matter, SOAP or REST.
Or a web app using JDBC.
Even though JDBC can use a
long-term TCP connection, it still does only Pull actions from the client. You
might think you could hook up database triggers to JDBC, but in fact you can’t
do server-to-client notifications via JDBC.
(not
covered in class--)
The
network technology to do notifications is called a publish-subscribe service,
or “pub-sub” for short. It can be done with JMS, Java Messaging Service,
another technology of Java EE, with the help of longer-term TCP connections to
a database. It’s not an easy thing to
work with.
Event Handling the REST way: using feeds
The closest thing in the REST
world to notification is an event “feed”, using the Atom protocol (Chap. 7 in
Webber et al.), or the older RSS protocol.
A feed doesn’t deliver events, but it organizes them to make it easy for
clients to pick them up now and then at their own convenience.
The example in Chap. 7:
Restbucks has occasional price changes, special drinks to put on the menu, etc.
These changes to its basic catalog are “events” that get put in a “feed”. The individual coffee shops “poll” the feed
to pick up these changes and apply them to their local menus. That’s the REST way to handle events.
The APIs between the layers
OK 3 layers. That means 2
APIs between layers:
Call into business
layer: the Service API, tells what the
service can do
Look at Software Layers
handout
In pa4, you will extend these
APIs to cover payment and receipts and options.
We want to go on to Chapter 5
to look at the hypermedia version of orderService, which comes with an Jersey
implementation I’ll post as orderDap, after converting it to tomcat. It is useful for pa4 because it has support
for payments and receipts.
Q: What’s hypermedia? The idea that a response from one URI should
present the all the next-URIs that follow from that state, to guide the user
around the service. We are not returning
URIs, just information relevant to the resource of the URI. In Chapter 5, the responses contain URIs too.
But first, we should look at
other “plain” REST services, i.e., not hypermedia. There’s more we can do with just URI
templates and XML messages.
The Jersey REST Samples.
Jersey comes with a whole
distribution of samples, available in a zip file for example at http://download.java.net/maven/2/com/sun/jersey/samples/jersey-samples/1.0.3/
One of the samples is a
bookmark app that has users with bookmarks
like the example we just looked at, with URI template /users/{userId}/bookmarks/{bookmarkId}.
However it serves JSON and
uses JPA, so it’s not directly in our ballpark.
Another Jersey sample is a
bookstore REST service: items are CDs or books, CDs have tracks. It shows how we can use inheritance in the
representational POJOs.
/ |
Bookstore |
GET |
/count |
Bookstore |
GET |
/time |
Bookstore |
GET |
/items/{itemid} |
Book,
CD |
GET |
/items/{itemid}/tracks/{num} |
Track |
GET |
The
Bookstore resource
returns a list of items, either CDs or books. The resource dynamically
references a Book or CD resource using the getItem method that
is annotated with @Path. Both the Book and CD resources
inherit from the Item class, therefore, the item can be managed as an Item
whether it’s really a Book or CD.
This shows an example where
subresources could more reasonably be used than the simple firstRest2 case,
that is, hand off to a subresource to handle the individual track requests.