![]() | ![]() |
![]() |
| Project | Ver 1.1 | Ver 1.2 | JDO | JPA | Samples |
| 1.1 | Preparation | O/R Mapping | Runtime | Extensions | Tutorials and Examples | Developer |
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 JPOX 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 JPOX JDO in the application. The JDO process is quite straightforward.
The tutorial guides you through this. You can obtain the code referenced in this tutorial from SourceForge (one of the files entitled "jpox-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 JPOX Enhancer if you don't add it). 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 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.jpox.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"
persistence-capable-superclass="org.jpox.tutorial.Product">
<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 JPOX 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. JPOX 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/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/jdo2-api.jar lib/jpox.jar lib/jpox-enhancer.jar lib/log4j.jar lib/bcel.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 JPOX 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/jpox-enhancer.jar:lib/jdo2-api.jar:lib/jpox.jar:lib/log4j.jar:lib/bcel.jar
-Dlog4j.configuration=file:log4j.properties
org.jpox.enhancer.JPOXEnhancer
target/classes/org/jpox/tutorial/package.jdo
Manually on Windows :
java -cp target\classes;lib\jpox-enhancer.jar;lib\jdo2-api.jar;lib\jpox.jar;lib\log4j.jar;lib\bcel.jar
-Dlog4j.configuration=file:log4j.properties
org.jpox.enhancer.JPOXEnhancer
target\classes\org\jpox\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. JPOX 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 jpox.properties file with your database details. Here we have a sample file (for MySQL)
javax.jdo.PersistenceManagerFactoryClass=org.jpox.PersistenceManagerFactoryImpl
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}
org.jpox.autoCreateSchema=true
org.jpox.validateTables=false
org.jpox.validateConstraints=falseNow we need to run JPOX 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/jpox.jar:lib/log4j.jar:lib/{jdbc_driver.jar}
-Dlog4j.configuration=file:log4j.properties
org.jpox.SchemaTool
-props jpox.properties
-create
target/classes/org/jpox/tutorial/package.jdo
Manually on Windows :
java -cp target\classes;lib\jdo2-api.jar;lib\jpox.jar;lib\log4j.jar;lib\{jdbc_driver.jar}
-Dlog4j.configuration=file:log4j.properties
org.jpox.SchemaTool
-props jpox.properties
-create
target\classes\org\jpox\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("jpox.properties");
PersistenceManager pm = pmf.getPersistenceManager();So we are creating a PersistenceManagerFactory using the file jpox.properties as used above for JPOX 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.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. The JPOX 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.
Using Ant (you need the included jpox.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/jpox.jar:lib/log4j.jar:lib/mysql-connector-java.jar:target/classes/:. org.jpox.tutorial.Main
Manually on Windows :
java -cp lib\jdo2-api.jar:lib\jpox.jar:lib\log4j.jar:lib\mysql-connector-java.jar:target\classes\:. org.jpox.tutorial.Main
Output :
JPOX 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 JPOX 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 JPOX Team |