CS 639 class 20

handout: OrderService.xsd

pa3: clients for orderService, which more-or-less follows Chap 4.

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 normal way to get a list, but when try to serialize something it doesn’t support, say an ArrayList object, on the server end, 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 end 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

 

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 xsd0.xsd)

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

Note that the schema is marked elementFormDefault=qualifiedas 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.

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