JDO UNPLUGGED - PART II
------------------------
by Farihah Noushene B.E.
=======================
(published in Developer IQ - Oct 2005)
The JDO examples can be tested by using sun's JDO reference implementation. A
number of other JDO implementations are also available. The JDO reference
implementation can be downloaded from www.jcp.org and selecting JSR-12 or
can be downloaded from sun java website. Goto
http://java.sun.com/jdo/index.html
and download jdo-1_0_1-ri.zip.
Extract the zip file to g:\jdo1.
Inside g:\jdo1 we can find the following four jar files
1. jdo.jar : It contains the standard interfaces and classes defined in
the JDO specification.
2. jdori.jar : It is the sun's reference implementation of JDO
specification.
3. btree.jar : It is a software used by JDO reference implementation to
manage the storage of data in a file.
4. jdori-enhancer.jar : It contains the reference enhancer
implementation. The classes of this jar file is also present in jdori.jar and so
we do not need this jar. By using this jar, we can create JDO in any
implementation and enhance the classes using this enhancer also.
Also there are three other jar files needed for our application. They are,
1. jta.jar : The synchronization interface defined in package
javax.transaction is used in JDO interface. It is present in this jar file. The
jar file can be downloaded form http://java.sun.com/products/jta/index.html
2. antlr.jar : It is the parsing technology used in the implementation of
JDO query language. It can be downloaded from http://www.antlr.org
3. xerces.jar : Xerces-j is used to parse XML file and it can be
downloaded from http://xml.apache.org/xerces-j/.
These three jars can be found in lib directory of hibernate(both 2 and 3) also.
--------------------------------------------------------------------------
First we will create a project directory called 'demojdo'
in f drive.
f:\>md demojdo
f:\>cd demojdo
f:\demojdo>md jdopack
When we want to persist classes package is essential in
JDO. 'jdopack' is the package name given to our java beans. Now set path and
classpath as follows,
f:\demojdo\jdopack>
set path=c:\windows\command;
g:\jdk1.4.2\bin
--------------------------------------------------------------------------
f:\demojdo\jdopack>
set classpath=f:\demojdo;
f:\demojdo\jdopack;
f:\demojdo\jdo.jar;
f:\demojdo\jdori.jar;
f:\demojdo\btree.jar;
f:\demojdo\jta.jar;
f:\demojdo\xerces.jar;
f:\demojdo\antlr.jar;
--------------------------------------------------------------------------
Now we shall see how to create a datastore. First we should create a property
file as shown below,
--------------------------------------------------------------------------
//f:\demojdo\jdopack\jdo.properties
javax.jdo.PersistenceManagerFactoryClass=
com.sun.jdori.fostore.FOStorePMF
javax.jdo.option.ConnectionURL=fostore:dbdemo
javax.jdo.option.ConnectionUserName=farihah
javax.jdo.option.ConnectionPassword=
javax.jdo.option.Optimistic=false
--------------------------------------------------------------------------
The property file consists of various properties that is used by the JDO program
in the runtime. The 'PersistenceManager FactoryClass' property is used to
specify the name of the implementation's class that implements the
PersistenceManagerFactory interface. It specifies which JDO implementation we
are using. The format of the 'ConnectionURL' property depends on the
datastore used. 'dbdemo' refers to the datastore in our current project folder.
It is possible to provide absolute path also. The other properties 'ConnectionUserName'
and 'ConnectionPassword' are necessary to establish connection to any
datastore.
The JDO reference implementation has its own storage facility called 'File
Object Store'(FOStore). We can create a new datastore by using FOStore
and test our application. To create a datastore edit the following client file.
-----------------------------------------------------------------------------
//f:\demojdo\jdopack\jdocreatedb.java import java.io.*; import java.util.*; import javax.jdo.*; public class jdocreatedb { public static void main(String args[]) { try { InputStream fis = new FileInputStream("jdo.properties"); Properties props= new Properties(); props.load(fis); props.put("com.sun.jdori.option.ConnectionCreate","true"); PersistenceManagerFactory factory = JDOHelper.getPersistenceManagerFactory(props); PersistenceManager manager = factory.getPersistenceManager(); Transaction tx = manager.currentTransaction(); tx.begin(); tx.commit(); } catch(Exception e1) { System.out.println(""+e1); } } }-------------------------------------------------------------------------
When we compile and run the above program we will get a FOStore database. It consists of two files dbdemo.btd and dbdemo.btx. The program creates a datastore using the jdo.properties file. 'com.sun.jdori.option.ConnectionCreate' is added to the property for creating a database. The 'PersistenceManagerFactory' provides property to control values that are used to establish a datastore connection. It is also responsible for creating and configuring the 'PersistenceManager' instance. 'JDOHelper' class provides methods to construct a 'PersistenceManagerFactory' instance from the properties object by using the method 'getPersistenceManagerFactory()'. The instance of 'PersistenceManager' is created from the 'PersistenceManager Factory' by using 'getPersistenceManager()' method.
To complete the datastore creation, we must begin and commit a transaction. The PersistenceManager's method currentTransaction() is used to create Transaction instance. The transaction consists of three methods begin(), commit() and rollback(). To begin a transaction begin() method is called. When we call commit(), all the changes are updated to the datastore and when we call rollback(), the changes are not recorded in the database.
----------------------------------------------------------------------------
Now we have created a datastore 'dbdemo'. Next we will see how to persist a class in it.
First we have create a class that is to be persisted. In JDO to persist a class, package is a 'must' thing. Here package name is 'jdopack'. We will create a simple javabean as shown below.
----------------------------------------------------------------------------
//f:\demojdo\jdopack\player.java package jdopack; public class player { String name; String game; public player() { } public player(String a,String b) { name = a; game = b; } //---------------------------------- public String getName() { return name; } public void setName(String b) { name = b; } //----------------------------------- public String getGame() { return game; } public void setGame(String c) { game = c; } }---------------------------------------
Next we have to edit the metadata file. The metadata file is an XML format file and JDO uses this metadata file to identify the classes that needs to be persisted and specify the persistence-related information that cannot be expressed in Java. The metadata file for a java package is named as 'package.jdo'. For our example, the metadata file is shown below,
-----------------------------------------------------------------
//f:\demojdo\jdopack\package.jdo <?xml version="1.0" encoding="UTF-8" ?> <!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="jdopack"> <class name="player" /> </package> </jdo>-----------------------------------------------------------------
Next we have to compile our java bean and enhance the class file. As already told, for the java class to be persisted, the class must be enhanced. The JDO provides a reference enhancer which reads ths class file produced by the java compiler and the metadata file to produce the 'enhanced class' file. The command for enhancement in our reference enhancer is shown below,
F:\demojdo\jdopack>javac player.java
(We will get the class file.)
F:\demojdo\jdopack>
java com.sun.jdori.enhancer.Main
\demojdo/jdopack/package.jdo
\demojdo/jdopack/player.class
(Type as a single line)
After the command gets executed we get the output as 'done'. This command
creates a folder in the name of our package ie., 'jdopack' and places the
enhanced class file in that folder. The full path of our enhanced class file is
'f:\demojdo\jdopack\jdopack'. Copy it to our project folder f:\demojdo\jdopack so that it is accessible to our client program. We no longer need our ordinary
class file.
Now let us see how to add, delete find and update the records in our datastore 'dbdemo'
and how to persist data in it.
To add a new record we must first get an instance of 'PersitenceManager' and
begin the Transaction as shown above. After that the records can be added using
the player bean's constructor with arguments as
player player1 = new player(a,b);
where a and b represents name and game. Alternatively, we can also use set methods and no argument constructor as
player player1 = new player();
player1.setName(a);
player1.setGame(b);
To make the player instance to be persistence we must call 'makePersistence(..)'
method of 'PersitenceManager' before commiting the transaction.( full code is
being given
shortly).
To find a record, ie., to access the instance in our datastore we can iterate an
extent or execute a query.
An extent is a facity used to access all the instance of the class. When we want
to show all the instance we can just iterate an extent. The 'getExtent(..)'
method of 'Extent' class is used to give class name. After that 'Iterator' class
is used to get all the records as shown below,
Extent extent = manager.getExtent
(player.class,true);
Iterator iter = extent.iterator();
while(iter.hasNext())
{
Object ob = (Object)iter.next();
System.out.println(ob.getName());
System.out.println(ob.getGame());
}
------
When we want to find a particular record we can use extent facility to get all
the records and filter them by executing a query . The JDO 'Query' interface is
used to select the instances that meet the specified criteria. The instance of
'Query' interface is created by using 'newQuery(..)' method defined in 'PersistenceManager'
interface. The Query is initialised with an extent and a query filter to apply
to that extent. The syntax is shown below,
Extent extent = manager.getExtent(player.class,true);
String filter = "name == a ";
Query query = manager.newQuery (extent,filter);
query.declareParameters("String a");
Collection list1 = (Collection)query.execute(a);
Iterator i = list1.iterator();
while(i.hasNext())
{
Object ob = (player)i.next();
System.out.println(ob.getName());
System.out.println(ob.getGame());
}
query.close(list1);
--------
The 'name' identifier in the filter indicates the name field of our class. The
filer expression requires the name field of the class to equal to the given
variable 'a'. Here we can use '==' operator directly to compare two strings.
After that the query is executed by using the method execute(). The query
parameter provides a value to be used when a query is executed. The query is
executed by using the command 'query.execute()' and the method returns the
result. The return type of the method is declared as Object. The returned
instance is always a Collection and hence we cast the query result as
Collection. Then we use 'Iterator' to get each individual objects as shown
above. Finally the query is closed by using
'close(..)' method
When we remove all the reference to a persistence instance, the instance will
not be automcatically deleted. We have to explicitly delete individual instance.
To delete an instance, we have to get the reference of that instance as shown
above and delete it. We can call 'deletePersistence(..)' method of 'PersitenceManager'
to delete that instance.
To update record we must first get an instance of 'PersitenceManager' and begin
the Transaction as usual. After that instance is located as shown above (to find
the record). After that we can use set methods and update the properties as
shown below
player1.setName(a);
manager.makePersistent(player1);
To make the player instance to be persistence we must call 'makePersistence(..)'
method of 'PersitenceManager' before commiting the transaction.
-----------------
The complete console program is given below,
f:\demojdo\jdopack> package jdopack; import java.io.*; import java.util.*; import javax.jdo.*; import javax.jdo.spi.*; public class jdoclientConsole { public static void main(String args[]) { PersistenceManagerFactory factory=null; PersistenceManager manager=null; Transaction tx; String s = ""; try { InputStream fis = new FileInputStream("jdo.properties"); Properties props = new Properties(); props.load(fis); factory = JDOHelper.getPersistenceManagerFactory(props); manager = factory. getPersistenceManager(); } catch(Exception e1) { System.out.println(""+e1); } try { do { System.out.println("Add/ Delete/ Showall/ Find/ Update"); DataInputStream ins = new DataInputStream(System.in); s = ins.readLine(); if(s.equals("add")) { tx = manager.currentTransaction(); tx.begin(); System.out.println("Enter Name:"); String a = ins.readLine(); System.out.println("Enter Game:"); String b = ins.readLine(); player player1 = new player(a,b); manager.makePersistent(player1); tx.commit(); } if(s.equals("delete")) { tx = manager.currentTransaction(); tx.begin(); System.out.println("Enter Name:"); String a = ins.readLine(); Extent extent = manager.getExtent (player.class,true); Query query = manager.newQuery (extent,"name == a"); query.declareParameters("String a"); Collection list1 = (Collection) query.execute(a); Iterator i = list1.iterator(); player player1 = null; while(i.hasNext()) { player1= (player)i.next(); manager.deletePersistent (player1); } query.close(list1); tx.commit(); } if(s.equals("find")) { tx = manager.currentTransaction(); tx.begin(); System.out.println("Enter Name:"); String a = ins.readLine(); Extent extent = manager.getExtent(player.class,true); Query query = manager.newQuery(extent,"name == a"); query.declareParameters("String a"); Collection list1 = (Collection)query.execute(a); Iterator i = list1.iterator(); player player1 = null; while(i.hasNext()) { player1= (player)i.next(); System.out.println(player1.getName()+".."+player1.getGame()); } query.close(list1); tx.commit(); } if(s.equals("update")) { tx = manager.currentTransaction(); tx.begin(); System.out.println("Change Name or Game"); String c = ins.readLine(); if(c.equals("name")) { System.out.println("Enter Game :"); String d = ins.readLine(); System.out.println("What is the new Name?"); String e = ins.readLine(); Extent extent = manager.getExtent (player.class,true); Query query = manager.newQuery (extent,"game == d"); query.declareParameters("String d"); Collection list1 = (Collection) query.execute(d); Iterator i = list1.iterator(); player player1 = null; while(i.hasNext()) { player1 = (player)i.next(); player1.setName(e); manager.makePersistent(player1); } query.close(list1); } if(c.equals("game")) { System.out.println("Enter Name :"); String d = ins.readLine(); System.out.println ("What is the new Game?"); String e = ins.readLine(); Extent extent = manager.getExtent(player.class,true); Query query = manager.newQuery(extent,"name == d"); query.declareParameters("String d"); Collection list1 = (Collection) query.execute(d); Iterator i = list1.iterator(); player player1 = null; while(i.hasNext()) { player1 = (player)i.next(); player1.setGame(e); manager.makePersistent(player1); } query.close(list1); } tx.commit(); } if(s.equals("showall")) { tx = manager.currentTransaction(); tx.begin(); Extent extent = manager.getExtent (player.class,true); Iterator it = extent.iterator(); while(it.hasNext()) { player player2 = (player) it.next(); System.out.println (player2.getName()+"---" +player2.getGame()); } tx.commit(); } }while(!s.equals("over")); } catch(Exception e1) { System.out.println(""+e1); } } }-------------------------------------------
We can use the enhanced class itself to compile and run the client program. This completes our two part tutorial on JDO.