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 15:07:40 UTC
svn commit: r1139777 [2/3] - in /incubator/isis/trunk/viewer: json/
json/applib/ json/applib2/ json/src/docbkx/ json/src/docbkx/guide/
json/src/site/apt/ json/viewer/
json/viewer/src/main/java/org/apache/isis/viewer/restful/viewer2/representations/
jso...
Copied: incubator/isis/trunk/viewer/json/src/docbkx/guide/isis-json-viewer.xml (from r1139763, 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-json-viewer.xml?p2=incubator/isis/trunk/viewer/json/src/docbkx/guide/isis-json-viewer.xml&p1=incubator/isis/trunk/viewer/json/src/docbkx/guide/isis-restful-viewer.xml&r1=1139763&r2=1139777&rev=1139777&view=diff
==============================================================================
--- incubator/isis/trunk/viewer/json/src/docbkx/guide/isis-restful-viewer.xml (original)
+++ incubator/isis/trunk/viewer/json/src/docbkx/guide/isis-json-viewer.xml Sun Jun 26 13:07:39 2011
@@ -43,11 +43,10 @@
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
+ <para><emphasis>Isis</emphasis>' <emphasis>json</emphasis> viewer
+ <package>[oai.viewer:json]</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>)
+ resources. Each domain object is exposed as an (<acronym>JSON</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
@@ -57,22 +56,22 @@
<sect1>
<title>Who this Guide is For</title>
- <para>This guide describes how to use the <emphasis>restful viewer
+ <para>This guide describes how to use the <emphasis>jsonl 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
+ as a webapp. It also describes how to use the <emphasis>json
viewer</emphasis>'s application library
- <package>[oai.viewer.restful:applib]</package> to write client-side
+ <package>[oai.viewer.json: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>
+ model.</para>
</listitem>
<listitem>
- <para>The Restful Viewer Modules</para>
+ <para>The JSON Viewer Modules</para>
<para>This ....</para>
</listitem>
@@ -112,2789 +111,17 @@
<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
+ <package>(oai.viewer:json)</package> refers to the parent module for
+ JSON 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>
+ <title>Xxx</title>
- <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(
- @PathParam("specFullName") final String specFullName,
- @PathParam("collectionName") final String collectionName);
-
- @GET
- @Path("/{specFullName}/action/{actionId}")
- @Produces( { "application/xhtml+xml", "text/html" })
- public abstract String specAction(
- @PathParam("specFullName") final String specFullName,
- @PathParam("actionId") final String actionId);
- ...
-}</programlisting>
-
- <para>This defines the following <acronym>URL</acronym>s all accepting
- <acronym>GET</acronym>:</para>
-
- <itemizedlist>
- <listitem>
- <para><emphasis>/specs/{specFullName}/property/{propertyName}</emphasis>
- for a resource representing a property definition</para>
- </listitem>
-
- <listitem>
- <para><emphasis>/specs/{specFullName}/collection/{propertyName}</emphasis>
- for a resource representing a collection definition</para>
- </listitem>
-
- <listitem>
- <para><emphasis>/specs/{specFullName}/action/{actionId}</emphasis>
- for a resource representing a action definition</para>
- </listitem>
- </itemizedlist>
-
- <para>Each of these resources generates a similar representation,
- listing the facets for that class member. For example, here is the
- resource for a property spec:</para>
-
- <screenshot>
- <screeninfo>Spec Member Resource</screeninfo>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/spec-member-resource.png" scale="33" />
- </imageobject>
- </mediaobject>
- </screenshot>
-
- <para>The raw <acronym>XHTML</acronym> (abbreviated) is:</para>
-
- <programlisting><div>
- <p>Owners</p>
- <ul class="isis-specification">
- <a href="/specs/org.apache.isis.examples.claims.dom.claim.Claim" rel="spec" rev="property" class="isis-specification">owning spec</a>
- </ul>
-</div>
[... 608 lines stripped ...]