isis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From danhayw...@apache.org
Subject svn commit: r1039874 [2/5] - in /incubator/isis/trunk: ./ alternatives/remoting/src/docbkx/guide/ alternatives/security/file/src/docbkx/guide/ alternatives/security/ldap/src/docbkx/guide/ applib/src/docbkx/guide/ core/metamodel/src/test/java/org/apache...
Date Sun, 28 Nov 2010 12:49:01 GMT
Modified: incubator/isis/trunk/applib/src/docbkx/guide/isis-applib.xml
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/applib/src/docbkx/guide/isis-applib.xml?rev=1039874&r1=1039873&r2=1039874&view=diff
==============================================================================
--- incubator/isis/trunk/applib/src/docbkx/guide/isis-applib.xml (original)
+++ incubator/isis/trunk/applib/src/docbkx/guide/isis-applib.xml Sun Nov 28 12:49:00 2010
@@ -1,6 +1,6 @@
 <?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">
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"file:./src/docbkx/dtd-4.5/docbookx.dtd">
 <!--
   Licensed to the Apache Software Foundation (ASF) under one
   or more contributor license agreements.  See the NOTICE file
@@ -81,885 +81,3535 @@
 
   <!-- main content -->
 
-  <chapter id="chp.Intro">
-    <title>Overview</title>
+  <part>
+    <title>The Default Programming Model</title>
 
-    <abstract>
-      <para>This chapter gives an overview of the main principles and patterns
-      that underly the Apache Isis approach.</para>
-    </abstract>
-
-    <sect1>
-      <title>Introduction</title>
-
-      <para><emphasis>Apache Isis</emphasis> is a full-stack open source
-      application development framework, designed to let you rapidly develop
-      enterprise business applications following a domain-driven philosophy.
-      Developing an application in Isis is - at least initially - about
-      focusing on the bit that matters to the business, the core domain logic.
-      It</para>
+    <chapter>
+      <title>Developing domain objects - a how-to guide</title>
 
-      <para></para>
+      <para>This section defines a set of conventions for writing domain
+      objects, that are together known as the '[[NAME]] (Java) Programming
+      Model'.</para>
+
+      <para>Following these conventions does not tie your domain objects to
+      the [[NAME]] Framework or any other framework: the resulting domain
+      objects may be run within any framework or platform that supports POJOs
+      (Plain Old Java Objects). A few of the conventions do make use of
+      Interfaces or Annotations that are necessarily defined somewhere - in
+      this case they are in the [[NAME]] AppLib. However, the AppLib is not
+      itself dependent upon the [[NAME]] Framework (and in theory another
+      framework implementation could support the same applib).</para>
+
+      <para>The conventions of the programming model are best described as
+      'intentional' - they convey an intention as to how domain objects, their
+      properties and behaviours, are to be made available to users. The
+      specific way in which those intentions are interpreted or implemented
+      will depend upon the framework, and/or the particular components or
+      options selected within that framework.</para>
+
+      <para>To pick a single example, marking up a domain class with the
+      annotation <code>@Bounded</code> is an indication that the class is
+      intended to have only a small number of instances and that the set does
+      not change very often - such as the class <code>Country</code>. This is
+      an indication to any interested framework that the whole set of
+      instances might be offered to the user in a convenient form such as a
+      drop-down list. The programming convention has <emphasis>not</emphasis>
+      been defined as <code>@DropDownList</code> because the user interface
+      might not support drop-down-lists - but it might provide a capability to
+      select from an <code>@Bounded</code> class by typing the initial letters
+      of the desired instance.</para>
+
+      <sect1>
+        <title>Object-level specifications</title>
+
+        <para>The first set of conventions are concerned with the capabilities
+        or behaviour of an object as a whole.</para>
+
+        <sect2>
+          <title condition="java">How to specify a title for an object</title>
+
+          <para>A title is used to identify an object to the user in the user
+          interface. For example, a Customer's title might be the
+          organization's customer reference, or perhaps (more informally)
+          their first and last names. By default, the framework will use the
+          object's <literal moreinfo="none">toString()</literal> method as the
+          title. However, if a <literal moreinfo="none">title()
+          </literal>method (returning a <literal
+          moreinfo="none">String</literal>) is present, then that is used
+          instead, thus:</para>
+
+          <para><programlisting>public String toString()</programlisting></para>
+
+          <para>or</para>
+
+          <para><programlisting>public String title()</programlisting></para>
+
+          <para>The reason for providing the option to use a <literal
+          moreinfo="none">title</literal> method is in case the programmer
+          needs to make use of the <literal moreinfo="none">toString</literal>
+          method for other purposes, such as for debugging.</para>
+        </sect2>
+
+        <sect2>
+          <title condition=".net">How to specify the icon for an
+          object</title>
+
+          <para condition="1.5">By default, the framework will look for an
+          image in the <filename class="directory"
+          moreinfo="none">images</filename> directory (which must be on the
+          classpath) that has the same name as the object class. So for an
+          object of type Customer, it will look for <filename
+          class="directory" moreinfo="none">Customer.gif</filename> or
+          <filename class="directory" moreinfo="none">Customer.png</filename>.
+          If it finds no such file, then it will work up the inheritance
+          hierarchy to see if there is an icon matching the name of any of the
+          super-classes, and use that instead. If no matching icon is found
+          then the framework will look for an image called <filename
+          class="directory" moreinfo="none">default</filename> in the images
+          directory, and if this has not been specified, then the framework
+          will use its own default image for an icon.</para>
+
+          <para>We strongly recommend that you adopt 'camel case' as the
+          convention for icon file names: if you have a class called
+          <classname condition="vb"> OrderLine</classname>, then call the icon
+          <filename class="directory" moreinfo="none">OrderLine.gif</filename>
+          or <filename class="directory"
+          moreinfo="none">OrderLine.png</filename> (JPEG suffixes
+          <filename>OrderLine.jpg</filename> or
+          <filename>OrderLine.jpeg</filename> will also be recognized but
+          generally GIF or PNG are to be preferred). Actually, the framework
+          will also recognise <filename class="directory"
+          moreinfo="none">orderline.gif</filename>, but some operating systems
+          and deployment environments are case sensitive, so it is good
+          practice to adopt an unambiguous convention.</para>
+
+          <para>The programmer may choose to specify, manually, which icon to
+          use, by specifying an <literal moreinfo="none">iconName</literal>
+          method:</para>
+
+          <programlisting format="linespecific">    public String iconName() {
+        return "Person";
+    }</programlisting>
+
+          <para>This makes it easy for more than one class to use the same
+          icon, without having to duplicate the image file.</para>
+
+          <para>The <code>iconName</code> method may also be used to specify
+          an individual icon for each instance. For example, an instance of
+          <classname>Product</classname> could use a photograph of the product
+          as an icon, using:</para>
+
+          <programlisting format="linespecific">    public String iconName() {
+        return getProductName() + "-photograph";
+    }</programlisting>
+
+          <para>or to vary the icon according to the status of the
+          object:<programlisting>    public String iconName() {
+        return "Order-" + getStatus();
+    }</programlisting></para>
+        </sect2>
+
+        <sect2>
+          <title condition="j#">How to specify a name and/or description for
+          an object</title>
+
+          <para>By default, the name (or type) of an object, as displayed to
+          the user will be the class name. However, if an <literal
+          moreinfo="none">@Named</literal> annotation is included, then this
+          will override the default name. This might be used to include
+          punctuation or other characters that may not be used within a class
+          name.</para>
+
+          <para>By default the framework will create a plural version of the
+          object name by adding an 's' to singular name, or a 'ies' to names
+          ending 'y'. For irregular nouns or other special case, the
+          <code>@Plural</code> annotation may be used to specify the plural
+          form of the name explicitly.</para>
+
+          <para>(Note that there is an entirely separate mechanism for dealing
+          with Internationalisation, which is described elsewhere).</para>
+
+          <para>The programmer may optionally also provide a <literal
+          moreinfo="none">@DescribedAs</literal> annotations, containing a
+          brief description of the object's purpose, from a user perspective.
+          The framework will make this available to the user in a form
+          appropriate to the user interface style - for example as 'balloon'
+          help.</para>
+        </sect2>
+
+        <sect2>
+          <title condition="vb">How to specify that an object should not be
+          persisted</title>
+
+          <para>Use the <literal moreinfo="none">@NotPersistable</literal>
+          annotation.</para>
+        </sect2>
+
+        <sect2>
+          <title>How to specify that an object should never be modified by the
+          user</title>
+
+          <para>Use the <literal moreinfo="none">@Immutable</literal>
+          annotation.</para>
+        </sect2>
+
+        <sect2>
+          <title>How to specify that a class of objects has a limited number
+          of instances</title>
+
+          <para>Use the <literal moreinfo="none">@Bounded</literal>
+          annotation. A common way of describing this is that the whole
+          (limited) set of instances may be rendered to the user as a drop
+          down list - but the actual interpretation will depend upon the form
+          of the user interface.</para>
+        </sect2>
+
+        <sect2>
+          <title>How to specify that an object should always be hidden from
+          the user</title>
+
+          <para>Use the <literal moreinfo="none">@Hidden</literal>
+          annotation.</para>
+        </sect2>
+      </sect1>
+
+      <sect1>
+        <title>The object lifecycle</title>
+
+        <para>These conventions are concerned with the creation, retrieval,
+        updating and deletion of objects.</para>
+
+        <sect2>
+          <title>How to create or delete objects within your code</title>
+
+          <para>When you create any domain object within your application
+          code, it is important that the framework is made aware of the
+          existence of this new object - in order that it may be persisted to
+          the object store, and in order that any services that the new object
+          needs are injected into it. Just specifying <literal
+          moreinfo="none">new Customer()</literal>, for example, will create a
+          Customer object, but that object will <emphasis>not</emphasis> be
+          known to the framework. However, since we do not want to tie our
+          domain objects to a particular framework, we use the idea of a
+          'container' to intermediate. The application library provides an
+          interface:</para>
+
+          <para><literal
+          moreinfo="none">org.apache.isis.applib.DomainObjectContainer</literal>
+          which in turn defines the following methods for managing domain
+          objects:</para>
+
+          <para><literal moreinfo="none">&lt;T&gt; T
+          newTransientInstance(final Class&lt;T&gt; ofClass)</literal> returns
+          a new instance of the specified class, that is transient (unsaved).
+          This may subsequently saved either by the user invoking the Save
+          action (that will automatically be rendered on the object view) or
+          programmatically by calling <literal moreinfo="none">void
+          makePersistent(Object transientObject)</literal></para>
+
+          <para><literal moreinfo="none">&lt;T&gt; T
+          newPersistentInstance(final Class&lt;T&gt; ofClass)</literal>
+          creates a new object already persisted.</para>
+
+          <para><literal moreinfo="none">boolean
+          isPersistent()</literal>checks whether an object has already been
+          persisted. (Useful in controlling visibility or availability of
+          properties or actions).</para>
+
+          <para><literal moreinfo="none">void remove(Object object)</literal>
+          deletes a persistent object from the object store.</para>
+
+          <para>Any framework that recognises the [[NAME]] Programming Model
+          will provide an implementation of <code>DomainObjectContainer</code>
+          and will take responsibility to inject a reference to that Container
+          into any domain object that needs it.</para>
+
+          <para>A domain object specifies that it needs to have a reference to
+          the Container injected into by including the following code:</para>
+
+          <programlisting format="linespecific">    private DomainObjectContainer container;
+
+    protected DomainObjectContainer getContainer() {
+        return this.container;
+    }
+    public final void setContainer(final DomainObjectContainer container) {
+        this.container = container;
+    }</programlisting>
+
+          <para>Creating or deleting objects is then done by invoking those
+          methods on the Container. For example the following code would then
+          create a new Customer object within another method:</para>
+
+          <programlisting format="linespecific">    Customer newCust = (Customer) getContainer().newTransientInstance(Customer.class);
+    newCust.setName("Charlie");
+    getContainer().persist(newCust);</programlisting>
+
+          <para>If you are able to make your domain object inherit from
+          <literal
+          moreinfo="none">org.apache.isis.applib.AbstractDomainObject</literal>
+          then you have direct access to those methods, so the code would
+          become:</para>
+
+          <programlisting format="linespecific">    Customer newCust = (Customer) newTransientInstance(Customer.class);
+    newCust.setName("Charlie");
+    persist(newCust);</programlisting>
+
+          <para>These methods are actually provided by the
+          <classname>org.apache.isis.applib.AbstractContainedObject</classname>
+          and so are also available on <literal
+          moreinfo="none">org.apache.isis.applib.AbstractService</literal>
+          (and, hence, on <literal
+          moreinfo="none">org.apache.isis.applib.AbstractFactoryAndRepository</literal>)
+          for creating objects within a service.</para>
+
+          <warning>
+            <para>It is possible to create a transient object within another
+            transient object. When the framework persists any transient
+            object, it will automatically persist any other transient object
+            referenced by that object. However, if any of these transient
+            objects are to be exposed to the user (while in their transient
+            state), then you need to write your code very carefully -
+            anticipating the fact that the user could elect to save any of the
+            transient objects at any point - which could cause the graph of
+            related objects to be persisted in an invalid state.</para>
+
+            <para>The recommended approach is, if possible, to mark these
+            supplementary classes as not persistable by the user (see <xref
+            linkend="not-persistable" />), or not to permit the user to create
+            a new transient object that is a child of an existing transient
+            object, but, rather, to require the user to save the parent object
+            first.</para>
+          </warning>
+        </sect2>
+
+        <sect2>
+          <title>How to insert behaviour into the object life cycle</title>
+
+          <para>The following is a list of methods that correspond to various
+          events in the life-cycle of a domain object. If a domain object
+          implements any of these methods (they are all optional) then the
+          framework will call that method whenever the corresponding event
+          occurs. For example, <literal
+          moreinfo="none"><methodname>persisted</methodname></literal> is
+          called after an object has been persisted. One reason for
+          implementing the <literal
+          moreinfo="none"><methodname>persisted</methodname></literal> method
+          might be to set up a reverse association that we do not want to be
+          set up until the new object has been persisted.</para>
+
+          <para><literal moreinfo="none">public void created() </literal>will
+          be called by the framework at logical creation of the object</para>
+
+          <para><literal moreinfo="none">public void loading()</literal> will
+          be called by the framework when a persistent object is about to be
+          loaded into memory</para>
+
+          <para><literal moreinfo="none">public void loaded()</literal> will
+          be called by the framework when a persistent object has just been
+          loaded into memory</para>
+
+          <para><literal moreinfo="none">public void persisting()
+          </literal>will be called by the framework just before a transient
+          object is first persisted. (For backwards compatibility
+          <methodname>saving()</methodname> is also supported).</para>
+
+          <para><literal moreinfo="none">public void persisted() </literal>
+          will be called by the framework just after a transient object is
+          first persisted. (For backwards compatibility
+          <methodname>saved()</methodname> is also supported).</para>
+
+          <para><literal moreinfo="none">public void updating() </literal>will
+          be called by the framework after any property on a persistent object
+          has been changed and just before this change is persisted</para>
+
+          <para><literal moreinfo="none">public void updated() </literal>will
+          be called by the framework just after a changed property on a
+          persistent object has been persisted</para>
+
+          <para><literal moreinfo="none">public void removing()</literal> will
+          be called by the framework when a persistent object is just about to
+          be deleted from the persistent object store. (For backwards
+          compatibility <methodname>deleting()</methodname> is also
+          supported).</para>
+
+          <para><literal moreinfo="none">public void removed()</literal> will
+          be called by the framework when a persistent object has just been
+          deleted from the persistent object store. (For backwards
+          compatibility <methodname>deleted()</methodname> is also
+          supported).</para>
+        </sect2>
+      </sect1>
+
+      <sect1>
+        <title>Properties</title>
+
+        <para>The following conventions are concerned with specifying the
+        properties of an object, and the way in which users can interact with
+        those properties.</para>
+
+        <sect2>
+          <title>How to add a property to an object</title>
+
+          <para>Properties are specified using the JavaBean conventions,
+          recognizing a standard accessor/mutator pair (<code>get</code> and
+          <code>set</code>). The syntax is:</para>
+
+          <para><programlisting>public &lt;property type&gt; get&lt;PropertyName&gt;() 
+
+public void set&lt;PropertyName&gt;(&lt;property type&gt; param)</programlisting></para>
+
+          <para>where <literal moreinfo="none">&lt;property type&gt;</literal>
+          is a primitive, a value object or an entity object.</para>
+
+          <para>Properties may reference either a value or another domain
+          object. Values include Java primitives, and JDK classes with value
+          semantics (<literal moreinfo="none">java.lang.Strings</literal> and
+          <literal moreinfo="none">java.util.Dates</literal>). A property
+          referencing another domain object is sometimes called an
+          association.</para>
+
+          <para>For example, the following example contains both a value
+          (<literal moreinfo="none">String</literal>) property and a reference
+          (<literal moreinfo="none">Organisation</literal>) property:</para>
+
+          <programlisting format="linespecific">public class Customer {
+    private String firstName;
+    public String getFirstName() {
+        return firstName;
+    }
+    public void setFirstName(String firstName) {
+        this.firstName = firstName;
+    }
+
+    private Organisation organisation;
+    public Organisation getOrganisation() {
+        return organisation;
+    }
+    public void setOrganisation(Organisation organisation) { 
+        this.organisation = organisation;
+    }
+
+    ...
+}</programlisting>
+        </sect2>
+
+        <sect2>
+          <title>How to prevent the user from modifying a property</title>
+
+          <para>Preventing the user from modifying a property value is known
+          as 'disabling' the property.</para>
+
+          <sect3>
+            <title>Disabling a property always</title>
+
+            <para>Use the <literal moreinfo="none">@Disabled</literal>
+            annotation.</para>
+          </sect3>
+
+          <sect3>
+            <title>Disabling a property under certain conditions</title>
+
+            <para>A <literal moreinfo="none">disable</literal> method can be
+            used to disable a particular instance's member under certain
+            conditions. The syntax is:</para>
+
+            <para><literal moreinfo="none">public String
+            disable&lt;PropertyName&gt;()</literal> A non-null return value
+            indicates the reason why the property cannot be modified. The
+            framework is responsible for providing this feedback to the user.
+            For example:</para>
+
+            <programlisting format="linespecific">public class OrderLine {
+    public String getQuantity() { ... }
+    public void setQuantity(int quantity) { ... }
+
+    public String disableFirstName() { 
+        if (this.hasBeenSubmitted()) {
+            return "Cannot alter any quantity after Order has been submitted"; 
+        }
+        return null;
+    }
+}</programlisting>
+          </sect3>
+
+          <sect3>
+            <title>Disabling a property for specific users or roles</title>
+
+            <para>Generally it is not good practice to embed knowledge of
+            roles and/or users into the domain classes. This is the
+            responsibility of the framework or platform and should be
+            specified and administered externally to the domain model.</para>
+
+            <para>However, in rare circumstances it might be necessary or
+            pragmatic to implement access control within the domain model
+            using the inherited <methodname>getUser()</methodname>
+            method:</para>
+
+            <para>For example:</para>
+
+            <programlisting format="linespecific">import org.apache.isis.applib.UserMemento;
+
+public class Employee {
+    public BigDecimal getSalary() { ... }
+    public void setSalary(BigDecimal salary) { ... }
+
+    public String validateSalary(BigDecimal salary) {
+        return salary.doubleValue() &gt;= 30000 &amp;&amp;
+              !getUser().hasRole("MODIFY_SALARY")?
+              "Need MODIFY_SALARY role to increase salary above 30000": null;
+    }
+}</programlisting>
+          </sect3>
+        </sect2>
+
+        <sect2>
+          <title>How to make a property optional (when saving an
+          object)</title>
+
+          <para>By default, when a new transient (unsaved) object is presented
+          to the user, values must be specified for all properties before the
+          object may be saved. To specify that a particular property is
+          optional, use the <literal moreinfo="none">@Optional</literal>
+          annotation.</para>
+        </sect2>
+
+        <sect2>
+          <title>How to specify the size of String properties</title>
+
+          <para>Use the <literal moreinfo="none">@MaxLength</literal>,
+          <literal moreinfo="none">@TypicalLength</literal> and <literal
+          moreinfo="none">@MultiLine</literal> annotations.</para>
+        </sect2>
+
+        <sect2>
+          <title>How to validate user input to a property</title>
+
+          <para>A <literal moreinfo="none">validate</literal> method is used
+          to check that a new value for a property is valid. If the proffered
+          value is deemed to be invalid then the property will not be changed.
+          A non-null return <code>String</code> indicates the reason why the
+          member cannot be modified/action be invoked; the framework is
+          responsible for providing this feedback to the user.</para>
+
+          <para>The syntax is:</para>
+
+          <para><programlisting>public String validate&lt;PropertyName&gt;(&lt;property type&gt; param)</programlisting></para>
+
+          <para>For example:</para>
+
+          <programlisting format="linespecific">public class Exam {
+    public int getMark() { ... }
+    public void setMark(int mark) { ... }
+    public validateMark(int mark) {
+        return !(mark &gt;= 0 &amp;&amp; mark &lt;= 30)?
+            "Mark must be in range 0 to 30"
+            :null;
+    }
+}</programlisting>
+
+          <sect3>
+            <title>Format validation</title>
+
+            <para>For properties that accept a text input string, such as
+            <code>String</code> and <code>Date</code>, there are convenient
+            mechanisms to validate and/or normalise the values typed
+            in.</para>
+
+            <para>For <literal moreinfo="none">Date</literal> and number
+            values the <literal moreinfo="none">@Mask</literal> annotation may
+            be used.</para>
+
+            <para>For <literal moreinfo="none">String</literal> properties the
+            <literal moreinfo="none">@RegEx</literal> annotation may be
+            used.</para>
+          </sect3>
+        </sect2>
+
+        <sect2>
+          <title>How to specify a set of choices and or a default value for a
+          property</title>
+
+          <para>The simplest way to provide the user with a set of choices for
+          a property (possibly rendered as a drop-down list, for example) is
+          to ensure that the type used by the property is marked up as
+          <code>@Bounded</code>. However, this is not always appropriate. For
+          example you might wish to provide the user with the choice of all
+          the Addresses known for that Customer, with the most recently-used
+          address as the default.</para>
+
+          <para>The syntax for specifying a default value is:</para>
+
+          <para><programlisting>public &lt;property type&gt; default&lt;PropertyName&gt;()</programlisting></para>
+
+          <para>And for specifying a list of choices is:</para>
+
+          <para><programlisting>public &lt;array or collection of property type&gt; choices&lt;PropertyName&gt;()</programlisting></para>
+
+          <para>The full code for our example above is:</para>
+
+          <programlisting format="linespecific">public class Order {
+    public Address getShippingAddress() { ... }
+    public void setShippingAddress() { ... }
+    public Address defaultShippingAddress() {
+        return getCustomer().normalAddress();
+    }
+    public List&lt;Address&gt; choicesShippingAddress() {
+        return getCustomer().allActiveAddresses();
+    }
+}</programlisting>
+        </sect2>
+
+        <sect2>
+          <title>How to set up the initial value of a property
+          programmatically</title>
+
+          <para>Initial values for properties may be set up programmatically
+          within the <literal moreinfo="none">created()</literal> method on
+          the object. (See Object: Life Cycle).</para>
+        </sect2>
+
+        <sect2>
+          <title>How to trigger other behaviour when a property is
+          changed</title>
+
+          <para>If you want to invoke functionality whenever a property is
+          changed by the user, then you should create a <literal
+          moreinfo="none">modify</literal> <literal
+          moreinfo="none">&lt;propertyName&gt;</literal> and include the
+          functionality within that. For example:</para>
+
+          <programlisting format="linespecific">public int getAmount() {}
+public void setAmount(int amount) {}
+
+public void modifyAmount(int amount) {
+     setAmount(amount);
+     addToTotal(amount);
+}</programlisting>
+
+          <para>The reason for the <literal
+          moreinfo="none">modifyAmount</literal> method is that it would not
+          be a good idea to include the <literal
+          moreinfo="none">addToTotal</literal> call within the <literal
+          moreinfo="none">setAmount</literal> method , because that method may
+          be called by the persistence mechanism when an object is retrieved
+          from storage.</para>
+
+          <para>You may optionally also specify a
+          <code>clear&lt;PropertyName&gt;</code> which works the same way as
+          modify <literal moreinfo="none">modify</literal> <literal
+          moreinfo="none">&lt;propertyName&gt;</literal> but is called when
+          the property is cleared by the user (i.e. the current value replaced
+          by nothing).</para>
+
+          <para>These methods may also be used for setting up bidirectional
+          relationships (using the 'mutual registration pattern'). For
+          example:</para>
+
+          <programlisting format="linespecific">public class Employee {
+    private Department department;
+    public Department getDepartment() {
+        return department;
+    }
+    public void setDepartment(Department department) { 
+        this.department = department;
+    }
+    public void modifyDepartment(Department department) {
+        setDepartment(department);
+        department.addToStaff(this);
+    }
+    public void clearDepartment(Department department) {
+        setDepartment(null);
+        department.removeFromStaff(this);
+    }
+
+    ...
+}</programlisting>
+        </sect2>
+
+        <sect2>
+          <title>How to control the order in which properties are
+          displayed</title>
+
+          <para>Use the <literal moreinfo="none">@MemberOrder</literal>
+          annotation.</para>
+        </sect2>
+
+        <sect2>
+          <title>How to specify a name and/or description for a
+          property</title>
+
+          <sect3>
+            <title>Specifying the name for a property</title>
+
+            <para>By default the framework will use the property name itself
+            to label the property on the user interface. If you wish to
+            over-ride this, use the <literal moreinfo="none">@Named
+            </literal>annotation on the property.</para>
+          </sect3>
+
+          <sect3>
+            <title>Specifying a description for a property</title>
+
+            <para>Use the <literal moreinfo="none">@DescribedAs</literal>
+            annotation on the property itself.</para>
+
+            <para>The framework will take responsibility to make this
+            description available to the user, for example in the form of a
+            'balloon help'.</para>
+          </sect3>
+        </sect2>
+
+        <sect2>
+          <title>How to hide a property from the user</title>
+
+          <sect3>
+            <title>Hiding a property always</title>
+
+            <para>Use the <literal moreinfo="none">@Hidden</literal>
+            annotation.</para>
+          </sect3>
+
+          <sect3>
+            <title>Hiding a property under certain conditions</title>
+
+            <para>A <literal moreinfo="none">hide</literal> method can be used
+            to indicate that a particular instance's member should be hidden
+            (rendered invisible to the user) under certain conditions. The
+            syntax is:</para>
+
+            <para><literal moreinfo="none">public boolean
+            hide&lt;PropertyName&gt;()</literal> A true return value indicates
+            that the property is hidden. For example:</para>
+
+            <programlisting format="linespecific">public class Order {
+    public String getShippingInstructions() { ... }
+    public void setShippingInstructions(String shippingInstructions) { ... }
+    public boolean hideShippingInstructions() {
+        return hasShipped();
+    }
+}</programlisting>
+          </sect3>
+
+          <sect3>
+            <title>Hiding a property for specific users or roles</title>
+
+            <para><emphasis role="strong">Important</emphasis>: see the
+            comments under 'Disabling a property for specific users or
+            roles'.</para>
+
+            <para>Session controls provide a way for the class to hide
+            properties from specific users, or users not in specific roles.
+            The syntax is: <literal moreinfo="none">public boolean
+            hide&lt;PropertyName&gt;(Session session)</literal> For
+            example:</para>
+
+            <programlisting format="linespecific">public class Employee {
+    public BigDecimal getSalary() { ... }
+    public void setSalary(BigDecimal salary) { ... }
+    public boolean hideSalary(UserMemento user, BigDecimal salary) {
+        return !user.hasRole("VIEW_SALARY");
+    }
+}</programlisting>
+          </sect3>
+        </sect2>
+
+        <sect2>
+          <title>How to make a property non-persisted</title>
+
+          <para>If there is no mutator (<code>set</code>) method then the
+          field is not only unmodifiable but will also
+          <emphasis>not</emphasis> be persisted. This approach is by design
+          and also happens to be compatible with Java Persistence Api (JPA)
+          semantics. This may be used to derive a property from other
+          information available to the object, for example:</para>
+
+          <programlisting format="linespecific">public class Employee {
+    public Department getDepartment() { ... }
+    public void setDepartment(Department department) { ... }
+    public void modifyDepartment(Department department) { ... }
+    public void clearDepartment(Department department) { ... }
+
+    // this is the derived property
+    public Employee getManager() {
+        if (getDepartment() == null) { return null; }
+        return getDepartment().getManager();
+    }
+
+    ...
+}</programlisting>
+
+          <para>If you need to have a <literal moreinfo="none">get</literal>
+          and <literal moreinfo="none">set</literal> method for the property
+          but do not wish to have that property persisted, use the <literal
+          moreinfo="none">@NotPersisted</literal> annotation.</para>
+        </sect2>
+      </sect1>
+
+      <sect1>
+        <title>Actions</title>
+
+        <para>An 'action' is a method that we expect the user to be able to
+        invoke via the user interface, though it may also be invoked
+        programmatically within the object model. The following conventions
+        are used to determine when and how methods are made available to the
+        user as actions.</para>
+
+        <sect2>
+          <title>How to add an action to an object</title>
+
+          <para>By default, any <literal moreinfo="none">public</literal>
+          instance method that you add to a class will be treated as a user
+          action, unless it represents a property, collection, or another
+          reserved method defined in this manual.</para>
+
+          <para>If you have a method that you don't want to be made available
+          as a user-action you should either make it <literal
+          moreinfo="none">protected</literal> or <literal
+          moreinfo="none">private</literal> or use the <literal
+          moreinfo="none">@Hidden</literal> annotation. Note also that
+          <literal moreinfo="none">static</literal> methods are ignored: such
+          functionality should reside in a service, such as a Repository or
+          Factory.</para>
+
+          <para>We refer to all methods that are intended to be invoked by
+          users as 'action methods'.</para>
+
+          <para>The syntax is:</para>
+
+          <para><programlisting>public void &lt;actionName&gt;([&lt;value or entity type&gt; param]...)</programlisting></para>
+
+          <para>or</para>
+
+          <para><programlisting>public &lt;return type&gt; &lt;actionName&gt;([&lt;value or entity type&gt; param]...)</programlisting></para>
+
+          <para>When a method returns a reference the viewer will attempt to
+          display that object. If the return value is <code>null</code> then
+          nothing is displayed.</para>
+        </sect2>
+
+        <sect2>
+          <title>How to specify parameters for an action</title>
+
+          <para>If an action method takes parameters, the viewing mechanism
+          will automatically require the user to specify these parameters (for
+          example, in the form of a dialog box) - and ensure that they are of
+          the correct type.</para>
+
+          <sect3>
+            <title>Specifying parameter names and/or descriptions</title>
+
+            <para>Unlike with properties, the framework cannot pick up the
+            names of parameters that you use within the domain code. By
+            default parameters will be labelled only with the type of the
+            object required (e.g. 'String:' or 'Customer:) If you want a
+            parameter to have a different name (such as 'First Name', 'Last
+            Name') then that parameter should be marked up with an <literal
+            moreinfo="none">@Named</literal> annotation - very often taking
+            the same form as the parameter name used in the code. (This is one
+            of the few forms of duplication that we cannot eliminate; the
+            parameter name is not available in the class' bytecode and so
+            cannot be inferred automatically. Alternatively though, you could
+            create a user-defined value type, using
+            <literal>@Value</literal>).</para>
+
+            <para>Similarly, any parameter may be given a short
+            user-description using the <literal
+            moreinfo="none">@DescribedAs</literal> annotation. The framework
+            takes responsibility to make this available to the user.</para>
+          </sect3>
+
+          <sect3>
+            <title>How to make a parameter optional</title>
+
+            <para>By default, the framework assumes that when an action method
+            is to be invoked, all the parameters are mandatory. You may
+            over-ride this behaviour by marking up one or more of the
+            paramaters with the <literal moreinfo="none">@Optional</literal>
+            annotation.</para>
+          </sect3>
+
+          <sect3>
+            <title>How to specify default values for parameters</title>
+
+            <para>When an action is about to be invoked, then default values
+            can be provided for any or all of its parameters.</para>
+
+            <para>There are two different ways to specify parameters; either
+            per parameter, or for all parameters. The per-parameter form is
+            simpler and probably preferred; the syntax is:</para>
+
+            <programlisting>public &lt;parameter type&gt; defaultN&lt;ActionName&gt;()</programlisting>
+
+            <para>where N indicates the 0-based parameter number. For
+            example:</para>
+
+            <programlisting format="linespecific">public class Customer {
+    public Order placeOrder(
+                      Product product,
+                      @Named("Quantity") 
+                      int quantity) {
+        ...
+    }
+    public Product default0PlaceOrder() {
+        return productMostRecentlyOrderedBy(this.getCustomer());
+    }
+}</programlisting>
+
+            <para>The syntax for specifying all the parameter default values
+            in one go is:</para>
+
+            <para><programlisting>public Object[] default&lt;ActionName&gt;([&lt;parameter type&gt; param]...)</programlisting></para>
+
+            <para>returning an array (which must have one element per
+            parameter in the action method signature) of corresponding default
+            values. For example:</para>
+
+            <programlisting format="linespecific">public class Customer {
+    public Order placeOrder(
+                      Product product,
+                      @Named("Quantity") 
+                      int quantity) {y
+        ...
+    }
+    public Object[] defaultPlaceOrder(
+                      Product product,
+                      int quantity) {
+        return new Object[] {productMostRecentlyOrderedBy(this.getCustomer()), 1};
+    }
+}</programlisting>
+          </sect3>
+
+          <sect3>
+            <title>How to specify a set of choices for parameter
+            values</title>
+
+            <para>The programmer may provide a set of choices for the value of
+            any or all of the parameters of an action. These will be made
+            available to the user - for example as a drop-down list.</para>
+
+            <para>As for defaults, there are two different ways to specify
+            parameters; either per parameter, or for all parameters. The
+            per-parameter form is simpler and probably preferred; the syntax
+            is:</para>
+
+            <programlisting>public List&lt;parameter type&gt; choicesN&lt;ActionName&gt;()</programlisting>
+
+            <para>where N indicates the 0-based parameter number. For
+            example:</para>
+
+            <programlisting format="linespecific">public class Order {
+    public Order placeOrder(
+                      Product product,
+                      @Named("Quantity") 
+                      int quantity) {
+        ...
+    }
+
+    public List&lt;Product&gt; choices0PlaceOrder() {
+        return lastFiveProductsOrderedBy(this.getCustomer());
+    }
+}</programlisting>
+
+            <para>The alternative mechanism is to supply all the parameter
+            choices in one go:</para>
+
+            <para><programlisting>public Object[] choices&lt;ActionName&gt;([&lt;parameter type&gt; param]...)</programlisting></para>
+
+            <para>returning an array, which must have one element per
+            parameter in the method signature. Each element of the array
+            should itself either be an array or a list, containing the set of
+            values representing the choices for that parameter, or <literal
+            moreinfo="none">null</literal> if there are no choices to be
+            specified for that parameter.</para>
+
+            <para>For example:</para>
+
+            <programlisting format="linespecific">public class Order {
+    public Order placeOrder(
+                      Product product,
+                      @Named("Quantity") 
+                      int quantity) {
+        ...
+    }
+
+    public Object[] choicesPlaceOrder(
+                      Product product,
+                      int quantity) {
+        return new Object[] {lastFiveProductsOrderedBy(this.getCustomer()).toArray(), null};
+    }
+}</programlisting>
+
+            <para>(Note that if the type of the property is annotated with
+            <literal moreinfo="none">@Bounded</literal>, then it is not
+            necessary to specify the choices for that parameter, as the user
+            will automatically be offered the full set to choose from.)</para>
+          </sect3>
+
+          <sect3>
+            <title>How to specify the length or format for text-input
+            parameters</title>
+
+            <para>Use the <literal moreinfo="none">@MaxLength</literal>,
+            <literal moreinfo="none">@TypicalLength</literal>, <literal
+            moreinfo="none">@MultiLine</literal>, <literal
+            moreinfo="none">@Mask</literal> or <literal
+            moreinfo="none">@RegEx</literal> annotations.</para>
+          </sect3>
+
+          <sect3>
+            <title>How to validate parameter values</title>
+
+            <para>A <literal moreinfo="none">validate</literal> method is used
+            to check that the set of arguments used by an action method is
+            valid. If the arguments are invalid then the framework will not
+            invoke the action. A non-null return String indicates the reason
+            why the member cannot be modified/action be invoked, and the
+            viewing mechanism will display this feedback to the user.</para>
+
+            <para>The syntax is:</para>
+
+            <para><programlisting>public String validate&lt;ActionName&gt;([&lt;parameter type&gt; param]...)</programlisting></para>
+
+            <para>For example:</para>
+
+            <programlisting format="linespecific">public class Customer {
+    public Order placeOrder(Product p, int quantity) { ... }
+    public String validatePlaceOrder(Product p, int quantity) {
+        if (p.isOutOfStock()) { return "Product is out of stock"; }
+        if (quantity &lt;= 0) { return "Quantity must be a positive value"; }
+        return null;
+    }</programlisting>
+          </sect3>
+        </sect2>
+
+        <sect2>
+          <title>How to specify conditions for invoking an action</title>
+
+          <sect3>
+            <title>Disabling an action based on the state of the
+            object</title>
+
+            <para>There may be circumstances in which we do not want the user
+            to be able to initiate the action at all - for example because
+            that action is not appropriate to the current state of the object
+            on which the action resides. Such rules are enforced by means of a
+            <literal moreinfo="none">disable</literal> method.</para>
+
+            <para>The syntax is:</para>
+
+            <para><programlisting>public String disable&lt;ActionName&gt;([&lt;parameter type&gt; param]...)</programlisting></para>
+
+            <para>A non-null return <code>String</code> indicates the reason
+            why the action may not be invoked. The framework takes
+            responsibility to provide this feedback to the user. For
+            example:</para>
+
+            <programlisting format="linespecific">public class Customer {
+    public Order placeOrder(Product p, int quantity) { ... }
+    public String disablePlaceOrder(Product p, int quantity) { 
+        return isBlackListed()?
+            "Blacklisted customers cannot place orders"
+            :null;
+    }</programlisting>
+
+            <para>It is also possible to permanently disable an action using
+            the <literal moreinfo="none">@Disabled</literal> annotation. One
+            possible reason for doing this might be during prototyping - to
+            indicate to the user that an action is planned, but has not yet
+            been implemented.</para>
+          </sect3>
+
+          <sect3>
+            <title>Disabling an action for certain users or roles</title>
+
+            <para>See 'Properties: Disabling a property for specific users or
+            roles'. The same technique can be applied to actions. However, the
+            caveats apply.</para>
+          </sect3>
+        </sect2>
+
+        <sect2>
+          <title>How to control the order in which actions appear on the
+          menu</title>
+
+          <para>Use the <literal moreinfo="none">@MemberOrder</literal>
+          annotation.</para>
+        </sect2>
+
+        <sect2>
+          <title>How to hide actions</title>
+
+          <sect3>
+            <title>Hiding an action always</title>
+
+            <para>Use the <literal moreinfo="none">@Hidden</literal>
+            annotation. (This is generally used where a <literal
+            moreinfo="none">public</literal> method on an object is not
+            intended to be a user action).</para>
+          </sect3>
+
+          <sect3>
+            <title>Hiding an action under certain conditions</title>
+
+            <para>A <literal moreinfo="none">hide</literal> method can be used
+            to indicate that an action should be hidden under certain
+            conditions. The syntax is:</para>
+
+            <para><programlisting>public boolean hide&lt;ActionName&gt;([&lt;parameter type&gt; param]...)</programlisting></para>
+
+            <para>A <literal moreinfo="none">true</literal> return value
+            indicates that the action should not be shown. For example:</para>
+
+            <programlisting format="linespecific">public class Order {
+    
+    public void applyDiscount(int percentage) { ... }
+    
+    public boolean hideApplyDiscount() {
+        return isWholesaleOrder();
+    }
+}</programlisting>
+          </sect3>
+
+          <sect3>
+            <title>Hiding an action for certain users or roles</title>
+
+            <para>See 'Properties: Hiding a property for specific users or
+            roles'. The same technique can be applied to actions. However, the
+            caveats apply.</para>
+          </sect3>
+        </sect2>
+
+        <sect2>
+          <title>How to pass a message back to the user</title>
+
+          <para>Sometimes, within an action it is necessary or desirable to
+          pass a message to the user, for example to inform them of the
+          results of their action ('5 payments have been issued') or that the
+          action was not successful ('No Customer found with name John
+          Smith'). <code>DomainObjectContainer</code> defines two methods for
+          this purpose:</para>
+
+          <para><programlisting>void informUser(String message)
+
+void warnUser(String message)</programlisting></para>
+
+          <para>These two methods provide different ways to send a message to
+          the user, representing increasing levels of severity. How each of
+          these messages is rendered visible to the user is determined by the
+          framework.</para>
+
+          <para>These two methods are also available on
+          <classname>AbstractDomainObject </classname>as a shortcut.</para>
+        </sect2>
+      </sect1>
+
+      <sect1>
+        <title>Collections</title>
+
+        <para>A collection is a list of references to several entity objects
+        that have a common type.</para>
+
+        <sect2>
+          <title>How to add a collection to an object</title>
+
+          <para>A collection is recognized via an accessor/mutator method pair
+          (<code>get</code> and set) for any type of collection provided by
+          the programming language. The syntax is:</para>
+
+          <para><programlisting>public &lt;collection type&gt; get&lt;CollectionName&gt;()
+
+private void set&lt;CollectionName&gt;(&lt;collection type&gt; param)</programlisting></para>
+
+          <para>It is recommended that the collections be specified using
+          generics (for example: <literal
+          moreinfo="none">List&lt;Customer&gt;</literal> ). That way the
+          framework will be able to display the collection based on that type
+          definition. (Generics are also required by some persistence
+          mechanisms). For example the viewer might display the collection as
+          a table, with the columns defined by the visible properties of that
+          type. The viewer will then automatically prevent the user from
+          adding objects not of that type. If generics are not used then the
+          type may be inferred from the <literal
+          moreinfo="none">addTo</literal> / <literal
+          moreinfo="none">removeFrom</literal> methods, if specified (see
+          below).</para>
+
+          <para>For example:</para>
+
+          <programlisting format="linespecific">public class Employee { ... }
+
+public class Department {
+    private List&lt;Employee&gt; employees = new ArrayList&lt;Employee&gt;();
+    public List &lt;Employee&gt; getEmployees() {
+        return employees;
+    }
+    private void setEmployees(List&lt;Employee&gt; employees) { 
+        this.employees = employees;
+    }
+    ...
+}</programlisting>
+        </sect2>
+
+        <sect2>
+          <title>How to trigger other behaviour when an object is added or
+          removed</title>
+
+          <para>A collection may have a corresponding <literal
+          moreinfo="none">addTo</literal> and/or <literal
+          moreinfo="none">removeFrom</literal> method. This is equivalent to
+          the <literal moreinfo="none">modify</literal> and <literal
+          moreinfo="none">clear</literal> methods for properties. The syntax
+          is:</para>
+
+          <para><programlisting>public void addTo&lt;CollectionName&gt;(&lt;entity type&gt; param)
+
+public void removeFrom&lt;CollectionName&gt;(&lt;entity type&gt; param)</programlisting></para>
+
+          <para>where <literal moreinfo="none">&lt;entity type&gt;</literal>
+          is the same type as the generic collection type. For example:</para>
+
+          <programlisting format="linespecific">public class Employee { ... }
+
+public class Department {
+    private List&lt;Employee&gt; employees = new ArrayList&lt;Employee&gt;();
+    public List &lt;Employee&gt; getEmployees() {
+        return employees;
+    }
+    private void setEmployees(List&lt;Employee&gt; employees) { 
+        this.employees = employees;
+    }
+    public void addToEmployees(Employee employee) {
+        employees.add(employee);
+    }
+    public void removeFromEmployees(Employee employee) {
+        employees.remove(employee);
+    }
+
+    ...
+}</programlisting>
+
+          <para>The addTo / removeFrom and modify / clear methods are
+          particularly useful in setting up bidirectional relationships using
+          the 'mutual registration pattern'; for a write-up of this pattern,
+          see <ulink
+          url="???">http://www.two-sdg.demon.co.uk/curbralan/papers/MutualRegistration.pdf</ulink>.</para>
+        </sect2>
+
+        <sect2>
+          <title>How to prevent the user from modifying a collection</title>
+
+          <para>Preventing the user from adding to or removing from a
+          collection is known as 'disabling' the collection.</para>
+
+          <sect3>
+            <title>Disabling a collection permanently</title>
+
+            <para>Use the <literal moreinfo="none">@Disabled</literal>
+            annotation.</para>
+          </sect3>
+
+          <sect3>
+            <title>Disabling a collection under certain conditions</title>
+
+            <para>A <literal moreinfo="none">disable</literal> method can be
+            used to disable a particular instance's collection under certain
+            conditions: The syntax is:</para>
+
+            <para><literal moreinfo="none">public String
+            disable&lt;CollectionName&gt;()</literal> For example:</para>
+
+            <programlisting format="linespecific">public class Department {
+    public List&lt;Employee&gt; getEmployees() { ... }
+    public void addToEmployees(Employee employee) { ... }
+    public void removeFromEmployees(Employee employee) { ... }
+    public void disableEmployees() {
+        return isClosed()? "This department is closed" : null;
+    }
+}</programlisting>
+          </sect3>
+
+          <sect3>
+            <title>Disabling a collection for specific users or roles</title>
+
+            <para>See Properties: Disabling a property for specific users or
+            roles'. The same technique can be applied to collections, with the
+            same caveats applying.</para>
+          </sect3>
+        </sect2>
+
+        <sect2>
+          <title>How to validate an object to be added or removed</title>
+
+          <para>A <literal moreinfo="none">validate</literal> method is used
+          to check that an object to be added or removed from a collection is
+          valid. A non-null return <code>String</code> indicates the reason
+          why the object cannot be added/removed, and the viewing mechanism
+          will display this to the user. The syntax is:</para>
+
+          <para><programlisting>public String validateAddTo&lt;CollectionName&gt;(&lt;property type&gt; param) 
+
+public String validateRemoveFrom&lt;CollectionName&gt;(&lt;property type&gt; param)</programlisting></para>
+
+          <para>For example:</para>
+
+          <programlisting format="linespecific">public class Department {
+    private List&lt;Employee&gt; employees = new ArrayList&lt;Employee&gt;();
+    public List&lt;Employee&gt; getEmployees() { ... }
+    private void setEmployees(List&lt;Employee&gt; employees) { ... }
+    public String validateAddToEmployee(Employee employee) {
+        return employee.isRetired()?
+            "Cannot add retired employees to department"
+            :null;
+}</programlisting>
+        </sect2>
+
+        <sect2>
+          <title>How to control the order in which collections are
+          displayed</title>
+
+          <para>Use the <literal moreinfo="none">@MemberOrder</literal>
+          annotation.</para>
+        </sect2>
+
+        <sect2>
+          <title>How to specify a name and/or description for a
+          collection</title>
+
+          <para>Use the <literal moreinfo="none">@Named</literal> and/or
+          <literal moreinfo="none">@DescribedAs</literal> annotations.</para>
+        </sect2>
+
+        <sect2>
+          <title>How to hide a collection</title>
+
+          <para>See 'Properties: How to hide a property'. The same approaches
+          work for collections.</para>
+        </sect2>
+
+        <sect2>
+          <title>How to create a derived collection</title>
+
+          <para>Collections can be derived, in the same way as properties.
+          These are not persisted, but are represented as read only
+          collections. For example:</para>
+
+          <programlisting format="linespecific">public class Department {
+    // Standard collection
+    List&lt;Employee&gt; employees = new ArrayList&lt;Employee&gt;();
+    public List&lt;Employee&gt; getEmployees() { ... }
+    private void setEmployees(List&lt;Employee&gt;) { ... }
+    void addToEmployees(final Employee employee) { ... }
+    void removeFromEmployees(final Employee employee) { ... }
+
+    // Derived collection
+    public List&lt;Employee&gt; getTerminatedEmployees() {
+        List&lt;Employee&gt; terminatedEmployees = new ArrayListt&lt;Employee&gt;();
+        for(Employee e: employees) {
+            if (e.isTerminated()) {
+                addTo(terminatedEmployees, e);
+            }
+        }
+        return terminatedEmployees;
+    }
+}</programlisting>
+        </sect2>
+      </sect1>
+
+      <sect1>
+        <title>Repositories and Factories</title>
+
+        <para>The [[NAME]] application library provides a class</para>
+
+        <para><literal
+        moreinfo="none">org.apache.isis.applib.AbstractFactoryAndRepository</literal></para>
+
+        <para>that makes it easy to write a Repository and/or Factory to work
+        entirely in memory. This is very useful during prototyping, as you can
+        quickly get your system up and running without having to deal with a
+        database. Refer to the JavaDoc documentation for that class for a full
+        list of methods available. However, the following describes some of
+        the most commonly-used methods:</para>
+
+        <para><literal moreinfo="none">&lt;T&gt; T newTransientInstance(final
+        Class&lt;T&gt; ofClass)</literal> returns a new instance of the
+        specified class, that is transient (unsaved). This may subsequently be
+        saved either by the user invoking the Save action (that will
+        automatically be rendered on the object view) or programmatically by
+        calling . . .</para>
+
+        <para><literal moreinfo="none">void makePersistent(Object
+        transientObject)</literal></para>
+
+        <para><literal moreinfo="none">&lt;T&gt; T newPersistentInstance(final
+        Class&lt;T&gt; ofClass)</literal> creates a new object already
+        persisted.</para>
+
+        <para><literal moreinfo="none">void disposeInstance(Object
+        persistentObject)</literal></para>
+
+        <para><literal moreinfo="none">&lt;T&gt; List&lt;T&gt;
+        allInstances(final Class&lt;T&gt; cls, final boolean
+        includeSubclasses)</literal> these may be iterated through for a
+        specific match.</para>
+
+        <para><literal moreinfo="none">&lt;T&gt; T firstMatch(final
+        Class&lt;T&gt; cls, final String title, final boolean
+        includeSubclasses)</literal>looks for an object with the title
+        specified.</para>
+
+        <para>There are a number of useful matching and filtering methods in
+        AbstractFactoryAndRepository.</para>
+
+        <para></para>
+
+        <para></para>
+
+        <para></para>
+
+        <sect2>
+          <title>Finding by pattern</title>
+
+          <remark>TODO: Complete this section to cover pattern-based
+          searching, including the fact that this works for both InMemory and
+          Hibernate repositories.</remark>
+        </sect2>
+      </sect1>
+
+      <sect1>
+        <title>Registering services</title>
+
+        <sect2>
+          <title>System repositories</title>
+
+          <para>As well as services defined programmatically, it is possible
+          to use a repository provided by the framework that will, for a
+          configured object type, provide methods to:</para>
 
-      <para></para>
-    </sect1>
+          <itemizedlist>
+            <listitem>
+              <para>Create a new transient instance</para>
+            </listitem>
 
-    <sect1>
-      <title>Principles</title>
+            <listitem>
+              <para>Create a new persisted instance</para>
+            </listitem>
 
-      <para><emphasis></emphasis></para>
+            <listitem>
+              <para>Find all persisted instances</para>
+            </listitem>
 
-      <para><emphasis></emphasis><note>
-          <para>TODO: distill some of the material on the trunk site.</para>
+            <listitem>
+              <para>Find instances with a specified title</para>
+            </listitem>
+          </itemizedlist>
 
-          <para></para>
-        </note></para>
+          <para>To register such a service prefix the class name with
+          'repository#', for example:</para>
 
-      <sect2>
-        <title>Ubiquitous Language</title>
+          <programlisting format="linespecific">isis.services = repository#bom.Booking</programlisting>
+        </sect2>
+      </sect1>
+
+      <sect1>
+        <title>@MustSatisfy specification</title>
+
+        <para>The <literal>@MustSatisfy</literal> annotation is an alternative
+        to using imperative validation, allowing validation rules to be
+        captured in an (implementation of a)
+        <classname>org.apache.isis.applib.spec.Specification</classname>.</para>
+
+        <para>For example:</para>
+
+        <programlisting format="linespecific">public class DomainObjectWithMustSatisfyAnnotations extends AbstractDomainObject {
+
+    private String lastName;
+    @MustSatisfy(SpecificationRequiresFirstLetterToBeUpperCase.class)
+    public String getLastName() {
+        resolve(lastName);
+        return lastName;
+    }
+    public void setLastName(String lastName) {
+        this.lastName = lastName;
+        objectChanged();
+    }
+
+    public void changeLastName(
+            @MustSatisfy(SpecificationRequiresFirstLetterToBeUpperCase.class)
+            String lastName
+            ) {
+        setLastName(lastName);
+    }
+
+}</programlisting>
+
+        <para><remark>TODO: @MustSatisfy may not work for action parameters;
+        see <ulink
+        url="???">http://dev.isis.apache.org/trac/ticket/669</ulink>.</remark></para>
+      </sect1>
+
+      <sect1>
+        <title>Value Types</title>
+
+        <para>In addition to the built-in value types it is also possible to
+        define user-defined value types. This is typically done using the
+        <classname>@Value</classname> annotation.</para>
+
+        <para>The <literal>@Value</literal> annotation is used to provide an
+        implementation of the <classname>ValueSemanticsProvider</classname>
+        interface. In turn this provides objects that allow the framework to
+        interact with the value, in particular for parsing (parsing strings
+        into values and display values as strings), and for encoding/decoding
+        (for serialization for client/server and used by some
+        persistors).</para>
+
+        <para>For more details, explore the built-in types within the applib,
+        for example
+        <classname>org.apache.isis.applib.value.Money</classname>.</para>
+
+        <programlisting format="linespecific">@Value(semanticsProviderName = "org.apache.isis.metamodel.value.MoneyValueSemanticsProvider")
+public class Money extends Magnitude {
+    ...
+}</programlisting>
+
+        <para>where <classname>MoneyValueSemanticsProvider</classname> is the
+        implementation of <classname>ValueSemanticsProvider</classname>
+        described above.</para>
+
+        <para>Using value types generally removes the need for using
+        <literal>@MustSatisfy</literal> annotation; the rules can instead move
+        down into a <methodname>validate</methodname> method on the value type
+        itself.</para>
+
+        <para><remark>TODO: need to beef up this discussion. Also, note that
+        it is possible to register value types using isis.properties rather
+        than the @Value annotation; this is particularly useful for
+        third-party value types.</remark></para>
+      </sect1>
+
+      <sect1>
+        <title>Resolve and ObjectChanged</title>
+
+        <para>In previous versions of the framework it was necessary to call
+        the inherited <methodname>resolve()</methodname> method within every
+        property or collection's getter, and
+        <methodname>objectChanged()</methodname> within every property's
+        setter and every collection's addTo or removeFrom.</para>
+
+        <para>These methods still exist in
+        <classname>AbstractDomainObject</classname>, but no longer need to be
+        called explicitly. Instead [[NAME]] 4.0 uses bytecode enhancement
+        (using either cglib or javassist) to automatically call these methods.
+        This bytecode enhancement can be disabled in
+        <filename>isis.properties</filename> file; if it is then the methods
+        must be called manually as they were in [[NAME]] 3.0.</para>
+      </sect1>
+    </chapter>
+  </part>
+
+  <part>
+    <title>Reference</title>
+
+    <chapter id="sec.RecognisedTypes">
+      <title>Recognised Types</title>
+
+      <abstract>
+        <para>*** yada yada</para>
+      </abstract>
+
+      <para>[[NAME]] creates an adapter for every domain object. There are
+      three categories of objects that are recognised: value, reference and
+      collection. Value and collection objects are dealt with on a class by
+      class basis, while all reference objects are dealt with in the same way
+      where the properties are seen as fields, and public methods as actions.
+      Listed below are all the recognised types.</para>
+
+      <sect1>
+        <title>Value objects</title>
+
+        <para>The following are built-in types. In addition to these any type
+        either annotated using <classname>@Value</classname>, or registered as
+        a value type using <filename>isis.properties</filename>, will also be
+        treated as a value type.</para>
 
-        <para></para>
+        <sect2>
+          <title>Primitive types</title>
 
-        <para></para>
+          <itemizedlist>
+            <listitem>
+              <para><literal moreinfo="none">boolean</literal></para>
+            </listitem>
 
-        <para></para>
+            <listitem>
+              <para><literal moreinfo="none">byte</literal></para>
+            </listitem>
 
-        <para></para>
-      </sect2>
+            <listitem>
+              <para><literal moreinfo="none">char</literal></para>
+            </listitem>
 
-      <sect2>
-        <title>Rapid Application Development</title>
+            <listitem>
+              <para><literal moreinfo="none">double</literal></para>
+            </listitem>
 
-        <para></para>
+            <listitem>
+              <para><literal moreinfo="none">float</literal></para>
+            </listitem>
 
-        <para></para>
+            <listitem>
+              <para><literal moreinfo="none">int</literal></para>
+            </listitem>
 
-        <note>
-          <para>TODO: discuss</para>
-        </note>
+            <listitem>
+              <para><literal moreinfo="none">long</literal></para>
+            </listitem>
 
-        <para>feedback loop</para>
+            <listitem>
+              <para><literal moreinfo="none">short</literal></para>
+            </listitem>
+          </itemizedlist>
+        </sect2>
 
-        <para>requirements traceability</para>
+        <sect2>
+          <title>Number classes</title>
 
-        <para></para>
-      </sect2>
+          <itemizedlist>
+            <listitem>
+              <para><classname>java.lang.Boolean</classname></para>
+            </listitem>
 
-      <sect2>
-        <title>Problem Solver, not Process Follower</title>
+            <listitem>
+              <para><classname>java.math.BigInteger</classname></para>
+            </listitem>
 
-        <para></para>
+            <listitem>
+              <para><classname>java.math.BigDecimal</classname></para>
+            </listitem>
 
-        <para></para>
+            <listitem>
+              <para><classname>java.lang.Byte</classname></para>
+            </listitem>
 
-        <note>
-          <para>TODO: discuss</para>
-        </note>
+            <listitem>
+              <para><classname>java.lang.Character</classname></para>
+            </listitem>
 
-        <para>Sovereign Applications vs Transient Applications</para>
+            <listitem>
+              <para><classname>java.lang.Double</classname></para>
+            </listitem>
 
-        <para></para>
+            <listitem>
+              <para><classname>java.lang.Float</classname></para>
+            </listitem>
 
-        <para>for sovereign applications</para>
+            <listitem>
+              <para><classname>java.lang.Integer</classname></para>
+            </listitem>
 
-        <para></para>
+            <listitem>
+              <para><classname>java.lang.Long</classname></para>
+            </listitem>
 
-        <para>incredible machine</para>
+            <listitem>
+              <para><classname>java.lang.Short</classname></para>
+            </listitem>
+          </itemizedlist>
+        </sect2>
 
-        <para></para>
+        <sect2>
+          <title>Java Classes</title>
 
-        <para></para>
-      </sect2>
+          <itemizedlist>
+            <listitem>
+              <para><classname>java.lang.String</classname></para>
+            </listitem>
 
-      <sect2>
-        <title>Commonly Trodden Paths</title>
+            <listitem>
+              <para><classname>java.util.Date</classname> (date and
+              time)</para>
+            </listitem>
 
-        <para></para>
+            <listitem>
+              <para><classname>java.sql.Date</classname> (date only)</para>
+            </listitem>
 
-        <para></para>
+            <listitem>
+              <para><classname>java.sql.Time</classname> (time only)</para>
+            </listitem>
 
-        <note>
-          <para>TODO: discuss</para>
-        </note>
+            <listitem>
+              <para><classname>java.sql.Timestamp</classname></para>
+            </listitem>
 
-        <para>for transient apps</para>
+            <listitem>
+              <para><classname>java.awt.Image</classname></para>
+            </listitem>
+          </itemizedlist>
+        </sect2>
 
-        <para></para>
+        <sect2>
+          <title>Application Library</title>
 
-        <para>Civil engineering analogy.... put in the paths afterwards</para>
+          <itemizedlist>
+            <listitem>
+              <para><classname>org.apache.isis.applib.value.Color</classname></para>
+            </listitem>
 
-        <para></para>
+            <listitem>
+              <para><classname>org.apache.isis.applib.value.Date</classname></para>
+            </listitem>
 
-        <para>Christopher Alexander - cardboard cutouts of where the windows
-        go</para>
+            <listitem>
+              <para><classname>org.apache.isis.applib.value.DateTime</classname></para>
+            </listitem>
 
-        <para></para>
+            <listitem>
+              <para><classname>org.apache.isis.applib.value.Image</classname></para>
+            </listitem>
+
+            <listitem>
+              <para><classname>org.apache.isis.applib.value.Money</classname></para>
+            </listitem>
 
-        <para>Database denormalization</para>
+            <listitem>
+              <para><classname>org.apache.isis.applib.value.Password</classname></para>
+            </listitem>
 
-        <para></para>
-      </sect2>
+            <listitem>
+              <para><classname>org.apache.isis.applib.value.Percentage</classname></para>
+            </listitem>
 
-      <sect2>
-        <title>Opinionated</title>
+            <listitem>
+              <para><classname>org.apache.isis.applib.value.Time</classname></para>
+            </listitem>
 
-        <para></para>
+            <listitem>
+              <para><classname>org.apache.isis.applib.value.TimeStamp</classname></para>
+            </listitem>
+          </itemizedlist>
+        </sect2>
+      </sect1>
 
-        <para></para>
+      <sect1>
+        <title>Collection objects</title>
 
-        <note>
-          <para>TODO: discuss</para>
-        </note>
+        <itemizedlist>
+          <listitem>
+            <para><classname>java.util.Collection</classname> (usually
+            <classname>java.util.ArrayList</classname>,
+            <code>java.util.LinkedList</code>,
+            <classname>java.util.LinkedHashSet</classname> or
+            <classname>java.util.TreeSet</classname>)</para>
+          </listitem>
 
-        <para></para>
+          <listitem>
+            <para>arrays</para>
+          </listitem>
+        </itemizedlist>
 
-        <para>convention over configuration</para>
+        <para>Note that <classname>java.util.Map</classname> is not supported
+        as a collection type.</para>
+      </sect1>
 
-        <para></para>
+      <sect1>
+        <title>Reference objects</title>
 
-        <para>framework, domain services, dependency injection</para>
+        <itemizedlist>
+          <listitem>
+            <para>all other domain classes (not annotated with
+            <literal>@Value</literal> / registered as a value using
+            <filename>isis.properties</filename>).</para>
+          </listitem>
+        </itemizedlist>
+      </sect1>
+    </chapter>
 
-        <para></para>
+    <chapter>
+      <title>Recognized Methods and Method Prefixes</title>
 
-        <para>JSR-299</para>
+      <abstract>
+        <para>***</para>
+      </abstract>
 
-        <para>don't want too many degrees of freedom. Work out of the box,
-        specify alternates later as needed</para>
+      <para>The Java 1.5 reflector allows the domain modeller to define
+      behaviourally complete domain objects, provide maximum feedback to the
+      user, and control any interaction that may take place (rather than place
+      that code in each and every user interface and back-end). This sections
+      lists the explicit methods that are recognised by the standard
+      reflector. All methods must be <code>public</code> to be
+      recognised.</para>
 
-        <para></para>
-      </sect2>
-    </sect1>
+      <para>Methods that do not get matched with any of the listed rules are
+      deemed to be action methods that we expect the user to invoke via the
+      user interface. These are public methods, of the following format</para>
 
-    <sect1>
-      <title>Patterns</title>
+      <programlisting format="linespecific">public void &lt;actionName&gt;([&lt;property type&gt; param]...)
+public &lt;type&gt; &lt;actionName&gt;([&lt;property type&gt; param]...)</programlisting>
 
-      <para>The framework is designed around two patterns:</para>
+      <para>that are not used for fields, titles, or for controlling other
+      methods. Essentially they are the methods left over from generating all
+      other aspects of the class.</para>
 
-      <para></para>
+      <para>When such a method returns a reference the framework will attempt
+      to display that object. If an action method returns <literal
+      moreinfo="none">null</literal> then nothing will be displayed.</para>
 
-      <sect2>
-        <title>Naked Objects Pattern</title>
+      <sect1 id="addto-method">
+        <title>addTo</title>
 
-        <para>The first architectural pattern is the naked objects pattern,
-        whereby the framework automatically generates an object-oriented user
-        interface (OOUI) for your domain objects. If required, this OOUI can
-        then be customized.</para>
+        <programlisting format="linespecific">public void addTo&lt;PropertyName&gt;(&lt;collection element type&gt; param)</programlisting>
 
-        <para></para>
-      </sect2>
+        <para>Used in conjunction with a collection, the <literal
+        moreinfo="none">addTo</literal> method is called by the framework when
+        the user adds an element to the collection. By providing this method
+        in conjunction with a non-generic collection it will be limited to a
+        specific type (rather than being used to store references of type
+        <classname>Object</classname>). This behaviour is similar to that of
+        the <methodname>modify</methodname> method for properties.</para>
 
-      <sect2>
-        <title>Hexagonal Architecture</title>
+        <para>See also <xref linkend="modify-method" /> and <xref
+        linkend="removefrom-method" /></para>
+      </sect1>
 
-        <para>The second core pattern implemented by <emphasis>Apache
-        Isis</emphasis> is the hexagonal architecture. This means it allows
-        the same domain model to be run with different viewers, either as a
-        desktop app or as a webapp. Equally, you can choose which object store
-        to use in order to persist your domain objects. The diagram below
-        shows the hexagonal architecture as it is implemented by Apache
-        Isis.</para>
+      <sect1>
+        <title>choices</title>
 
-        <para></para>
+        <bridgehead>On a property</bridgehead>
 
-        <para></para>
+        <programlisting format="linespecific">public &lt;property type&gt;[] choices&lt;PropertyName&gt;([&lt;property type&gt; param])
 
-        <note>
-          <para>TODO: discuss</para>
-        </note>
+public List&lt;property type&gt; choices&lt;PropertyName&gt;([&lt;property type&gt; param])</programlisting>
 
-        <para>*** picture of the hexagonal architecture here.</para>
+        <para>Used in conjunction with a property, the
+        <methodname>choices</methodname> method provides the user with a set
+        of options for setting a property. This method is called when the user
+        interface makes the options available, hence its return value can be
+        based on the current state of the object. Note - this does not limit
+        the state of the field, see the <methodname>validate</methodname>
+        methods for a way to do that.</para>
 
-        <para></para>
+        <bridgehead>On parameters on an action</bridgehead>
 
-        <para></para>
-      </sect2>
+        <para>Either:</para>
 
-      <sect2>
-        <title>Dependency Injection</title>
+        <programlisting format="linespecific">public Object[] choicesN&lt;actionName&gt;()
 
-        <para></para>
+public List&lt;parameter type&gt; choicesN&lt;parameterNumber&gt;&lt;actionName&gt;()</programlisting>
 
-        <para></para>
+        <para>where N is the 0-based parameter number.</para>
 
-        <para></para>
-      </sect2>
-    </sect1>
+        <para>Or:</para>
 
-    <sect1>
-      <title>Benefits and Consequences</title>
+        <programlisting format="linespecific">public Object[] choices&lt;actionName&gt;([&lt;parameter type&gt; param]...)
 
-      <para></para>
+public List&lt;parameter type&gt; choices&lt;parameterNumber&gt;&lt;actionName&gt;([&lt;parameter type&gt; param])</programlisting>
 
-      <para><note>
-          <para>TODO: review stuff below, copied-n-pasted from site
-          docs.</para>
-        </note></para>
-
-      <para>As you might imagine, not needing to write any GUI code
-      substantially speeds up development, and shortens the feedback loop to
-      allow you to improve your core domain model without lots of GUI code
-      slowing you down.</para>
-
-      <para>The OOUIs generated by Apache Isis are especially suitable to
-      "expert" users, typically those internal to your organization who have a
-      good understanding of the domain and just want to get their job done.
-      But for less expert users (or for a webapp deployed on the internet), a
-      more scripted UI may be called for. Isis therefore lets you customize
-      the user interface according to your users' needs.</para>
-
-      <para>Alternatively, you might want to just use Isis as a design tool.
-      The framework goes to a lot of trouble to ensure that the domain objects
-      you build have no dependencies on the framework: they are basically
-      annotated pojos that follow a number of straightforward programming
-      conventions. So, you can use Isis to rapidly evolve your domain objects,
-      and then deploy them within some other runtime framework if you
-      wish.</para>
+        <para>Complements an action method, or a specific paramter within an
+        action.</para>
 
-      <para></para>
+        <para>The <methodname>choices</methodname> method provides a set of
+        options for the parameters of an action. This method is called when
+        the user interface prompts for the parameters from the user, so the
+        options cannot depend on the state of any of the other parameters.
+        Note - this does not limit the state of the parameter, see the
+        <methodname>validate</methodname> methods for a way to do that.</para>
 
-      <para></para>
+        <para>For each parameter the array should contain either <literal
+        moreinfo="none">null</literal>, an array, or a collection.</para>
+      </sect1>
 
-      <note>
-        <para>TODO: include some of the benefits cited for NO pattern, from
-        website: faster development cycle, greater agility, empowering style
-        of UI, requirements analysis/traceability; play to developer
-        strengths</para>
-      </note>
+      <sect1>
+        <title id="clear-method">clear</title>
 
-      <para></para>
+        <programlisting format="linespecific">public void clear&lt;PropertyName&gt;()</programlisting>
 
-      <sect2>
-        <title>Playing to Developer Strengths</title>
+        <para>Used in conjunction with a property, the
+        <methodname>clear</methodname> method is called when the user (rather
+        than the framework) clears a reference field, or blanks (so there is
+        no entry) a value field.</para>
 
-        <para></para>
+        <para>See also <xref linkend="modify-method" /></para>
+      </sect1>
 
-        <para></para>
+      <sect1>
+        <title>created</title>
 
-        <note>
-          <para>TODO: discuss</para>
-        </note>
+        <programlisting format="linespecific">public void created()</programlisting>
 
-        <para>domain programmer/business analyst</para>
+        <para>Life cycle method called by framework when an object is first
+        created. This is the instance's logical creation. This method will
+        <emphasis>not</emphasis> be called when the object is recreated during
+        persistence or remoting.</para>
+      </sect1>
 
-        <para></para>
+      <sect1>
+        <title>default</title>
 
-        <para>application integration expert (domain services)</para>
+        <bridgehead>For a property</bridgehead>
 
-        <para></para>
+        <programlisting format="linespecific">public &lt;parameter type&gt; default&lt;actionName&gt;([&lt;parameter type&gt; param]...)</programlisting>
 
-        <para>customizer (UI expert)</para>
+        <para>Complements a get/set method for a reference or value
+        property.</para>
 
-        <para></para>
+        <para>Provides the default reference or value for a property to be set
+        to when an object is first created, or the user asks for a property to
+        be reset.</para>
+
+        <bridgehead>For parameters on an action</bridgehead>
+
+        <para>Either:</para>
+
+        <programlisting format="linespecific">public Object[] defaultN&lt;actionName&gt;()
+
+public List&lt;parameter type&gt; defaultN&lt;parameterNumber&gt;&lt;actionName&gt;()</programlisting>
+
+        <para>where N is the 0-based parameter number.</para>
+
+        <para>Or:</para>
+
+        <programlisting format="linespecific">public Object[] default&lt;actionName&gt;([&lt;parameter type&gt; param]...)
+
+public List&lt;parameter type&gt; default&lt;parameterNumber&gt;&lt;actionName&gt;([&lt;parameter type&gt; param])</programlisting>
+
+        <para>Complements an action method, or a specific parameter on an
+        action method.</para>
+
+        <para>Provides the defaults that should be used for the parameters
+        expected by an action method. The values should be provided as an
+        array with the same number of elements as the number of parameters.
+        Any parameter that does not have a default should have its
+        corresponding element in the array set to null.</para>
+      </sect1>
+
+      <sect1>
+        <title>deleted</title>
+
+        <para>Deprecated but still supported; replaced by
+        <methodname>removed()</methodname></para>
 
-        <para>architectural integration</para>
+        <programlisting format="linespecific">public void deleted()</programlisting>
+
+        <para>Life cycle method called by framework when an object has just
+        been removed from the persistent store. At this point the object will
+        exist in memory, but no longer exist in the persistent store.</para>
+      </sect1>
+
+      <sect1>
+        <title>deleting</title>
+
+        <para>Deprecated but still supported; replaced by
+        <methodname>removing()</methodname></para>
+
+        <programlisting format="linespecific">public void deleting()</programlisting>
+
+        <para>Life cycle method called by framework when an object is just
+        about to be removed from the persistent store. At this point the
+        object still exists in the persistent store.</para>
+      </sect1>
+
+      <sect1>
+        <title>disable</title>
+
+        <programlisting format="linespecific">public String disable&lt;PropertyName&gt;([&lt;property type&gt; param])
+
+public String disable&lt;actionName&gt;([&lt;parameter type&gt; param]...)</programlisting>
+
+        <para>Complements a get/set method for a field, or an action
+        method.</para>
+
+        <para>The <literal moreinfo="none">disable</literal> dynamically
+        controls whether a field is editable, or an action can be initiated.
+        If a <classname>String</classname> object is returned the field or
+        action is disabled and the string is made visible to user to inform
+        them why it is disabled. If the method returns <literal
+        moreinfo="none">null</literal> then field or action remains
+        enabled.</para>
+      </sect1>
+
+      <sect1>
+        <title>get</title>
+
+        <bridgehead>Value or reference property</bridgehead>
+
+        <programlisting format="linespecific">public &lt;property type&gt; get&lt;PropertyName&gt;()</programlisting>
+
+        <para>A standard JavaBean accessor/mutator pair will be recognised as
+        a field for a value or reference. Values include Java primitives,
+        <classname>String</classname>s and <classname>Date</classname>s, and

[... 2132 lines stripped ...]


Mime
View raw message