Wednesday, February 24, 2010

How to create a simple Naked Objects Application in NetBeans

Naked Objects is an open source application framework that lets you concentrate on domain objects and automagically generates a GUI for interacting with them. This sounds (and actually is) very interesting, as the domain is what we should most interested in, instead of boilerplate, as everybody who is fond of DDD knows.

Being NetBeans my favourite IDE, as you might have suspected, I'll try to jot down some notes on how to use it to create a very simple Naked Objects application.

First things first, you have to download the Naked Objects framework; you have various options, I chose to download the zip file for Ant. After unzipping the file you should find a folder named lib that contains - o great wonder and surprise - all the necessary libs.

As I suppose I could use all this stuff in more than one project, I created a new library in NetBeans:


Click on the New Library... button and you'll be prompted a library name and type


Then click on the Add Jar/Folder... button and add all the jars in the lib folder. You should get something like this:


Ok, now we can proceed to creating a new application. As a disclaimer, this is not necessarily the best way to do it, but it is how my inner cogs work (or don't work). If yours are different, you'll have to compose all the pieces of the puzzle in a different order.

Let's suppose we want to use the DnD GUI, so I go with a new Java Application:


Click on the Next> button and enter a name for your project; don't use a dedicated folder for libraries and don't have the IDE create a main class for you.


Click on the Finish button. Ok, now we should instruct our project to be a Naked Object Application. Right click the Libraries node to add all necessary references:


Select the library you've previosly created and you're almost ready to go.

Now, if you try to run the application NetBeans complains because you have not chosen a Main Class. Right click the project node and the Run node in the Categories tree, and insert org.nakedobjects.runtime.NakedObjects as the Main Class.


Click on the OK button. Ok, now we can try to run the application... just to get another complain


Exception in thread "main" org.nakedobjects.metamodel.commons.exceptions.NakedObjectException: failed to load 'nakedobjects.properties'; tried using: [file system (directory 'config'), file system (directory 'src/main/webapp/WEB-INF'), context loader classpath]

It seems fair... after all we have to provide some configuration. Create a new properties file, name it nakedobjects and put it in the config folder. Obviously this is not enough, and you can check it yourself trying to run the application: NetBeans will complain again (don't shoot the messenger) about the lack of services.

To define services, we have to write some code. Let's suppose we want to deal with all Walt Disney characters - I hope there are no legal issues with this - so let's create a class that represents one:


package it.moz.noapp;

import org.nakedobjects.applib.AbstractDomainObject;
import org.nakedobjects.applib.annotation.DescribedAs;
import org.nakedobjects.applib.annotation.MemberOrder;

@DescribedAs("Character")
public class Character extends AbstractDomainObject {

private String firstname;
private String lastName;

@MemberOrder(sequence = "1")
public String getFirstname() {
resolve(firstname);
return firstname;
}

public void setFirstname(String firstname) {
this.firstname = firstname;
objectChanged();
}

@MemberOrder(sequence = "2")
public String getLastName() {
resolve(lastName);
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
objectChanged();
}

public String title() {
return getFirstname() + " " + getLastName();
}
}

Notice how this class, that is a domain object, extends the class AbstractDomainObject provided by the framework. The annotation @DescribedAs tells you how the object will be referred to in the GUI, while @MemberOrder defines the order in which members are presented. You can find every detail on the Naked Objects website.

The next step is telling our application that such a domain object exists, so we'll add the following line in our nakedobject.properties file:

nakedobjects.services=repository#it.moz.noapp.Character

Ok, let's start the application...


uh oh... User name and password? ehrm... let's provide the application with them! The problem is that if you want to add an empty file - unlike for properties files - NetBeans asks you whether you want to add it to the src folder or to the test folder, i.e. the folders (already) defined in the project. As you want neither, you must manually add an empty passwords file to the config folder. Before complaining about NetBeans, keep in mind that you can always define the config folder as a new source package folder, but let's skip this option.

Fill in a username and a password...
user:pass
And that's it, you can start your application!


To create a new instance you right-click the Characters icon and select the appropriate item from the drop down list, insert the desired values and here's your brand new character. Rinse and repeat and you'll get something like this:


As you can see, you now have a Disney Character directory without having written a single line of code but your domain class.

Unluckily, if you close your application all your efforts have been vain, so you should add the support for persistence. But this will be the subject for another post...

4 comments:

sandeep.gadhvi said...

hi, Liked the tutorial very much. its very interesting and helpful.
thanks.

.MOz said...

You're welcome!

Dan said...

Hi,

Thanks for this write-up, and glad you've enjoyed using Naked Objects. Some notes:

1. Naked Objects is also available via Maven, which these days is natively supported by NetBeans, isn't it? There's also a Maven archetype, so you can get going somewhat more quickly using this. This will include a sample nakedobjects.properties file, for example.

2. In your app, you use the @DescribedAs annotation but just specify the name of the class. The idea of @DescribedAs is to provide a longer tooltip.

3. Although it's the most convenient and what we usually do, there's no specific need to inherit from AbstractDomainObject.

4. To get around providing a passwords file, you can start the application in "exploration" mode, using --type exploration. This will log you in either as a user called 'exploration'. Or, if you want to easily switch between different users, you can create a property key nakedobjects.exploration.users; you'll start off logged in as the first user listed, e.g: nakedobjects.exploration.users=sven:role1, dick:role2, bob:role1|role2

5. Possibly worth pointing out, using the repository#com.mycompany.SomeDomainObject is a nice way to get going quickly, but after a while we normally write a custom repository (e.g. com.mycompany.CharacterRepository) to provide the ability to perform complex actions than simple CRUD.

Good stuff, though, and hope to see some similar posts in the future!

Cheers
Dan
Domain Driven Design using Naked Objects

.MOz said...

Thanks Dan, your comment is very clear, just like all your posts :-)

I think the most interesting points are #3 and #5, and the're probably worth some more details, which I might, sooner or later, try to provide... Stay tuned, I could use some help of yours!