You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2011/06/26 13:51:10 UTC
svn commit: r1139763 [2/10] - in /incubator/isis/trunk/viewer: json/
json/applib2/ json/applib2/src/ json/applib2/src/main/
json/applib2/src/main/java/ json/applib2/src/main/java/META-INF/
json/applib2/src/main/java/org/ json/applib2/src/main/java/org/...
Added: incubator/isis/trunk/viewer/json/src/docbkx/guide/isis-restful-viewer.xml
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/viewer/json/src/docbkx/guide/isis-restful-viewer.xml?rev=1139763&view=auto
==============================================================================
--- incubator/isis/trunk/viewer/json/src/docbkx/guide/isis-restful-viewer.xml (added)
+++ incubator/isis/trunk/viewer/json/src/docbkx/guide/isis-restful-viewer.xml Sun Jun 26 11:51:01 2011
@@ -0,0 +1,2900 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"file:./src/docbkx/dtd-4.5/docbookx.dtd">
+<book>
+ <bookinfo>
+ <title><?eval ${docbkxGuideTitle}?></title>
+
+ <subtitle><?eval ${docbkxGuideSubTitle}?></subtitle>
+
+ <releaseinfo><?eval ${project.version}?></releaseinfo>
+
+ <authorgroup>
+ <author>
+ <firstname>Dan</firstname>
+
+ <surname>Haywood</surname>
+ </author>
+ </authorgroup>
+
+ <legalnotice>
+ <para>Permission is granted to make and distribute verbatim copies of
+ this manual provided that the copyright notice and this permission
+ notice are preserved on all copies.</para>
+ </legalnotice>
+ </bookinfo>
+
+ <!-- front matter -->
+
+ <toc></toc>
+
+ <preface id="preface">
+ <title>Preface</title>
+
+ <para><emphasis>Apache Isis</emphasis> is designed to allow programmers
+ rapidly develop domain-driven applications following the <ulink
+ url="http://en.wikipedia.org/wiki/Naked_Objects">Naked Objects</ulink>
+ pattern. It is made up of a core framework that supports supports variouys
+ viewers, along with <acronym>API</acronym>s and implementations relating
+ to security, the programming model, the runtime (persistence) and profile
+ stores (user preferences). <emphasis>Apache Isis</emphasis> is hosted at
+ the <ulink url="http://incubator.apache.org/isis">Apache
+ Foundation</ulink>, and is licensed under <ulink
+ url="http://www.apache.org/licenses/LICENSE-2.0.html">Apache Software
+ License v2</ulink>.</para>
+
+ <para><emphasis>Isis</emphasis>' <emphasis>restful</emphasis> viewer
+ <package>[oai.viewer:restful]</package> renders each domain objects as
+ <ulink
+ url="http://en.wikipedia.org/wiki/Representational_State_Transfer">RESTful</ulink>
+ resources. Each domain object is exposed as an (<acronym>XHTML</acronym>)
+ resource through <acronym>HTTP GET</acronym> and can be used to access
+ other related objects by following links that represent the associations
+ of the domain object. The domain object can be interacted with by
+ modifying its state (through <acronym>HTTP PUT</acronym>) or by invoking
+ its actions (through <acronym>HTTP POST</acronym>).</para>
+
+ <sect1>
+ <title>Who this Guide is For</title>
+
+ <para>This guide describes how to use the <emphasis>restful viewer
+ </emphasis>both in prototype mode and how to deploy it into production
+ as a webapp. It also describes how to use the <emphasis>restful
+ viewer</emphasis>'s application library
+ <package>[oai.viewer.restful:applib]</package> to write client-side
+ applications. It is divided into the following chapters:<itemizedlist>
+ <listitem>
+ <para>Introduction</para>
+
+ <para>This chapter briefly introduces the concept of
+ <acronym>REST</acronym> and how it is mapped to the Isis domain
+ model. </para>
+ </listitem>
+
+ <listitem>
+ <para>The Restful Viewer Modules</para>
+
+ <para>This ....</para>
+ </listitem>
+
+ <listitem>
+ <para>Xxx</para>
+ </listitem>
+
+ <listitem>
+ <para>Xxx</para>
+ </listitem>
+
+ <listitem>
+ <para>Xxx</para>
+ </listitem>
+ </itemizedlist></para>
+ </sect1>
+
+ <sect1>
+ <title>Abbreviations used in this Guide</title>
+
+ <para><emphasis>Apache Isis</emphasis> is built using Maven, which
+ identifies every module with a <emphasis>groupId</emphasis>, an
+ <emphasis>artifactId</emphasis>, a <emphasis>version</emphasis>, and a
+ <emphasis>type</emphasis>. These are called the Maven
+ <emphasis>co-ordinates</emphasis>. In this guide we identify each module
+ using notation <package>(groupId:artifactId)</package>; you should
+ assume that the <emphasis>version</emphasis> is the latest version, and
+ the <emphasis>type</emphasis> is the default JAR artifact<footnote>
+ <para>Maven modules can create other artifacts too, such as a test
+ JAR artifact. This would be indicated with a type of test-jar. But
+ the default artifact is a regular JAR.</para>
+ </footnote>. Hence <package>(org.apache.isis:core)</package> is the
+ Maven module with a <emphasis>groupId</emphasis> of
+ <package>org.apache.isis</package> and an
+ <emphasis>artifactId</emphasis> of <package>core</package>.</para>
+
+ <para>As a further convenience, we use "oai" as an abbreviation for
+ <package>org.apache.isis</package>. Hence
+ <package>(oai.viewer:restful)</package> refers to the parent module for
+ Restful viewer. We also use the "oai" abbreviation within package
+ names.</para>
+ </sect1>
+ </preface>
+
+ <!-- main content -->
+
+ <chapter id="chp.Introduction">
+ <title>Introduction</title>
+
+ <abstract>
+ <para>An introduction to <acronym>REST</acronym> and how it maps onto an
+ <emphasis>Apache Isis</emphasis> domain model.</para>
+ </abstract>
+
+ <para>This chapter briefly explains what <acronym>REST</acronym> is, and
+ why you might want to use it. It then explains how the <emphasis>restful
+ viewer</emphasis> exposes your domain model using <acronym>REST</acronym>.
+ </para>
+
+ <sect1>
+ <title>Introducing REST</title>
+
+ <para>Web services were introduced as a means for different computer
+ systems to interact by network even though they may be implemented in
+ different technologies and with different implied domain models.
+ <acronym>SOAP</acronym> is probably the best well-known protocol for
+ doing this, though there have been others. These days there is a whole
+ bunch of specifications over and above those for SOAP; together these
+ are typically called <acronym>WS-*</acronym>.</para>
+
+ <para>Whatever; what characterizes the <acronym>WS-*</acronym>
+ implementations is that they expose only a single endpoint to be
+ invoked; in effect just another way of doing a remote procedure call.
+ Put another way, <acronym>WS-*</acronym> -style web services provide an
+ for a verb - "do this for me". In fact, this <acronym>RPC</acronym>
+ endpoint usually accepts many different message types, and uses some
+ sort of dispatcher to route the message so it can be processed
+ correctly.</para>
+
+ <para><acronym>REST</acronym> (standing for <ulink
+ url="http://en.wikipedia.org/wiki/Representational_State_Transfer"><emphasis>REpresentational
+ State Transfer</emphasis></ulink>) in contrast is a style of designing
+ web services that is modelled on the human web sites. Rather than expose
+ a single endpoint, it exposes multiple endpoints. And these endpoints
+ don't represent verbs, they represent things (or nouns). But
+ <acronym>REST</acronym> goes further than this, because it also
+ restricts what we can do with those resources to the standard
+ <acronym>HTTP</acronym> verbs: <acronym>GET</acronym> (read),
+ <acronym>PUT</acronym> (update), <acronym>DELETE</acronym> (er, delete)
+ and <acronym>POST</acronym> (invoke, or change in some way). The first
+ three of these are idempotent (can be invoked multiple times with no
+ side effects). This is an important characteristic for building scalable
+ systems, and is not one that the <acronym>RPC</acronym> approach towards
+ web services supports at all well.</para>
+
+ <para>What happens if we perform an <acronym>HTTP</acronym>
+ <acronym>GET</acronym> on a resource? Well, we get a representation of
+ that resource. <acronym>REST</acronym> doesn't mandate what that
+ representation is, but typical choices are <acronym>JSON</acronym>,
+ <acronym>XHTML</acronym> or a custom <acronym>XML</acronym> dialect.
+ However, what <acronym>REST</acronym> does emphasise is that these
+ resources should be linked together, again analogous to the way that the
+ human web works with hyperlinks.</para>
+
+ <para>So <acronym>REST</acronym> is much more closely associated with
+ the web - and <acronym>HTTP</acronym> in particular - than
+ <acronym>WS-*</acronym> -style web services ever were. But - so the
+ thinking goes - the vast majority of web services are deployed over the
+ web, so why disregard the web's semantics?</para>
+
+ <para>For much more on the design principles and philosophy behind
+ <acronym>REST</acronym>, you might want to read Richardson & Ruby's
+ <ulink url="http://oreilly.com/catalog/9780596529260">RESTful Web
+ Services</ulink>.</para>
+ </sect1>
+
+ <sect1 id="sec.IntroducingRestfulObjects">
+ <title>Introducing the Restful Viewer</title>
+
+ <para>As already stated, the <emphasis>Isis</emphasis>'
+ <emphasis>restful viewer</emphasis> automatically exposes a domain model
+ using <acronym>REST</acronym>. That is, the resources are the actual
+ domain objects, or - in some cases - a class member of one of those
+ objects. The following table shows the resources exposed:</para>
+
+ <table>
+ <title>Verbs by Resources</title>
+
+ <tgroup cols="5">
+ <colspec align="center" />
+
+ <thead>
+ <row>
+ <entry align="center">Verb \ Resource</entry>
+
+ <entry align="center">Object</entry>
+
+ <entry align="center">Property</entry>
+
+ <entry align="center">Collection</entry>
+
+ <entry align="center">Action</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry>GET</entry>
+
+ <entry>current state of all properties</entry>
+
+ <entry>n/a</entry>
+
+ <entry>current contents</entry>
+
+ <entry>n/a</entry>
+ </row>
+
+ <row>
+ <entry>PUT</entry>
+
+ <entry>create</entry>
+
+ <entry>set</entry>
+
+ <entry>add to</entry>
+
+ <entry>n/a</entry>
+ </row>
+
+ <row>
+ <entry>DELETE</entry>
+
+ <entry>remove</entry>
+
+ <entry>clear</entry>
+
+ <entry>remove from</entry>
+
+ <entry>n/a</entry>
+ </row>
+
+ <row>
+ <entry>POST</entry>
+
+ <entry>n/a</entry>
+
+ <entry>n/a</entry>
+
+ <entry>n/a</entry>
+
+ <entry>invoke</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>The <emphasis>restful viewer</emphasis> exposes a
+ <acronym>URL</acronym> for each of the columns. So, for example:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>a <classname>Customer</classname> instance id=12345 might be
+ exposed as <uri>http://localhost:8080/object/CUS|12345</uri>, where
+ "CUS|12345" is the (string representation of) the internal Naked
+ Objects object identifier (or <acronym>Oid</acronym>) that uniquely
+ identifies the domain object. Performing a <acronym>GET</acronym> on
+ this would list all of the properties of the
+ <classname>Customer</classname>.</para>
+ </listitem>
+
+ <listitem>
+ <para>the <varname>orders</varname> collection for this same
+ <classname>Customer</classname> would be exposed as
+ <uri>http://localhost:8080/object/CUS|12345/collection/orders</uri>.
+ Performing a <acronym>GET</acronym> on this would list (links to)
+ the contents of the collection.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>So much for interacting with the resources, but what of their
+ representation? Well, (following the suggestion in Richardson &
+ Ruby's book) the <emphasis>restful viewer </emphasis>renders the domain
+ objects using <acronym>XHTML</acronym>. This gives us a natural way to
+ express links between resources: we just use hyperlinks using the
+ <sgmltag><a href="..."/></sgmltag> tag. It also means that we can
+ inspect the domain objects from an web browser. For example, here's
+ Firefox displaying the resource representing an
+ <classname>EmployeeRepository</classname> (part of of the example claims
+ application, in trunk/examples/claims):</para>
+
+ <screenshot>
+ <screeninfo>OID / Naked Object / pojo relationship and
+ maps</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/resource-example.png" scale="40" />
+ </imageobject>
+ </mediaobject>
+ </screenshot>
+
+ <para>In fact, the <emphasis>restful viewer </emphasis>also serves up a
+ smidgeon of Javascript as well, to allow the web browser to perform
+ <acronym>PUT</acronym> and <acronym>DELETE</acronym> as well as the
+ usual <acronym>GET</acronym> and <acronym>POST</acronym>. This won't be
+ needed by your own custom written web apps, of course. (It also won't be
+ needed once <acronym>XHTML</acronym> 5 - with its support for these
+ additional <acronym>HTTP</acronym> verbs - becomes mainstream).</para>
+
+ <para>In case you're interested, behind the scenes the <emphasis>restful
+ viewer</emphasis> is implemented using <ulink
+ url="http://jboss.org/resteasy">JBoss RestEasy</ulink> (licensed under
+ Apache License v2, the same as <emphasis>Isis</emphasis> itself).</para>
+ </sect1>
+
+ <sect1>
+ <title>Limitations of REST</title>
+
+ <para>Because <acronym>REST</acronym> is newer than the original
+ <acronym>WS-*</acronym>-style services, it currently lacks some
+ supporting features. For example, some of the supporting
+ <acronym>WS-*</acronym> specifications deal with such things as security
+ credentials and transaction propagation. At the time of writing
+ <acronym>REST</acronym> is yet to gain these sorts of additional
+ support. That said, the <emphasis>restful viewer</emphasis> provides
+ some basic support for security. This is discussed in the chapters that
+ follow.</para>
+ </sect1>
+ </chapter>
+
+ <chapter>
+ <title id="chp.Prototyping">Using the QuickStart Archetype and the Restful
+ Viewer</title>
+
+ <abstract>
+ <para>How to get started prototyping with <emphasis>restful
+ viewer.</emphasis></para>
+ </abstract>
+
+ <para>The easiest way to get started is to run the
+ <emphasis>Isis</emphasis> quickstart archetype (eg as documented on
+ <emphasis>Isis</emphasis>' website). Once you've done this, you'll end up
+ with an set of modules that allow the application to be booted using the
+ <emphasis>restful viewer</emphasis>. It includes the following
+ modules:</para>
+
+ <programlisting>myapp/pom.xml
+ myapp-dom/pom.xml # domain object model
+ myapp-fixture/pom.xml # fixtures for seeding object store
+ myapp-objstore-dflt/pom.xml # repository implementations for the default object store
+ myapp-quickrun/pom.xml # run the application during development/prototyping
+ myapp-viewer-restful/pom.xml # run the application as a webapp using the restful viewer</programlisting>
+
+ <para>where 'myapp' is the artifactId specified when you ran the <code>mvn
+ archetype:generate</code> goal.</para>
+
+ <para>This chapter describes in more detail the contents of these modules,
+ and then describes how to get started with running the <emphasis>restful
+ viewer</emphasis> for prototyping purposes.</para>
+
+ <sect1 id="sec.ParentModule">
+ <title>Understanding the Generated Modules</title>
+
+ <para>Before we run the application, let's look at the modules generated
+ for us by the archetype.</para>
+
+ <sect2>
+ <title>The Parent Module</title>
+
+ <para>The parent module includes as an import a reference to the
+ Apache Isis <emphasis>release</emphasis> artifact
+ <package>[oai:release]</package>:</para>
+
+ <programlisting><dependencyManagement>
+ <dependencies>
+
+ <!-- Apache Isis -->
+ <dependency>
+ <groupId>org.apache.isis</groupId>
+ <artifactId>release</artifactId>
+ <version>x.x.x</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ ...
+
+ </dependencies>
+</dependencyManagement></programlisting>
+
+ <para>where <emphasis>x.x.x</emphasis> is the version of
+ <emphasis>Isis</emphasis> that you are using. The <code>scope</code>
+ of <emphasis>import</emphasis> means that all
+ <code><properties></code> of this artifact are imported, and any
+ <code><dependencyManagement>/<dependencies></code> are
+ imported also.</para>
+
+ <para>If you locate the <acronym>POM</acronym> for this artifact (eg
+ by looking in <filename>~/.m2/repository</filename>) then you'll see
+ that it defines:</para>
+
+ <programlisting><properties>
+ <isis.viewer-restful.version>y.y.y</isis.viewer-restful.version>
+ ....
+</properties></programlisting>
+
+ <para>where y.y.y is the corresponding version of the restful
+ viewer.</para>
+
+ <note>
+ <para>At the time of writing the version of Isis
+ <emphasis>core</emphasis> (x.x.x) and the version of
+ <emphasis>restful viewer</emphasis> (y.y.y) have been the same. This
+ may not always remain the case (just as Maven's plugins are
+ versioned separately from Maven itself).</para>
+ </note>
+
+ <para>In the <emphasis>release</emphasis> artifact's
+ <code><dependencyManagement></code> section you'll also find the
+ following:</para>
+
+ <programlisting><dependencyManagement>
+ <dependencies>
+ ...
+ <!-- viewer: restful -->
+ <dependency>
+ <groupId>org.apache.isis.viewer</groupId>
+ <artifactId>restful</artifactId>
+ <version>${isis.viewer-restful.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.isis.viewer</groupId>
+ <artifactId>restful-applib</artifactId>
+ <version>${isis.viewer-restful.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.isis.viewer</groupId>
+ <artifactId>restful-viewer</artifactId>
+ <version>${isis.viewer-restful.version}</version>
+ </dependency>
+ ...
+ </dependencies>
+</dependencyManagement></programlisting>
+
+ <para>The <package>[oai.viewer:restful]</package> module is the parent
+ for <emphasis>restful viewer</emphasis>
+ (<code><packaging>pom</packaging></code>). That means that
+ it doesn't provide any Java classesper se. The <emphasis>restful
+ viewer</emphasis> module
+ <package>[oai.viewer.restful:viewer]</package> on the other hand does
+ provide a <acronym>JAR</acronym> artifact, being the main
+ implementation of the viewer. The <emphasis>restful applib</emphasis>
+ module <package>[oai.viewer.restful:applib]</package> meanwhile is
+ used for writing client-side applications that use an exposed Isis
+ module, the topic of <xref
+ linkend="chp.WritingClientSideApps" />.</para>
+ </sect2>
+
+ <sect2 id="sec.TheQuickRunModule">
+ <title>The QuickRun Module</title>
+
+ <para>First, the <emphasis>quickrun</emphasis> module's parent is the
+ parent module of the previous section, so all of the definitions in
+ the parent <acronym>POM</acronym> are inherited. Delving further, If
+ you look at the <classname><dependencies></classname> for the
+ generated quickrun module, then you'll see a dependency on the
+ <emphasis>restful viewer</emphasis>'s <emphasis>viewer</emphasis>
+ module:</para>
+
+ <programlisting><dependencies>
+ ...
+ <!-- viewer: restful -->
+ <dependency>
+ <groupId>org.apache.isis.viewer</groupId>
+ <artifactId>restful-viewer</artifactId>
+ </dependency>
+ ...
+</dependencyManagement></programlisting>
+
+ <para>It also includes a <classname><profile></classname> to
+ allow the application to be run as a standalone JAR, with an embedded
+ Jetty viewer.</para>
+
+ <programlisting><profiles>
+ ...
+ <profile>
+ <!-- prereqs: mvn package -->
+ <!-- mvn antrun:run -D exec=restful -->
+ <id>exec-restful</id>
+ <activation>
+ <property>
+ <name>exec</name>
+ <value>restful</value>
+ </property>
+ </activation>
+ ...
+ </profile>
+ ...
+</profiles></programlisting>
+
+ <para>This profile defines a goal for the antrun plugin to execute the
+ generated <acronym>JAR</acronym><footnote>
+ <para>The generated JAR uses the maven-shade-plugin to package up
+ all dependencies. </para>
+ </footnote> from the command line using:</para>
+
+ <para><programlisting>java -jar xxx.jar -type exploration -viewer org.apache.isis.viewer.restful.viewer.embedded.RestfulViewerInstaller</programlisting></para>
+
+ <para>The installer specified by the <code>-viewer</code> flag acts as
+ a bridge to the embedded Jetty viewer.</para>
+
+ <para>Taking all the above together, it allows us to run the
+ application from the command line if we wish (discussed further in
+ <xref linkend="sec.RunningFromTheQuickRunModule" />). Moreover, the
+ generated <acronym>JAR</acronym> is built using the <ulink
+ url="http://maven.apache.org/plugins/maven-shade-plugin/">Maven shade
+ plugin</ulink>, so that it also packages up all dependencies. This
+ means that you can distribute this <acronym>JAR</acronym> - eg to your
+ project's stakeholders for review - as a self-contained entity.</para>
+
+ <para>Finally, the <emphasis>quickrun</emphasis> module also includes
+ a <filename>.launch</filename> configuration (in
+ <filename>ide/eclipse/launch</filename>) which lets us run the
+ application from within the Eclipse <acronym>IDE</acronym>. This is
+ equivalent to the <acronym>POM</acronym> profile described
+ above.</para>
+ </sect2>
+
+ <sect2 id="sec.TheViewerRestfulModule">
+ <title>The Viewer-Restful Module</title>
+
+ <para>Although the <emphasis>quickrun</emphasis> module is convenient
+ for prototyping, it isn't intended for runtime deployment. Instead,
+ you'll want a module that follows the webapp conventions and generates
+ a <acronym>WAR</acronym> file. This is the point of the generated
+ <emphasis>viewer-restful</emphasis> module.</para>
+
+ <para>Like the <emphasis>quickrun</emphasis> module, the
+ <emphasis>viewer-restful</emphasis> module inherits from the parent
+ module and so inherits the various definitions of the parent module.
+ And, not surprisingly, its <code><dependencies></code> section
+ includes a reference to the
+ <package>[oai.viewer.restful:viewer]</package> module.</para>
+
+ <para>More significantly, the <emphasis>viewer-restful</emphasis> has
+ the standard directory structure for a webapp, with
+ <filename>src/main/webapp/WEB-INF</filename> holding the
+ <filename>web.xml</filename> along with <emphasis>Isis</emphasis>' own
+ configuration files (<filename>isis.properties</filename> and
+ others).</para>
+
+ <para>The following sections look at the <filename>web.xml</filename>
+ in more detail</para>
+
+ <sect3>
+ <title>JAX-RS Configuration</title>
+
+ <para>The <filename>web.xml</filename> defines the following context
+ parameter:</para>
+
+ <programlisting><context-param>
+ <param-name>javax.ws.rs.Application</param-name>
+ <param-value>org.apache.isis.viewer.restful.viewer.RestfulApplication</param-value>
+</context-param></programlisting>
+
+ <para>This is used by <emphasis>RestEasy</emphasis> (the underlying
+ <acronym>JAX-RS</acronym> reference implementation) to define the
+ resources to be exposed. (These resources are discussed further in
+ <xref linkend="chp.Resources" />). <emphasis>RestEasy</emphasis>
+ itself is loaded through a context listener:</para>
+
+ <programlisting><listener>
+ <listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
+</listener></programlisting>
+
+ <para><emphasis>RestEasy</emphasis> also requires that its servlet
+ is registered:<programlisting><servlet>
+ <servlet-name>RestEasy</servlet-name>
+ <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
+</servlet>
+...
+<servlet-mapping>
+ <servlet-name>RestEasy</servlet-name>
+ <url-pattern>/</url-pattern>
+</servlet-mapping></programlisting></para>
+ </sect3>
+
+ <sect3>
+ <title>Isis Session handling (using the <emphasis>Default
+ Runtime</emphasis>)</title>
+
+ <para>An <emphasis>Isis</emphasis> session is required in order for
+ the <emphasis>restful viewer</emphasis> to interact with the
+ <emphasis>Isis</emphasis> runtime and interrogate the
+ metamodel/retrieve domain objects.</para>
+
+ <para>The first part of the required configuration is to set up an
+ <emphasis>Isis</emphasis> "context"; basically a set of factories
+ that are used to create a session for each subsequent request. This
+ is done using a context listener (defined in the <emphasis>default
+ runtime</emphasis>,
+ <package>[oai.runtimes.dflt:webapp]</package>):</para>
+
+ <programlisting><listener>
+ <listener-class>org.apache.isis.runtimes.dflt.webapp.IsisWebAppBootstrapper</listener-class>
+</listener></programlisting>
+
+ <para>The session is created for each request using the
+ <classname>IsisSessionFilter</classname>:</para>
+
+ <programlisting><filter>
+ <filter-name>IsisSessionFilter</filter-name>
+ <filter-class>org.apache.isis.runtimes.dflt.webapp.IsisSessionFilter</filter-class>
+ <init-param>
+ <param-name>authenticationSessionLookupStrategy</param-name>
+ <param-value>org.apache.isis.viewer.restful.viewer.authentication.AuthenticationSessionLookupStrategyTrusted</param-value>
+ </init-param>
+</filter>
+...
+<filter-mapping>
+ <filter-name>IsisSessionFilter</filter-name>
+ <url-pattern>*</url-pattern>
+</filter-mapping></programlisting>
+
+ <para>Note the <code><init-param></code> for the filter, which
+ defines a strategy for obtaining the authenticationSession (that is,
+ the user's credentials). In the architect specifies a strategy
+ whereby the caller is effectively trusted. However, other strategies
+ can be plugged in as required. This is discussed further in <xref
+ linkend="chp.DeployingRestfulObjectsWebapps" />.</para>
+ </sect3>
+
+ <sect3>
+ <title>Resources</title>
+
+ <para>Finally, the <filename>web.xml</filename> also declares a
+ servlet and a filter which are used for serving up and caching
+ certain supporting resources, most notably Javascript. The
+ Javascript is referenced by the generated <acronym>XHTML</acronym>
+ resources, and allow the web browser to submit RESTful requests
+ using HTTP PUT and HTTP DELETE (as well as the usual HTTP GET and
+ HTTP POST).</para>
+
+ <para>The <classname>ResourceServlet</classname> (defined by
+ <package>[oai.core:webapp]</package>) is used serve up static
+ content from either the classpath or file:</para>
+
+ <programlisting><servlet>
+ <servlet-name>Resource</servlet-name>
+ <servlet-class>org.apache.isis.core.webapp.content.ResourceServlet</servlet-class>
+</servlet>
+...
+<servlet-mapping>
+ <servlet-name>Resource</servlet-name>
+ <url-pattern>*.js</url-pattern>
+</servlet-mapping>
+<servlet-mapping>
+ <servlet-name>Resource</servlet-name>
+ <url-pattern>*.gif</url-pattern>
+</servlet-mapping>
+<servlet-mapping>
+ <servlet-name>Resource</servlet-name>
+ <url-pattern>*.png</url-pattern>
+</servlet-mapping></programlisting>
+
+ <para>The <classname>ResourceCachingFilter</classname> (also defined
+ by <package>[oai.core:webapp]</package>) is used to decorate any
+ static resources (Javascript, CSS or images) so that they are cached
+ client-side:</para>
+
+ <programlisting><filter>
+ <filter-name>ResourceCachingFilter</filter-name>
+ <filter-class>org.apache.isis.core.webapp.content.ResourceCachingFilter</filter-class>
+ <init-param>
+ <param-name>CacheTime</param-name>
+ <param-value>86400</param-value>
+ </init-param>
+</filter>
+...
+<filter-mapping>
+ <filter-name>ResourceCachingFilter</filter-name>
+ <url-pattern>*.js</url-pattern>
+</filter-mapping>
+<filter-mapping>
+ <filter-name>ResourceCachingFilter</filter-name>
+ <url-pattern>*.css</url-pattern>
+</filter-mapping>
+<filter-mapping>
+ <filter-name>ResourceCachingFilter</filter-name>
+ <url-pattern>*.jpg</url-pattern>
+</filter-mapping>
+<filter-mapping>
+ <filter-name>ResourceCachingFilter</filter-name>
+ <url-pattern>*.png</url-pattern>
+</filter-mapping>
+<filter-mapping>
+ <filter-name>ResourceCachingFilter</filter-name>
+ <url-pattern>*.gif</url-pattern>
+</filter-mapping></programlisting>
+ </sect3>
+ </sect2>
+ </sect1>
+
+ <sect1>
+ <title>Running the Viewer</title>
+
+ <para>The viewer can be run in a number of ways.</para>
+
+ <sect2 id="sec.RunningFromTheQuickRunModule">
+ <title>Running from the QuickRun Module</title>
+
+ <para>To run the viewer in a prototyping mode (that is, using the
+ standalone <acronym>JAR</acronym> and embedded Jetty webserver), you
+ can either:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>run from the command-line using Maven:</para>
+
+ <programlisting>cd viewer-restful
+mvn antrun:run -D exec=restful</programlisting>
+ </listitem>
+
+ <listitem>
+ <para>import into your <acronym>IDE</acronym> and use its in-built
+ support for running Maven goals, and run the above-mentioned
+ goal</para>
+
+ <para>In the case of Eclipse, this support is provided through the
+ <emphasis>m2eclipse</emphasis> plugin.</para>
+ </listitem>
+
+ <listitem>
+ <para>import into the Eclipse <acronym>IDE</acronym> and run using
+ the <filename>.launch</filename> configuration</para>
+
+ <para>Navigate to the <emphasis>quickrun</emphasis> module's
+ <filename>ide/eclipse/launch</filename> directory, select the
+ <filename>quickstart-quickrun-restful.launch</filename>
+ configuration, and use Run > Run As >
+ quickstart-quickrun-restful to launch in regular mode (or Debug
+ > Debug As > quickstart-quickrun-restful to launch in debug
+ mode).</para>
+ </listitem>
+ </itemizedlist>
+ </sect2>
+
+ <sect2>
+ <title>Running from the Viewer-Restful Module</title>
+
+ <para>To run the viewer as a webapp (that is, by hosting the
+ <acronym>WAR</acronym> in an separate instance of a Jetty web server),
+ you can either:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>run from the command-line using Maven:</para>
+
+ <programlisting>cd viewer-restful
+mvn jetty:run</programlisting>
+ </listitem>
+
+ <listitem>
+ <para>import into your <acronym>IDE</acronym> and use its in-built
+ support for running Maven goals, and run the above-mentioned
+ goal</para>
+
+ <para>In the case of Eclipse, this support is provided through the
+ <emphasis>m2eclipse</emphasis> plugin.</para>
+ </listitem>
+
+ <listitem>
+ <para>import into the Eclipse <acronym>IDE</acronym> and run using
+ the <filename>.launch</filename> configuration</para>
+
+ <para>Navigate to the <emphasis>viewer-restful</emphasis> module's
+ <filename>ide/eclipse/launch</filename> directory, select the
+ <filename>quickstart-viewer-restful.launch</filename>
+ configuration, and use Run > Run As >
+ quickstart-viewer-restful to launch in regular mode (or Debug >
+ Debug As > quickstart-viewer-restful to launch in debug
+ mode).</para>
+
+ <note>
+ <para>It's confusing perhaps, but this isn't quite the same as
+ running from the quickrun module: this launch configuration runs
+ the <classname>oai.WebServer</classname> utility class provided
+ by <emphasis>Isis</emphasis> which simply runs up the webapp
+ defined by <filename>web.xml</filename>. The quickrun module, on
+ the other hand, uses the special bridge class discussed in <xref
+ linkend="sec.TheQuickRunModule" />.</para>
+ </note>
+ </listitem>
+
+ <listitem>
+ <para>import into your <acronym>IDE</acronym> and use your
+ <acronym>IDE</acronym>'s native support for running
+ webapps.</para>
+
+ <para>In the case of Eclipse, this is its <acronym>WTP</acronym>
+ support (in the enterprise editions).</para>
+ </listitem>
+ </itemizedlist>
+ </sect2>
+ </sect1>
+
+ <sect1>
+ <title>Testing the Viewer</title>
+
+ <para>The point of restful viewer is to allow the domain objects to be
+ interacted with programmatically through <acronym>HTTP</acronym>, which
+ implies writing a custom client that submits the relevant
+ <acronym>HTTP</acronym> requests. Indeed, this is the topic of <xref
+ linkend="chp.WritingClientSideApps" />.</para>
+
+ <para>However, it is also useful to be able to browse the resources
+ directly, and because they are exposed using XHTML, this is possible to
+ do using a web browser. Therefore, boot up Firefox and browse to <ulink
+ url="http://localhost:8080">http://localhost:8080</ulink>. You should
+ either immediately be connected to the site, or see a link to the
+ context where the site is hosted.</para>
+
+ <note>
+ <para>Firefox is currently the only supported web browser for testing
+ in this way.</para>
+ </note>
+
+ <para>From the site, you should see links to access the services; these
+ are (representations of) the registered services (typically
+ repositories) in <filename>isis.properties</filename> configuration
+ file.</para>
+
+ <para>These structure of the resources is discussed further in <xref
+ linkend="chp.Resources" />.</para>
+ </sect1>
+ </chapter>
+
+ <chapter id="chp.Resources">
+ <title>Resources</title>
+
+ <abstract>
+ <para>A walk-through of the resources exposed by the restful viewer, and
+ how they are linked together.</para>
+ </abstract>
+
+ <para>Understanding how to interact with resources and how to interpret
+ their representations is central to the <acronym>REST</acronym>ful
+ approach. This chapter describes in detail the resources that are
+ available; in effect, the <acronym>API</acronym> for using domain objects
+ exposed using the <emphasis>restful viewer</emphasis>.</para>
+
+ <para>In order to invoke a <acronym>HTTP</acronym> method on a resource,
+ the <acronym>URL</acronym> must be constructed correctly. After that, the
+ client code then needs to handle the response.</para>
+
+ <para>Each of the resources is defined as interfaces annotated using
+ <classname>javax.ws.rs</classname> (<acronym>JAX-RS</acronym>)
+ annotations. <acronym>JAX-RS</acronym> is the Java <acronym>API</acronym>
+ for Restful Web Services, part of Java EE 6. Its annotations are used by
+ <acronym>JAX-RS</acronym> libraries such as <emphasis>RestEasy</emphasis>,
+ or <ulink url="https://jersey.dev.java.net/">Jersey</ulink> (the latter is
+ the reference implementation). These libraries expose the resources as
+ endpoints and route requests through to server-side methods (implemented
+ by the <emphasis>restful viewer</emphasis>).</para>
+
+ <para>As such, we can use these interfaces as a way of describing the
+ resources provided by the <emphasis>restful viewer</emphasis>. Let's go
+ through each in turn.</para>
+
+ <sect1 id="sec.HomePageResource">
+ <title>HomePageResource</title>
+
+ <para>To start with, we have
+ <classname>HomePageResource</classname>:</para>
+
+ <programlisting>import javax.ws.rs.GET;
+import javax.ws.rs.Produces;
+
+public interface HomePageResource {
+
+ @GET
+ @Produces( {"application/xhtml+xml", "text/html"} )
+ public String resources();
+}</programlisting>
+
+ <para>Because there is no <classname>@javax.ws.rs.Path</classname>
+ annotation, this in effect says that the root URL "/" (eg <ulink
+ url="http://localhost:8080/">http://localhost:8080/</ulink>) is a valid
+ resource. What you'll get back is an <acronym>XHTML</acronym> page that
+ identifies the current user (in exploration mode this is always
+ hard-coded), and then lists the resources available: the services (ie
+ repositories), the specifications (metamodel), and details on the
+ current user.</para>
+
+ <screenshot>
+ <screeninfo>Home Page Resource</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/home-page-resource.png" scale="40" />
+ </imageobject>
+ </mediaobject>
+ </screenshot>
+
+ <para>These blocks are always present on every page.</para>
+
+ <para>Meanwhile the raw <acronym>XHTML</acronym> - what your client code
+ must parse - looks something like:</para>
+
+ <programlisting><?xml version="1.0"?>
+<html>
+ <head><title>Home Page</title></head>
+ <body id="body">
+ <div>
+ <p>Logged in as</p>
+ <ul class="isis-session">
+ <li><a href="/user" rel="user" rev="resource" class="isis-user">sven</a></li>
+ </ul>
+ </div>
+ <div class="isis-section">
+ <p class="isis-section">Resources</p>
+ <ul class="isis-resources">
+ <li>
+ <a href="/services" rel="services" rev="resources" class="isis-resource">
+ Services
+ </a>
+ </li>
+ <li>
+ <a href="/specs" rel="specs" rev="resources" class="isis-resource">
+ Specifications (MetaModel)
+ </a>
+ </li>
+ <li>
+ <a href="/user" rel="user" rev="resources" class="isis-resource">
+ User (Security)
+ </a>
+ </li>
+ </ul>
+ </div>
+ </body>
+</html></programlisting>
+
+ <para>Note the use of <varname>class</varname> attributes to distinguish
+ the different types of properties. For example, the XPath expression
+ <emphasis>//a[@class='isis-resource']/@href</emphasis> will return the
+ links to all resources available. One of these -
+ <emphasis>/services</emphasis> - is the list of services, so lets look
+ at that next.</para>
+
+ <para><note>
+ <para>Depending on feedback, the format of the
+ <acronym>XHTML</acronym> may evolve in the future, eg to add in
+ further class attributes.</para>
+ </note></para>
+ </sect1>
+
+ <sect1>
+ <title>Services Resource</title>
+
+ <para>The <emphasis>/services</emphasis> link indicated in <xref
+ linkend="sec.HomePageResource" /> corresponds to the
+ <classname>ServicesResource</classname>:</para>
+
+ <programlisting>import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+
+public interface ServicesResource {
+
+ @GET
+ @Produces( {"application/xhtml+xml", "text/html"} )
+ @Path("/")
+ public String services();
+}</programlisting>
+
+ <para>The implementation of this interface in the <emphasis>restful
+ viewer</emphasis> (<classname>ServicesResourceImpl</classname>) also
+ defines a <code>@Path("/services")</code> for the class as a whole. This
+ therefore defines a <acronym>URL</acronym> in the form
+ <emphasis>/services</emphasis> supporting the <acronym>GET</acronym>
+ method.</para>
+
+ <note>
+ <para>It would be preferable, perhaps, for the
+ <code>@Path("/services")</code> annotation should reside on the
+ interface, not the implementation. This does not seem to be the way
+ that <emphasis>RestEasy</emphasis>, the underlying library used by the
+ <emphasis>restful viewer</emphasis>, works, however.</para>
+ </note>
+
+ <para>Here's the resource that's returned, as shown in a browser:</para>
+
+ <para><screenshot>
+ <screeninfo>Services Resource</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/services-resource.png" scale="40" />
+ </imageobject>
+ </mediaobject>
+ </screenshot>The first two sections are the same; what's new is the
+ list of services, corresponding to the registered services in
+ <filename>isis.properties</filename>. The <acronym>XHTML</acronym> for
+ this is:</para>
+
+ <programlisting><?xml version="1.0"?>
+<html>
+ <head><title>Services</title></head>
+ <body id="body">
+ ...
+ <div class="isis-section">
+ <p class="isis-section">Services</p>
+ <ul class="isis-services">
+ <li>
+ <a href="/object/OID:1" rel="service" rev="services" class="isis-service">
+ Employees
+ </a>
+ </li>
+ <li>
+ <a href="/object/OID:2" rel="service" rev="services" class="isis-service">
+ Claims
+ </a>
+ </li>
+ </ul>
+ </div>
+ </body>
+</html></programlisting>
+
+ <para>Again, we can use XPath to pull back the resources:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis>//a[@class='isis-service']/@href</emphasis> will
+ return the hyperlinks to the object resources representing these
+ services, in the form <emphasis>/object/OID</emphasis>.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>And let's look at object resources next.</para>
+ </sect1>
+
+ <sect1>
+ <title>Object Resource</title>
+
+ <para>The <emphasis>/object</emphasis> link indicated above corresponds
+ to the <classname>ObjectResource</classname> interface. This defines the
+ set of interactions described in <xref
+ linkend="sec.IntroducingRestfulObjects" />:</para>
+
+ <programlisting>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 {
+
+ ...
+}</programlisting>
+
+ <para>The implementation of this interface in the <emphasis>restful
+ viewer</emphasis> (<classname>ObjectResourceImpl</classname>) also
+ defines a <code>@Path("/object")</code> for the class as a whole. All
+ <acronym>URL</acronym> paths are therefore prefixed
+ <emphasis>/object/{oid}</emphasis>.</para>
+
+ <note>
+ <para>Again, it would be preferable if the <code>@Path</code>
+ annotation resided on the interface, not the implementation. This does
+ not seem to be the way that <emphasis>RestEasy</emphasis> works,
+ however.</para>
+ </note>
+
+ <para>Let's break it down into sections, starting with the
+ object.</para>
+
+ <sect2>
+ <title>Objects</title>
+
+ <para>The <emphasis>/objects/OID</emphasis> resource corresponds to
+ the <classname>ObjectResource</classname> interface:</para>
+
+ <programlisting>...
+
+public interface ObjectResource {
+
+ @GET
+ @Path("/{oid}")
+ @Produces( { "application/xhtml+xml", "text/html" })
+ public String object(
+ @PathParam("oid") final String oidStr);
+
+ ...
+}</programlisting>
+
+ <para>This defines <emphasis>/object/{oid}</emphasis> as a
+ <acronym>URL</acronym> supporting <acronym>GET</acronym>. Here's what
+ calling this method gives for a repository object:</para>
+
+ <para><screenshot>
+ <screeninfo>ClaimRepository Resource</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/object-claims-resource.png"
+ scale="40" />
+ </imageobject>
+ </mediaobject>
+ </screenshot>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.</para>
+
+ <para>Let's also look at a typical domain object:</para>
+
+ <screenshot>
+ <screeninfo>Claim Resource</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/object-claim-resource.png" scale="40" />
+ </imageobject>
+ </mediaobject>
+ </screenshot>
+
+ <para>The structure is the same, but here there are properties and
+ collections, as well as actions. Let's look at the
+ <acronym>XHTML</acronym> that represents this domain object, starting
+ with the title:</para>
+
+ <screenshot>
+ <screeninfo>Object Resource's Title section</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/object-claim-title-section.png"
+ scale="70" />
+ </imageobject>
+ </mediaobject>
+ </screenshot>
+
+ <para>The raw <emphasis>XHTML</emphasis> looks like:</para>
+
+ <programlisting><div>
+ <table border="1">
+ <tr>
+ <td>Object title</td>
+ <td class="isis-title">
+ <p>New - 2009-11-28</p>
+ </td>
+ </tr>
+ <tr>
+ <td>OID</td>
+ <td class="isis-oid">
+ <a href="/object/OID:C" rel="object" rev="object" class="isis-oid">
+ OID:C
+ </a>
+ </td>
+ </tr>
+ <tr>
+ <td>Specification</td>
+ <td class="isis-specification">
+ <a href="/specs/org.apache.isis.examples.claims.dom.claim.Claim"
+ rel="spec" rev="object" class="isis-specification">
+ org.apache.isis.examples.claims.dom.claim.Claim
+ </a>
+ </td>
+ </tr>
+ </table>
+</div></programlisting>
+
+ <para>Some useful XPath expressions:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis>//td[@class='isis-title']/p/text()</emphasis> will
+ return the title</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>//td[@class='isis-oid']/a/text()</emphasis> is the
+ OID (as a string)</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>//td[@class='isis-specification']/a/@href</emphasis>
+ is a link the (resource repreenting the) specification of this
+ object, in the form
+ <emphasis>/specs/{fullyQualifiedClassName}</emphasis></para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Next up is the properties section:</para>
+
+ <screenshot>
+ <screeninfo>Object Resource's Properties section</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/object-claim-properties-section.png"
+ scale="50" />
+ </imageobject>
+ </mediaobject>
+ </screenshot>
+
+ <para>The raw <acronym>XHTML</acronym> (abbreviated; just the first
+ property is listed) is:</para>
+
+ <programlisting><div class="isis-properties">
+ <p class="isis-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.apache.isis.examples.claims.dom.claim.Claim/property/description"
+ rel="propertySpec" rev="property" class="isis-property">Description</a>
+ </td>
+ <td>
+ <a href="/specs/java.lang.String" rel="propertyTypeSpec"
+ rev="property" class="isis-property">java.lang.String</a>
+ </td>
+ <td>
+ <p class="isis-visible">N</p>
+ </td>
+ <td>
+ <p class="isis-property">Meeting at clients</p>
+ </td>
+ <td>
+ <p class="isis-usable">N</p>
+ </td>
+ <td>
+ <p />
+ </td>
+ <td>
+ <p class="isis-visible">N</p>
+ </td>
+ <td>
+ <div class="isis-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="isis-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="isis-valid" id="property-invalid-description" />
+ </td>
+ </tr>
+ ...
+ </table>
+</div></programlisting>
+
+ <para>Some useful XPath expressions are:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis>//div[@class='isis-properties']//tr/td[1]/a/text()</emphasis>
+ returns the property names</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>//div[@class='isis-properties']//tr/td[2]/a/@href</emphasis>
+ returns links to (resources representing the) property types, in
+ the form
+ <emphasis>/specs/{fullyQualifiedClassName}</emphasis></para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>//div[@class='isis-properties']//tr/td[3]/p/text()</emphasis>
+ returns whether properties are invisible (N=not invisible)</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>//div[@class='isis-properties']//tr/td[4]</emphasis>
+ returns the <sgmltag><td></sgmltag> table cells containing
+ the values; the values will either be <sgmltag><p></sgmltag>
+ (values) or <sgmltag><a href=...></sgmltag>
+ (references)</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>and so on.</para>
+
+ <para>The "modify" and "clear" columns bear further description. These
+ are used to perform <acronym>PUT</acronym>s and
+ <acronym>DELETE</acronym>s on the resources that represent the
+ property. Because XHTML4 does not support <acronym>PUT</acronym> and
+ <acronym>DELETE</acronym> verbs in forms, they actually call
+ Javascript fragments to do these calls. See <xref
+ linkend="sec.Properties" /> for further details of the format of these
+ requests.</para>
+
+ <para>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 <acronym>OID</acronym>.</para>
+
+ <para>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.</para>
+
+ <para>Let's now look at the collections section:</para>
+
+ <screenshot>
+ <screeninfo>Object Resource's Collections section</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/object-claim-collections-section.png"
+ scale="50" />
+ </imageobject>
+ </mediaobject>
+ </screenshot>
+
+ <para>The raw <acronym>XHTML</acronym> is:</para>
+
+ <programlisting><div class="isis-collections">
+ <p class="isis-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.apache.isis.examples.claims.dom.claim.Claim/collection/items"
+ rel="propertySpec" rev="collection" class="isis-collection">
+ Items
+ </a>
+ </td>
+ <td>
+ <a href="/specs/org.apache.isis.examples.claims.dom.claim.ClaimItem"
+ rel="propertyTypeSpec" rev="property" class="isis-property">
+ org.apache.isis.examples.claims.dom.claim.ClaimItem
+ </a>
+ </td>
+ <td>
+ <p class="isis-visible">N</p>
+ </td>
+ <td>
+ <p class="isis-usable">N</p>
+ </td>
+ <td>
+ <a href="/object/OID:C/collection/items"
+ rel="collection" rev="nakedObject" class="isis-collection">items</a>
+ </td>
+ <td>
+ <div class="isis-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="isis-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="isis-valid" id="collection-invalid-items" />
+ </td>
+ </tr>
+ </table>
+</div></programlisting>
+
+ <para>In this particular case there is only a single collection, but
+ in general there could be many.</para>
+
+ <para>Some useful XPath expressions are:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis>//div[@class='isis-collections']//tr/td[1]/a/text()</emphasis>
+ returns the collection names</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>//div[@class='isis-properties']//tr/td[2]/a/@href</emphasis>
+ returns links to (resources representing the) type of the
+ collection, in the form
+ <emphasis>/specs/{fullyQualifiedClassName}</emphasis></para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>//div[@class='isis-properties']//tr/td[3]/p/text()</emphasis>
+ returns whether collections are invisible (N=not invisible)</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>//div[@class='isis-collections']//tr/td[5]/a/@href</emphasis>
+ returns a link to a resource representing the contents of the
+ collection, in the form
+ <emphasis>/object/{oid}/collection/{collectionId}</emphasis></para>
+ </listitem>
+ </itemizedlist>
+
+ <para>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</para>
+
+ <para>Similar to properties, the "addTo" and "removeFrom" columns are
+ used to submit <acronym>PUT</acronym> or <acronym>DELETE</acronym>s
+ against the collection resource. See <xref
+ linkend="sec.Collections" /> for more details. The arguments provided
+ are the OIDs of objects in the collection.</para>
+
+ <para>Finally, let's look at actions:</para>
+
+ <screenshot>
+ <screeninfo>Object Resource's Actions section</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/object-claim-actions-section.png"
+ scale="50" />
+ </imageobject>
+ </mediaobject>
+ </screenshot>
+
+ <para>The raw <acronym>XHTML</acronym> (abbreviated; just the first
+ action is listed) is:</para>
+
+ <programlisting><div class="isis-actions">
+ <p class="isis-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.apache.isis.examples.claims.dom.claim.Claim/action/addItem(int,double,java.lang.String)"
+ rel="actionSpec" rev="action" class="isis-action">Add Item</a>
+ </td>
+ <td>
+ <p class="isis-action">USER</p>
+ </td>
+ <td>
+ <a href="/specs/void" rel="actionReturnTypeSpec" rev="action" class="isis-action">void</a>
+ </td>
+ <td>
+ <p class="isis-action">3</p>
+ </td>
+ <td>
+ <p class="isis-visible">N</p>
+ </td>
+ <td>
+ <p class="isis-usable">N</p>
+ </td>
+ <td>
+ <p />
+ </td>
+ <td>
+ <a href="/object/OID:C" rel="actionRealTarget" rev="action" class="isis-action">OID:C</a>
+ </td>
+ <td>
+ <div class="isis-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></programlisting>
+
+ <para>Some useful XPath expressions are:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis>//div[@class='isis-actions']//tr/td[1]/a/text()</emphasis>
+ returns the names of each action</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>//div[@class='isis-actions']//tr/td[3]/a/@href</emphasis>
+ returns links to (resources representing the) type of the returned
+ result of each action, in the form
+ <emphasis>/specs/{fullyQualifiedClassName}</emphasis></para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>//div[@class='isis-actions']//tr/td[5]/p/text()</emphasis>
+ returns whether each action is invisible or not (N=not
+ invisible)</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>//div[@class='isis-actions']//tr/td[8]/a/text()</emphasis>
+ returns the <acronym>OID</acronym> of the real target; more on
+ this in a moment</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>//div[@class='isis-actions']//tr/td[9]//form</emphasis>
+ returns a form to invoke the action using
+ <acronym>POST</acronym></para>
+ </listitem>
+ </itemizedlist>
+
+ <para>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</para>
+
+ <para>There is no javascript calls this time; invoking actions is just
+ a <acronym>POST</acronym>. The arguments provided are the same as for
+ properties: text for parseable values, or the <acronym>OID</acronym>s
+ of objects for references.</para>
+
+ <para>The "realTarget" column is provided to support contributed
+ actions. For example, here are the actions listed for a domain object
+ (<classname>Employee</classname>) where the
+ <methodname>claimsFor()</methodname> action is contributed (by the
+ <classname>ClaimsRepository</classname>):</para>
+
+ <screenshot>
+ <screeninfo>Contributed Actions</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/object-employee-contributed-actions.png"
+ scale="50" />
+ </imageobject>
+ </mediaobject>
+ </screenshot>
+
+ <para>In the <emphasis>DnD viewer</emphasis> 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
+ (<classname>Employee</classname>).</para>
+
+ <para>And that concludes our run-through of the <acronym>GET</acronym>
+ verb for object resources. Phew!</para>
+
+ <note>
+ <para><acronym>PUT</acronym> and <acronym>DELETE</acronym> verbs for
+ object resources have not yet been implemented.</para>
+ </note>
+ </sect2>
+
+ <sect2 id="sec.Properties">
+ <title>Properties</title>
+
+ <para>The next set of resources exposed by
+ <classname>ObjectResource</classname> are those specific to
+ properties:</para>
+
+ <programlisting>...
+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);
+ ...
+}</programlisting>
+
+ <para>This defines
+ <emphasis>/object/{oid}/property/{propertyId}</emphasis> as the
+ <acronym>URL</acronym> supporting:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><acronym>PUT</acronym>, to change the value of a property;
+ the proposedValue should be a query parameter to this
+ <acronym>URL</acronym>;</para>
+ </listitem>
+
+ <listitem>
+ <para><acronym>DELETE</acronym>, to clear the property</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Calling these will first validate the change, and if accepted
+ apply the change:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>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 "isis-reason".</para>
+ </listitem>
+
+ <listitem>
+ <para>If the validation succeeds, the returned
+ <acronym>XHTML</acronym> is the object's title only.</para>
+ </listitem>
+ </itemizedlist>
+ </sect2>
+
+ <sect2 id="sec.Collections">
+ <title>Collections</title>
+
+ <para>The next set of resources exposed by
+ <classname>ObjectResource</classname> are those for
+ collections:</para>
+
+ <programlisting>...
+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);
+ ...
+}</programlisting>
+
+ <para>This defines
+ <emphasis>/object/{oid}/property/{collectionId}</emphasis> as a
+ <acronym>URL</acronym> supporting:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><acronym>GET</acronym>, to read the contents of this
+ collection.</para>
+ </listitem>
+
+ <listitem>
+ <para><acronym>PUT</acronym>, to add an item to the collection;
+ the proposedValue should be a query parameter to this
+ <acronym>URL</acronym> and contain an OID;</para>
+ </listitem>
+
+ <listitem>
+ <para><acronym>DELETE</acronym>, to remove an item to the
+ collection; the proposedValue should be a query parameter to this
+ <acronym>URL</acronym> and contain an OID;</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>The handling of <acronym>PUT</acronym> and the
+ <acronym>DELETE</acronym> 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 "isis-reason". Otherwise the object's title and OID are
+ returned.</para>
+
+ <note>
+ <para>We could perhaps change this to return the new contents of the
+ collection, ie as if a GET had been performed?</para>
+ </note>
+
+ <para>A <acronym>GET</acronym> meanwhile returns the following:</para>
+
+ <screenshot>
+ <screeninfo>Collection Contents</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/collection-items-resource.png"
+ scale="50" />
+ </imageobject>
+ </mediaobject>
+ </screenshot>
+
+ <para>The raw <acronym>XHTML</acronym> for the contents part of this
+ is:</para>
+
+ <programlisting><div class="isis-collection">
+ <p class="isis-collection">items</p>
+ <ul class="isis-collection">
+ <li>
+ <a href="/object/OID:D" rel="object" rev="results" class="isis-action-result">
+ Car parking
+ </a>
+ </li>
+ <li>
+ <a href="/object/OID:E" rel="object" rev="results" class="isis-action-result">
+ Reading - London (return)
+ </a>
+ </li>
+ </ul>
+</div></programlisting>
+
+ <para>Useful XPath here is:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis>//div[@class='isis-collection']//li/a/@href</emphasis>
+ to return the links to object resources in the collection</para>
+ </listitem>
+ </itemizedlist>
+ </sect2>
+
+ <sect2 id="sec.Actions">
+ <title>Actions</title>
+
+ <para>The final set of resources exposed by
+ <classname>ObjectResource</classname> is for actions:</para>
+
+ <programlisting>...
+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);
+ ...
+}</programlisting>
+
+ <para>This defines
+ <emphasis>/object/{oid}/property/{actionId}</emphasis> as a
+ <acronym>URL</acronym> supporting a POST. What's noteworthy here is
+ the last argument, an <classname>java.io.InputStream</classname>. This
+ provides a handle to the POST's input stream which contains the
+ parameter/argument pairs.</para>
+
+ <para>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:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>for reference types, the value should be the (string
+ representation of the) <acronym>OID</acronym> of the entity</para>
+ </listitem>
+
+ <listitem>
+ <para>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 <classname>ParseableFacet</classname> for the
+ parameter's type)</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>For example, for an action <code>findCustomers(registeredDate,
+ CustomerType)</code> then the parameters would be something
+ like:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>arg0=20090103</para>
+ </listitem>
+
+ <listitem>
+ <para>arg1=CTP|12</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>where <userinput>20090103</userinput> is 3-Jan-2009 in parseable
+ format, and <userinput>CTP|12</userinput> is the
+ <acronym>OID</acronym> (as assigned by the object store) for
+ <classname>CustomerType</classname> with ID=12.</para>
+
+ <para>When an action is invoked, the response always includes the
+ <acronym>OID</acronym> and title of the object on which the action was
+ invoked. In addition:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>if the action returned an object, then the response will
+ include a link to the object</para>
+
+ <note>
+ <para>We could perhaps change this to return the GET of the
+ returned object?</para>
+ </note>
+ </listitem>
+
+ <listitem>
+ <para>if the action returned a collection of objects, then the
+ response will return a list of links to the objects</para>
+ </listitem>
+
+ <listitem>
+ <para>if the action returned void; then nothing further is added
+ to the response</para>
+ </listitem>
+ </itemizedlist>
+ </sect2>
+ </sect1>
+
+ <sect1>
+ <title>Metamodel (specs) Resource</title>
+
+ <para>The
+ <emphasis><emphasis>/</emphasis>specs/{fullyQualifedClassName}</emphasis>
+ links indicated in several places in the representations produced by
+ <classname>ObjectResource</classname> corresponds to the
+ <classname>SpecsResource</classname>:</para>
+
+ <programlisting>import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+
+public interface SpecsResource {
+ ...
+}</programlisting>
+
+ <para>The implementation of this interface in <emphasis>restful
+ viewer</emphasis> (<classname>SpecsResourceImpl</classname>) also
+ defines a <code>@Path("/specs")</code> for the class as a whole. This
+ therefore defines a <acronym>URL</acronym> in the form
+ <emphasis>/services</emphasis> supporting the GET method.</para>
+
+ <note>
+ <para>As elsewhere, it would be preferable that the <code>@Path</code>
+ annotation should reside on the interface, not the implementation.
+ This seems to be a limitation with <emphasis>RestEasy</emphasis>, the
+ underlying library used by the <emphasis>restful
+ viewer</emphasis>.</para>
+ </note>
+
+ <para>The purpose of the <emphasis>/specs/</emphasis> family of
+ resources is to describe the structure of the domain objects, ie expose
+ a metamodel for the domain objects. Client-side applications might
+ choose to iterate through all the specs resources first and cache them;
+ this would then simplify the task of rendering domain objects.</para>
+
+ <para>Again, let's break the resources provided by
+ <classname>SpecsResource</classname> into sections.</para>
+
+ <sect2>
+ <title>All Classes</title>
+
+ <para>First up, we have a resource to list all classes (or
+ specs):</para>
+
+ <programlisting>import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+
+public interface SpecsResource {
+
+ @GET
+ @Path("/")
+ @Produces( { "application/xhtml+xml", "text/html" })
+ public abstract String specs();
+
+ ...
+}</programlisting>
+
+ <para>This defines <emphasis>/specs</emphasis> as a
+ <acronym>URL</acronym> accepting <acronym>GET</acronym>. This returns
+ the following:</para>
+
+ <screenshot>
+ <screeninfo>Specs Resource</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/specs-resource.png" scale="50" />
+ </imageobject>
+ </mediaobject>
+ </screenshot>
+
+ <para>The raw <acronym>XHTML</acronym> produced (abbreviated)
+ is:</para>
+
+ <programlisting><div class="isis-section">
+ <p class="isis-section">Specifications</p>
+ <ul class="isis-specifications">
+ ...
+ <li>
+ <a href="/specs/int" rel="spec" rev="specs"
+ class="isis-specification">int</a>
+ </li>
+ ...
+ <li>
+ <a href="/specs/java.lang.String" rel="spec" rev="specs"
+ class="isis-specification">java.lang.String</a>
+ </li>
+ ...
+ <li>
+ <a href="/specs/org.apache.isis.applib.value.Date" rel="spec" rev="specs"
+ class="isis-specification">org.apache.isis.applib.value.Date</a>
+ </li>
+ ..
+ <li>
+ <a href="/specs/org.apache.isis.examples.claims.dom.claim.Claim" rel="spec" rev="specs"
+ class="isis-specification">org.apache.isis.examples.claims.dom.claim.Claim</a>
+ </li>
+ <li>
+ <a href="/specs/org.apache.isis.examples.claims.dom.claim.ClaimItem" rel="spec" rev="specs"
+ class="isis-specification">org.apache.isis.examples.claims.dom.claim.ClaimItem</a>
+ </li>
+ ...
+ <li>
+ <a href="/specs/void" rel="spec" rev="specs"
+ class="isis-specification">void</a>
+ </li>
+ </ul>
+</div></programlisting>
+
+ <para>Useful XPath expressions:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis>//a[@class='isis-specification']/@href</emphasis>
+ will give links to resources for all specifications</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Let's look at an individual specification next.</para>
+ </sect2>
+
+ <sect2 id="sec.spec">
+ <title>Class (<classname>ObjectSpecification</classname>)</title>
+
+ <para>The resource for a specification is:</para>
+
+ <programlisting>...
+
+public interface SpecsResource {
+ ...
+ @GET
+ @Path("/{specFullName}")
+ @Produces( { "application/xhtml+xml", "text/html" })
+ public abstract String spec(
+ @PathParam("specFullName") final String specFullName);
+ ...
+}</programlisting>
+
+ <para>This defines <emphasis>/specs/{specFullName}</emphasis> as a
+ <acronym>URL</acronym> accepting <acronym>GET</acronym>. This
+ returns:</para>
+
+ <screenshot>
+ <screeninfo>Spec Resource</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/spec-resource.png" scale="36" />
+ </imageobject>
+ </mediaobject>
+ </screenshot>
+
+ <para>The raw <acronym>XHTML</acronym> for this breaks into five
+ regions.</para>
+
+ <para>First (abbreviated) we have the facets, which define additional
+ semantics to the holder (in this case, the spec):</para>
+
+ <programlisting><div class="isis-facets">
+ <p class="isis-facets">Facets</p>
+ <table border="1">
+ <tr>
+ <th>FacetType</th>
+ <th>Implementation</th>
+ ...
+ </tr>
+ ...
+ <tr>
+ <td>
+ <a href="org.apache.isis.examples.claims.dom.claim.Claim/facet/org.apache.isis.core.metamodel.facets.object.plural.PluralFacet"
+ rel="facet" rev="spec" class="isis-facet">org.apache.isis.core.metamodel.facets.object.plural.PluralFacet</a>
+ </td>
+ <td>
+ <p>org.apache.isis.core.metamodel.facets.object.plural.PluralFacetInferred</p>
+ </td>
+ ...
+ </tr>
+ ...
+ <tr>
+ <td>
+ <a href="org.apache.isis.claims.dom.claim.Claim/facet/org.apache.isis.core.metamodel.facets.named.NamedFacet"
+ rel="facet" rev="spec" class="isis-facet">org.apache.isis.core.metamodel.facets.named.NamedFacet</a>
+ </td>
+ <td>
+ <p>org.apache.isis.core.metamodel.facets.named.NamedFacetInferred</p>
+ </td>
+ ...
+ </tr>
+ ...
+ <tr>
+ <td>
+ <a href="org.apache.isis.examples.claims.dom.claim.Claim/facet/org.apache.isis.core.metamodel.facets.describedas.DescribedAsFacet" rel="facet" rev="spec" class="isis-facet">org.apache.isis.core.metamodel.facets.describedas.DescribedAsFacet</a>
+ </td>
+ <td>
+ <p>org.apache.isis.core.progmodel.facets.fallback.DescribedAsFacetNone</p>
+ </td>
+ ...
+ </tr>
+ ...
+ </table>
+</div></programlisting>
+
+ <para>Many of the facets listed will not be that relevant to us, but
+ some - such as the singular name of a class
+ (<classname>NamedFacet</classname>), the plural name of a class
+ (<classname>PluralFacet</classname>) and the description of a class
+ (<classname>DescribedAsFacet</classname>) will be useful for
+ presentation purposes. It is also possible to define additional facets
+ that might be relevant to your own client-side application. For
+ example, if you were writing a mash-up <acronym>GUI</acronym> and
+ wanted to render an <classname>Address</classname> domain object
+ within a map, you might want to define a
+ <classname>MapCoordinatesFacet</classname>.</para>
+
+ <note>
+ <para>Actually, this isn't quite true; there is currently no way in
+ the <emphasis>restful viewer</emphasis> to evaluate a facet for a
+ particular domain object instance.</para>
+ </note>
+
+ <para>As ever, we can use XPath to pull out values:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis>//div[@class='isis-facets']//a[.='org.apache.isis.core.metamodel.facets.object.plural.PluralFacet']/@href</emphasis>
+ will pull out the link for the <classname>PluralFacet</classname>,
+ if there is one.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Next we have the (definition of the) properties for a
+ spec:</para>
+
+ <programlisting><div class="isis-properties">
+ <p class="isis-properties">Properties</p>
+ <ul class="isis-properties">
+ <li>
+ <a href="/specs/org.apache.isis.examples.claims.dom.claim.Claim/property/description"
+ rel="property" rev="spec" class="isis-property">description</a>
+ </li>
+ <li>
+ <a href="/specs/org.apache.isis.examples.claims.dom.claim.Claim/property/date"
+ rel="property" rev="spec" class="isis-property">date</a>
+ </li>
+ ...
+ </ul>
+</div></programlisting>
+
+ <para>Useful XPath queries here:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis>//div[@class='isis-properties']//a/text()</emphasis>
+ returns the property names</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>//div[@class='isis-properties']//a/@href</emphasis>
+ returns links to the property definitions (see <xref
+ linkend="sec.SpecMembers" />)</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Similarly, we have collections:</para>
+
+ <programlisting><div class="isis-collections">
+ <p class="isis-collections">Collections</p>
+ <ul class="isis-collections">
+ <li>
+ <a href="/specs/org.apache.isis.examples.claims.dom.claim.Claim/collection/items"
+ rel="collection" rev="spec" class="isis-collection">items</a>
+ </li>
+ ...
+ </ul>
+</div></programlisting>
+
+ <para>Useful XPath queries here:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis>//div[@class='isis-collections']//a/text()</emphasis>
+ returns the collection names</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>//div[@class='sis-collections']//a/@href</emphasis>
+ returns links to the collection definitions (see <xref
+ linkend="sec.SpecMembers" />)</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Lastly, the actions. These fall into three groups: regular
+ (USER) actions, debug actions (annotated with
+ <classname>@Debug</classname>) and exploration actions (that are
+ available only in exploration mode):</para>
+
+ <programlisting><div class="isis-actions">
+ <p class="isis-actions">USER actions</p>
+ <ul class="isis-actions">
+ <li>
+ <a href="/specs/org.apache.isis.examples.claims.dom.claim.Claim/action/addItem(int,double,java.lang.String)"
+ rel="action" rev="spec" class="isis-action">addItem(int,double,java.lang.String)</a>
+ </li>
+ <li>
+ <a href="/specs/org.apache.isis.examples.claims.dom.claim.Claim/action/submit(org.apache.isis.examples.claims.dom.claim.Approver)"
+ rel="action" rev="spec" class="isis-action">submit(org.apache.isis.examples.claims.dom.claim.Approver)</a>
+ </li>
+ </ul>
+</div>
+<div class="isis-actions">
+ <p class="isis-actions">DEBUG actions</p>
+ <ul class="isis-actions" />
+</div>
+<div class="isis-actions">
+ <p class="isis-actions">EXPLORATION actions</p>
+ <ul class="isis-actions" />
+</div></programlisting>
+
+ <para>Useful XPath queries here:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis>//div[@class='isis-actions' and p/text()='USER
+ actions']//a/@href</emphasis> returns links to the regular user
+ actions</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>//div[@class='isis-actions' and p/text()='DEBUG
+ actions']//a/@href</emphasis> returns links to the debug
+ actions</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>//div[@class='isis-actions' and
+ p/text()='EXPLORATION actions']//a/@href</emphasis> returns links
+ to the exploration actions</para>
+ </listitem>
+ </itemizedlist>
+ </sect2>
+
+ <sect2 id="sec.SpecMembers">
+ <title>Class Members (<classname>ObjectMember</classname>)</title>
+
+ <para>The next set of resources provided by SpecsResource are for the
+ individual class members (properties, collections or actions):</para>
+
+ <programlisting>...
+
+public interface SpecsResource {
+ ...
+ @GET
+ @Path("/{specFullName}/property/{propertyName}")
+ @Produces( { "application/xhtml+xml", "text/html" })
+ public abstract String specProperty(
+ @PathParam("specFullName") final String specFullName,
+ @PathParam("propertyName") final String propertyName);
+
+ @GET
+ @Path("/{specFullName}/collection/{collectionName}")
+ @Produces( { "application/xhtml+xml", "text/html" })
+ public abstract String specCollection(
[... 661 lines stripped ...]