An application can be JDO-enabled via many routes depending on the development process of the
project in question. For example the project could use Eclipse as the IDE for developing classes.
In that case the project would typically use the DataNucleus Eclipse plugin. Alternatively the
project could use Ant, Maven or some other build tool. In this case this tutorial should be used
as a guiding way for using DataNucleus in the application. The JDO process is quite straightforward.
-
Step 1 : Design your domain/model classes as you would do normally
-
Step 2 : Define their persistence definition using Meta-Data.
-
Step 3 : Compile your classes, and instrument them (using the DataNucleus enhancer).
-
Step 4 : Generate the database tables where your classes are to be persisted.
-
Step 5 : Write your code to persist your objects within the DAO layer.
-
Step 6 : Run your application.
The tutorial guides you through this. You can obtain the code referenced in this tutorial from
SourceForge (one of the files entitled "datanucleus-samples-tutorial-*").
Do this as you would normally.
The only JDO constraint on any Java class that needs persisting
is that it has a default constructor (this can be private if you prefer, and will actually be added
by the DataNucleus Enhancer if you don't add it ;-) )
.
To give a working example, let us consider an application handling products in a store.
package org.datanucleus.samples.jdo.tutorial;
public class Product
{
String name = null;
String description = null;
double price = 0.0;
protected Product()
{
}
public Product(String name, String desc, double price)
{
this.name = name;
this.description = desc;
this.price = price;
}
}
package org.datanucleus.jdo.tutorial;
public class Book extends Product
{
String author=null;
String isbn=null;
String publisher=null;
public Book(String name, String desc, double price, String author,
String isbn, String publisher)
{
super(name,desc,price);
this.author = author;
this.isbn = isbn;
this.publisher = publisher;
}
}
So we have inheritance between 2 classes. Some data in the store will be of type
Product
,
and some will be
Book
. This allows us to extend our store further in the future and provide
DVD
items for example, and so on. In traditional persistence using, for example EJB CMP,
this cannot be persisted directly. Instead the developer would have to generate a level above the
entity beans to define the inheritance. This is messy. With JDO, we don't have this problem - we
can simply throw objects across to JDO and it will persist them, and allow them to be retrieved
maintaining their inheritances.
You now need to define how the classes should be persisted, in terms of which fields are persisted
etc. This is performed by writing a Meta-Data persistence definition for each class in a JDO
MetaData file. There are several ways to do this, including using XDoclet, however the most common way is to write the Meta-Data file
manually. For example, for our 2 domain classes
<?xml version="1.0"?>
<!DOCTYPE jdo PUBLIC
"-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 2.0//EN"
"http://java.sun.com/dtd/jdo_2_0.dtd">
<jdo>
<package name="org.datanucleus.samples.jdo.tutorial">
<class name="Product" identity-type="datastore">
<inheritance strategy="new-table"/>
<field name="name" persistence-modifier="persistent">
<column length="100" jdbc-type="VARCHAR"/>
</field>
<field name="description" persistence-modifier="persistent">
<column length="255" jdbc-type="VARCHAR"/>
</field>
<field name="price" persistence-modifier="persistent"/>
</class>
<class name="Book" identity-type="datastore">
<inheritance strategy="new-table"/>
<field name="isbn" persistence-modifier="persistent">
<column length="20" jdbc-type="VARCHAR"/>
</field>
<field name="author" persistence-modifier="persistent">
<column length="40" jdbc-type="VARCHAR"/>
</field>
<field name="publisher" persistence-modifier="persistent">
<column length="40" jdbc-type="VARCHAR"/>
</field>
</class>
</package>
</jdo>
With JDO you have various options as far as where these MetaData files are placed in the file
structure, and whether they refer to a single class, or multiple classes in a package. With the
above example, we have both classes specified in the same file
package.jdo
, in the package
these classes are in.
In this tutorial we are using
datastore identity
which means that all objects of these classes
will be assigned an
identity
by DataNucleus to be able to reference them. You should read about
datastore identity and
application identity when designing your systems persistence.
JDO relies on the classes that you want to persist being
PersistenceCapable
. That is, they
need to implement this Java interface. You could write your classes manually to do this but this
would be laborious. Alternatively you can use a post-processing step to compilation that "enhances"
your compiled classes, adding on the necessary extra methods to make them
PersistenceCapable
.
DataNucleus JDO
provides its own byte-code enhancer for instrumenting/enhancing your classes for
use by any JDO implementation. You will need to obtain the Enhancer JAR (as well as the SUN JDO JAR
of course) to use this.
To understand on how to invoke the enhancer you need to visualise where the various source and jdo files are stored
src/java/com/datanucleus/samples/jdo/tutorial/package.jdo
src/java/com/datanucleus/samples/jdo/tutorial/Book.java
src/java/com/datanucleus/samples/jdo/tutorial/Product.java
target/classes/com/datanucleus/samples/jdo/tutorial/package.jdo
target/classes/com/datanucleus/samples/jdo/tutorial/Book.class
target/classes/com/datanucleus/samples/jdo/tutorial/Product.class
lib/jdo2-api.jar
lib/datanucleus-core.jar
lib/datanucleus-enhancer.jar
lib/log4j.jar
lib/asm.jar
The first thing to do is compile your domain/model classes. You can do this in any way you wish, but the downloadable
JAR provides an Ant task, and a Maven project to do this for you.
Using Ant :
ant compile
Using Maven :
maven java:compile
To enhance classes using the DataNucleus Enhancer, you need to invoke a command something like this from
the root of your project.
Using Ant :
ant enhance
Using Maven : (this is usually done automatically after the java:compile goal)
maven jpox:enhance
Manually on Linux/Unix :
java -cp target/classes:lib/datanucleus-enhancer.jar:lib/jdo2-api.jar:lib/datanucleus-core.jar:
lib/log4j.jar:lib/asm.jar
-Dlog4j.configuration=file:log4j.properties
org.datanucleus.enhancer.DataNucleusEnhancer
target/classes/com/datanucleus/samples/jdo/tutorial/package.jdo
Manually on Windows :
java -cp target\classes;lib\datanucleus-enhancer.jar;lib\jdo2-api.jar;lib\datanucleus-core.jar;
lib\log4j.jar;lib\asm.jar
-Dlog4j.configuration=file:log4j.properties
org.datanucleus.enhancer.DataNucleusEnhancer
target\classes\com\datanucleus\samples\jdo\tutorial\package.jdo
[Command shown on many lines to aid reading - should be on single line]
The
log4j.properties
is a configuration file for logging, using Log4J.
Any errors encountered during enhancement will be listed in the generated log file.
This command enhances the .class files that are defined by the package.jdo file. If you accidentally
omitted this step, at the point of running your application and trying to persist an object, you
would get a
ClassNotPersistenceCapableException
thrown.
You can alternatively build your application using either Maven or Ant instead of the above manual
method. The use of the enhancer with these 2 build systems are documented in the Enhancer Guide
The output of this step are a set of class files that represent
PersistenceCapable
classes.
This step is optional, depending on whether you have an existing database schema. If you haven't, at
this point you can use the SchemaTool to generate the
tables where these domain objects will be persisted. DataNucleus SchemaTool is a command line utility (it
can be invoked from Maven/Ant in a similar way to how the Enhancer is invoked). The first thing that
you need is to update the
datanucleus.properties
file with your database details.
Here we have a sample file (for MySQL)
javax.jdo.PersistenceManagerFactoryClass=org.datanucleus.jdo.JDOPersistenceManagerFactory
javax.jdo.option.ConnectionDriverName=com.mysql.jdbc.Driver
javax.jdo.option.ConnectionURL=jdbc:mysql://localhost/myDB
javax.jdo.option.ConnectionUserName={login}
javax.jdo.option.ConnectionPassword={password}
datanucleus.autoCreateSchema=true
datanucleus.validateTables=false
datanucleus.validateConstraints=false
Now we need to run DataNucleus SchemaTool. For our case above you would do something like this
Using Ant :
ant createschema
Using Maven :
maven jpox:schema-create
Manually on Linux/Unix :
java -cp target/classes:lib/jdo2-api.jar:lib/datanucleus-core.jar:lib/datanucleus-rdbms.jar:
lib/log4j.jar:lib/{jdbc_driver.jar}
-Dlog4j.configuration=file:log4j.properties
org.datanucleus.store.rdbms.SchemaTool
-props datanucleus.properties
-create
target/classes/com/datanucleus/samples/jdo/tutorial/package.jdo
Manually on Windows :
java -cp target\classes;lib\jdo2-api.jar;lib\datanucleus-core.jar;lib\datanucleus-rdbms.jar;
lib\log4j.jar;lib\{jdbc_driver.jar}
-Dlog4j.configuration=file:log4j.properties
org.datanucleus.store.rdbms.SchemaTool
-props datanucleus.properties
-create
target\classes\com\datanucleus\samples\jdo\tutorial\package.jdo
[Command shown on many lines to aid reading. Should be on single line]
This will generate the required tables, indexes, and foreign keys for the classes defined in the
JDO Meta-Data file.
Writing your own classes to be persisted is the start point, but you now need to define which
objects of these classes are actually persisted, and when. Interaction with the persistence
framework of JDO is performed via a PersistenceManager. This provides methods for persisting of
objects, removal of objects, querying for persisted objects, etc. This section gives examples of
typical scenarios encountered in an application.
The initial step is to obtain access to a PersistenceManager, which you do as follows
PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory("datanucleus.properties");
PersistenceManager pm = pmf.getPersistenceManager();
So we are creating a PersistenceManagerFactory using the file
datanucleus.properties
as used above for
DataNucleus SchemaTool. This will contain all properties necessary for our persistence usage.
This file is found at the root of the CLASSPATH.
Now that the application has a PersistenceManager it can persist objects. This is performed as follows
Transaction tx=pm.currentTransaction();
try
{
tx.begin();
Product product = new Product("Sony Discman","A standard discman from Sony",49.99);
pm.makePersistent(product);
tx.commit();
}
finally
{
if (tx.isActive())
{
tx.rollback();
}
pm.close();
}
Please note that the
finally
step is important in that it tidies up connections to the
datastore and the PersistenceManager.
If you want to retrieve an object from persistent storage, something like this will give what you
need. This uses a "Query", and retrieves all Product objects that have a price below 150.00,
ordering them in ascending price order.
Transaction tx=pm.currentTransaction();
try
{
tx.begin();
Extent e = pm.getExtent(org.datanucleus.jdo.tutorial.Product.class,true);
Query q = pm.newQuery(e,"price < 150.00");
q.setOrdering("price ascending");
Collection c = (Collection)q.execute();
Iterator iter = c.iterator();
while (iter.hasNext())
{
Product p = (Product)iter.next();
... (use the retrieved objects)
}
tx.commit();
}
finally
{
if (tx.isActive())
{
tx.rollback();
}
pm.close();
}
If you want to delete an object from persistence, you would perform an operation something like
Transaction tx = pm.currentTransaction();
try
{
tx.begin();
... (retrieval of objects etc)
pm.deletePersistent(product);
tx.commit();
}
finally
{
if (tx.isActive())
{
tx.rollback();
}
pm.close();
}
Clearly you can perform a large range of operations on objects. We can't hope to show all of these
here. Any good JDO book will provide many examples.
To run your JDO-enabled application will require a few things to be available in the Java CLASSPATH, these being
-
Any properties file for the PersistenceManagerFactory creation
-
The JDO MetaData files for your persistable classes
-
Any JDBC driver classes needed for accessing your datastore
-
The Log4J JAR allowing for logging
-
The JDO2 API JAR (defining the JDO2 interface)
-
The
DataNucleus Core
and
DataNucleus RDBMS
JARs
After that it is simply a question of starting your application and all should be taken care of.
You can access the
DataNucleus
Log file by specifying the
Log4J
configuration properties, and any messages from DataNucleus will be output in the normal way. The DataNucleus log
is a very powerful way of finding problems since it can list all SQL actually sent to the datastore
as well as many other parts of the persistence process.
A sample
datanucleus.properties
could be like this
javax.jdo.PersistenceManagerFactoryClass=org.datanucleus.jdo.JDOPersistenceManagerFactory
javax.jdo.option.ConnectionDriverName=org.hsqldb.jdbcDriver
javax.jdo.option.ConnectionURL=jdbc:hsqldb:mem:jpox
javax.jdo.option.ConnectionUserName=sa
javax.jdo.option.ConnectionPassword=
datanucleus.autoCreateSchema=true
datanucleus.validateTables=false
datanucleus.validateConstraints=false
Using Ant (you need the included "datanucleus.properties" to specify your database)
ant run
Using Maven ("runtutorial" goal included in the download JAR):
maven runtutorial
Manually on Linux/Unix :
java -cp lib/jdo2-api.jar:lib/datanucleus-core.jar:lib/datanucleus-rdbms.jar:lib/log4j.jar:
lib/mysql-connector-java.jar:target/classes/:. org.datanucleus.samples.jdo.tutorial.Main
Manually on Windows :
java -cp lib\jdo2-api.jar;lib\datanucleus-core.jar;lib\datanucleus-rdbms.jar;lib\log4j.jar;
lib\mysql-connector-java.jar;target\classes\;. org.datanucleus.samples.jdo.tutorial.Main
Output :
DataNucleus Tutorial
=============
Persisting products
Product and Book have been persisted
Retrieving Extent for Products
> Product : Sony Discman [A standard discman from Sony]
> Book : JRR Tolkien - Lord of the Rings by Tolkien
Executing Query for Products with price below 150.00
> Book : JRR Tolkien - Lord of the Rings by Tolkien
Deleting all products from persistence
Deleted 2 products
End of Tutorial
If you have any questions about this tutorial and how to develop applications for use with
DataNucleus
please
read the online documentation since answers are to be found there. If you don't find what you're looking for
go to our
Forums
.
Again, you can download the sample classes from this tutorial from
SourceForge.
The DataNucleus Team