CS 639 class 20

Demo on using eclipse for orderService

More Complicated URI Templates (relevant to pa3 part on designing an extended orderService)

There is a way to pick up “the rest” of the URI after matching a prefix of it. Or picking up something fitting a regular expression, but we don’t really need these forms.

 

URI Templates can be more complicated:

Example from pa3.html:  /{eventId}/{inviteId}

So if events are id’d by “e001”, etc., and invites by 1, 2, 3,...

an individual invitation could have URI path “/e021/32”

 

There can be constant parts after a parameter, like this:

/customers/{id}/address

 

Or even multiple parameters for text between /s, like this:

/customers/{firstname}-{lastname}

which matches “/customers/bill-burke” for example.

 

This example is from Burke, RESTful Java with JAX-RS.  He has detailed discussion of URI Templates.

Last time: We looked at Jersey client code in Test2.java of firstRest. We saw how Jersey can serialize and deserialize DOM object trees and POJOs that express the same data structure as XML, using JAXB.  The natural question comes up: what else can Jersey serialize?  Anything that JAXB can do, plus at least DOM, we know from Test2. Jersey docs mention SAX too, of course just for reading XML. 

Jersey contains many serializers and deserializers. I haven’t yet figured out a way to get a list via documentation, but when try to serialize something it doesn’t support, say an ArrayList<String> object, on the server end (using a Resource object) you see:

 

SEVERE: A message body writer for Java class java.util.ArrayList, and Java type class java.util.ArrayList, and MIME media type application/xml was not found

Apr 4, 2012 6:29:07 PM com.sun.jersey.spi.container.ContainerResponse write

SEVERE: The registered message body writers compatible with the MIME media type are:

application/xml ->                <-- specially for media type application/xml

  com.sun.jersey.core.impl.provider.entity.XMLJAXBElementProvider$App

  com.sun.jersey.core.impl.provider.entity.DocumentProvider  <---DOM

  com.sun.jersey.core.impl.provider.entity.SourceProvider$SourceWriter

  com.sun.jersey.core.impl.provider.entity.XMLRootElementProvider$App

  com.sun.jersey.core.impl.provider.entity.XMLListElementProvider$App

*/* ->                                <--useful for all media types

  com.sun.jersey.core.impl.provider.entity.FormProvider

  com.sun.jersey.core.impl.provider.entity.StringProvider

  com.sun.jersey.core.impl.provider.entity.ByteArrayProvider

  com.sun.jersey.core.impl.provider.entity.FileProvider

  com.sun.jersey.core.impl.provider.entity.InputStreamProvider

  com.sun.jersey.core.impl.provider.entity.DataSourceProvider

  com.sun.jersey.core.impl.provider.entity.XMLJAXBElementProvider$General

  com.sun.jersey.core.impl.provider.entity.ReaderProvider

  com.sun.jersey.core.impl.provider.entity.DocumentProvider

  com.sun.jersey.core.impl.provider.entity.StreamingOutputProvider

  com.sun.jersey.core.impl.provider.entity.SourceProvider$SourceWriter

  com.sun.jersey.server.impl.template.ViewableMessageBodyWriter

  com.sun.jersey.json.impl.provider.entity.JSONJAXBElementProvider$General

  com.sun.jersey.json.impl.provider.entity.JSONArrayProvider$General

  com.sun.jersey.json.impl.provider.entity.JSONObjectProvider$General

  com.sun.jersey.core.impl.provider.entity.XMLRootElementProvider$General

  com.sun.jersey.core.impl.provider.entity.XMLListElementProvider$General

  com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider$General

  com.sun.jersey.json.impl.provider.entity.JSONListElementProvider$General

 

Unfortunately, trying serialization of ArrayList on the client with WebResource only yields the first part:

A message body writer for Java class java.util.ArrayList, and Java type class java.util.ArrayList, and MIME media type application/xml was not found

 

Another way: look at this package in the online sources, say at grepcode.com. Click the Hierarchy button to see the subclasses. List is a subset of the above, has none of the names with XML in them.

 

It turns out that it’s the generic type involved in ArrayList<String> that trips up Jersey here. There is a newer way to handle them. Maybe we can get back to this advanced topic.

 

This gives an idea that many ways are there. And this list expands with time (i.e. versions of JAX-RS, still relatively new). 

 

So you see that Jersey thinks of a serializer as a “message body writer”, and also has “message body readers” for XML-to-Java conversions. These important facilities are available for both server and client code.  However, they are implementation objects, so no Javadoc easily available.

 

Look at Chap. 4 as guide to basics of orderService, plus a few differences...

pg. 57 summary of 4 basic actions using URI templates, all "customer" actions, or "ordinary user" actions

our orderService has 2 more, considered "admin" actions

DELETE /order     delete all orders

POST /poke          make oldest order READY

So we see there are two kinds of users, ordinary and admin, as is common with web apps.

If we added authentication and authorization, we can restrict users to their proper actions--see Chap. 9 if interested.

Another top-level view is the state diagram of Fig 4-1, pg 56. This chapter does not do payments (that's in Chap. 5), so the states are simplified to PREPARING and READY

      place-order-action             poke-action
start-------------------->PREPARING--------------->READY
                            ^   |
                            |_ _| update
                            
Orders can also be deleted from PREPARING and READY state.

Creating an Order: POST order for orderService

Creating an order--see pg. 58.  Unlike GETs, the success code here is 201 Created, not 200 OK.

The order XML is shown on pg., 59, and note that it uses a namespace related to the company, and application/xml as the mediatype. Also note that <name> here is <drink> for our orderService, and we have no <quantity> element.

How does the client know the proper format for this message?

Could be via good WADL served by the server--see pg. 86, where local href to "order.xsd" (order.xsd is not listed anywhere in the book, though)

Jersey server-side support does serve WADL, see "ant get-wadl" in build.xml (and much improved over last year)

From application.wadl served by orderService:

  <grammars>

        <include href="application.wadl/xsd0.xsd">

            <doc xml:lang="en" title="Generated"/>

        </include>

    </grammars>

This promises a schema xsd0.xsd obtainable at application.wadl/xsd0.xsd in the site. See this schema in the handout.

Later, look at this XSD and the corresponding JAXB annotations.

So there is a way for the client to get the XSD and from it, figure out what is needed to be sent in to create an order.

In Chap. 4, the client finds out the assigned id of the order by accessing the Location header on the POST response.  From last class, you can see you would need to use the wrapped response object to get this.

our orderService returns the id in the response body.

So our response looks like the XML on pg. 60 with

·         <quantity> dropped,

·         constants in all-caps,

·         <status> PREPARING,

·         <id>1234</id> as first child of <order>

·         <location> the second child, before <item>

·         no <items>, just sequence of <item>.

·         <drink> instead of <name>

So the client does not have to access a header to get the id and thus the URI for the new order.

Errors from Create order: 400 = Bad Request, 500 = Server Error

Bad Order Requests and Default Laxness of JAXB deserialization

Example of bad request that actually returns 400: one with id specified. Only the server gets to assign the id.

Another example of possible bad request, on pg. 61: no <name>/<drink> element. This is not actually enforced by our orderService, because by default, JAXB just processes what it finds in the XML that matches the POJO fields.

In fact, JAXB is very permissive unless you turn on validation: child elements can be out of order and still be processed. We don't have validation on. Maybe later.

Without validation, JAXB just ignores a child element it doesn't understand. So misspelled LARGER instead of LARGE (as in order.xml of the provided project) just returns an order without a size in current system.

If you turn on validation, you can get specific information on validation errors--

JAXB Deserialization with Validation turned on (we're not doing this yet):

XML ---> validation -deserializaton ---> POJOs
       |
      v

               validation errors

 We can capture the validation errors in ValidationEvent objects, which contain line and col of the source XML problem, a message, and the severity level.

orderService Status Requests using GET

GET status, pg. 64.

The first GET response should have status (and id too, in our case). No change should occur in the resource due to a GET. 

In our case a POST to /poke can change this order's status, so two GETs can see different status values

pg. 67: see URI template in action to pull out the orderId from the URI coming in.

Also, @Path on the class sets a starting path for the class, and then @Path on the method adds to it. (In firstRest, just had @Path on the class)

See return value of String from GET: means this method needs to generate XML text in a String.

This is using XStream, still another way to generate XML that we are not covering.  We could use DOM here for example.

The code returns a String to Jersey here, the simplest thing to serialize.

The throws show how to generate HTTP error conditions (from the server) without wrapping the response up in a bigger object.

pg. 67 Errata 2nd line from bottom: /{orderId} (not {/ordered}, transpose / and {

orderService Update Order actions

PUT to update an order--pg. 68-69

First bullet on pg.68 does not agree with our big table, but recall POST is also the catch-all, so not really discordant.

Other two bullets do agree

For us, PUT expects an order already there, so get 404 if not.

Choice of success returns: 200 with order XML, 204 without

We allow updates of PREPARING orders but not READY orders, so can get failure:

Choice of failure codes discussed: 405 Not Allowed or 409 Conflict (clashing representations) our orderService send s 409.

Note that PUT always replaces the whole representation, not like database row update.

pp. 72-74 .NET implementation: see URI template in use here too.

DELETE order, pp. 75-76: we currently allow DELETE in either state.  We do return a rep on a successful DELETE.

OrderService.xsd: handout (AKA schema1.xsd)

This is generated by Jersey from the POJOs of the implementation.

Note that the schema is marked elementFormDefault=”qualified” as we have restricted ourselves to, to avoid strange dependencies of NS prefix usage on global and non-global elements. And it matters, because this schema has non-global elements such as size.

A global element is one defined as a direct child of <schema>.  We see that <order> and <item> are global elements, and the other elements are non-global. Global elements can match against root elements of XML documents.  So we see that an XML doc with <item> at the root can be validated with this schema, as well as ones with <order> at the root.

We see the application-level namespace is given a prefix tns, but this is used only on a subset of app-specific names in use in the schema. The ones with name=xxx may not have a prefix because they are adding new names into the target namespace—you cannot use a schema to put new names into some other namespace, so the xxx here must be a local name. It says so in the schema of schemas.

ref=”tns:itemThere is a new element attribute form for item within <order>’s type:  Since <item> is defined at top level, the <item> child of <order> refers to that declaration rather than repeating it here.  So it can be a root element of a document or a child element of <order> in the document. This style of schema definition is fairly common in practice. For one thing, such schemas can work properly even without the elementFormDefault being “qualified” (if all elements are defined at top level) since the differences between qualified and unqualified apply only to elements declared below the top level. For an example done both ways, see http://www.w3schools.com/schema/schema_example.asp. Also, po.xsd in the XML Schema Primer (this doc is also linked from the class web page). The schema of schemas says that the ref’s attribute value is of type QName, so it can point out of the schema’s namespace into another namespace. That brings us into the territory of multiple schemas, which we have been deferring.

<xs:complexType name="orderRepresentation">

    <xs:sequence>

      <xs:element name="id" type="xs:string" minOccurs="0"/>

      <xs:element ref="tns:item" maxOccurs="unbounded"/>

      <xs:element name="location" type="tns:location"/>

      <xs:element name="cost" type="xs:decimal" minOccurs="0"/>

      <xs:element name="status" type="tns:orderStatus" minOccurs="0"/>

    </xs:sequence>

  </xs:complexType>

See this type definition:

 

<xs:simpleType name="size">

    <xs:restriction base="xs:string">

      <xs:enumeration value="LARGE"/>

      <xs:enumeration value="SMALL"/>

      <xs:enumeration value="MEDIUM"/>

    </xs:restriction>

  </xs:simpleType>

 

This is defining a type of local name “size” in the target NS of restbucks, here using tns: prefix.  Thus references to this type will be tns:size.

So we should pay attention to simpleTypes in XSDs now.

XML Schema Simple Types

A simple type in XML Schema is a type for element text content or attribute values. They are built up from the primitive data types listed in Table 2.1 such as xsd:string and xsd:decimal.

So <temperature>66.9</temperature> can be xsd:decimal, or a restricted type that requires that temperature < 200.

This type describes strings that are exactly one of these three strings.  That's a restriction of xs:string.

Then we also have

<xs:complexType name="item">

    <xs:sequence>

      <xs:element name="milk" type="tns:milk"/>

      <xs:element name="size" type="tns:size"/>

      <xs:element name="drink" type="tns:drink"/>

    </xs:sequence>

</xs:complexType>

 

as a global element, i.e,, this is a direct child of <xs:schema>. So this schema will validate XML with root element <item>, as well as allow this construct in other places.

However, since size is “inside” item only, the schema will not validate XML with root element <size> or <milk> etc.

In Harold, pg. 36 we have in the DTD--

<!ATTLIST Price Currency (USD|CAN|GBP) #REQUIRED>

but on pg. 40, in the XSD for MoneyType, used for Price element:

<xsd:attribute name="currency" type = "xsd:string"/>

We can do better now: define a simple type for currency:

   <xsd:simpleType name="CurrencyType">

       <xsd:restriction base="xsd:string">

            <xsd:enumeration value="USD" />

            <xsd:enumeration value="CAN" />

            <xsd:enumeration value="GBP" />

  </xsd:restriction>
   </xsd:simpleType>

<xsd:attribute name="currency" type = "CurrencyType"/>

Next time: more simple types, more on JAXB