Mai 14 2008

Create CRUD-Mashups rapidly with Naked Objects and NetBeans

Published by at 5:00 PM under Hibernate,Java,NetBeans



In this blog i will show how easy and fast you can create Database-Mashups with full CRUD support, using Naked Objects.

Naked Objects is an open source Java-based application development platform which can use a transient (fake) or a real existing database. Support for Hibernate is included, so you can connect to every supported database.
Naked Objects also generates HTML and Window(DND) -Interfaces which are both
customizable.

Note:
Download-links to all files are available at the end of this blog-entry.


Prerequisites

Download the Naked Objects Framework http://www.nakedobjects.org/downloads/index.shtml and extract the included JAR-files from the directory “/lib“.

Naked Objects JAR files


Create the prototype

Create a new simple Java Application, name it “NakedObjectsDNDapp” and disable
the field “Create Main Class“. Naked Objects is using a specific class.

Naded Objects - create new java application


Open the project-properties and add the extracted JAR-files to the project.

Naked Objects - project properties


Switch to the category “run” and write in the field “Main Class“:

org.nakedobjects.nof.boot.NakedObjects


Naked Objects - Run parameter


The skeletal structure for this project is now finished. Your NetBeans should look like this:

Naked Objects - skeletal structure for this project


Create domain objects

This example is using the domain objects “Developer” (stores some personal informations) and “Skill” (some various skills). A developer can have 0..* skills. That’s it.

Create the class file “Developer“:

Naked Objects - create class file


and insert this code:

Developer.java

package eu.jdevelop.nakedobjects.domains;

import java.util.ArrayList;
import java.util.List;
import org.nakedobjects.applib.AbstractDomainObject;
import org.nakedobjects.applib.annotation.DescribedAs;
import org.nakedobjects.applib.annotation.MemberOrder;
import org.nakedobjects.applib.annotation.Optional;


/**
 * Domain object for Java Developers.
 *
 * @author Siegfried Bolz (http://blog.jdevelop.eu)
 */

@DescribedAs("Java Developer")
public class Developer  extends AbstractDomainObject {

    private String name;
    private int age;
    private String webpage;
    private List<skill> skillList=new ArrayList<skill>();


    /**
     * Identification of this object
     *
     * @return String
     */
    public String title() {
        return getName();
    }

    /**
     * Getter for name.
     *
     * @MemberOrder(sequence = "1") :
     * Mechanism for specifying the order in which fields and/or actions are rendered
     * in the user interface
     *
     * @return String
     */
    @MemberOrder(sequence = "1")
    public String getName() {
        resolve(name);
        return name;
    }

    /**
     * Setter for name.
     *
     * @param name
     */
    public void setName(String name) {
        this.name = name;
        objectChanged();
    }

    /**
     * Validating age. Allowed range is from 0 to 100
     *
     * @param age
     * @return String
     */
    public String validateAge(int age) {
        return !(age >= 0 && age <= 100) ? "Number must be in range 0 to 100" : null;
    }

    @MemberOrder(sequence = "2")
    public int getAge() {
        resolve(age);
        return age;
    }

    public void setAge(int age) {
        this.age = age;
        objectChanged();
    }

    @MemberOrder(sequence = "3")
    @Optional
    public String getWebpage() {
        resolve(webpage);
        return webpage;
    }

    public void setWebpage(String webpage) {
        this.webpage = webpage;
        objectChanged();
    }

    /**
     * Selection-list for Skills-objects
     *
     * @return List
     */
    public List<skill> getSkillList() {
        resolve(skillList);
        return skillList;
    }

    public void setSkillList(List<skill> skillList) {
        this.skillList = skillList;
        objectChanged();
    }

    public void addToSkillList(Skill skills) {
        this.skillList.add(skills);
        objectChanged();
    }

    public void removeFromSkillList(Skill skills) {
        this.skillList.remove(skills);
        objectChanged();
    }

    /**
     * Custom image for this object (must be in the images directory, which must be on the classpath).
     * Allowed are "gif" and "png" files. Here i am using the file "developer.png"
     *
     * @return IconName
     */
    public String iconName() {
        return "developer";
    }

} // .EOF



Create the class file “Skill” and insert this code:

Skill.java

package eu.jdevelop.nakedobjects.domains;

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

/**
 * Domain object for Skills
 *
 * @author Siegfried Bolz (http://blog.jdevelop.eu)
 */

@DescribedAs("Various skills")
public class Skill  extends AbstractDomainObject {

    private String skill;
    private String description;


    /**
     * Identification of this object
     *
     * @return String
     */
    public String title() {
        return getSkill();
    }

    @MemberOrder(sequence = "1")
    public String getSkill() {
        resolve(skill);
        return skill;
    }

    public void setSkill(String skill) {
        this.skill = skill;
        objectChanged();
    }

    @MemberOrder(sequence = "2")
    public String getDescription() {
        resolve(description);
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
        objectChanged();
    }

} // .EOF



Create some prototype data

Once your prototype progresses beyond the trivial stage, you will want to have some data fixtures available – so that you aren’t having to re-create your demonstration Developers and other objects from scratch each time you run the prototype.

Create the class “DeveloperFixture“:

Naked Objects - data fixtures


and insert this code:

DeveloperFixture.java

package eu.jdevelop.nakedobjects.fixtures;

import eu.jdevelop.nakedobjects.domains.Developer;
import org.nakedobjects.applib.fixtures.AbstractFixture;

/**
 * This class is used to fill the prototype with data.
 *
 * @author Siegfried Bolz (http://blog.jdevelop.eu)
 */
public class DeveloperFixture  extends AbstractFixture{

    @Override
    public void install() {
        createNewDeveloper("Duke",23,"http://www.java.com/en/dukeszone/");
        createNewDeveloper("Siegfried Bolz",32,"http://blog.jdevelop.eu");
    }

    /**
     * Creates new instances of Developer.
     *
     * @param name
     * @param age
     * @param webpage
     */
    public void createNewDeveloper(String name, int age, String webpage) {
        Developer dev;
        dev = (Developer) newTransientInstance(Developer.class);
        dev.setName(name);
        dev.setAge(age);
        dev.setWebpage(webpage);

        makePersistent(dev);
    }

}



Alright, you have now added 3 class-files to your project.

Naked Objects - all class files created


Create configuration-files

Now create the configuration-files. Choose “New Properties File“.

Naked Objects - create new property file


and name it “nakedobjects“, located in the directory “/config“.

Naked Objects - configuration file


Insert this configuration code:

nakedobjects.properties

nakedobjects.services=repository#eu.jdevelop.nakedobjects.domains.Developer,repository#eu.jdevelop.nakedobjects.domains.Skill
nakedobjects.fixtures=eu.jdevelop.nakedobjects.fixtures.DeveloperFixture



Naked Objects - configuration for dnd


Create a new “Empy File“, name it “passwords” and put it into the directory “/config“.


Naked Objects - password file


Insert this line:

passwords

duke:pass



Naked Objects - filled password file


Launch the DND application

Build, deploy and launch the project. A login-window must appear.

Naked Objects - launch the DND application


Insert “duke” into “User name” and “pass” into “Password“.

Naked Objects - DND login


After the successful login, you see the Naked Objects DragAndDrop user interface.

Naked Objects - DND interface


On the top left side, you see the domain objects. Rightclick on “Developers” and choose “All Instances” to see the data fixtures, created in “DeveloperFixture.java“.

Naked Objects - domain objects


Naked OBjects - create new instances


You can create some skills and use drag and drop to add them to a “Skill List“.

Naked Objects - drag and drop instances


After closing this application, all changes are lost. To prevent this, you have to switch to a persistence layer based on Hibernate.


Specifying Hibernate for persistence

To use a persistence layer based on Hibernate a small amount of configuration is required.
First open the projects properties and move to the category “Run“. Add this line to
the “Arguments“-field:

--type standalone --persistor hibernate


Naked Objects - add Hibernate arguments


After that, copy across the Hibernate configuration file – hibernate.cfg.xml – from the distribution’s resource directory. In its newly copied state this file specifies that the database is HSQLDB, but it does contain other configurations that can be uncommented so you can use other databases such as MySQL or SQLServer.

hibernate.cfg.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="show_sql">true</property>

        <!-- hsqldb -->
        <property name="bytecode.use_reflection_optimizer">false</property>
        <property name="hibernate.query.substitutions">true 1, false 0</property>
        <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
        <property name="connection.username">sa</property>
        <property name="connection.password"></property>
        <property name="connection.url">jdbc:hsqldb:file:hsql/db</property>
        <property name="dialect">org.hibernate.dialect.HSQLDialect</property>


        <!--  sql server  -->
    	<!-- disabled
        <property name="bytecode.use_reflection_optimizer">false</property>
	<property name="hibernate.query.substitutions">true 1, false 0</property>
        <property name="connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
        <property name="connection.username">sa</property>
        <property name="connection.password"></property>
        <property name="connection.url">jdbc:sqlserver://localhost:1287;databaseName=expenses;integratedSecurity=true;</property>
        <property name="dialect">org.hibernate.dialect.SQLServerDialect</property>
	-->

	<!--  MySQL  -->
    	<!-- disabled
	<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/nakedobjects</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password"></property>
        <property name="hibernate.connection.pool_size">6</property>
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
	-->

	<!-- postgres   -->
    	<!-- disabled
        <property name="connection.url">jdbc:postgresql://localhost:5432/expenses</property>
        <property name="connection.username">postgres</property>
        <property name="connection.password"></property>
        <property name="connection.driver_class">org.postgresql.Driver</property>
        <property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>
        -->

        <!-- Derby  -->
    	<!-- disabled
        <property name="connection.driver_class">org.apache.derby.jdbc.EmbeddedDriver</property>
         connection is jdbc:derby:test or jdbc:derby:test;create=true to create DB
        <property name="connection.url">jdbc:derby:test;create=true</property>
        <property name="dialect">org.hibernate.dialect.DB2Dialect</property>
 	-->

 	<property name="current_session_context_class">
            org.hibernate.context.ThreadLocalSessionContext
    	</property>

	<property name="connection.provider_class">
	    org.hibernate.connection.C3P0ConnectionProvider
    	</property>

        <property name="hibernate.c3p0.acquire_increment">1</property>
        <property name="hibernate.c3p0.idle_test_period">100</property> <!-- seconds -->
        <property name="hibernate.c3p0.max_size">90</property>
        <property name="hibernate.c3p0.max_statements">0</property>
        <property name="hibernate.c3p0.min_size">10</property>
        <property name="hibernate.c3p0.timeout">100</property> <!-- seconds -->
   </session-factory>
</hibernate-configuration>


Naked Objects - hibernate.cfg.xml


Open the file “/config/nakedobjects.properties“, remove the second line and add this line:

nakedobjects.properties

nakedobjects.persistence.hibernate.classes=eu.jdevelop.nakedobjects.domains.Developer,eu.jdevelop.nakedobjects.domains.Skill


Naked Objects - configuration file modified


Launch the Hibernate application

Build, deploy and launch the project. As before, a login-window must appear and you can now store objects in the HSQL-Database.

Take a look at the updated file structure of your project:

Naked Objects - file structure


Naked Objects has created two directorys:

  • /hsql : folder for the HSQLDB files
  • /mappings : Hibernate mappings for the domain objects



Switch to the HTML interface

Switching between the DND and the HTML user interfaces for your application is just a matter of specifying a different run configuration. You don’t have to configurate a web server, Naked Objects is delievered with a pre-configured jetty-server.

Open again the project properties and modify the “Arguments“-field:

-v html --type standalone --persistor hibernate


Naked Objects - html properties


Extract the directory “../web” from the distribution’s example directory and copy it to your project.

Naked Objects - web directory


Launch the HTML application

Build, deploy and launch the project. Open your favourite web browser with this URL:

http://localhost:8080/logon.app

Naked Objects - html login page


Log on using a username and password specified in your passwords file. That’s it!

Naked Objects - html interface


Downloads


Note:
You can read in my other blog how to open an existing NetBeans project.


Technorati Tags: , , , , ,

6 responses so far

6 Responses to “Create CRUD-Mashups rapidly with Naked Objects and NetBeans”

  1. Dan Haywood sagt:

    Hi Siegfried,

    Thanks for taking the time to put this mini-tutorial together. Nice to see the Naked Objects message being spread a little wider.

    Only (tiny) objection is that Naked Objects goes beyond “CRUD” applications, allowing the application/controller layer to be dispensed with completely. But that’s probably a distinction worth making in a comment but perhaps not in your main posting.

    Cheers
    Dan

  2. Hey Sieggi, a big thank you for this great tutorial! You really helped me understanding some details I haven’t known so far.

  3. Ana sagt:

    Hi!!! I was trying to make my first NO proyect following this guide, but i couldn’t even make it work the first time. I followed exactly all you said, but i’ve found two problems i can’t resolve:

    1) Netbeans finds a problem with the code line makePersistent(dev);, it can’t find the method.

    2) When i try to run it, Netbeans says can not find the main class.

    Could you please help me? I must develop a NO proyect, and i begin to feel helpless.

  4. [...] tutorial on using Naked Objects 3.0 with NetBeans has been put together bySiegfried Bolz on his blog. Nice to see he goes all the way through to Hibernate and shows off the HTML interface [...]

  5. @Ana I’ve had the same problems, apparently the post refers to a previous version of NO as makePersistent() is now deprecated and you should use the persist() method of the AbstractContainedObject class instead. The same goes for the runner.

    You may want to take a look at this post of mine http://andreamoz.blogspot.com/2010/02/how-to-create-simple-naked-objects.html in which I explain a working procedure to create a new NO application in NetBeans.

  6. At last I understand the mistake I did! Your tutorial really helped me. Thanks.