Getting started with Naked Objects Version 4.0

As we have recently released the next version of Naked Objects I thought it would be a good idea to do a series of blogs introducing various aspects of it.  The first is about how to get it and run it.

Naked Objects is available, as before, from SourceForge (http://sourceforge.net/projects/nakedobjects/) but now you have a choice about how you use it: with Maven, Ant or just using the jars with your favourite IDE. Maven provides the most flexibility, so that is what I’m going to look at now.  Although with Maven you can get up and running without downloading anything from SourceForge, I strongly recommend that you start off by downloading nakedobjects-4.n.n-for-maven.zip or nakedobjects-4.n.n-for-maven.tar.gz from the download page.  This will ensure that you have access to the documentation, some useful resources like icons and a set of examples that you can browse and run, and later experiment with. Once downloaded extract the contents and you’ll end up with a directory called nakedobjects-4.n.n.

Running an example

Let’s start off by looking at the examples to see what Naked Objects looks like when it runs.

Before we can run anything we need to build it.  Using Maven we can do this in one step. So go to one of the example’s directory, in this case we use the claims one as it the simplest, and use the package goal to compile and package it all.

$ cd nakedobjects-4.0.0/examples/orders
$ mvn package
[INFO] Scanning for projects...
Downloading: http://repo1.maven.org/maven2/org/nakedobjects/release/4.0.0/release-4.0.0.pom
7K downloaded
[INFO] ------------------------------------------------------------------------
[INFO] Building Example Orders DOM
[INFO]    task-segment: [package]
[INFO] ------------------------------------------------------------------------
[INFO] [resources:resources]
[INFO] Using default encoding to copy filtered resources.
Downloading: http://repo1.maven.org/maven2/org/nakedobjects/applib/4.0.0/applib-4.0.0.pom
2K downloaded
Downloading: http://repo1.maven.org/maven2/org/nakedobjects/core/4.0.0/core-4.0.0.pom
5K downloaded
Downloading: http://repo1.maven.org/maven2/org/nakedobjects/nakedobjects-parent/5/nakedobjects-parent-5.pom
14K downloaded
:
:
:
Downloading: http://repo1.maven.org/maven2/org/nakedobjects/plugins/xml-persistor/1.0.0/xml-persistor-1.0.0.jar
53K downloaded
Downloading: http://repo1.maven.org/maven2/org/nakedobjects/plugins/xstream-marshalling/1.0.0/xstream-marshalling-1.0.0.jar
7K downloaded
Downloading: http://repo1.maven.org/maven2/org/nakedobjects/core/remoting/4.0.0/remoting-4.0.0.jar
195K downloaded
[INFO] [compiler:compile]
[INFO] Nothing to compile - all classes are up to date
[INFO] [resources:testResources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:testCompile]
[INFO] No sources to compile
[INFO] [surefire:test]
[INFO] No tests to run.
[INFO] [jar:jar]
[INFO] [assembly:single {execution: default}]
[INFO] Reading assembly descriptor: src/main/assembly/descriptor.xml
[INFO] Processing DependencySet (output=lib)
[INFO] Building zip: /home/bob/tmp/nakedobjects-4.0.0/examples/orders/target/orders-demo-4.0.0-commandline.zip
[WARNING] Assembly file: /home/bob/tmp/nakedobjects-4.0.0/examples/orders/target/orders-demo-4.0.0-commandline.zip is not a regular file (it may be a directory). It cannot be attached to the project build for installation or deployment.
[INFO] Processing DependencySet (output=lib)
[INFO] Copying files to /home/bob/tmp/nakedobjects-4.0.0/examples/orders/target/orders-demo-4.0.0-commandline.dir
[WARNING] Assembly file: /home/bob/tmp/nakedobjects-4.0.0/examples/orders/target/orders-demo-4.0.0-commandline.dir is not a regular file (it may be a directory). It cannot be attached to the project build for installation or deployment.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1 minute 21 seconds
[INFO] Finished at: Wed Aug 12 20:13:35 BST 2009
[INFO] Final Memory: 25M/495M
[INFO] ------------------------------------------------------------------------
$

As you can see from the output Maven downloads all the dependencies that the application needs, compiles the code, tests it and then creates a distribution for it. The results can be seen in commandline/target/ where there is both a zip file and exploded version. Before sending the zip files to all you friends lets take a look at it. So go into the exploded version and run the nakedobjects script.

$ cd target/orders-demo-4.0.0-commandline.dir/orders-demo-4.0.0/
$ ./nakedobjects.sh

When started you will be prompted for a user name and password. Enter sven and pass and press the Logon button.

The opening screen shows a set of service objects. Here we have right-clicked on the Products icons to access its actions.

These actions correspond to the two public methods in the ProductRepository class:

    public List<Product> showAll() {
        return allInstances(Product.class);
    }

    public Product findByCode(@Named("Code") final String code) {
        return firstMatch(Product.class, new Filter<Product>() {
            public boolean accept(Product obj) {
                return code.equals(obj.getCode());
            }
        });
    }

What important to remember here, and in all the following screen shots is that the views are created from the code that I am showing you.  There is no code in the application for creating these views, it is Naked Objects building a model of the domain objects and then creating views automatically to show the objects to the user.  This will be further demonstrated later when we use another interface to show the same objects.

After selecting the Show All option, a list of all the products is opened. Double clicking on one of those opens up a view for that specific object.

This time it is the properties (the get/set method pairs) that are used and shown as fields. Notice that the properties are annotated to indicate things like length, and that the code property should only be enabled until the object is persisted.  As well as the properties there is also an object title method that is picked up by convention. This method just returns a String to use as the title, and in this case uses a utility class to build the title from the properties.

    public String title() {
        TitleBuffer t = new TitleBuffer();
        if (getCode() != null){
           t.append(getCode());
           t.append(":", getDescription());
        }
        return t.toString();
    }

    private String code;
    @TypicalLength(9)
    @MaxLength(9)
    @Disabled(When.ONCE_PERSISTED)
    public String getCode() {
        return this.code;
    }
    public void setCode(String code) {
        this.code = code;
    }

    private String description;
    @TypicalLength(50)
    @MaxLength(255)
    public String getDescription() {
        return this.description;
    }
    public void setDescription(String description) {
        this.description = description;
    }

    private Double price;
    public Double getPrice() {
        return this.price;
    }
    public void setPrice(Double price) {
        this.price = price;
    }

The next screen shots shows a view for a particular customer, which differs in layout as it contains a collection. After right-clicking on the customer’s icon the order’s singular public method is shown as an action. There is also a submenu that provides the options available from the Orders service object, in this case these is just the one and that accept a Customer objects as it one parameter.

After clicking on this option, a dialog is brought up to allow the methods parameters to be entered.  The method being

   public void placeOrder(
            Product p,
            @Named("Quantity") Integer quantity ) {
        Order order = (Order)getContainer().newTransientInstance(Order.class);
        order.modifyCustomer(this);
        order.modifyProduct(p);
        order.setOrderDate(new Date(Clock.getTime()));
        order.setQuantity(quantity);
        addToOrders(order);
        modifyLastOrder(order);
        getContainer().persist(order);
    }

As you can see from the method’s code this will create a new Order object and sets up its properties using a combination of the entered values, the current Customer object and some other programmatically derived values. When the OK button is pressed the dialog will be closed, this method will be called and then any changed views updated. In this case the Customer object was changed by having the new item added to its order list. The next screen shot show this after the user has clicked on the new item in the tree view on the left-hand side, which results in the new object being show on the right-hand side.

Now for another viewer. Shut down the application by right-clicking on the background and selecting Quit. Next run the script again but with a parameter to indicate that the HTML viewer is to be used

$ ./nakedobjects.sh --viewer html

Now open up a web browser and open the URL http://localhost:8080/logon.app and log in as before with sven and pass

The opening page shows the same three service object, this time across the top of the page.  In this next screen shot I have clicked the Products link and get presented with the options from the product repository.

This time I click the Show All link instead of double-clicking the icons. This shows a list of the products, each of which is hyperlinked.  I have not click on them yet as the HTML viewer only shows one object at a time.

Clicking on one of the items in the list open it up and adds the list to the history bar (titled “6 Objects”).

Using the Find Customer option on the Customers service object I then searched for a specific customer that resulted in the following screen.

As for the earlier web page this one does not show us the contained objects, but provides us with a link to the list of orders. The options in this viewer are shown on the left hand side as links instead of as a popup menu.  But as in Drag and Drop user interface all the available actions are shown. Again, clicking on the right link, this time the Place Order… one, we open up a dialog that prompts us for the parameters of the underlying method.

After changing the fields if needed we press on the Ok button and the action method is run creating a new order and adding it to the customer’s order list as we saw before.

That concludes my first blog about the new version of Naked Objects.  I suggest that you try a few of things out on the Order project, adding new properties and public methods and see how the user interfaces change.  In the next part I’ll show you how create a new application from scratch using a Maven archetype.

2 Comments so far

  1. gferrer on September 17th, 2009

    Hi guys,

    First let me congratulate you for your fourth installment (looks pretty sleek btw). I heard something about a headless archetype somewhere in ur wiki, and I wonder if its possible to mix swing components with the default DnD viewer; also is it possible to ajaxify the html viewer? like the rico live grid or ext-js goodies? and is there an architectural hook to start rendering my domain objects with swing or swt or something?

  2. rmatthews on October 6th, 2009

    Thanks for that. I spent some time pondering whether these things are possible. The DND viewer is written using the basic AWT facilities, rather than its widgets. This is the same foundation that Swing is built on, so it should be possible to make use of Swing by providing a Swing area within the DND, such a JPanel, which could then be used to add swing components. After that, the amount of mandatory integration with the DND framework would be minimal.

    The use of Ajax is certainly possible, but would need to be built into the viewer itself, unlike the suggestion above, for Swing in the DND, which could just be an extension. Nobody in the team at the moment has the necessary background in Swing or Ajax and as there are many other things to work on these kind of things aren’t going to get much attention until other developers come on board with these specific interests.

    As far as your last question is concerned the framework is itself the hook. It provides you with metadata about your domain model and a way to access the all the objects. This is all generalised so that you and framework deal with a common object type: the NakedObject. By asking the framework for these objects and the metadata about them your code can then build up an interface that the user can interact through. The framework then provides the way to manipulate those domain objects without having to know their types. The best thing to do is to look at the code for one of the clients of Naked Objects, specifically the DND or HTML viewer, or possibly Scimpi as it is probably the simplest and most compact one. Alternatively look at Dan Haywood’s SWT based interface that he has been working on. Finally, I should add that now that the framework has been redesigned to provide APIs we need to start documenting how to use it, so look out for that.

Leave a reply