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 EclipseJDO plugin (described in a different tutorial). 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 JPOX JDO in the application
Do this as you would normally. The only constraint on any Java class that needs persisting is that it has a default constructor (this can be private if you prefer). To give a working example, let us consider an application handling products in a store.
package org.jpox.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.jpox.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 MetaData persistence definition for each class in a JDO MetaData file. There are several ways to do this, including using XDoclet (see ref ..), however the most common way is to write the MetaData file manually. For example, for our classes
<?xml version="1.0"?>
<!DOCTYPE jdo PUBLIC "-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 1.0//EN"
"http://java.sun.com/dtd/jdo_1_0.dtd">
<jdo>
<package name="org.jpox.tutorial">
<class name="Product" identity-type="datastore">
<field name="name" persistence-modifier="persistent">
<extension vendor-name="jpox" key="length" value="max 100"/>
</field>
<field name="description" persistence-modifier="persistent">
<extension vendor-name="jpox" key="length" value="max 255"/>
</field>
<field name="price" persistence-modifier="persistent"/>
</class>
<class name="Book" identity-type="datastore"
persistence-capable-superclass="org.jpox.tutorial.Product">
<field name="isbn" persistence-modifier="persistent">
<extension vendor-name="jpox" key="length" value="max 20"/>
</field>
<field name="author" persistence-modifier="persistent">
<extension vendor-name="jpox" key="length" value="max 40"/>
</field>
<field name="publisher" persistence-modifier="persistent">
<extension vendor-name="jpox" key="length" value="max 40"/>
</field>
</class>
</package>
</jdo>
With JDO 1.0.1 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.
JPOX JDO provides its own byte-code enhancer for enhancing your classes for use by a JDO implementation. You will need to obtain the Enhancer JAR (as well as the SUN JDO JAR of course). To understand on how to invoke the enhancer you need to visualise where the various source and jdo files are stored
src/java/org/jpox/tutorial/package.jdo
src/java/org/jpox/tutorial/Book.java
src/java/org/jpox/tutorial/Product.java
target/classes/org/jpox/tutorial/package.jdo
target/classes/org/jpox/tutorial/Book.class
target/classes/org/jpox/tutorial/Product.class
lib/jdo.jar
lib/jpox.jar
lib/jpox-enhancer.jar
lib/log4j.jar
lib/bcel.jar
To enhance classes using the JPOX Enhancer, you need to invoke a command something like this.
java -cp target/classes:lib/jpox-enhancer.jar:lib/jdo.jar:lib/jpox.jar:lib/log4j.jar:lib/bcel.jar
org.jpox.enhancer.JPOXEnhancer
target/classes/org/jpox/tutorial/package.jdo
[Command shown on 3 lines to aid reading - should be on single line]
[Be aware that on Windows, \ is used instead of /]
This 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
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
Properties properties = new Properties();
properties.setProperty("javax.jdo.PersistenceManagerFactoryClass","org.jpox.PersistenceManagerFactoryImpl");
properties.setProperty("javax.jdo.option.ConnectionDriverName","com.mysql.jdbc.Driver");
properties.setProperty("javax.jdo.option.ConnectionURL","jdbc:mysql://localhost/myDB");
properties.setProperty("javax.jdo.option.ConnectionUserName","login");
properties.setProperty("javax.jdo.option.ConnectionPassword","password");
properties.setProperty("org.jpox.autoCreateSchema","true");
properties.setProperty("org.jpox.validateTables","false");
properties.setProperty("org.jpox.validateConstraints","false");
PersistenceManagerFactory pmfactory = JDOHelper.getPersistenceManagerFactory(properties);
PersistenceManager pm = pmfactory.getPersistenceManager();
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.jpox.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
After that it is simply a question of starting your application and all should be taken care of. You can access the JPOX JDO Log file by specifying the Log4J configuration properties, and any messages from JPOX will be output in the normal way.
If you have any questions about this tutorial and how to develop applications for use with JPOX JDO please go to our Forums. You can download the sample classes from this tutorial from SourceForge. The JPOX Team |