3.3. Object Resource

The /object link indicated above corresponds to the ObjectResource interface. This defines the set of interactions described in Section 1.2, “Introducing Restful Objects”:

import java.io.InputStream;

import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;

public interface ObjectResource {

  ...
}

The implementation of this interface in Restful Objects viewer (ObjectResourceImpl) also defines a @Path("/object") for the class as a whole. All URL paths are therefore prefixed /object/{oid}.

Note

I believe that the @Path annotation should reside on the interface, not the implementation. This seems to be a limitation with RestEasy 1.0.2, the underlying library used by Restful Objects.

Let's break it down into sections, starting with the object.

3.3.1. Objects

The /objects/OID resource corresponds to the ObjectResource interface:

...

public interface ObjectResource {

  @GET
  @Path("/{oid}")
  @Produces( { "application/xhtml+xml", "text/html" })
  public String object(
    @PathParam("oid") final String oidStr);

  ...
}

This defines /object/{oid} as a URL supporting GET. Here's what calling this method gives for a repository object:

As ever, we get the initial "logged in" and "resources" sections. The remaining sections are details about this object, providing its title, the properties, the list of collections and then the actions. For repositories, the only items of significance here are the actions.

Let's also look at a typical domain object:

The structure is the same, but here there are properties and collections, as well as actions. Let's look at the XHTML that represents this domain object, starting with the title:

The raw XHTML looks like:

<div>
  <table border="1">
    <tr>
      <td>Object title</td>
      <td class="nof-title">
        <p>New - 2009-11-28</p>
     </td>
    </tr>
    <tr>
      <td>OID</td>
      <td class="nof-oid">
        <a href="/object/OID:C" rel="object" rev="object" class="nof-oid">
          OID:C
        </a>
      </td>
    </tr>
    <tr>
      <td>Specification</td>
      <td class="nof-specification">
        <a href="/specs/org.nakedobjects.examples.claims.dom.claim.Claim" 
           rel="spec" rev="object" class="nof-specification">
          org.nakedobjects.examples.claims.dom.claim.Claim
        </a>
      </td>
    </tr>
  </table>
</div>

Some useful XPath expressions:

  • //td[@class='nof-title']/p/text() will return the title

  • //td[@class='nof-oid']/a/text() is the OID (as a string)

  • //td[@class='nof-specification']/a/@href is a link the (resource repreenting the) specification of this object, in the form /specs/{fullyQualifiedClassName}

Next up is the properties section:

The raw XHTML (abbreviated; just the first property is listed) is:

<div class="nof-properties">
  <p class="nof-properties">Properties</p>
  <table border="1">
    <tr>
      <th>Name</th>
      <th>Type</th>
      <th>Hidden</th>
      <th>Access</th>
      <th>Disabled</th>
      <th>Disabled Reason</th>
      <th>Parseable</th>
      <th>Modify</th>
      <th>Clear</th>
      <th>Invalid Reason</th>
    </tr>
    <tr>
      <td>
        <a href="/specs/org.nakedobjects.examples.claims.dom.claim.Claim/property/description" 
           rel="propertySpec" rev="property" class="nof-property">Description</a>
      </td>
      <td>
        <a href="/specs/java.lang.String" rel="propertyTypeSpec" 
           rev="property" class="nof-property">java.lang.String</a>
      </td>
      <td>
        <p class="nof-visible">N</p>
      </td>
      <td>
        <p class="nof-property">Meeting at clients</p>
      </td>
      <td>
        <p class="nof-usable">N</p>
      </td>
      <td>
        <p />
      </td>
      <td>
        <p class="nof-visible">N</p>
      </td>
      <td>
        <div class="nof-property">
          <form name="property-description">
            <input type="value" name="proposedValue" />
            <input type="button" value="Set" 
              onclick="modifyProperty(&quot;/object/OID:C&quot;,&quot;description&quot;,proposedValue.value);" />
          </form>
        </div>
      </td>
      <td>
        <div class="nof-property">
          <form name="property-description">
            <input type="button" value="Clear" 
              onclick="clearProperty(&quot;/object/OID:C&quot;,&quot;description&quot;);" />
          </form>
        </div>
      </td>
      <td>
        <p class="nof-valid" id="property-invalid-description" />
      </td>
    </tr>
    ...
  </table>
</div>

Some useful XPath expressions are:

  • //div[@class='nof-properties']//tr/td[1]/a/text() returns the property names

  • //div[@class='nof-properties']//tr/td[2]/a/@href returns links to (resources representing the) property types, in the form /specs/{fullyQualifiedClassName}

  • //div[@class='nof-properties']//tr/td[3]/p/text() returns whether properties are invisible (N=not invisible)

  • //div[@class='nof-properties']//tr/td[4] returns the <td> table cells containing the values; the values will either be <p> (values) or <a href=...> (references)

and so on.

The "modify" and "clear" columns bear further description. These are used to perform PUTs and DELETEs on the resources that represent the property. Because XHTML4 does not support PUT and DELETE verbs in forms, they actually call Javascript fragments to do these calls. See Section 3.3.2, “Properties” for further details of the format of these requests.

The values that are entered into modify for value properties is the parseable text form (eg TRUE for a boolean); for reference properties it is the OID.

If a property is disabled, then the "disabled reason" column will indicate why. If a property is enabled but the proposed property value is invalid, then the "invalid reason" will indicate why. Note that it takes a round-trip to do this validation, because the domain objects are not in any sense serialized into the browser.

Let's now look at the collections section:

The raw XHTML is:

<div class="nof-collections">
  <p class="nof-collections">Collections</p>
  <table border="1">
    <tr>
      <th>Name</th>
      <th>Type</th>
      <th>Hidden</th>
      <th>Disabled</th>
      <th>Access</th>
      <th>AddTo</th>
      <th>RemoveFrom</th>
      <th>Invalid Reason</th>
    </tr>
    <tr>
      <td>
        <a href="/specs/org.nakedobjects.examples.claims.dom.claim.Claim/collection/items" 
           rel="propertySpec" rev="collection" class="nof-collection">
          Items
        </a>
      </td>
      <td>
        <a href="/specs/org.nakedobjects.examples.claims.dom.claim.ClaimItem" 
           rel="propertyTypeSpec" rev="property" class="nof-property">
          org.nakedobjects.examples.claims.dom.claim.ClaimItem
        </a>
      </td>
      <td>
        <p class="nof-visible">N</p>
      </td>
      <td>
        <p class="nof-usable">N</p>
      </td>
      <td>
       <a href="/object/OID:C/collection/items" 
          rel="collection" rev="nakedObject" class="nof-collection">items</a>
      </td>
      <td>
        <div class="nof-collection">
          <form name="collection-items">
            <input type="value" name="proposedValue" />
            <input type="button" value="Add" 
              onclick="addToCollection(&quot;/object/OID:C&quot;, &quot;items&quot;, proposedValue.value);" />
          </form>
        </div>
      </td>
      <td>
        <div class="nof-collection">
          <form name="collection-items">
            <input type="value" name="proposedValue" />
            <input type="button" value="Remove" 
              onclick="removeFromCollection(&quot;/object/OID:C&quot;, &quot;items&quot;, proposedValue.value);" />
          </form>
        </div>
      </td>
      <td>
        <p class="nof-valid" id="collection-invalid-items" />
      </td>
    </tr>
  </table>
</div>

In this particular case there is only a single collection, but in general there could be many.

Some useful XPath expressions are:

  • //div[@class='nof-collections']//tr/td[1]/a/text() returns the collection names

  • //div[@class='nof-properties']//tr/td[2]/a/@href returns links to (resources representing the) type of the collection, in the form /specs/{fullyQualifiedClassName}

  • //div[@class='nof-properties']//tr/td[3]/p/text() returns whether collections are invisible (N=not invisible)

  • //div[@class='nof-collections']//tr/td[5]/a/@href returns a link to a resource representing the contents of the collection, in the form /object/{oid}/collection/{collectionId}

and so on. Note that the table doesn't show the contents of each collection, instead it gives us a link to access the contents

Similar to properties, the "addTo" and "removeFrom" columns are used to submit PUT or DELETEs against the collection resource. See Section 3.3.3, “Collections” for more details. The arguments provided are the OIDs of objects in the collection.

Finally, let's look at actions:

The raw XHTML (abbreviated; just the first action is listed) is:

<div class="nof-actions">
  <p class="nof-actions">Actions</p>
  <table border="1">
    <tr>
      <th>Name</th>
      <th>Type</th>
      <th>Type</th>
      <th># Params</th>
      <th>Hidden</th>
      <th>Disabled</th>
      <th>Disabled Reason</th>
      <th>Real Target</th>
      <th>Invoke</th>
    </tr>
    <tr>
      <td>
        <a href="/specs/org.nakedobjects.examples.claims.dom.claim.Claim/action/addItem(int,double,java.lang.String)"
           rel="actionSpec" rev="action" class="nof-action">Add Item</a>
      </td>
      <td>
        <p class="nof-action">USER</p>
      </td>
      <td>
        <a href="/specs/void" rel="actionReturnTypeSpec" rev="action" class="nof-action">void</a>
      </td>
      <td>
        <p class="nof-action">3</p>
      </td>
      <td>
        <p class="nof-visible">N</p>
      </td>
      <td>
        <p class="nof-usable">N</p>
      </td>
      <td>
        <p />
      </td>
      <td>
        <a href="/object/OID:C" rel="actionRealTarget" rev="action" class="nof-action">OID:C</a>
      </td>
      <td>
        <div class="nof-action">
          <form name="action-addItem(int,double,java.lang.String)" method="POST" 
                action="/object/OID:C/action/addItem(int,double,java.lang.String)">
            <p>Days since</p>
            <input type="value" name="arg0" />
            <p>Amount</p>
            <input type="value" name="arg1" />
            <p>Description</p>
            <input type="value" name="arg2" />
            <input type="submit" value="Invoke" />
          </form>
        </div>
      </td>
    </tr>
    ...
  </table>
</div>

Some useful XPath expressions are:

  • //div[@class='nof-actions']//tr/td[1]/a/text() returns the names of each action

  • //div[@class='nof-actions']//tr/td[3]/a/@href returns links to (resources representing the) type of the returned result of each action, in the form /specs/{fullyQualifiedClassName}

  • //div[@class='nof-actions']//tr/td[5]/p/text() returns whether each action is invisible or not (N=not invisible)

  • //div[@class='nof-actions']//tr/td[8]/a/text() returns the OID of the real target; more on this in a moment

  • //div[@class='nof-actions']//tr/td[9]//form returns a form to invoke the action using POST

and so on. Note that the table doesn't show the contents of each collection, instead it gives us a link to access the contents

There is no javascript calls this time; invoking actions is just a POST. The arguments provided are the same as for properties: text for parseable values, or the OIDs of objects for references.

The "realTarget" column is provided to support contributed actions. For example, here are the actions listed for a domain object (Employee) where the claimsFor() action is contributed (by the ClaimsRepository):

In the DnD viewer this action would appear to reside on the domain object. In reality though the action resides on the repository, taking a single argument - the domain object (Employee).

And that concludes our run-through of the GET verb for object resources. Phew!

Note

PUT and DELETE verbs for object resources have not yet been implemented.

3.3.2. Properties

The next set of resources exposed by ObjectResource are those specific to properties:

...
public interface ObjectResource {
  ...
  @PUT
  @Path("/{oid}/property/{propertyId}")
  @Produces( { "application/xhtml+xml", "text/html" })
  public String modifyProperty(
    @PathParam("oid") final String oidStr,
    @PathParam("propertyId") final String propertyId,
    @QueryParam("proposedValue") final String proposedValue);

  @DELETE
  @Path("/{oid}/property/{propertyId}")
  @Produces( { "application/xhtml+xml", "text/html" })
  public String clearProperty(
    @PathParam("oid") final String oidStr,
    @PathParam("propertyId") final String propertyId);
  ...
}

This defines /object/{oid}/property/{propertyId} as the URL supporting:

  • PUT, to change the value of a property; the proposedValue should be a query parameter to this URL;

  • DELETE, to clear the property

Calling these will first validate the change, and if accepted apply the change:

  • If the validation fails, then an exception will be thrown. This translates to a response with error code in the range [400, 500), and with a response header of "nof-reason".

  • If the validation succeeds, the returned XHTML is the object's title only.

3.3.3. Collections

The next set of resources exposed by ObjectResource are those for collections:

...
public interface ObjectResource {
  ...
  @GET
  @Path("/{oid}/collection/{collectionId}")
  @Produces( { "application/xhtml+xml", "text/html" })
  public String accessCollection(
    @PathParam("oid") final String oidStr,
    @PathParam("collectionId") final String collectionId);

  @PUT
  @Path("/{oid}/collection/{collectionId}")
  @Produces( { "application/xhtml+xml", "text/html" })
  public String addToCollection(
    @PathParam("oid") final String oidStr,
    @PathParam("collectionId") final String collectionId,
    @QueryParam("proposedValue") final String proposedValueOidStr);

  @DELETE
  @Path("/{oid}/collection/{collectionId}")
  @Produces( { "application/xhtml+xml", "text/html" })
  public String removeFromCollection(
    @PathParam("oid") final String oidStr,
    @PathParam("collectionId") final String collectionId,
    @QueryParam("proposedValue") final String proposedValueOidStr);
  ...
}

This defines /object/{oid}/property/{collectionId} as a URL supporting:

  • GET, to read the contents of this collection.

  • PUT, to add an item to the collection; the proposedValue should be a query parameter to this URL and contain an OID;

  • DELETE, to remove an item to the collection; the proposedValue should be a query parameter to this URL and contain an OID;

The handling of PUT and the DELETE is similar to that of properties. The proposed value is validated first, and if invalid then a exception is thrown resulting in a response in range [400, 500) with a response header of "nof-reason". Otherwise the object's title and OID are returned.

Note

We could perhaps change this to return the new contents of the collection, ie as if a GET had been performed?

A GET meanwhile returns the following:

The raw XHTML for the contents part of this is:

<div class="nof-collection">
  <p class="nof-collection">items</p>
  <ul class="nof-collection">
    <li>
      <a href="/object/OID:D" rel="object" rev="results" class="nof-action-result">
        Car parking
      </a>
    </li>
    <li>
      <a href="/object/OID:E" rel="object" rev="results" class="nof-action-result">
        Reading - London (return)
      </a>
    </li>
  </ul>
</div>

Useful XPath here is:

  • //div[@class='nof-collection']//li/a/@href to return the links to object resources in the collection

3.3.4. Actions

The final set of resources exposed by ObjectResource is for actions:

...
public interface ObjectResource {
  ...
  @POST
  @Path("/{oid}/action/{actionId}")
  @Produces( { "application/xhtml+xml", "text/html" })
  public String invokeAction(
    @PathParam("oid") final String oidStr,
    @PathParam("actionId") final String actionId, 
    final InputStream body);
  ...
}

This defines /object/{oid}/property/{actionId} as a URL supporting a POST. What's noteworthy here is the last argument, an java.io.InputStream. This provides a handle to the POST's input stream which contains the parameter/argument pairs.

The parameters should be named arg0, arg1, arg2 and so on, with the parameter value representing the argument. What this value is will depend on whether the parameter's type is a reference (entity) type or a parseable value type:

  • for reference types, the value should be the (string representation of the) OID of the entity

  • for value types, the value should be in parseable string format. In practical terms, use the same string format as would work in the the DnD viewer. (To be precise, it's the format understood by the ParseableFacet for the parameter's type)

For example, for an action findCustomers(registeredDate, CustomerType) then the parameters would be something like:

  • arg0=20090103

  • arg1=CTP|12

where 20090103 is 3-Jan-2009 in parseable format, and CTP|12 is the OID (as assigned by the object store) for CustomerType with ID=12.

When an action is invoked, the response always includes the OID and title of the object on which the action was invoked. In addition:

  • if the action returned an object, then the response will include a link to the object

    Note

    We could perhaps change this to return the GET of the returned object?

  • if the action returned a collection of objects, then the response will return a list of links to the objects

  • if the action returned void; then nothing further is added to the response