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 2014/02/12 00:31:19 UTC

[22/51] [partial] ISIS-694: mothballing the docbkx folders.

http://git-wip-us.apache.org/repos/asf/isis/blob/7a7836e3/mothballed/docbkx/component/viewer/wicket/src/docbkx/guide/isis-wicket-viewer.md
----------------------------------------------------------------------
diff --git a/mothballed/docbkx/component/viewer/wicket/src/docbkx/guide/isis-wicket-viewer.md b/mothballed/docbkx/component/viewer/wicket/src/docbkx/guide/isis-wicket-viewer.md
new file mode 100644
index 0000000..f9728be
--- /dev/null
+++ b/mothballed/docbkx/component/viewer/wicket/src/docbkx/guide/isis-wicket-viewer.md
@@ -0,0 +1,2976 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+Preface
+=======
+
+The *Apache Isis Wicket Viewer* provides a customizable web-based viewer
+for *Apache Isis* implemented using the [Apache
+Wicket](http://wicket.apache.org) framework. This user guide is written
+for developers looking to write *Apache Isis* applications and deploy
+them using the *Wicket Viewer*. It assumes familiarity with writing
+*Isis* applications, but that is all that is needed to get an
+application up-and-running with the generic OOUI.
+
+Familiarity with *Apache Wicket* is useful to understand how the wicket
+viewer fits together, but is essential unless you want to start
+customizing the UI. If you're interested in learning more about *Wicket*
+itself, then [Wicket In Action](http://www.manning.com/dashorst/)
+(Martijn Dashort & Eelco Hillenius) is definitely worth reading.
+
+Introduction
+============
+
+> This introductory chapter describes the objective of the *Wicket
+> Viewer*, and the target audience for this guide.
+
+Introducing the Apache Isis Wicket Viewer
+-----------------------------------------
+
+The *Wicket Viewer* provides a generic OOUI web-based viewer for *Apache
+Isis* domain models, using [Apache Wicket](http://wicket.apache.org) as
+the underlying web framework.
+
+What this means for you, the developer, is that you can build a web
+application solely by developing the domain model as pojos. The *Wicket
+Viewer* will then render your domain objects in a web UI using ready
+provided *Wicket* Components.
+
+This generic UI provides a lot of functionality out-of-the-box:
+
+-   Each domain entity is rendered as a form, with the appropriate
+    individual component type for its values. This entity form also
+    allows editable references to other objects, too.
+
+-   Moreover, any collections of a domain entity (eg Order /
+    OrderDetail) are also automatically rendered as a list, a table, or
+    in any other appropriate representation. Both the scalar and
+    collection references let the end-user easily "walk the graph"
+    around your domain model.
+
+-   Finally, the vuewer also renders actions (commands/behaviors) for
+    your domain objects, and lets these actions to be invoked. This is
+    what makes *Apache Isis*-based applications that much more than
+    simple CRUD applications.
+
+You can see examples of the UI in ?.
+
+Over and above this generic interface, you are then free to customize
+this interface in various ways. Your customizations can be general (eg
+providing a way to render a collection of Locatable objects in a
+google-maps mashup) or targetted (eg a particular way to render a
+ShoppingCartWizard). Generally these customizations take the form of
+bespoke *Wicket* Components, though simple customizations can be
+performed just by modifying the CSS. Again you can see some examples of
+these customizations in ?.
+
+*Apache Isis* webapps that use the *Wicket Viewer* are bootstrapped in
+the same as vanilla *Wicket* applications, with the *Wicket Viewer*
+providing an implementation of *Wicket*'s `WebApplication` class that
+additionally bootstraps the *Apache Isis* runtime. Authentication is
+performed using *Apache Isis*' own security mechanism (which itself is
+pluggable).
+
+The Wicket Viewer compared to other Wicket RAD Frameworks
+---------------------------------------------------------
+
+### Differences in Capability
+
+There are several frameworks that aim either to provide a back-end to
+*Wicket* and/or that aim to eliminate some of the boilerplate; notable
+examples are [Wicketopia](http://wicketopia.sourceforge.net), [Wicket
+RAD](http://sites.google.com/site/wicketrad) and
+[DataBinder](http://databinder.net/wicket/show/overview). There are also
+precanned archetypes, such as jWeekEnd's
+[LegUp](http://jweekend.co.uk/dev/LegUp) archetypes and
+[IoLite](http://wicketstuff.org/confluence/display/STUFFWIKI/Wicket-Iolite),
+that do some of the wiring for back-end technologies like
+[Spring](http://springframework.org) and
+[Hibernate](http://hibernate.org). So, how does *Wicket Viewer* for
+*Apache Isis* compare to them?
+
+Well, compared to *Wicketopia* for example, *Wicket Viewer* shares the
+following ideas:
+
+-   both frameworks support pluggable editors for Javabean properties
+
+-   both frameworks allow the metamodel to be enhanced declaratively
+    using annotations (eg @Length); these are picked up by the editors
+
+-   both frameworks support (or aspire to support) the metamodel being
+    built from various sources, including for example *Hibernate* or
+    JSR-303 annotations etc. In the case of the *Wicket Viewer* this is
+    done by using *Apache Isis*' own metamodel.
+
+But there are some differences too; through *Wicket Viewer*'s use of the
+*Apache Isis* it:
+
+-   allows the metamodel to be enhanced imperatively as well as
+    declaratively; naming conventions are used to associate supporting
+    methods with the properties
+
+-   supports user-defined value types (using *Apache Isis*' @Value
+    annotation); important for domain-driven applications
+
+-   supports three level of business rule (both declaratively and
+    imperatively): is the entity class member visible, is it usable, is
+    the value proposed valid. For most other frameworks, only the last
+    of these (validation of proposed values) is typically supported
+
+-   supports properties which are references to other entities, not just
+    simple value types. In particular, the *Wicket Viewer*'s property
+    editor for references allows instances to be found by invoking
+    repositories in-situ
+
+-   renders entity collections as well as entity properties
+
+-   renders entity actions (commands), allowing more than simple CRUD
+    behavior to be exposed. Indeed, it's possible for the domain entity
+    to be immutable except through the invocation of actions
+
+The flip side of the *Wicket Viewer*'s more extensive metamodel support
+is that it uses *Apache Isis*' own metamodel API. In contrast,
+*Wicketopia* (only supporting properties and not collections or actions)
+can get by using java.bean.PropertyDescriptor from the JDK.
+
+Compared to frameworks and archetypes that use *Hibernate* for the
+backend, the *Wicket Viewer* (again by leveraging the rest of the
+*Apache Isis* framework) is more general here too. So, it has a Session
+concept that is analogous to a *Hibernate* session (and if using the
+*JPA ObjectStore* as a backend, the *Apache Isis*' Session just wraps
+the JPA provider's PersistenceContext *e*'s). But it also supports other
+back-end persistence stores too. Indeed, *Apache Isis*' default to
+support rapid development we usually use an in-memory object store.
+
+The *Wicket Viewer* can also handle non-persisted objects as well as
+persisted objects; with every managed object is stored in an identity
+map. This support for non-persisted objects is important because it is
+central to supporting specialized use cases, including managing
+workflows for entering data, and dashboards for analyzing data.
+
+A few other points worthy of mention:
+
+-   The *Wicket Viewer* will automatically serialize both persisted and
+    non-persisted objects, irrespective of whether the pojo itself is
+    serializable. This is important if deploying on a cluster.
+
+-   Through the *Apache Isis* core framework, every managed object also
+    automatically has any domain service dependencies automatically
+    injected into it),
+
+-   Again, courtesy of *Apache Isis* core, every persisted object has a
+    unique, immutable and serializable object Id (OID). This can be a
+    very useful resource when integrating with external services such as
+    REST and ESBs.
+
+-   *Apache Isis* core also provides automatic dirty tracking, and
+    optimistic locking.
+
+Downsides? Currently *Apache Isis* does not support some of the
+Enterprise Java APIs such as JTA, so interactions with domain services
+that ultimately delegate to transaction stores (such as JMS) cannot be
+enlisted in the same transaction as the persistence store. And,
+obviously, it introduces a dependency on the *Apache Isis* framework
+over and above technologies such as the JPA provider implementation.
+
+### Differences in Philosophy
+
+Aside from differences in capability, there's also a difference in
+philosophy.
+
+Frameworks such as *Wicketopia* make it easy to render a form to edit
+the properties of an entity, but the application developer remains in
+control of the rest of the application service layer, and in wiring the
+various pages together.
+
+With the *Wicket Viewer*, though, it is the framework that is in control
+of this layer too, because the links between pages are ultimately
+rendered by the property editor Components provided by the viewer, and -
+in rendering the links representing references - controls . What that
+also means is that every page rendered by the *Wicket Viewer* is always
+of either an object (typical case), or an action parameter dialog, or of
+a collection (the result of invoking an action).
+
+Within this constraint, there is a lot of flexibility, though, because
+every element of the page can be customized. Internally the *Wicket
+Viewer* uses the chain of responsibility pattern to determine how which
+Component type to use to render a page element. This works at a
+fine-grained level (eg a date editor) and also at a larger-scale, (eg
+rendering a collection of Locatable entities on a google maps). See ?
+for more on this.
+
+### Part of the *Apache Isis* framework
+
+The *Wicket Viewer* is only one of a number of viewers available for
+*Apache Isis*. What that means is that you can take your same domain
+objects model and deploy them in other architectures. For example, the
+DnD viewer is a rich, desktop GUI that employs a drag-n-drop metaphor
+(hence its name). It can be run as a standalone single-user application
+or in client/server mode. Even if you don't deploy this viewer in
+production, the way that it displays domain objects makes for a very
+good development tool: something akin to a UML design tool, only
+animated.
+
+*Apache Isis* also supports a number of different ways to test your
+application. Domain objects written to the *Apache Isis* programming
+model are just pojos, and so can easily be unit tested using frameworks
+such as [JUnit](http://junit.org) and [JMock](http://jmock.org). As a
+step up from that, *Apache Isis* provides its own integrations with
+JUnit, providing a "headless" programming model that wraps your domain
+objects in proxies. This allows unit testing as if through the lens of a
+GUI; trying to invoke an action that is disabled will throw an
+exception.
+
+Moving up to story testing/BDD, *Apache Isis* integrates with
+[Concordion](http://concordion.org). The business analyst specifies the
+behavior of the system in HTML, and then the developer wire up this
+specification to the domain model using a set of fixtures that interact
+with the domain objects following the same rules as the viewers. This
+allows application-level testing without the hassle of using a GUI
+testing framework such as *Selenium*.
+
+One final point: *Apache Isis* has a strong separation between its
+programming model and the framework that understands that programming
+model. So, your domain objects depend only on the *Apache Isis* applib
+(which defines annotations such as @RegEx), not the framework itself.
+This allows you to take your domain objects and deploy them on other
+frameworks later, if need be. The *Wicket Viewer* maintains this strong
+separation, defining its own applib for annotations and features unique
+to the *Wicket Viewer*.
+
+The *Wicket Viewer* compared to other *Apache Isis* viewers
+-----------------------------------------------------------
+
+Because the *Wicket Viewer* renders your domain model within a webapp,
+it is to some extent similar to the HTML viewer that is provided
+out-of-the-box by *Apache Isis* itself. However, unlike the HTML viewer,
+the *Wicket Viewer* is highly customizable. The *Wicket Viewer* itself
+essentially consists of a set of [Wicket](http://wicket.apache.org)
+Components that are used to render domain objects, individual member
+elements of domain objects, and indeed collections of domain objects.
+The components provided are sufficient to render any *Apache Isis*
+domain model. However, any developer with experience of *Wicket* can
+easily write their own components and register them with the *Wicket
+Viewer*. In this way, custom renderings of domain objects can be
+achieved.
+
+Typical Flow for Developing a Wicket Objects Application
+--------------------------------------------------------
+
+There are, of course, lots of ways to skin any given cat, but here's how
+you might go about developing an *Apache Isis* application to be
+deployed using the *Wicket Viewer*:
+
+-   use the *Apache Isis* application archetype to create an outline
+    domain model, running against the in-memory object store. The
+    structure of a *Apache Isis* application is reviewed in ?.
+
+-   (optionally) use the DnD viewer to define some of the basic domain
+    services and entities. Or, you might want to skip this step and
+    develop solely using Wicket.
+
+-   run your application under *Wicket*, either using a built-in Jetty
+    web server (see ?) or as a regular webapp (see ?).
+
+-   customize the look-n-feel to use your preferred fonts and logos by
+    updating the CSS (see ?). You can also use CSS to fine-tune the
+    layout for selected objects or object members (see ?).
+
+-   continue to develop your domain application, identifying properties,
+    collections and defining behavior through actions. Also, define
+    fixtures to represent pre-canned scenarios to explore with your
+    domain expert. Check out the core *Apache Isis* documentation for
+    more on developing domain objects.
+
+-   fine tune the set of Components used to render your entities. The
+    *Wicket Viewer* provides built-in Components to render every element
+    of your domain objects, and in some cases provides more than one
+    Component. When the *Wicket Viewer* provides a number of alternate
+    views like this, you might prefer only one. Or, you might use an
+    existing Component and adapt it into your own Component. In either
+    case, you'll need to fine-tune the set of ComponentFactorys (see ?).
+
+-   implement custom representations of some entities (or collections of
+    entities), where it makes sense. For example, you might want to
+    display objects that have a location in a google maps mashup, or
+    objects that have a date/time in a calendar. Ultimately these custom
+    representations are also just ComponentFactorys. A number of
+    Components (including one for google maps and one for charting) are
+    described in ?; use these directly or use them as inspiration for
+    your own.
+
+-   support specialized use cases, if you have any. That is, rather than
+    require the end-user to interact directly with persisted entities,
+    introduce transient process objects to manage workflow and bulk
+    input, or write transient report objects to provide dashboards
+
+-   as you continue to develop your application, you may need to
+    integrate with external services. For example, you might want to
+    send out an email, or invoke a web service exposed by some other
+    system in your enterprise. Define an interface for these domain
+    services, and register their implementation in the *Apache Isis*
+    configuration file. See the main *Apache Isis* documentation for
+    more details on this.
+
+-   ultimately your application will be ready to deploy. Before you do,
+    though, remember that you'll need to sort out persistence and
+    security (see ?)
+
+Enough verbiage. The next chapter is a run through of a simple
+application, screenshot by screenshot, so you can quickly assess whether
+the *Wicket Viewer* fits your needs.
+
+Application Walkthrough
+=======================
+
+> This chapter is a collection of screenshots to give you an idea of
+> what the
+> Wicket Viewer
+> can do.
+
+Most of the screenshots in this chapter require no specific GUI code; in
+fact the first six sections require no specialized code other than the
+domain objects. The GUI that you see is generated by the *Wicket Viewer*
+at runtime, directly from the domain model. You can find all the code
+for the domain objects in ?.
+
+Logging on, and the Application Services Menu
+---------------------------------------------
+
+The *Wicket Viewer* integrates with *Apache Isis* authentication
+mechanism (which is itself pluggable); so we start off with a login
+screen:
+
+![](images/010-login.png)
+
+The initial home page shows a welcome message and more importantly a
+menu bar for each of the registered services defined in the domain
+application. These application services are the start points for the
+user, allowing them to find existing objects and to create new ones. For
+example the `Employees` menu item corresponds to the EmployeeRepository
+class.
+
+![](images/020-services-bar.png)
+
+From the menu bar we can get to the menu items for each service. So, for
+example, the `Employees` domain service provides two actions,
+`All Employees` and `Find
+      Employees`. These are generated automatically from corresponding
+methods - allEmployees() and findEmployees() - in the EmployeeRepository
+service.
+
+![](images/030-services-action.png)
+
+Viewing Entities and Collections of Entities
+--------------------------------------------
+
+Because the `All Employees` action takes no arguments, invoking it just
+returns its results. In this case the action returns a collection (of
+Employees), and so the viewer renders the collection as a table. If the
+action had returned a single object, then that would have been rendered
+instead.
+
+![](images/040-action-result.png)
+
+Clicking on one of the links takes us to a page rendering that object,
+in this case an Employee. There is a form for the entity's properties on
+the left, and summary details on the right. In this particular case the
+entity has no collections; we'll see one that does shortly.
+
+![](images/050-entity-form.png)
+
+In the summary section we an image, a title and the entity actions. All
+these are rendered directly from a metamodel built by inspecting the
+entity's class. Just as we can invoke actions on the services, we can
+also invoke actions on the entities; for example, to view this
+Employee's Claims with the `Claims For,,,` action.
+
+![](images/060-entity-actions.png)
+
+As before, this action returns a collection (of Claims) and so is
+rendered as a table.
+
+![](images/070-entity-action-results.png)
+
+Clicking on a link to a Claim again renders the entity. This is rendered
+in a similar manner to the Employee entity seen earlier. However, the
+Claim entity also has a collection (of ClaimItems), so these are also
+rendered.
+
+![](images/080-entity-form-and-collections.png)
+
+Editing Objects
+---------------
+
+In *Apache Isis* applications, we modify objects either by invoking
+actions on them or by editing them directly. Which properties are
+editable is determined by the entity itself, with the *Wicket Viewer*
+providing an appropriate editor for each property type. In the following
+screenshot we see the Claim entity being edited.
+
+![](images/090-entity-editing-scalars.png)
+
+As well as supporting the editing of properties with value types
+(boolean, String, Date etc), the viewer also allows properties
+representing references to other entities to be edited. For example,
+each Claim has an `approver` (of type Approver, and implemented by
+Employee). Thus, the viewer gives us the ability to find an Employee
+from the `Employees` repository:
+
+![](images/100-entity-editing-references.png)
+
+Leaving us with the `approver` reference set up:
+
+![](images/110-entity-editing-references-result.png)
+
+Invoking Actions
+----------------
+
+Being able to edit entities makes it easy to build CRUD-style
+(create/read/update/delete) applications. The *Wicket Viewer* also
+allows arbitrary actions to be performed on entities. In the screenshot
+below, we see the `Add Item` action (corresponding to addItem() method
+on the Claim class) being called:
+
+![](images/120-entity-action.png)
+
+Because this action takes parameters, the viewer renders a dialog form
+for the user to complete. Just as with the entity editor, we can specify
+parameters of any type, including references to other entities if we
+wish). In this particular case the parameter types are just numbers and
+strings:
+
+![](images/130-entity-action-parameters.png)
+
+When the action is complete, the entity is modified, by adding a new
+ClaimItem into the Claim's `items` collection.
+
+![](images/140-entity-modified.png)
+
+Admittedly, this `Add Item` action just a CRUD-style action. But the
+business logic in the action could be arbitrarily complex. The other
+action in Claim is `Submit`, which could perform lots of business
+processing:
+
+![](images/150-entity-action-more-complex.png)
+
+This action also takes an argument, being a reference to an Approver:
+
+![](images/160-entity-action-reference-parameters.png)
+
+When the action is performed, the object's state is updated, along with
+any other processing. For example, a message could have been sent via an
+enterprise service bus to the processing department. Note the title of
+the Claim entity has also been updated:
+
+![](images/170-entity-title-updated.png)
+
+Business Rules
+--------------
+
+In addition to actions, we can also capture business rules by means of
+validation. For example, a Claim, once submitted, cannot be submitted
+again. With the *Wicket Viewer*, this is shown by a tooltip:
+
+![](images/180-entity-validation.png)
+
+*Apache Isis* supports three different types of validation: whether the
+class member (property, collection or action) is visible; whether it is
+usable, and, whether the proposed value or arguments are valid. Or, more
+pithily, "can you see it, can you use it, can you do it". The viewer
+surfaces all of these different validation rules in the GUI.
+
+View Components
+---------------
+
+The pages rendered by the *Wicket Viewer* are built from multiple
+*Apache Wicket* Components. For example, the application service menu
+bar has its own Component:
+
+![](images/200-view-components-application-service.png)
+
+Likewise, there's a Component to render an entire entity:
+
+![](images/205-view-components-entity-simple.png)
+
+And there's a Component to display the properties of an entity:
+
+![](images/210-view-components-entity-properties.png)
+
+And in turn there's a Component for every entity property:
+
+![](images/220-view-components-entity-property.png)
+
+There are Components such as these for every class member, including
+collections, actions and, indeed, action parameters. In fact, you can
+think of the *Wicket Viewer* as basically a collection of pre-canned
+Components that know how to render the *Apache Isis* metamodel.
+
+Note, by the way, the CSS classes. Each HTML element can be targetted
+either by its type (a string scalar), or by its class member (the
+Claim's `description` property), or both. The viewer therefore makes it
+easy to contribute custom CSS that applies to every page.
+
+Alternate Views
+---------------
+
+As we've seen already, there's a Component to render an entire entity.
+In fact, it's possible to provide more than one Component to do this. We
+could also view the entity in a tabbed view:
+
+![](images/230-multiple-views-for-entities.png)
+
+When there is more than one Component capable of rendering the object,
+the viewer allows the view to be selected:
+
+![](images/230-multiple-views-for-entities.png)
+
+This works for collections too; using the selector we can view a
+collection of Employees in a variety of ways:
+
+![](images/240-multiple-views-for-collections.png)
+
+Selecting the `icons` view shows the collection of Employees as icons:
+
+![](images/270-customize-ui-icons.png)
+
+So far all the screenshots we've seen have been generated from a basic
+domain application, with no custom GUI coding (see ?). But the *Wicket
+Viewer* is also extensible. So, we can write custom views/components,
+provide a corresponding ComponentFactory and then plug them into the
+*Wicket Viewer*'s registry of ComponentFactorys. For example, if we make
+Employee implement a view-specific Locatable interface, then we can
+render them on a google-maps mashup:
+
+![](images/280-customize-ui-maps-mashup.png)
+
+The selector, by the way, is actually implemented as yet another
+view/component, capable of rendering the entity or collection. It
+queries the ComponentFactory registry to determine how many other
+ComponentFactorys there are capable of rendering the entity or
+collection; if more than one then it provides a drop-down and then
+delegates to the other Components to do the work.
+
+Specialized Use Cases
+---------------------
+
+Being able to easily render entities and collection of entities without
+any custom UI coding is great for being able to develop an understanding
+of the problem domain. However, it doesn't always make sense to let the
+user interact directly with the domain objects. For example, if the
+domain objects are very fine-grained such that clicking into them would
+be tedious for the user to do, it makes sense to introduce another
+object that collect the required data and walk the graph of domain
+objects on the users behalf. Or, more straight forwardly, the use case
+might be particularly complex or subtle, and we want to provide the user
+with additional guidance.
+
+The *Wicket Viewer* therefore lets us work with objects designed to
+guide the user through the use case. Because they represent a particular
+solution to help the user achieve their objective, you can think of them
+as being part of the solution space (whereas regular domain objects
+belong to the problem space). Another name also given for objects of
+this type is "process objects"; they take the user through a particular
+process.
+
+For example, we might have a wizard that takes the user through the
+process of making a new Claim:
+
+![](images/300-process-objects.png)
+
+The object this action returns is not a Claim, instead it is a
+ClaimWizard. Unlike Claim, this is not persisted; its state is bound to
+a particular users' session. The design of the ClaimWizard is like any
+other wizard, taking the user through a number of pages; first an
+introductory page:
+
+![](images/310-wizard-intro-page.png)
+
+After that we are taken through pages for each of the properties; For
+example the next page prompts for the Claim's `claimant`:
+
+![](images/320-wizard-claimant-page.png)
+
+The Claim's `approver` and `description` properties likewise have the
+own pages, for example:
+
+![](images/330-wizard-approver-page.png)
+
+The final page allows the user to review details, then confirm:
+
+![](images/340-wizard-finish-page.png)
+
+On finish, the ClaimWizard will create and persists the Claim.
+
+Process objects like wizards are primarily concerned with inputting
+data. We can also have objects that are tailored towards the output of
+data, eg for reporting. For example, we could have a (non-persisted)
+ClaimSummary object that sums up Claim amounts by Claimant:
+
+![](images/400-analyze-claim-summary.png)
+
+We can then combine this with custom views, eg to represent a collection
+of such ClaimExpenseSummarys as a pie chart:
+
+![](images/410-analyze-summary-piechart.png)
+
+There's some guidance on writing application code to deal with such
+specialized use cases in ?.
+
+Running the Application
+=======================
+
+> This chapter describes how to take an *Apache Isis* application and
+> get it running using the *Wicket Viewer*, with the non-customized,
+> generic OOUI.
+
+Applications deployed to run with the *Wicket Viewer* are, ultimately
+just *Wicket* webapps that happen to boot up *Apache Isis*. As such,
+they are bootstrapped with a `web.xml` that is structured the same as
+any other *Wicket* application.
+
+This chapter describes how to run up such a webapp starting with a
+regular *Apache Isis* application.
+
+Structure of an Apache Isis Application
+---------------------------------------
+
+We recommend that you use *Apache Isis*' Maven application archetype to
+set up your application. Doing so will result in a multi-module project
+that contains the following modules:
+
+-   `app`
+
+    Main (parent) module, whose `pom.xml` references the submodules
+
+-   `app/dom`
+
+    Domain object model, plus interfaces for services, repositories and
+    factories
+
+-   app/domsvc
+
+    Implementation of domain services (not repositories/factories)
+
+-   `app/objectstore-default`
+
+    Implementation of repositories/factories for the default object
+    store
+
+-   `app/fixture`
+
+    Fixtures, used to seed (in-memory) object store when running in
+    exploration/prototype mode
+
+-   `app/commandline`
+
+    Bootstrap for running from the command line (typically, the DnD
+    viewer or HTML viewer)
+
+-   `app/viewer-wicket`
+
+    The application set up to be run using wicket, and packaged up as a
+    webapp.
+
+You will see that the archetypes creates a number of other
+`app/viewer-xxx` and `app/objectstore-xxx` modules. You can delete those
+modules that aren't relevant to your final deployment (probably the
+`app/viewer-xxx` modules and most of the `app/objectstore-xxx` modules,
+or you can just ignore them. If you do delete any modules, remember to
+remove their reference from the parent `app/pom.xml` file'a \<modules\>
+section).
+
+### The viewer-wicket module's web.xml
+
+The `viewer-wicket` module aready contains a `web.xml` file to define
+the web app, in the `src/main/webapp` directory. The contents of this is
+largely boilerplate, and will be very familiar if you already know the
+*Apache Wicket* framework:
+
+    <?xml version="1.0" encoding="ISO-8859-1"?>
+    <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+     xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
+     version="2.4">
+
+      <display-name>claims</display-name>
+      <filter>
+        <filter-name>wicket.app</filter-name>
+        <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
+        <init-param>
+          <param-name>applicationClassName</param-name>
+          <param-value>org.apache.isis.viewer.wicket.viewer.IsisWicketApplication</param-value>
+        </init-param>
+      </filter>
+
+      <filter-mapping>
+        <filter-name>wicket.app</filter-name>
+        <url-pattern>/*</url-pattern>
+      </filter-mapping>
+
+    </web-app>
+
+The IsisWicketApplication is a subclass of *Wicket*'s own WebApplication
+that bootstraps *Apache Isis*, handles authentication and sets up
+sessions and transactions.
+
+### Deployment Mode
+
+*Apache Wicket* webapps can be run in one of two "configuration type"s,
+either in the `development` configuration type or in the `deployment`
+configuration type. In Wicket, the configuration type can be specified
+as either:
+
+1.  A system property: `-D
+                wicket.configuration`
+
+2.  as a servlet specific `<init-param>`
+
+3.  as a context specific `<context-param>`
+
+Setting this value changes various properties, such as whether templates
+are reloaded. Wicket's Application\#configure() method is the place to
+look for all the differences.
+
+For its part, *Apache Isis* defines various "deployment mode"s. For
+example, `exploration` and `prototype` mode are both intended for
+single-user development, with the former requiring no login and also
+including any actions annotated as `@Exploration`. For multi-user
+(production) use, *Apache Isis* provides the `server` deployment mode,
+associating a separate *Apache Isis* runtime (IsisContext) to each
+thread (ie bound to a `ThreadLocal`).
+
+The *Wicket Viewer* maps *Wicket*'s `development` configuration type to
+*Apache Isis*' `prototype` deployment mode. However, the `server`
+deployment mode provided by *Apache Isis* is not quite appropriate for a
+*Wicket* webapp, because there could be multiple concurrent requests for
+a given user (originating from the same browser/user agent). The *Wicket
+Viewer* therefore defines a custom deployment mode which binds the
+*Apache Isis* runtime to the *Wicket* session (see the
+IsisContextForWicket class if you're interested in such things).
+
+What all this means is that selecting between *Apache Isis* deployment
+modes is done just by specifying the *Apache Wicket* configuration type.
+If you're already familiar with Wicket there's therefore nothing new to
+learn: just configure the webapp to run in either `development` or
+`deployment` mode.
+
+### Security
+
+Since both of the deployment modes supported by *Wicket Objects* require
+a login, it means we need to set up security. The IsisWicketApplication
+class provided by the *Wicket Viewer* subclasses from *Wicket*'s own
+AuthenticatedWebApplication, and serves up a sign-in page. To ensure
+that this sign-in page appears, every web page served up by the *Wicket
+Viewer* is annotated with
+`@AuthorizeInstantiation("org.apache.isis.viewer.wicket.roles.USER")`,
+which requires that every login has a role called
+`org.apache.isis.viewer.wicket.roles.USER`.
+
+*Apache Isis* deployment modes provide a couple of ways of avoiding
+login during development. For example, in `exploration` mode the viewers
+automatically login, while in `exploration` mode and `prototype` mode
+specifying a `LogonFixture` will means an automatic logon using the
+details provided within that fixture. The *Wicket Viewer* does not
+support `exploration` mode, however, and does not currently support
+LogonFixture. What that means is that it's always necessary to login.
+
+The *Wicket Viewer* delegates to *Apache Isis* to authentication.
+*Apache Isis*' default authentication mechanism is a no-op and requires
+no configuration. If you decide to a different authentication mechanism
+(eg file-based security, org.apache.isis.alternatives.security:file, or
+LDAP-based security, org.apache.isis.alternatives.security:ldap) then
+refer to the appropriate documentation for that module.
+
+The *Wicket Viewer* simply always places each login into the
+`org.apache.isis.viewer.wicket.roles.USER` role, to ensure that once the
+sign-in page is navigated past, that the user can access each web page.
+
+One consequence of this design is that the roles cannot currently be
+used by the *Apache Isis* domain objects nor the authorization
+mechanism; every user is simply in the USER role. This will be addressed
+in the future.
+
+Running as a WAR
+----------------
+
+The most straightforward approach for running a *Wicket
+Viewer*application is to build a WAR archive from the `viewer-wicket`
+module. Most IDEs will then allow this WAR to be deployed on an external
+servlet container, for debugging. For example, in Eclipse this is done
+by Run As \> Server:
+
+![](images/RunAsServer.png)
+
+and then select the external servlet container to deploy against:
+
+![](images/RunAsServer-dialog.png)
+
+If deploying this way, then the web browser URL may be slightly
+different. For example with Eclipse the URL to specify is
+<http://localhost:8080/webappname>.
+
+Running using *Isis*' WebServer class
+-------------------------------------
+
+As an alternative to deploying as a webapp, you can use Isis' WebServer
+class. This class has its own main() to bootstraps Jetty and configures
+a webapp from the `web.xml` file. If using Eclipse, for example, then yo
+can create a `.launch` configuration to run your application using
+WebServer.
+
+### Adding Dependency to Bootstrap
+
+The only thing you need to do is to edit the `viewer-wicket` module's
+`pom.xml`; add/comment in:
+
+    <dependency>
+     <groupId>org.apache.isis.core</groupId>
+     <artifactId>webserver</artifactId>
+    </dependency>
+
+### Running the Application
+
+Running the application is just a matter of running the
+org.apache.isis.WebServer. For example, in Eclipse the following launch
+configuration should suffice:
+
+![](images/WebServer-launch.png)
+
+Running this will boot strap a Jetty webserver:
+
+![](images/WebServer-running.png)
+
+You can then log on using <http://localhost:8080>:
+
+![](images/WicketObjects-logon-page.png)
+
+Customizing the Startup
+-----------------------
+
+Most of the remaining chapters address various means by which the UI
+generated by the *Wicket Viewer* can be customized. Before we go any
+further, though, we should mention that the viewer uses dependency
+injection provided by [Guice](http://google-guice.googlecode.com). It
+comes with default bindings, so customizing the *Wicket Viewer* requires
+overriding these default bindings.
+
+Note: this usage of Guice is likely to be replaced by JSR-299 based
+dependency mechanism.
+
+Specifically, in IsisWicketApplication, there's a method
+newIsisWicketModule():
+
+    public class IsisWicketApplication extends AuthenticatedWebApplication {
+      ...
+      protected Module newIsisWicketModule() {
+        return new IsisWicketModule();
+      }
+    }
+
+This method can be overridden in your own subclass of
+IsisWicketApplication, providing a new implementation of *Guice*'s
+Module interface. Typically you'll just want to override one or two of
+the bindings, so you should use the Modules helper class:
+
+    public class MyApplication extends IsisWicketApplication {
+      ...
+      protected Module newIsisWicketModule() {
+        return Modules.override(super.newIsisWicketModule()).with(
+          new AbstractModule() {
+            @Override
+            protected void configure() {
+              // override bindings here
+            }
+          }
+        );
+      }
+    }
+
+To pick up your subclass of IsisWicketApplication, just update the
+`web.xml` file.
+
+Customizing CSS
+===============
+
+> This chapter describes how to customize the UI generated by the
+> *Wicket Viewer* by providing application-specific CSS.
+
+CSS is used heavily by the *Wicket Viewer*, with the HTML of each
+Component using CSS classes for the styling. But you can override the
+default styling by supplying an application-level CSS file.
+
+By default this file should be called `application.css` and should
+reside within `WEB-INF` directory.
+
+There are two levels at which we can override the default styling,
+either generically or specific to a particular domain. Let's look at
+both.
+
+Generic CSS
+-----------
+
+The name of each class indicates the nature of what is being rendered,
+and each Component provides some default styling so that the
+out-of-the-box UI is usable. For example, an entity icon, title and
+actions are rendered as:
+
+![](images/EntitySummary.png)
+
+The icon and title for this are rendered as:
+
+    <div class="entitySummary">
+      <img src="?wicket:interface=:4:entity:entity:entitySummary:entityImage:1:IResourceListener::"
+           class="entityImage" wicket:id="entityImage">
+      <label class="entityTitle" wicket:id="entityTitle">Fred Smith</label>
+      ...
+    </div>
+
+So, to change the font, you could use:
+
+    div.entitySummary > label.entityTitle {
+      color: maroon;
+      font-size: xx-large;
+      font-weight: bolder;
+    }
+
+This would render the entity icon and title as:
+
+![](images/EntitySummary-Css.png)
+
+In this way you can develop a look-n-feel for the application (or
+perhaps your organization).
+
+Specific CSS
+------------
+
+As well as targetting HTML elements generically, individual class
+members can also be targetted for a particular domain model.
+
+For example, the properties of a Claim object might be rendered as:
+
+![](images/Claim-properties.png)
+
+The HTML for the description property is:
+
+    <div class="Claim-description" wicket:id="scalar">
+      <wicket:panel>
+        <div class="string scalarPanel">
+          <label wicket:id="scalarIfRegular" for="scalarValue3d">
+            <span class="scalarName" wicket:id="scalarName">description</span>
+            <span class="scalarValue">
+              <input type="text" title="" size="25" disabled="disabled"
+                 value="Meeting at clients" wicket:id="scalarValue"
+                 id="scalarValue3d"
+                 name="properties:1:scalar:scalarIfRegular:scalarValue">
+            </span>
+          </label>
+          <span wicket:id="feedback">
+            <wicket:panel>
+            </wicket:panel>
+          </span>
+        </div>
+      </wicket:panel>
+    </div>
+
+To change the label of this specific element, we could use:
+
+    .Claim-description .scalarName {
+      color: maroon;
+      font-weight: bolder;
+    }
+
+which would give us:
+
+![](images/Claim-properties-CSS.png)
+
+This is a slightly trite example, but demonstrates the point.
+
+Changing the location/name of the application CSS file
+------------------------------------------------------
+
+As already mentioned, the default for the application CSS file is in
+`WEB-INF/application.css`. If for any reason you want to change this,
+you can do so by subclassing IsisWicketApplication and overriding the
+newIsisWicketModule() method.
+
+For example, to use `css/myapp.css` (under `WEB-INF`) you would write:
+
+    public class MyApplication extends IsisWicketApplication {
+      ...
+      protected Module newIsisWicketModule() {
+        return Modules.override(super.newIsisWicketModule()).with(
+          new AbstractModule() {
+            @Override
+            protected void configure() {
+              bindConstant().annotatedWith(ApplicationCssUrl.class).to("css/myapp.css");
+            }
+          }
+        );
+      }
+    }
+
+Your custom application should then be registered in `web.xml`, as
+described in ?.
+
+Using the Wicket Viewer AppLib
+==============================
+
+> This chapter explains how to use certain viewer-specific features in
+> your domain application.
+
+Many *Isis* components have their own application library, the *Wicket
+Viewer* included. This allows you to specify additional viewer-specific
+semantics within your domain model; the viewer can then render them
+appropriately.
+
+Configuring the Project Modules
+-------------------------------
+
+In order to use the viewer-specific features, the `dom` module must
+reference the applib, and the `viewer-wicket` module must be configured
+appropriately.
+
+### Referencing the AppLib
+
+In the dom project, add in a `<dependency>` to the *Wicket Viewer*
+applib:
+
+    <dependencies>
+      ...
+
+      <!-- Wicket Viewer -->
+      <dependency>
+        <groupId>org.apache.isis.viewer.wicket</groupId>
+        <artifactId>applib</artifactId>
+      </dependency>
+
+      ...
+    </dependencies>
+
+This will allow you to use the *Wicket Viewer*'s annotations etc. in
+your domain objects.
+
+### Configuring the *Wicket Viewer* Facets
+
+In addition, you must also configure your application so that the *Isis*
+metamodel contains the information to be picked up by the *Wicket
+Viewer*.
+
+In the `viewer-wicket` module, add the following to `isis.properties`:
+
+    isis.reflector.facets.include=\
+        org.apache.isis.viewer.wicket.metamodel.wizardpagedesc.WizardPageDescriptionAnnotationFacetFactory\
+       ,org.apache.isis.viewer.wicket.metamodel.cssclass.CssClassAnnotationFacetFactory
+
+This basically instructs *Apache Isis* to capture additional information
+(facets) in its metamodel. Now let's look at what these facets are used
+for.
+
+@CssClass
+---------
+
+The @CssClass annotation allows you to specify an additional CSS class
+(or classes) applied on any object type, property, collection or action.
+This CSS will be added verbatim to any CSS classes that are normally
+applied by the *Wicket Viewer* itself.
+
+\*\*\* TODO: complete.
+
+There is further discussion on
+
+@WizardPageDescription
+----------------------
+
+It's common for wizards to have a description explaining what the user
+is expected to do. This can be modeled as a String property annotated
+with @WizardPageDescription, for example:
+
+    @NotPersistable
+    public class ClaimWizard extends AbstractDomainObject {
+
+        ...
+
+        @WizardPageDescription
+        @MemberOrder(sequence = "1")
+        public String getPageDescription() { ... }
+
+        ...
+    }
+
+Adding this annotation causes the *Wicket Viewer* to select a different
+Component to be used to render this property; specifically, one that
+renders the value as a large label. You can see the result of this
+annotation in below (the label above the claimant).
+
+![](images/320-wizard-claimant-page.png)
+
+Note that this annotation only affects the description; the three
+buttons shown in the above screenshot are as a result of the wizard
+being implemented as a custom component. For more on that topic, see ?.
+
+Customizing the Component Set
+=============================
+
+> This chapter describes the how to customize the UI by modifying the
+> set of components used to render objects, properties, collections or
+> actions.
+
+The *Wicket Viewer* offers several ways in which the UI rendered can be
+customized, from simply tweaking the CSS (see ?) through to the use of
+custom components for mashups and wizards. This chapter explains how to
+use pre-existing custom components; ? explains how to write your own
+components, and lists some components that have already been developed.
+
+There are more details provided in each of the sections that follow.
+
+Component Factories
+-------------------
+
+### ComponentFactory interface
+
+At its heart the *Wicket Viewer* consists of a set of *Wicket*
+`Component`s and corresponding IModel\<?\>s that are used to render
+entities, collections of elements and indeed individual members of
+elements. Each Components is created by a corresponding
+ComponentFactory, with the factory to use discovered using a
+chain-of-responsibility pattern.
+
+The Components created by the *Wicket Viewer* vary in size from
+rendering an entire collection of entities all the way down to a single
+property of an entity. You can find the full set of built-in Components
+by searching for implementations of ComponentFactory:
+
+![](images/ComponentFactory-hierarchy.png)
+
+For example, the CollectionContentsAsAjaxTableFactory class is used to
+render a collection of entities (eg returned from an action invocation)
+as, erm, an ajax table;
+
+    public class CollectionContentsAsAjaxTableFactory extends ComponentFactoryAbstract {
+      private static final long serialVersionUID = 1L;
+      private static final String NAME = "styled";
+
+      public CollectionContentsAsAjaxTableFactory() {
+        super(ComponentType.COLLECTION_OF_ENTITIES, NAME);
+      }
+
+      @Override
+      public boolean appliesTo(IModel<?> model) {
+        return model instanceof EntityCollectionModel;
+      }
+
+      public Component createComponent(String id, IModel<?> model) {
+        EntityCollectionModel collectionModel = (EntityCollectionModel) model;
+        return new CollectionContentsAsAjaxTable(id, collectionModel);
+      }
+    }
+
+The selection of the ComponentFactory is based on two criteria: the
+ComponentType, and the IModel\<?\>. Broadly speaking the ComponentType
+standardizes the `wicket:id` used in the HTML fragment (so
+`<div wicket:id="collectionContents"/>` would map onto the
+ComponentType.COLLECTION\_CONTENTS, while the IModel\<?\> is the
+corresponding information used for the rendering of that component. But
+there's a semi-formal relationship between these two concepts; the
+ComponentType effectively acting as a power-type for the subclass of
+IModel\<?\> that is supplied.
+
+The superclass ComponentFactoryAbstract takes responsibility for
+checking that the ComponentType matches the `wicket:id`, while
+delegating the checking of the IModel to its subtype:
+
+    public abstract class ComponentFactoryAbstract implements ComponentFactory ... {
+      ...
+      public final boolean appliesTo(ComponentType componentType, IModel<?> model) {
+        return componentType == getComponentType() && appliesTo(model);
+      }
+
+      protected abstract boolean appliesTo(IModel<?> model);
+      ...
+    }
+
+The subclass then refines this check by overriding appliesTo() to also
+check the model; returning true indicates that the ComponentFactory is
+able to render that model, after which the createComponent() method is
+then called to actually create the instance. So in
+CollectionContentsAsAjaxTableFactory, its implementation simply checks
+if the supplied model is an EntityCollectionModel. More
+sophisticated/less generic ComponentFactory might also make additional
+checks; you can find some examples of these in ?.
+
+### Registering ComponentFactorys using META-INF Services
+
+The easiest way to register new ComponentFactorys is using the JDK's own
+ServiceLoader capability.
+
+All that is needed is for your ComponentFactory to be registered in a
+file on the classpath call
+`META-INF/services/org.apache.isis.viewer.wicket.ui.ComponentFactory`.
+The contents of this file should be the fully qualified class name of
+your ComponentFactory implementation. And that's it! Registering the
+ComponentFactory is done automatically just by virtue of updating the
+classpath. You'll find that the custom components described in ? all use
+this technique.
+
+Note that this technique does not allow you to remove existing
+ComponentFactorys, only add new ones. So if you do want to exclude any
+of the built-in ComponentFactorys, then you will still need to use the
+ComponentFactoryList method.
+
+> **Note**
+>
+> This capability is provided by the ComponentFactoryRegistry component,
+> which is also bound in the IsisWicketModule. If you wanted to, you
+> could replace this higher-level registry component with your own
+> implementation. There's probably very little need to do this though,
+> given that you can just as easily customize using ComponentFactoryList
+> or `META-INF` services.
+
+### Registering ComponentFactorys using a custom ComponentFactoryList
+
+The set of ComponentFactorys that are provided with the *Wicket Viewer*
+are specified by the ComponentFactoryList interface.
+
+If you only want to add new factories, we recommend using the technique
+described in ?. But if you want to remove support for any of the default
+factories, or perhaps change the order in which factories are
+registered, you'll need to do use write and the bind in your own
+implementation of ComponentFactoryList.
+
+To write your implementation of ComponentFactoryList, start with the
+default implementation, ComponentFactoryListDefault. You'll see that it
+is written so that it can be easily subclassed and overridden on an
+as-needed basis. Worst case scenario, you can copy-and-paste code as
+necessary.
+
+Then, you need to override the binding in newIsisWicketModule(), eg:
+
+    public class MyApplication extends IsisWicketApplication {
+      ...
+      protected Module newIsisWicketModule() {
+        return Modules.override(super.newIsisWicketModule()).with(
+          new AbstractModule() {
+            @Override
+            protected void configure() {
+              bind(ComponentFactoryList.class).to(MyComponentFactoryList.class);
+            }
+          }
+        );
+      }
+    }
+
+You should also ensure that your MyComponentFactoryList is annotated
+with @Singleton.
+
+And, do remember to update `web.xml` to reference your subclass of
+IsisWicketApplication.
+
+Advanced Customization
+----------------------
+
+This section covers a couple of more advanced customization topics.
+
+### Page Registry
+
+While the content of any given web page rendered by the *Wicket Viewer*
+is made up of multiple Components, there are in fact only a small number
+of WebPages:
+
+-   WelcomePage displays the initial home page with a welcome message
+
+-   EntityPage displays a single entity
+
+-   ActionPage displays an action dialog or the results of invoking an
+    action.
+
+Each of these has a corresponding HTML page which defines the content of
+that page. In many cases the look-n-feel of these pages can be adjusted
+simply using CSS, as described in ?. If necessary though an entirely
+different page layout can be specified, for example to put the menubar
+on the left rather than at the top.
+
+The easiest approach to define a new page is to subclass PageAbstract
+superclass and then provide a different implementation of PageRegistry.
+As for ComponentFactorys, this is done by providing a new
+implementation, and then overriding a binding in newIsisWicketModule().
+
+The default pages are specified by PageClassListDefault:
+
+    public class PageClassListDefault implements PageClassList  {
+
+      @Override
+      pulic void registerPages(PageRegistrySpi pageRegistry) {
+        pageRegistry.registerPage(PageType.SIGN_IN, WicketSignInPage.class);
+        pageRegistry.registerPage(PageType.SIGN_OUT, WicketSignOutPage.class);
+        pageRegistry.registerPage(PageType.ENTITY, EntityPage.class);
+        pageRegistry.registerPage(PageType.HOME, HomePage.class);
+        pageRegistry.registerPage(PageType.ACTION, ActionPage.class);
+      }
+    }
+
+You can easily copy-n-paste this to create your own implementation. Note
+though that there must be a registered page for every PageType instance,
+otherwise the *Wicket Viewer* will fail fast on boot time.
+
+Overriding the binding is done in the usual way:
+
+    public class MyApplication extends IsisWicketApplication {
+      ...
+      protected Module newIsisWicketModule() {
+        return Modules.override(super.newIsisWicketModule()).with(
+          new AbstractModule() {
+            @Override
+            protected void configure() {
+              bind(PageClassList.class).to(MyPageClassList.class);
+            }
+          }
+        );
+      }
+    }
+
+Don't forget to update the web.xml to specify your subclass of
+IsisWicketApplication.
+
+> **Note**
+>
+> If all you want is to provide a custom rendering of a particular
+> interface or class, then you should instead write and register a
+> ComponentFactory, with a ComponentType.ENTITY and filtering the
+> EntityModel. The custom components described in ? do this, as does the
+> component registered in the test application to render a wizard (see
+> ?).
+
+### Subclassing IsisWicketApplication
+
+As we've seen, you can also customize *Wicket Objects* in various ways
+by subclassing the IsisWicketApplication bootstrap. The most common
+reason for doing so is to override the default implementation of
+ComponentFactoryList.
+
+This design follows the general style of *Wicket*; in fact, you'll see
+that IsisWicketApplication itself overrides a number of other methods
+(such as newRequestCycle() and newConverterLocator()), in order to hook
+*Apache Isis* into the rest of Wicket.
+
+In general it's unlikely that you'll need to alter the behavior of these
+hook methods; but it's useful to know that *Wicket Objects* doesn't
+particularly interfere with the way in which you may be used to
+customizing regular *Wicket* applications.
+
+Writing Custom Components
+=========================
+
+> This chapter provides some further guidance on objects designed to
+> support specialized use cases.
+
+Back in the application walkthrough (see ?) we saw that the *Wicket
+Viewer* has support for non-persisted objects that are designed to
+support specialized use cases. Whereas regular persisted domain objects
+can be thought of as part of the problem space, such non-persisted
+objects can be thought of as being part of the solution space because
+they offer a particular solution to a particular user objective. We call
+these objects *process objects* because objects they help a user perform
+a particular process.
+
+This chapter provides some general guidance on writing such process
+objects, and outlines the support that exists in *Wicket Objects* for
+writing custom components for such objects.
+
+Custom Components for Process Objects
+-------------------------------------
+
+Because process objects are there to guide the user, they often go
+hand-in-hand with custom components so that they can be rendered in a
+particular way.
+
+For example, in the application walkthrough we saw that a ClaimWizard
+process object is rendered with its previous(), next() and finish()
+actions as regular buttons:
+
+![](images/320-wizard-claimant-page.png)
+
+Similarly, the ClaimExpenseSummary object (or rather, a collection of
+them) hooks into the capabilities of the googlecharts component
+(discussed in ?):
+
+![](images/410-analyze-summary-piechart.png)
+
+You can use any of the *Wicket Viewer*'s built-in Components that are
+used to build the generic views for your own custom views; search down
+the ComponentFactory inheritance hierarchy and there's a good chance
+you'll find something of use. For example, you can easily add components
+to represent properties in a wizard (the custom Component for
+ClaimWizard does precisely this; you can inspect the code in ?).
+
+The *Wicket Viewer* also has a small number of Components intended for
+writing custom views.
+
+### ProcessObjectPanelAbstract
+
+The ProcessObjectPanelAbstract is intended to be used as the superclass
+for any panel-like Component that will render a process object. Its
+model is intended to be an EntityModel, which wraps the process object.
+
+This adapter class contains a number of convenience methods to help
+build panels:
+
+-   addProperties(Form\<?\> form, String id)
+
+    This adds the currently visible properties from the process object
+    to the provided form
+
+-   isValid(Form\<?\> form)
+
+    This validates the process object, where the form holds the
+    properties
+
+-   executeNoArgAction(String actionId)
+
+    Executes the indicated action on the process object (expected to
+    take no-arguments).
+
+Although minimal, these methods are sufficient to build a basic wizard.
+The executeNoArgAction() method, for example, allows `Previous`, `Next`
+and `Finish` buttons to be added.
+
+### Help Wanted!
+
+As you can see, the level of support provided by the *Wicket Viewer* for
+custom views is, admittedly, quite limited. There's nothing to prevent
+you from writing your own, of course, but to do so you'll need to use
+with the *Apache Isis* metamodel APIs.
+
+We hope to extend the components available as *Wicket Objects* continues
+to be developed. But in the meantime, if you build a Component that you
+think would be generally useful, please consider contributing it back to
+this project for the benefit of others.
+
+Use a Page enum for Wizards
+---------------------------
+
+Here's just a bit of good old-fashioned advice; consider using an enum
+to track the state of your wizards.
+
+For example, the ClaimWizard in the example app has the following enum
+defined:
+
+    @NotPersistable
+    public class ClaimWizard extends AbstractDomainObject {
+
+        public enum Page {
+            INTRO("This wizard will take you through the process of creating a claim"),
+            CLAIMANT("Enter the claimant that is making this claim"),
+            APPROVER("By default, the claimant's own approver will approve this claim.  " +
+              "Update here if another approver will approve this claim."),
+            DESCRIPTION("Update the description if required."),
+            SUMMARY("Confirm all details, or go back and amend if needed");
+
+            private String description;
+            private Page(String description) {
+                this.description = description;
+            }
+
+            public String getDescription() {
+                return description;
+            }
+
+            public boolean hasPrevious() {
+                return ordinal() > 0;
+            }
+            public Page previous() {
+                if (hasPrevious()) {
+                    return values()[ordinal() - 1];
+                } else {
+                    return this;
+                }
+            }
+
+            public boolean hasNext() {
+                return ordinal() < values().length - 1;
+            }
+            public Page next() {
+                if (hasNext()) {
+                    return values()[ordinal() + 1];
+                } else {
+                    return this;
+                }
+            }
+
+            @Ignore
+            public boolean is(Page... pages) {
+                for (Page page : pages) {
+                    if (page == this) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+        }
+
+        ...
+    }
+
+This not only defines the descriptions of each Page, it also includes
+some logic for the previous() and next() actions to delegate to:
+
+    @NotPersistable
+    public class ClaimWizard extends AbstractDomainObject {
+
+        // {{ Page
+        private Page page;
+        @Hidden
+        public Page getPage() { ... }
+        public void setPage(final Page page) { ... }
+        // }}
+
+
+        // {{ Page Description
+        @WizardPageDescription
+        @MemberOrder(sequence = "1")
+        public String getPageDescription() { ... }
+
+        // {{ previous
+        @MemberOrder(sequence = "1")
+        public void previous() {
+            setPage(getPage().previous());
+        }
+        public String disablePrevious() {
+            return coalesce(noPreviousPage(), confirmIfOnSummaryPage());
+        }
+        private String noPreviousPage() {
+            return !getPage().hasPrevious() ? "no previous page" : null;
+        }
+        // }}
+
+        // {{ next
+        @MemberOrder(sequence = "2")
+        public void next() {
+            setPage(getPage().next());
+        }
+        public String disableNext() {
+            return coalesce(noNextPage(), confirmIfOnSummaryPage());
+        }
+        private String noNextPage() {
+            return !getPage().hasNext() ? "no next page" : null;
+        }
+        // }}
+
+        ...
+    }
+
+Custom Components in isis-contrib
+=================================
+
+> This chapter describes a number of custom components for the *Wicket
+> Viewer*. Some of these integrate third party components and/or
+> experimental.
+
+As was described in ?, the *Wicket Viewer* is designed to be extensible,
+allowing you to plug in more sophisticated renderings of the domain
+objects that make up your application. This chapter describes a number
+of custom components that demonstrate this capability, most of which are
+basically wrappers around functionality within the *Wicket*'s companion
+[WicketStuff](http://wicketstuff.org) project.
+
+The components here are probably best considered as examples rather than
+formally part of the *Wicket Viewer*, if only because we want the
+*Wicket Viewer* to depend just on core *Wicket*, not *WicketStuff*. But
+what you will find is that all the components here follow a similar
+layout, so you can easily adapt copy them into your own projects and
+adapt them as you feel fit.
+
+About the Components
+--------------------
+
+The source for these components is available at \*\*\*.
+
+### Common Layout
+
+Most of the components define their own interfaces or annotations; these
+are then implemented or annotated on the domain classes so that the
+component knows whether it applies or not (see discussion on
+ComponentFactory, in ?).
+
+To minimize the coupling between the domain objects and the component
+implementation, we separate out the interfaces/annotations into an
+applib.
+
+![](images/views-common-layout.png)
+
+The naming convention for these modules is:
+
+-   `org.starobjects.wicket:view-xxx` for the parent module for view
+    'xxx'
+
+-   `org.starobjects.wicket:view-xxx-applib` for the applib submodule
+
+-   `org.starobjects.wicket:view-xxx-view` for the view submodule (that
+    contains the actual ComponentFactory and Component implementations)
+
+### Adding Dependency Management for Custom Views
+
+In the parent project's `pom.xml`, specify the modules of the custom
+views that you want to use, along with the version:
+
+    <dependencyManagement>
+      <dependencies>
+        ...
+
+        <!-- Wicket Viewer view extensions -->
+        <dependency>
+          <groupId>org.apache.isis.viewer.wicket</groupId>
+          <artifactId>view-gmap2-applib</artifactId>
+          <version>${wicketobjects.version}</version>
+        </dependency>
+
+        <dependency>
+          <groupId>org.apache.isis.viewer.wicket</groupId>
+          <artifactId>view-gmap2-view</artifactId>
+          <version>${wicketobjects.version}</version>
+        </dependency>
+
+        <dependency>
+          <groupId>org.apache.isis.viewer.wicket</groupId>
+          <artifactId>view-googlecharts-applib</artifactId>
+          <version>${wicketobjects.version}</version>
+        </dependency>
+
+        <dependency>
+          <groupId>org.apache.isis.viewer.wicket</groupId>
+          <artifactId>view-googlecharts-view</artifactId>
+          <version>${wicketobjects.version}</version>
+        </dependency>
+
+        <dependency>
+          <groupId>org.apache.isis.viewer.wicket</groupId>
+          <artifactId>view-calendarviews-applib</artifactId>
+          <version>${wicketobjects.version}</version>
+        </dependency>
+
+        <dependency>
+          <groupId>org.apache.isis.viewer.wicket</groupId>
+          <artifactId>view-calendarviews-view</artifactId>
+          <version>${wicketobjects.version}</version>
+        </dependency>
+
+        <dependency>
+          <groupId>org.apache.isis.viewer.wicket</groupId>
+          <artifactId>view-cooldatasoftmenu-view</artifactId>
+          <version>${wicketobjects.version}</version>
+        </dependency>
+
+        ...
+      <dependencies>
+    </dependencyManagement>
+
+### Adding the Custom View's AppLibs as Dependencies
+
+\*\*\* Again, if you intend to use any of the custom components (see ?),
+then also add in dependencies to their respective applibs (if they have
+one):
+
+    <dependencies>
+      ...
+
+      <!-- Wicket Viewer view extensions -->
+      <dependency>
+        <groupId>org.starobjects.wicket</groupId>
+        <artifactId>view-calendarviews-applib</artifactId>
+      </dependency>
+
+      <dependency>
+        <groupId>org.starobjects.wicket</groupId>
+        <artifactId>view-gmap2-applib</artifactId>
+      </dependency>
+
+      <dependency>
+        <groupId>org.starobjects.wicket</groupId>
+        <artifactId>view-googlecharts-applib</artifactId>
+      </dependency>
+
+      ...
+    </dependencies>
+
+### Update Classpath
+
+The classpath for both the `dom` submodule and the `commandline` /
+`webapp` submodule each need to be updated (see ? for an overview of the
+typical structure of an *Apache Isis* application):
+
+-   the `dom` submodule should be updated to reference the
+    view-xxx-applib submodule for each custom component
+
+-   the `commandline` / `webapp` module should be updated to reference
+    the `view-xxx-view` submodule for each custom component
+
+Gmap2
+-----
+
+The gmap2 component renders a collection of objects in a Google map:
+
+![](images/280-customize-ui-maps-mashup.png)
+
+All that is required is for the object to implement Locatable interface,
+which in turn returns a Location value object:
+
+    package org.apache.isis.viewer.wicket.view.gmap2.applib;
+
+    public interface Locatable {
+        Location getLocation();
+    }
+
+If deploying on localhost, no API key is required. However, internet
+deployments do require an key, which should be specified as an
+init-parameter for the *Wicket* filter in `web.xml`:
+
+    <?xml version="1.0" encoding="ISO-8859-1"?>
+    <web-app ... >
+
+      ...
+
+      <filter>
+        <filter-name>wicket.app</filter-name>
+        <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
+        <init-param>
+          <param-name>applicationClassName</param-name>
+          <param-value>org.apache.isis.viewer.wicket.viewer.app.IsisWicketApplication</param-value>
+        </init-param>
+        <init-param>
+          <param-name>GOOGLE_MAPS_API_KEY</param-name>
+          <param-value>(key here)</param-value>
+        </init-param>
+      </filter>
+
+    </web-app>
+
+Google Charts
+-------------
+
+The googlechart component provides basic charting capabilities. It
+currently supports a single chart type; to render a collection as a pie
+chart:
+
+![](images/410-analyze-summary-piechart.png)
+
+All that is required is for the object to implement the (horribly named)
+PieChartable:
+
+    package org.apache.isis.viewer.wicket.view.googlecharts.applib;
+
+    public interface PieChartable {
+
+      double getPieChartValue();
+      String getPieChartLabel();
+    }
+
+The label is used to point to each sector on the pie chart, the value
+determines the size of each sector relative to the other sectors.
+
+CoolDataSoft Application Services Menu
+--------------------------------------
+
+The CoolDataSoft application services menu provides a different
+look-n-feel for the application services menu, using Ajax instead of
+CSS:
+
+![](images/cooldatasoft-appmenu.png)
+
+The implementation is based upon code lifted from the
+[wicket-menu](http://code.google.com/p/wicket-menu/) project, hosted on
+code.google.com. Please note that this code is GPLv3 and so cannot be
+used freely in commercial applications.
+
+Deployment Topics
+=================
+
+> This chapter touches on various topics that should be addressed prior
+> to deployment.
+
+Before you can deploy your application into production there are a
+number of things to be addressed. Most significantly of these is
+persistence, but security is another important topic.
+
+Because the *Wicket Viewer* runs on top of *Apache Isis*, many of the
+deployment tasks are based on the way in which *Apache Isis* tackles
+them.
+
+This chapter briefly outlines the main tasks from a *Wicket Objects*
+perspective. You might, though, want to dig out my book, [Domain Driven
+Design using Naked Objects](http://pragprog.com/titles/dhnako), for more
+in-depth coverage of the *Apache Isis* side-of-things (it covers *Apache
+Isis*' predecessor, *Naked Objects*, but is still broadly applicable).
+
+Running in a WebApp
+-------------------
+
+When developing *Apache Isis* applications you can run from either the
+`commandline` project or from the `webapp` project (see ?). If you've
+been using the former, then you'll need to switch to running from the
+latter so that your application can be built as a WAR for deployment.
+Take care to ensure that:
+
+-   the classpath dependencies are the same (so that any custom
+    components you're using or have written are picked up)
+
+-   that the `isis.properties` config file is the same
+
+Persistence
+-----------
+
+If you've been using the in-memory object store for development,
+obviously you'll need to switch to a persistent object store before you
+deploy.
+
+Going into the details of that is outside the scope of this guide, but
+it's worth noting that you have a number of options:
+
+-   the simplest persistence mechanism (albeit still only really for
+    prototyping) is to use the XML object store. You can specify this in
+    `isis.properties`:
+
+        isis.persistor=xml
+        isis.xmlos.dir=/tmp/xml
+
+-   more likely though you'll want to use a relational database. One
+    option is [JPA Objects](http://jpaobjects.sourceforge.net), another
+    sister project to *Apache Isis* (like *Wicket Objects* itself, in
+    fact). There's reasonable coverage in the
+    [DDDuNO](http://pragprog.com/titles/dhnako) book.
+
+-   *Apache Isis* also has (will have) a JDBC-based object store, SQL
+    Object Store
+
+-   If relational databases aren't your thing, *Apache Isis* also has
+    (will have) a BerkeleyDB Object Store
+
+Security
+--------
+
+By default, *Wicket Objects* is configured to use *Apache Isis*' default
+authentication and authorization. This are both file-based, with a
+simple passwords file to define users, and a similar file to define
+authorization. *Apache Isis* does though provide an implementation for
+both that use LDAP. This is discussed in the other *Apache Isis*
+documentation and in Dan Haywood's book. Alternatively, you could always
+write your own implementations to hook into your own security
+infrastructure.
+
+See also ?.
+
+Wicket DEPLOYMENT mode
+----------------------
+
+Finally, you'll also want to switch into Wicket deployment mode (ie for
+production). This is done in the normal way, by modifying *web.xml*:
+
+    <?xml version="1.0" encoding="ISO-8859-1"?>
+    <web-app ... >
+
+      ...
+
+      <filter>
+        <filter-name>wicket.app</filter-name>
+        <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
+        <init-param>
+          <param-name>applicationClassName</param-name>
+          <param-value>org.apache.isis.viewer.wicket.viewer.app.IsisWicketApplication</param-value>
+        </init-param>
+        <init-param>
+          <param-name>configuration</param-name>
+          <param-value>deployment</param-value>
+        </init-param>
+      </filter>
+
+    </web-app>
+
+Doing this also disables *Apache Isis* "exploration" actions (any action
+annotated with @Exploration will no longer be visible).
+
+Example Application
+===================
+
+> This appendix contains (almost) all the code that makes up the example
+> application shown in the screenshots in ?. The purpose in including
+> these listings is just to give you an idea of what it takes to write a
+> *Wicket Objects* application; this isn't a full tutorial on what it
+> all means.
+
+If you're interested in trying out the application, you'll find it at
+<https://wicketobjects.svn.sourceforge.net/svnroot/wicketobjects/trunk/testapp/claims>.
+
+Domain Application (Problem Space / Persisted Objects)
+------------------------------------------------------
+
+Most of the application shown in the screenshots (see ?) requires only
+the domain model. This is made up of three main entities, Employee,
+Claim and ClaimItem. The dependency between employee and claims package
+is acyclic; every Claim has a Claimant and an Approver, and Employee
+implements both the Approver and Claimant interfaces.
+
+### claims package
+
+#### Claim
+
+The Claim class is by far the largest domain class. Below is a listing
+of all the methods; the body of the getters and setters and some of the
+validation methods have been omitted.
+
+    package org.apache.isis.examples.claims.dom.claim;
+
+    import java.util.ArrayList;
+    import java.util.List;
+
+    import org.apache.isis.applib.AbstractDomainObject;
+    import org.apache.isis.applib.annotation.Disabled;
+    import org.apache.isis.applib.annotation.Ignore;
+    import org.apache.isis.applib.annotation.MaxLength;
+    import org.apache.isis.applib.annotation.MemberOrder;
+    import org.apache.isis.applib.annotation.Named;
+    import org.apache.isis.applib.annotation.Optional;
+    import org.apache.isis.applib.value.Date;
+    import org.apache.isis.applib.value.Money;
+    import org.apache.isis.viewer.wicket.applib.CalendarEvent;
+    import org.apache.isis.viewer.wicket.applib.Calendarable;
+
+    public class Claim extends AbstractDomainObject implements Calendarable {
+
+        // {{ Title
+        public String title() {
+            return getStatus() + " - " + getDate();
+        }
+        // }}
+
+        // {{ Lifecycle
+        public void created() {
+            status = "New";
+            date = new Date();
+        }
+        // }}
+
+        // {{ Rush
+        private boolean rush;
+        @MemberOrder(sequence = "1.2")
+        public boolean getRush() { ... }
+        public void setRush(final boolean flag) { ... }
+        // }}
+
+        // {{ Description
+        private String description;
+        @MemberOrder(sequence = "1")
+        public String getDescription() { ... }
+        public void setDescription(String description) { ... }
+        public String validateDescription(final String description) { ... }
+        // }}
+
+        // {{ Date
+        private Date date;
+        @MemberOrder(sequence = "2")
+        public Date getDate() { ... }
+        public void setDate(Date date) { ... }
+        public String disableDate() { ... }
+        // }}
+
+        // {{ Status
+        private String status;
+        @Disabled
+        @MemberOrder(sequence = "3")
+        @MaxLength(5)
+        public String getStatus() { ... }
+        public void setStatus(String status) { ... }
+        // }}
+
+        // {{ Claimant
+        private Claimant claimant;
+        @Disabled
+        @MemberOrder(sequence = "4")
+        public Claimant getClaimant() { ... }
+        public void setClaimant(Claimant claimant) { ... }
+        // }}
+
+        // {{ Approver
+        private Approver approver;
+        @MemberOrder(sequence = "5")
+        @Optional
+        public Approver getApprover() { ... }
+        public void setApprover(Approver approver) { ... }
+        public String disableApprover() { ... }
+        public String validateApprover(final Approver approver) {
+            if (approver == null)
+                return null;
+            return approver == getClaimant() ? "Can't approve own claims" : null;
+        }
+        // }}
+
+        // {{ Items
+        private List<ClaimItem> items = new ArrayList<ClaimItem>();
+        @MemberOrder(sequence = "6")
+        public List<ClaimItem> getItems() { ... }
+        public void addToItems(ClaimItem item) { ... }
+        // }}
+
+        // {{ action: Submit
+        public void submit(Approver approver) { ... }
+        public String disableSubmit() {
+            return getStatus().equals("New") ? null
+                    : "Claim has already been submitted";
+        }
+        public Object default0Submit() {
+            return getClaimant().getApprover();
+        }
+        // }}
+
+        // {{ action: addItem
+        public void addItem(@Named("Days since") int days,
+                @Named("Amount") double amount,
+                @Named("Description") String description) {
+            ClaimItem claimItem = newTransientInstance(ClaimItem.class);
+            Date date = new Date();
+            date = date.add(0, 0, days);
+            claimItem.setDateIncurred(date);
+            claimItem.setDescription(description);
+            claimItem.setAmount(new Money(amount, "USD"));
+            persist(claimItem);
+            addToItems(claimItem);
+        }
+        public String disableAddItem() { ... }
+            return "Submitted".equals(getStatus()) ? "Already submitted" : null;
+        }
+        // }}
+
+        // object-level validation
+        public String validate() { ... }
+    }
+
+Some points worth noting:
+
+-   Although Claim is inheriting from *Apache Isis*'
+    AbstractDomainObject class, this isn't mandatory.
+
+-   Claim has reference properties of type Claimant and Approver. As
+    we'll see below these are interfaces. References to both interface
+    and classes is supported in *Apache Isis*.
+
+-   The Claim uses a Money class, a value type provided by *Apache
+    Isis*. It's also possible to write ones own value types (or indeed
+    use third-party value types such as JodaTime).
+
+#### ClaimItem
+
+A Claim has a collection of ClaimItems. A ClaimItem is somewhat simpler
+than Claim, and doesn't have any particular behavior itself:
+
+    package org.apache.isis.examples.claims.dom.claim;
+
+    import org.apache.isis.applib.AbstractDomainObject;
+    import org.apache.isis.applib.annotation.MemberOrder;
+    import org.apache.isis.applib.value.Date;
+    import org.apache.isis.applib.value.Money;
+
+    public class ClaimItem extends AbstractDomainObject {
+
+        // {{ Title
+        public String title() {
+            return getDescription();
+        }
+        // }}
+
+        // {{ DateIncurred
+        private Date dateIncurred;
+        @MemberOrder(sequence = "1")
+        public Date getDateIncurred() { ... }
+        public void setDateIncurred(Date dateIncurred) { ... }
+        // }}
+
+        // {{ Description
+        private String description;
+        @MemberOrder(sequence = "2")
+        public String getDescription() { ... }
+        public void setDescription(String description) { ... }
+        // }}
+
+        // {{ Amount
+        private Money amount;
+        @MemberOrder(sequence = "3")
+        public Money getAmount() { ... }
+        public void setAmount(Money price) { ... }
+        // }}
+    }
+
+#### Approver and Claimant
+
+The Approver and Claimant interfaces decouple Claim from any classes
+outside the claims package. The Approver interface is, in fact, empty:
+
+    package org.apache.isis.examples.claims.dom.claim;
+
+    public interface Approver {
+
+    }
+
+There's not a lot more to Claimant:
+
+    package org.apache.isis.examples.claims.dom.claim;
+
+    public interface Claimant {
+
+        Approver getApprover();
+
+        String title();
+    }
+
+#### ClaimRepository
+
+The ClaimRepository interface is one of the two domain services (as
+appearing in the menu bar), and is defined as:
+
+    package org.apache.isis.examples.claims.dom.claim;
+
+    import java.util.List;
+
+    import org.apache.isis.applib.annotation.Named;
+    import org.apache.isis.applib.value.Date;
+
+    @Named("Claims")
+    public interface ClaimRepository {
+
+        public List<Claim> allClaims();
+
+        public List<Claim> findClaims(@Named("Description") String description);
+
+        public List<Claim> claimsFor(Claimant claimant);
+
+        public List<Claim> claimsSince(Claimant claimant, Date since);
+
+        public ClaimWizard newClaim(Claimant claimant);
+
+        public List<ClaimantExpenseSummary> analyseClaimantExpenses();
+    }
+
+### employee package
+
+The employee package depends on the claim package in that the Employee
+class implements the Claimant and Approver interfaces. Among other
+things, this allows the actions of the ClaimRepository to be
+"contributed" to the Employee class (appear in a "claims" submenu for
+each Employee).
+
+#### Employee
+
+The Employee class is the other main class in this app:
+
+    package org.apache.isis.examples.claims.dom.employee;
+
+    import org.apache.isis.applib.AbstractDomainObject;
+    import org.apache.isis.applib.annotation.Disabled;
+    import org.apache.isis.applib.annotation.MemberOrder;
+    import org.apache.isis.examples.claims.dom.claim.Approver;
+    import org.apache.isis.examples.claims.dom.claim.Claimant;
+    import org.apache.isis.viewer.wicket.applib.Locatable;
+    import org.apache.isis.viewer.wicket.applib.Location;
+
+    public class Employee extends AbstractDomainObject implements Claimant,
+            Approver, Locatable {
+
+        // {{ Title
+        public String title() {
+            return getName();
+        }
+
+        // }}
+
+        // {{ Icon
+        public String iconName() {
+            return getName().replaceAll(" ", "");
+        }
+        // }}
+
+        // {{ Name
+        private String name;
+        @MemberOrder(sequence = "1")
+        public String getName() { ... }
+        public void setName(String lastName) { ... }
+        // }}
+
+        // {{ Approver
+        private Approver approver;
+        @MemberOrder(sequence = "2")
+        public Approver getApprover() { ... }
+        public void setApprover(Approver approver) { ... }
+        // }}
+
+        // {{ Location
+        private Location location;
+        @Disabled
+        @MemberOrder(sequence = "1")
+        public Location getLocation() { ... }
+        public void setLocation(final Location location) { ... }
+        // }}
+    }
+
+A couple points worth noting:
+
+-   The Employee class has an iconName() method. This is used to render
+    Employees with a customized image for each instance.
+
+-   Employee also implements Locatable. This is used to render the
+    Employee in the gmap2 (google maps mashup) view (see ?).
+
+#### EmployeeRepository
+
+The EmployeeRepository interface defines the other domain service (on
+the services menu):
+
+    package org.apache.isis.examples.claims.dom.employee;
+
+    import java.util.List;
+
+    import org.apache.isis.applib.annotation.Named;
+
+    @Named("Employees")
+    public interface EmployeeRepository {
+
+        public List<Employee> allEmployees();
+        public List<Employee> findEmployees(@Named("Name") String name);
+    }
+
+Specialized Use Cases
+---------------------
+
+Domain objects to support specialized use cases (solution space objects)
+are not persisted; instead their state is serialized into the *Wicket*
+page components.
+
+### ClaimWizard
+
+The ClaimWizard uses an internal `page` field (of type Page enum) to
+determine which page the user is on; from this we determine which
+properties should be visible, and whether the `previous()`, `next()` and
+`finish()` actions are available.
+
+    package org.apache.isis.examples.claims.dom.claim;
+
+    import java.util.Calendar;
+    import java.util.List;
+
+    import org.apache.isis.applib.AbstractDomainObject;
+    import org.apache.isis.applib.annotation.Disabled;
+    import org.apache.isis.applib.annotation.Hidden;
+    import org.apache.isis.applib.annotation.Ignore;
+    import org.apache.isis.applib.annotation.MemberOrder;
+    import org.apache.isis.applib.annotation.NotPersistable;
+    import org.apache.isis.applib.annotation.TypicalLength;
+    import org.apache.isis.applib.clock.Clock;
+    import org.apache.isis.examples.claims.dom.employee.EmployeeRepository;
+    import org.apache.isis.viewer.wicket.applib.WizardPageDescription;
+
+    @NotPersistable
+    public class ClaimWizard extends AbstractDomainObject {
+
+        public enum Page {
+            INTRO("This wizard will take you through the process of creating a claim"),
+            CLAIMANT("Enter the claimant that is making this claim"),
+            APPROVER("By default, the claimant's own approver will approve this claim.  " +
+                     "Update here if another approver will approve this claim."),
+            DESCRIPTION("Update the description if required."),
+            SUMMARY("Confirm all details, or go back and amend if needed");
+
+            private String description;
+            private Page(String description) {
+                this.description = description;
+            }
+
+            public String getDescription() {
+                return description;
+            }
+
+            public boolean hasPrevious() {
+                return ordinal() > 0;
+            }
+            public Page previous() {
+                if (hasPrevious()) {
+                    return values()[ordinal() - 1];
+                } else {
+                    return this;
+                }
+            }
+
+            public boolean hasNext() {
+                return ordinal() < values().length - 1;
+            }
+            public Page next() {
+                if (hasNext()) {
+                    return values()[ordinal() + 1];
+                } else {
+                    return this;
+                }
+            }
+
+            @Ignore
+            public boolean is(Page... pages) {
+                for (Page page : pages) {
+                    if (page == this) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+        }
+
+        

<TRUNCATED>