Naked Objects
By Richard Pawson and Robert Matthews

Enriching object behaviours

Specifying About objects to control access

We have seen several examples of controlling access to classes, objects, fields and methods using an about... method that corresponds to a class, object, accessor or action method. These methods all return an org.nakedobjects.object.control.About object. The About object provides four pieces of information about the class, object, field or method it is supporting, for potential use by the viewing mechanism or any other service. These are:

  • Whether it should be accessible to the current user.
  • Whether it can be used while the object is in its current state.
  • The name it should be known by (if it needs to differ from the name that is automatically generated by the framework from the class or method name).
  • A description of the class, object or method it is controlling.

All About objects are derived from the About interface. This interface declares four methods that represent the information mentioned above:

  • canAccess
  • canUse
  • getName
  • getDescription

The last two return String objects, whilst the first two each return a org.nakedobjects.object.control.Permission object. A Permission object is used instead of a simple boolean because in addition to specifying whether the access/use has been allowed or disallowed, it can also provide a reason, in the form of a textual message. This is further simplified by the fact that the Permission class is sub-classed as org.nakedobjects.object.control.Allow and org.nakedobjects.object.control.Veto, which simply hold a reason String and indicate the state by their type.

Using the About interface you can define your own About class and exercise complete control over your objects. However, the ready-made About classes provided by the framework will be sufficient for most purposes.

Ready-made About objects

The simplest way to apply control is to use ready-made About objects. All of the basic About classes (such as org.nakedobjects.object.control.ClassAbout, org.nakedobjects.object.control.FieldAbout and org.nakedobjects.object.control.ActionAbout) have publicly-available constants (such as UNINSTANTIABLE, READ_ONLY and ENABLE, which determine the usability of classes, fields and methods respectively).

To provide some flexibility these classes also have static methods that will provide an About object based on a flag that you supply. For example ActionAbout has the method enable that takes a boolean and will return the ENABLE object if the flag is true and the DISABLE object if false. There is also a complementary method called disable. This allows us to disable an action... method on a specified condition, as shown below:

public About aboutActionSell() {
    return ActionAbout.disable(getCustomer() == null);
}
Building About objects

When you need an About to do more than just disable something (for example, you want to change a field or method name), then the ready-made About objects we have discussed so far are not suitable as they have no provision for conveying any additional information. Things are even more complicated when there are a number of influences that each partly determine whether something should be allowed or not. For example, consider the Location class. It has a method actionNewBooking(Location) that allows two locations to be used to create a new Booking using the two locations as pick-up and drop-off points. This method should only be allowed if the two location objects are different, and that they are also in the same city. If we implement the about... method using the static About objects (as shown below) then the users will know when they can't drop an object, but will not know why:

public About aboutActionNewBooking(Location location) {
    boolean differentLocations = !equals(location);
    boolean sameCity = (getCity() != null) && getCity().equals(location.getCity());

    return ActionAbout.enable(differentLocations && sameCity);
}

We need to be able to include the reason why something is disallowed. This is catered for in the Permission objects that we mentioned earlier. These are used within the org.nakedobjects.object.control.ProgrammableAbout class, which allows us to build up an About object by explicitly setting its state or conditionally modifying it as conditions are checked. For example, here is an alternative version of the previous method using this class:

public About aboutActionNewBooking(Location location) {
    boolean differentLocations = !equals(location);
    boolean sameCity = (getCity() != null) && getCity().equals(location.getCity());

    ProgrammableAbout about = new ProgrammableAbout();
    about.makeAvailableOnCondition(differentLocations, 
	"Two different locations are required");
    about.makeAvailableOnCondition(sameCity, 
	"Locations must be in the same city");
    return about;
}

Using the same two flags we've added these conditions to the ProgrammableAbout object using the makeAvailableOnCondition method. This does nothing if the flag is true, but if it is false then this method ensures that a subsequent call to canUse will return a Veto object that includes the specified text as the reason, or part of the reason, that this option is not available. This information will be displayed to the user when the drop is invalid and describes whether the locations are the same or are in different cities.

The following version further extends the method so that the About now contains a description of the method. This is in line with our philosophy that the documentation should be part of the code and not written and maintained separately. It could be used (although it is not at the moment) within the framework to describe the option to the user at the point where he might want to use it. Alternatively, it could be used by a program that automatically generates the complete documentation for an application. This version also shows the changeNameIfAvailable method that sets up the name of the About so that it reflects the action to be performed. Using this version of the method, the name will only be changed if the action is allowed:

public About aboutActionNewBooking(Location location) {
    boolean differentLocations = !equals(location);
    boolean sameCity = (getCity() != null) && getCity().equals(location.getCity());

    ProgrammableAbout about = new ProgrammableAbout();
    about.setDescription("Giving one location to another location creates " +
	"a new booking going from the given location " + 
	"to the receiving location.");
    about.makeAvailableOnCondition(differentLocations, 
	"Two different locations are required");
    about.makeAvailableOnCondition(sameCity, 
	"Locations must be in the same city");
    about.changeNameIfAvailable("New booking from " + location.title() +
	" to " + title());
    return about;
}
Areas of control

The following summarizes what aspects of a naked object can be controlled and how it should be done.

  • A class

    Add a static aboutClass method to class.

    Use ClassAbout to make a class uninstantiable.

  • An object

    Add an about method to class.

    Use ObjectAbout or the ProgrammableAbout to make an instance read-only.

  • A field

    For value objects assign an About using the value object's setAbout method.

    For associations, add aboutVariable method to the class matching the getVariable method you wish to control.

    Use FieldAbout to make an field read-only or the ProgrammableAbout to make an field read-only or change the name of the field.

  • An action method

    Add an aboutActionMethod method to the class matching the actionMethod method.

    Use ActionAbout to disable the method or the ProgrammableAbout to disable the method or change the name of the option.