The only code in a Scimpi is the domain model; there is generally no web application code other than the markup in the pages. Building a domain model is detailed in the manual for the Naked Objects Framework.
In essence a domain model should define classes for each type of object in the system. The classes are written in as standard Java classes that use the getter and setter methods to make the properties of an object available and have a way to inform a container that they have changed their state or still need to load it. The easiest way of creating such classes is to extend AbstractDomainObject object as this provides a simple way notify the container of the requests for dealing with the objects persistence. The following class show a simple but typical domain object that can be used in a Naked Object system. This object represent an employee that has a name and knows it approver.
package org.nakedobject.app.cart;
import org.nakedobjects.applib.AbstractDomainObject;
import org.nakedobjects.applib.annotation.MemberOrder;
public class Employee extends AbstractDomainObject {
private String name;
private Employee approver;
@MemberOrder(sequence="1")
public String getName() {
resolve(name);
return name;
}
public void setName(String lastName) {
this.name = lastName;
objectChanged();
}
@MemberOrder(sequence="2")
public Employee getApprover() {
resolve(approver);
return approver;
}
public void setApprover(Employee approver) {
this.approver = approver;
objectChanged();
}
public String title() {
return getName();
}
}
Each Scimpi application builds upon the following directory structure, which is based on the standard layout required by Servlet and JSP based Java web applications.
webapp/
index.shtml
login.shtml
generic/
action.shtml
collection.shtml
edit.shtml
object.shtml
images/
banner.jpg
bg-button.gif
Claim.gif
ClaimItem.gif
Default.png
Employee.gif
logo.png
style/
screen.css
template.shtml
WEB-INF/
lib/
logging.properties
nakedobjects.properties
passwords
web.xml
The file index.shtml is the welcome file for the web application; the welcome file is the file that is served when no files is specified. For example http://localhost:8080/expenses will return the file index.shtml file from expenses webapp directory.
The file login.shtml is a log on page that is used to authenticate the user via Naked Objects.
The images directory is used for both the icons for objects and for images used by the style sheet and templates.
The WEB-INF directory contains all the configuration files.
The generic directory holds default pages for viewing, editing and running actions on objects.
Scimpi processes requests for resources that have the extensions shtml and app specially. All other resources, such images, text files and HTML documents, are assumed to be files and return directly as such. Specially handled request are handled by Scimpi's dispatcher where the resources with the app extension are mapped to Scimpi actions and those with the shtml extension cause the corresponding file to be read in and processed as Scimpi templates containing Scimpi tags that are to be replaced by the processor.
However, when a request is made for a generic page (as _generic.shtml, _generic_edit.shtml and _generic_action.shtml) Scimpi seeks the most suitable file to process the request. The request is based on the object reference held by the RESULT variable. Using this object it first looks for a directory named after the objects class, and if it exists will look for a suitable file. If no such directory exists then a file in the generic directory is used. The file, from either the generic or class named directory, depends on the generic page name. For _generic.shtml a file called objects.shtml or collection.shtml is used depending on whether the referenced object is an object or a collection. For _generic_edit.shtml a file called edit.shtml is used. When the request is _generic_action.shtml Scimpi looks for an shtml file with the same name as requested in the method parameter.
All web applications are built on HTTP, which is stateless, so Scimpi provides a way maintaining state between requests on your behalf. By asking Scimpi to store values for you, either implicitly or explicitly, your web application can easily refer to objects and other data that were used previously. Without such a capability each request would effectively be the first request and all needed information would have to be encoded within the web page. Every variable in Scimpi is known by its given name and is kept for a set duration, known as its scope. In addition to the variables that are defined by the web application there are others that are automatically provided by the system.
The variable tag allows a variable to be explicitly set up. This tag simply stores the content of the block with the associated name. So the following markup creates a variable called duration and stores the value "1250" within it (note that it is a string, not a number, as it is taken from the HTML page).
<swf:variable name="duration">1250</swf:variable>
Once a variable has been declared it can be used within the HTML, as markup itself or as attribute, by wrapping the name with ${ and }. So now, for example, we can output the value variable in a bold form using the following
<b>${value}</b>
that will result in the following HTML being received by the browser.
<b>1250</b>
Most commonly it is the tags that implicitly set up variables with the results of their actions or with references to objects. The following example shows an action that places its result, a collection of claims, into the claims variable, after which the table tag refers to the collection via the same variable (which is written as ${claims} to show that it is a variable).
<swf:run-action object="service:claims" method="allClaims" result-name="claims"/>
<swf:table collection="${claims}"/>
Note that if you didn't specify a variable for the result to be put in then the default variable RESULT would be used instead. The same applies to the table tag, which would use the variable RESULT to find the claim. This is the same for all other tags the have an attribute for a variable name, or that need to refer to an object or collection.
ScopeIn the previous examples the two variables that we declared would only be available while the current page is being prepared and would not exist when the subsequent page is requested. These variable therefore have narrowest scope. From the widest to narrowest the four available scopes are:-
To specific a scope when specifying a variable simply add a scope attribute with one of the four scope names.
Scimpi provide a mechanism to refer to objects that are held by Naked Objects from within a web page, or as part of a URL. An implementation of ObjectMapping generates a textual string from the object's OID. This can then be used as the object attribute for many of the tags. Most commonly these references are stored in, and used from variables, this is why for tags that produce results you need to specify a variable for the reference to be placed into.
If an object attribute starts with service: Scimpi will find the service object with the identifier as specified after that prefix. The example shows how to run a method on the service identified as Claims, which is the claims repository
<swf:run-action object="service:Claims" method="myRecentClaims" />
Using the RESULT variable. When the object/collection attribute is not specified within a tag that must refer to an object Scimpi uses the reference held by the RESULT variable instead. This special variable is set up when a tag, which produces a results (such as the action tags, collection or link), also has no variable attribute (e.g. result-name or element-name) specified. This allows us to use have code like
<swf:run-action object="service:Claims" method="myRecentClaims" /> <swf:table/>
instead of the more verbose
<swf:run-action object="service:Claims" method="myRecentClaims" result-name="claims" /> <swf:table collection="claims"/>
This special variable is only available during the request and will be replaced by the next tag that produces a result. For example the following will fail on the last line as RESULT will contain the reference to the last element in the collection as set by the collection tag and not the collection as originally set by the run-action tag.
<swf:run-action object="service:claims" method="allClaims" /> <swf:collection> <li><swf:title icon="off"/></li> </swf:collection> <swf:table/> <!--this line will fail-->
To fix this the run-action should specify a result-name attribute and both the collection and table tags should specify a collection attribute that uses the variable as specified in result-name attribute.
<swf:run-action object="service:claims" method="allClaims" result-name="claims"/>
<swf:collection collection="${claims}">
<li><swf:title icon="off"/></li>
</swf:collection>
<swf:table collection="${claims}"/>
As Scimpi has a mechanism for finding the most appropriate page for rendering a view of an object (the generic pages, such as _generic.html) there are some details about page references that you should be aware of. Essentially, because the page that was requested might not be the page that was served, the relative location of referenced files might not be as first expected.
To make this concrete we will use a simple example. Consider a claims page generated in response to a request likehttp://localhost:8080/expenses/Claim/object.shtml?claim=... that contains a list of expenses whose hyper-links are defined as _generic.html so that the most suitable page will be used. When such a link is clicked on the URL used by the browser would, therefore, be something like http://localhost:8080/expenses/Claim/_generic.shtml?_result=.... Now as the page that is returned would be generated from the most suitable template it would use the file object.shtml from the ExpenseItem directory rather than the Claim directory. However, the generated page when displayed by the browser will still have a base URL of http://localhost:8080/expenses/Claim/. An image tag on that page, such as <img src="person.png"/>, will, therefore, result in a request from the browser of http://localhost:8080/expenses/Claim/person.png. This obviously will not find the file as it is ExpenseItem directory; so a URL intended to be relative to the current page ends up being relative to the page in the previous request.
To get round such a problem the URL specified should use the system variables _context and _directory to set up the full path. So returning to our above example img tag should be changed to
<img src="${_context}${_directory}person.png"/>
so that web application context name and the directory that the template file is actually in are appended with the image name creating a path that absolutely identifies the resource as the resultant HTML shows.
<img src="/expenses/Claim/person.png"/>
There are four such system variables that relate to URLs:
Such issues can also arise when creating links that are intended to show a particular object or run an action. As you not only have to get the location correct but also pass over the reference to the object to be shown and, for actions, pass over the method name, all by creating a long URL it is simpler to use one of the Scimpi link tags that takes care of all this for you. So instead of an a tag like
<a href="_generic_edit.shtml?_result=${item}">edit</a>
use the Scimpi edit-link tag as follows.
<swf:edit-link object="${item}">edit</swf:edit-link></a>
Other link tags are object-link, action-link and new-action-link.
There are a number of configuration files for each web application and these are placed in the WEB-INF directory. This section describes the common settings that are used. Most configuration aspects affect the Naked Objects framework and are detailed in its manual.
Services. The service objects that Naked Objects instantiates and makes available to your web application are listed in the nakedobjects.properties file with the services properties. The example segment below will make the classes org.example.services.ClaimantRepository and org.example.services.ClaimRepository available.
nakedobjects.services.prefix=org.example.services nakedobjects.services=ClaimantRepository, ClaimRepository
Fixtures. Fixtures are run the first time that your web application is started and can be used to prime the object store with an initial set of domain objects such as reference or demo objects. Fixtures are specified in the nakedobjects.properties file with the fixtures properties. The following snippet loads up the org.nakedobject.app.cart.fixtures.ClaimsFixture class on the first startup.
nakedobjects.fixtures=org.nakedobject.app.cart.fixtures.ClaimsFixture
XML object store. The template code provided is designed to run with the XML object store; other persistence layers can be used and are outlined in the Naked Objects manual. As this is a file based store the place it expects to find its files must remain both consistence and in existence. The problem comes down to the servlet container and the root path it gives its web application. Typically the only reliable system independent place is the web applications extraction directory but this is replaced each time a web application is redeployed. As there are no other guaranteed cross-platform directories we can default to it is best to specify where the object store should be placed. The location of the XML object store files are specified in the nakedobjects.properties file with the xmlos.dir property. The following snippet places the files in the tmp/example-data directory, which on Tomcat will be relative the startup directory (a better option is to use a rooted path that absolutely identifies where the files are to be placed).
nakedobjects.xmlos.dir=tmp/example-data
Passwords. The default authentication for the template code is through a password file, Naked Object's most basic authorisation implementation; other authentication methods can be used and are outlined in the Naked Objects manual. The passwords file contains a set of user names and passwords that Scimpi and Naked Objects will allow user to log in with. The example below defines a set of Naked Objects users; that is the users are users of the system and not just Scimpi.
# username:password sven:pass dick:pass bob:pass
If the users are defined by the web application rather than through Naked Objects then it becomes the domain model's responsibility to identify and authenticate the users. To allow for this the password file must contain a system user, and Scimpi must automatically connect as that user. This is done via servlet initialisation parameters that are set in the web.xml configuration file, which the servlet container processes. In the servlet block two init-parameter blocks are added to specify the user name and password. The following snippet shows the servlet block once the two parameters have been added.
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.nakedobjects.webapp.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>username</param-name>
<param-value>webapp</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>pass</param-value>
</init-param>
</servlet>
The user name and password specified for auto-login should then be added to the password file so that the system user can be authenticated. This can be done by adding the following line to the password file.
webapp:pass
Each tag is used in the form
<swf:tag-name attribute-name="attribute value" />
for an empty tag, while a tag containing other tags will be of the form
<swf:tag-name attribute-name="attribute value">
enclosed text or tags
</swf:tag-name>
Scimpi markup, being XML embedded in XHTML pages, is case sensitive. All tag and attribute names must be lower case.
Scimpi pages can import chunks of markup from other files as well use a template to form the basis of a page. The import tag simply reads in a specified file for inclusion at the point of the tag. If the file has an shtml extension that file is also processed. This is useful for including common elements in file such as a header or footer.
The template tag similarly reads in a specified file, but while it is reading it in it looks for a content tag and suspends reading when it finds one. The remainder of current file is then read in and processed before the reading of the template file is completed. So given the two files, my-template.html and my-page.shtml, as listed here
<hmtl> <head> <title>Scimpi Page</title> </head> <body> <swf:content /> </body> </html>
<swf:template file="my-template.shtml" /> <h1>My new page</h1>
the resultant markup will be as follows,
<hmtl> <head> <title>Scimpi Page</title> </head> <body> <h1>My new page</h1> </body> </html>
where the content tag has been replaced with content of the original file (but without the template tag).
Another tool for minimising page size is move common markup into separate files and import those block into the multiple files when needed using the import tag. When using this technique it is useful to indicate in the segments file name that it is in an import; we place an underscore at beginning of such files.
Scimpi has a number of tags that allow objects, and parts of objects, to displayed. The whole object can be displayed using the short-form and long-form tags; the difference between these two is the short version does not display properties that are collections while long version shows these as tables.
Linking properties. Each reference property can be marked so it provides a link to a page that shows more details about that object. For each property that requires a link add a link tag to the short-form/long-form block specifying the name of the property in the name attribute. By default the page that you will be linked to is the most appropriate one for that type of object; alternatively you can specify a view attribute so the links is to a specific page. The following example ensures that the approver field is hyper-linked and the user will be taken the generic object view page.
<swf:long-form>
<swf:link name="approver"/>
</swf:long-form>
Specifying object properties to include. By default all properties are shown for these tags, but an explicit list of properties can be specified using the include and exclude tags. When a include tag is added all other properties that do not also have an include tag will be excluded. The following example shows how the claimant property can be removed by using a exclude tag.
<swf:long-form>
<swf:exclude name="claimant"/>
</swf:long-form>
Fields and labels. In addition to displaying the complete or partial object using the form tags a property's label and content can also be accessed directly allowing an object's view to be constructed manually. The label tag gets the field's proper name while the field tag get the field's contents. Both take the name of the field in the field attribute. The following example creates a simple colon separated view of the current object, showing the claimant, description and status labels and field contents.
<div class="form">
<div><swf:label field="claimant"/>: <swf:field field="claimant"/></div>
<div><swf:label field="description"/>: <swf:field field="description"/></div>
<div><swf:label field="status"/>: <swf:field field="status"/></div>
</div>
List and table views of collections can be most simply created using the list and table tags. These tags can be used to create a view from either an explicit collection or a collection property within an object. If the field attribute is specified then a collection is deemed to be an object's property otherwise it is an explicit collection. When no collection or object attribute is specified the RESULT variable is used.
The list tag creates a numbered list of the form
<ol><li>Submitted - Meeting with client</li> <li>Submitted - Meeting in city office</li> <li>New - Meeting at clients</li> </ol>
but it can also show as bulleted form (as a ul block) by specifying the type attribute.
The table tag creates a table with a row for each element and a column for each association/value property; collection properties are not shown. By default each column has a header that shows the name of the property, but this can be prevented via the heading attribute.
Linking collection elements. Within list and tables we can provide links to pages that show or manipulate the individual items. By adding a link attribute Scimpi will create a hyper-link (an a tag) to the specified page that includes a reference to the current element. This Scimpi markup
<swf:list type="circle" link="_generic.shtml"/>
therefore generates the following HTML markup instead of the first element in the example above.
<li><a href="_generic.shtml?_result=Porg.nakedobject.app.cart.Claim@fdzsbkg0"> Submitted - Meeting with client</a></li>
The parameter name can be specified using the element-name attribute and, as can seen in the example, this defaults to RESULT.
As tables can show the element, as a row, and other objects, as the columns, it is possible to make the objects link to other pages instead of the row. For each column that should be linked a link tag should be added to the table block and the name attribute set to identify the property to provide the link on. The following example creates a link that lets us view the approver in detail.
<swf:table>
<swf:link name="approver" view="_generic.shtml"/>
</swf:table>
Specifying the columns in a table. The columns displayed in a table can be controlled by adding include and exclude tag to the table block. By using an exclude tag you indicate that a named property is not be shown thereby reducing the number of columns shown as needed. The include tag indicates that you want to show a named property but not any others thereby allowing the exact number of columns specified. The following example excludes the approver and claimant columns so all the rest still show.
<swf:table heading="no" > <swf:exclude name="approver"/> <swf:exclude name="claimant"/> </swf:table>
While the list and table tags provide a quick and simple way of displaying a collection the collection tag provides the mechanism for building up your own view of a collection element by element. The collection tag takes the same attributes for determining the collection as the list and table tags do. The content between the opening and closing tags is processed for each element of the collection. By default the element's reference is put in the RESULT variable, but this can be changed by adding the element-name attribute. The following example shows a collection tag used within a ul tag to create a series of li elements from the current collection object.
<ul><swf:collection>
<li><swf:title icon="off"/></li>
</swf:collection></ul>
<ol>
<li>Submitted - Meeting with client</li>
<li>Submitted - Meeting in city office</li>
<li>New - Meeting at clients</li>
</ol>
The element-type tag can be used to get hold of the type of elements a collection holds. If the system is configured with internationalization then the name will be localized.
An object's title can be displayed using the title tag. The default version displays an icon image as well as the title text, but this can be prevented by setting the icon attribute to no. The following example displays an icon and title text as a level three heading.
<h3><swf:title/></h3>
<h3><img class="title-icon" src="/example/images/Default.png" />Submitted - Meeting with client</h3>
Using the edit tag we can display an HTML form for an object. Any disabled or uneditable properties are simply shown by title while the fields to be edited have the most suitable input field created for them.
Reference fields won't work particularly well in the default tag as there is no other available references to set the field to unless that field has some options or a default defined for it in the model. To make it possible for the user to select a suitable reference to set the field with the selector tag can be used to create a drop-down or options list with suitable choices. This tag can either take a collection or an object and a method that results in a collection and will create an object selection widget. The following example shows how the default approver field can be replaced by a list showing all the claimants as provided by the claimants repository.
<swf:edit>
<swf:selector field="approver" object="service:claimants" method="allClaimants" type="list"/>
</swf:edit>
If we want to the give the user some control over what is selectable, instead of providing a long and too comprehensive list, we can first prompt the user for criteria that can be used when calling a method that has one or more parameters. Scimpi then creates a form that collected the parameters for that method and after the user presses the search button it will create a selection list based on the method call using those parameters. In the following example the selector tag uses the findClaimants method that takes a String parameter. This results in a single field form that invokes the search method and generates a drop-down list (the default type of selector).
<swf:edit>
<swf:selector field="approver" object="service:claimants" method="findClaimants"/>
</swf:edit>
If more control over the entry field is required then you can define your own field within a form-field tag. This tag simply replaces the auto-generated field with contained block of markup leaving you with the responsibility of setting it up correctly. This typically means you need to determine the options and ensure that the HTML field has a name that matches the property in the object. The following simplified example creates a drop-down list for the name property; the field attribute of the Scimpi tag and the name attribute of the HTML tag must have the same field name.
<swf:form-field field="name">
<select name="name">
<option>best</option>
<option>average</option>
<option>worst</option>
</select>
</swf:form-field>
Controlling the visible fields. Like the object views, the properties shown in the edit form can be controlled using the include and exclude tags. The exclude tag simply removes the named field from the complete set of fields, while a set of include tags defines the complete list of fields to be shown. It is important to remember that the object cannot be saved if all the required properties are not set, or if entries are invalid. This can happen when you exclude such fields unless they have a default value. The following example removes the status and claimant fields from the property set.
<swf:edit>
<swf:exclude name="status"/>
<swf:exclude name="claimant"/>
</swf:edit>
Two special tags provide access to all actions for an object and for all the actions on all the service objects. These tags - methods and services - are typically used for generic pages but can be used on specific pages as a way of minimising the amount of tags required to make a number of your actions available. The methods tag will, except on service objects, also provide an edit option that will open up an edit view. By default all the actions are displayed, either as buttons or links to action pages, but the list can be controlled using the include and exclude tags. The following example will provide access to all the methods from the claimant service except the allClaimants one; there will be no edit option also as it is for a service.
<swf:methods object="service:claimants" >
<swf:exclude name="allClaimants"/>
</swf:methods>
Common attributes. All the other action tags target a specific object to run a specific action on. These are specified by the object and method attributes respectively. Also the name of the variable that will hold the results can be specified with the result-name attribute, with its scope being set via the scope attribute. For all the tags that will forward you to another page after executing can specify that page when: the result is returned (the view attribute); when no result is returned (void); and when an error (such as a validation failure) occurs (error).
In-line actions. Actions can be run as they are come across while processing a page using the run-action tag. These are typically used when details are needed for other tags in the page. The following example shows how a table of all the claims can be displayed by running the allClaims method on the claims repository.
<swf:run-action object="service:claims" method="allClaims"/> <swf:table/>
Immediate actions. Some actions can be invoked by the user immediately while others require input from the user before they can be run (these are covered next). Web users expect links to take them to another page while buttons will make a change to the state of the system, so Scimpi provides the action-link and action-button tags to allow the appropriate rendering. Both tags operate in the same way but while one is rendered as a hyper-link the other is a form with no fields, just a button. These tags are typically used with methods that do not have parameters as the following example shows.
<swf:action-link object="service:claimants" method="allClaimants"/>
If a method has parameters and they either have a suitable default value or you have access to suitable value through the page then these tags can also be used for these parameterised methods. If the tag specifies a method with parameters it will expect a parameter tag to specify the parameter's value or will use the default value as specified by the model. If neither of these exists then an error will be generated. The following example creates a form with a button that runs the one parameter submit method where the parameter value is that held by the approver variable.
<swf:action-button object="${claim}" method="submit">
<swf:parameter number="1" value="${approver}"/>
</swf:action-button>
Prompted actions. When an action requires input from the user the action-form tag should be used to create an HTML form with fields for the parameters. Each parameter is displayed as an appropriate entry field and, by default, all the parameters made visible but this can be controlled using the include and exclude tags. Using include you can build up a list of all the parameters you want to be shown (any parameter then not specified through an include is excluded by default), while by using exclude, specific parameters can be removed from the full list. Only parameters that are optional or have a default value should, however, be excluded as otherwise the action will not be able to be run.
By default the most suitable HTML field is used for each particular parameter but it is possible to provide your own fields when needed. The simplest option is to use the selector tag to provide a selection option - as a drop-down, list or set of radio buttons - to the user instead of the default field. The use of the selector tag is discussed in the previous section (see Link). The alternative is to create your own input field using the form-field tag, again this is described above (see Link). The following example shows the selector tag in use to provide a list of possible approvers.
<swf:action-form method="submit" view="_generic.shtml" void="../index.shtml">
<swf:selector field="param0" object="service:claimants" method="allClaimants"/>
</swf:action-form>