Mai 14 2008
Create CRUD-Mashups rapidly with Naked Objects and 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“.
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.
Open the project-properties and add the extracted JAR-files to the project.
Switch to the category “run” and write in the field “Main Class“:
org.nakedobjects.nof.boot.NakedObjects
The skeletal structure for this project is now finished. Your NetBeans should look like this:
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“:
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“:
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.
Create configuration-files
Now create the configuration-files. Choose “New Properties File“.
and name it “nakedobjects“, located in the directory “/config“.
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
Create a new “Empy File“, name it “passwords” and put it into the directory “/config“.
Insert this line:
passwords
duke:pass
Launch the DND application
Build, deploy and launch the project. A login-window must appear.
Insert “duke” into “User name” and “pass” into “Password“.
After the successful login, you see the Naked Objects DragAndDrop user 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“.
You can create some skills and use drag and drop to add them to a “Skill List“.
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
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>
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
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 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
Extract the directory “../web” from the distribution’s example directory and copy it to your project.
Launch the HTML application
Build, deploy and launch the project. Open your favourite web browser with this URL:
http://localhost:8080/logon.app
Log on using a username and password specified in your passwords file. That’s it!
Downloads
- JAR-files : download
- DND Project : download
- DND with Hibernate Project : download
- HTML with Hibernate Project : download
Note:
You can read in my other blog how to open an existing NetBeans project.
6 responses so far
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
Hey Sieggi, a big thank you for this great tutorial! You really helped me understanding some details I haven’t known so far.
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.
[...] 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 [...]
@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.
At last I understand the mistake I did! Your tutorial really helped me. Thanks.