Naked Objects
By Richard Pawson and Robert Matthews

Appendix A: Getting started

Writing an Application

To understand the principles of coding Naked Object applications we will now look at a very simple, but complete, application. The requirement is for a system that allows us to quickly organize employees into teams so they can work on specific projects. When a project is set up, distinct skills are identified, and individuals are assigned to the project based on those requirements.

This will require three classes whose objects will represent the projects, the employees and the roles (a role being a combined set of skills). These classes will need to relate to each other: a project identifying its required roles and each role identifying the individual who is to join the team.

The classes we will define for this application, therefore, are: Employee, Role and Project. Each Project object will hold a collection of Role objects and each Role will hold a reference to an Employee object.

We start by defining the classes for the three types of object. For each class we need to create a .java file and within it declare the class as an extension to the AbstractNakedObject class.

Start the three classes as follows:-


Project.java
      
import org.nakedobjects.object.AbstractNakedObject;

public class Project extends AbstractNakedObject {
}

Role.java

import org.nakedobjects.object.AbstractNakedObject;

public class Role extends AbstractNakedObject {
}

Employee.java

import org.nakedobjects.object.AbstractNakedObject;

public class Employee extends AbstractNakedObject {
}
   

Now we consider what fields each object should have. First we add fields that allow the user to identify the different objects (e.g. so we can see that one object represents Dave and the other represents John). Next we add fields that describe any relationships between the objects (e.g. every role is performed by an employee so a Role object will need a field to reference an Employee object).

Employee Objects

Taking the simplest object first, an Employee need only have a name as this should be enough to distinguish it. To store this name we add a private final variable, of the type TextString, called name to the Employee class. A TextString value object stores simple textual information. The variable is marked as final as it is a composite part of the Employee and should never be replaced. As it is final we initialize it as soon as it is declared (alternatively, this could be done within the constructor). To make this field available to other objects, and to the framework so it can be displayed, we add an accessor method that will return the reference to the value object.


Employee.java

import org.nakedobjects.object.AbstractNakedObject;
import org.nakedobjects.object.value.TextString;

public class Employee extends AbstractNakedObject {
  private final TextString name = new TextString();

  public TextString getName() {
    return name;
  }
}
Role Objects

Next, we do a similar thing for the Role class as this also requires a name. In addition to this basic data we also need to hold a reference to the Employee object that this role is being performed by. To do this we declare a private field of the type that we want to keep a reference to; in this example it needs to be an instance of the Employee class. Like the value object, we also need to make this field available so we define a standard pair of accessor methods (getEmployee and setEmployee).

Inside these two methods you will see two necessary calls that keep the object current in the object store (our link to a persistence mechanism) and in any other views of the same object (on both the local and any remote clients). In the set... methods for any reference objects (as opposed to the value objects we saw earlier) the objectChanged method should be invoked. This notifies the object store that this object needs to be stored away again and also notifies any other views showing this object so they can refresh themselves.

Within get... methods, resolve should be called to ensure that the object that is being requested has been completely loaded from the object store. This is required as each object is stored independently using soft references rather than as one large object graph.


Role.java

import org.nakedobjects.object.AbstractNakedObject;
import org.nakedobjects.object.value.TextString;

public class Role extends AbstractNakedObject {
  private final TextString name = new TextString();
  private Employee employee;

  public TextString getName() {
    return name;
  }

  public Employee getEmployee() {
    resolve(employee);
    return employee;
  }

  public void setEmployee(Employee employee) {
    this.employee = employee;
    objectChanged();
  }
}
Project Objects

Project is more complex in what it contains, but is actually simpler to code. As a project involves many roles the Project object will need to store a number of Role references in some kind of collection. To create a collection field that is a composite part of the object, we make use of the InternalCollection class provided by the framework and declare it as private and final. To initialize the collection we create a new object, specifying the type of objects it is allowed to hold (Role objects) and a reference to the object that it belongs to (this project). As with the composite TextString, this field only requires a get method (in fact, as it is marked final a set method would not compile).

As for the two previous classes the Project should also have a name field and this is added as before.


Project.java

import java.util.Enumeration;
import org.nakedobjects.object.AbstractNakedObject;
import org.nakedobjects.object.collection.InternalCollection;
import org.nakedobjects.object.control.About;
import org.nakedobjects.object.control.ActionAbout;
import org.nakedobjects.object.value.Case;
import org.nakedobjects.object.value.TextString;

public class Project extends AbstractNakedObject {
  private final TextString name = new TextString();
  private final InternalCollection roles = new InternalCollection(Role.class, this);

  public TextString getName() {
    return name;
  }

  public InternalCollection getRoles() {
    return roles;
  }
}

In addition to the two fields that this object offers we will add the following method, which will be made available to the user from the object's pop-up menu. This method is simple: it creates a new Role object; sets the name field using a text value; and then adds the new role to the project's roles field. It ends by returning the new role object, which, when invoked thought the graphical interface, will result in the new object being displayed. (Admittedly, this method is somewhat superfluous, but it does demonstrate how easy it is to offer object behaviour to the user.)

  public Role actionAddProjectLeader() {
      Role projectLeader = (Role)createInstance(Role.class);
      projectLeader.getName().setValue("Project Leader");
      roles.add(projectLeader);
      return projectLeader;
  }

The above method, however, is only suitable when no project leader has been assigned already (as will be the case before the method is first invoked). Methods like this can be controlled by a corresponding about... method. An about... method must return an About object, which can be queried later to determine whether the menu item for the action method should be disabled or not.

The method below is matched to the actionAddProjectLeader method by its similar name. When invoked, the collection held in the roles field is iterated through. If one of its Role objects has the name 'project leader' then an About object - hardwired to disable the option - is returned. If none of the roles match, then an About object - hardwired to enable the option - is returned instead. Both of these objects are retrieved from the ActionAbout class.

  public About aboutActionAddProjectLeader(){
      Enumeration e = getRoles().elements();
      while(e.hasMoreElements()){
	  Role role = (Role)e.nextElement();
	  if(role.getName().contains("project leader", Case.INSENSITIVE)){
	      return ActionAbout.DISABLE;
	  }
      }
      return ActionAbout.ENABLE;
  }
Titles

Before we can compile and run the application we have to implement the title method for each class. Then when the objects are displayed they will each have a distinct title allowing the user to distinguish each object from the others. Each of the objects we have just defined has a name field which we will use as the title for each object by adding the following code to each of the three classes. To implement the title method we must return a Title object, and the easiest way to get a suitable Title object is to ask another Naked object for one. We do this here by asking the name field for its Title object.

  public Title title() {
     return name.title();
  }

The Title class is part of the main package and needs to be imported.

import org.nakedobjects.object.Title;