
Object-Relational Mapping with Apache Jakarta OJB
Pages: 1, 2, 3
2.4 Deploying and Running
2.4.1 Editing the Deployment Descriptor
repository.xml
is the OJB deployment descriptor. Its purpose is
very much like that of the ejb-jar.xml
descriptor. OJB comes with a sample
repository.xml
file that you can modify for your application. You
should copy the following files to your project directory:
repository.xml
, repository_internal.xml
,
repository.dtd
, and OJB.properties.
Example 9: A Sample repository.xml
File
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE descriptor-repository SYSTEM "repository.dtd" [
<!ENTITY user SYSTEM "repository_user.xml">
<!ENTITY internal SYSTEM "repository_internal.xml">
]>
<descriptor-repository version="0.9.6"
isolation-level="read-uncommitted">
<!-- The Default JDBC Connection. If a class-descriptor does not
specify its own JDBC Connection, the Connection specified here
will be used. -->
<jdbc-connection-descriptor
platform="Hsqldb"
jdbc-level="2.0"
driver="org.hsqldb.jdbcDriver"
protocol="jdbc"
subprotocol="hsqldb:hsql"
dbalias="//localhost"
username="sa"
password=""/>
<!-- include user defined mappings here -->
&user;
<!-- include ojb internal mappings here -->
&internal;
</descriptor-repository>
The sample repository.xml
file includes two XML fragments (external
entities), repository_internal.xml
and
repository_user.xml
. You have already copied
repository_internal.xml
to your project directory. What about
repository_user.xml
? It is the OJB descriptor fragment we have
covered in the previous sections. You need to create a file called
repository_user.xml
and put the mapping details inside. All three
XML files and fragments must be in your application's classpath.
2.4.2 Setup OJB Internal Tables
Before we can run our applications, we must set up the OJB internal tables.
This step is done once and is relatively painless. The steps below should be
helpful. (Assume OJB_HOME
points to where you've unzipped the OJB
distribution.)
Modify
OJB_HOME/build.properties
. At the beginning of the file, uncomment the appropriate database you are planning to use. If you plan to use Hypersonic database, that part of the properties file should look like this:Table 10: OJB
build.properties
profile=hsqldb #profile=mssqldb #profile=mysql #profile=db2 #profile=oracle #profile=msaccess #profile=postgresql #profile=informix #profile=sybase #profile=sapdb
In the
OJB_HOME/profile
directory, modify the corresponding database profile file. For the Hypersonic database, the file is calledhsqldb.profile
. In general, you only need to make sure that all of the database URLs are correct. In the case of Hypersonic, the file should be:Example 11: OJB Database Profile
dbmsName = Hsqldb jdbcLevel = 2.0 urlProtocol = jdbc urlSubprotocol = hsqldb:hsql urlDbalias = //localhost createDatabaseUrl = ${urlProtocol}:${urlSubprotocol}:${urlDbalias} buildDatabaseUrl = ${urlProtocol}:${urlSubprotocol}:${urlDbalias} databaseUrl = ${urlProtocol}:${urlSubprotocol}:${urlDbalias} databaseDriver = org.hsqldb.jdbcDriver databaseUser = sa databasePassword = databaseHost = 127.0.0.1
(Note: The
createDatabaseUrl
,buildDatabaseUrl
, anddatabaseUrl
variables are all incorrect in the OJB 0.9.7 distribution. Make sure the URLs are right after string substitutions are done.)If you have Ant installed, you can simply invoke
ant prepare-testdb
. Otherwise,OJB_HOME/bin
contains bothbuild.sh
andbuild.bat
scripts that invoke Ant, distributed with the OJB package. (If you are not using Hypersonic, make sure your JDBC driver is in the classpath or that the .jar file is copied over to theOJB_HOME/lib
directory.)You should see "BUILD SUCCESSFUL" at the end. Otherwise, check your database profile and the on-screen log messages.
2.4.3 The Test Application
JUnit is a good way to test your application and verify settings. This test
application shows the OJB classes we use to persist and query objects. They are
PersistenceBroker
, Criteria
, and Query
. To run the application, you should have
the OJB distribution .jar files in your CLASSPATH
. In addition, the
OJB.properties
file and OJB XML descriptor files should also be in
the CLASSPATH
.
Example 12: Test Application
public class EmployeeTest extends TestCase
{
private PersistenceBroker broker = null;
public EmployeeTest(String arg0)
{
super(arg0);
broker = PersistenceBrokerFactory.defaultPersistenceBroker();
}
public static void main(String[] args)
{
junit.textui.TestRunner.run(EmployeeTest.class);
}
public void testQuery() throws Exception
{
broker.beginTransaction();
Manager manager = newManager();
manager.setName("John Smith");
manager.setProjectNumber(new Integer(10));
broker.store(manager);
Employee employee = newEmployee();
employee.setName("David Cosby");
broker.store(employee);
broker.commitTransaction();
Criteria crit = new Criteria();
Query q = QueryFactory.newQuery(EmployeeImpl.class, crit);
Collection results = broker.getCollectionByQuery(q);
assertTrue(results.size() == 2);
}
private Employee newEmployee()
{
return new EmployeeImpl();
}
private Manager newManager()
{
return new ManagerImpl();
}
}
That's it. With only a few lines of extra code, your business objects can be made persistent without having to be remodeled to entity beans.
3. Conclusion
Free and robust persistence frameworks are available today. They have good object-relational mapping capabilities, so that developers can work on the object models that are most natural for the business requirements. Given the complexities of today's business applications, the capabilities provided by these frameworks should not be overlooked.
4. Appendix
It is often desirable to decouple your application from the specifics of a
persistence framework, so that you can easily switch frameworks in the future. I
recommend creating custom PersistenceManager
and Transaction
classes for this purpose. For example:
Example 13: PersistenceManager
and Transaction
Interfaces
/**
* The abstract base class for all PersistenceManager. It provides
* method to persist and object and to obtain the current
* transaction.
*/
public abstract class PersistenceManager
{
public static PersistenceManager getInstance()
{
return new OJBPersistenceManager();
}
public abstract void makePersistent(Object o)
throws PersistenceException;
public abstract Transaction currentTransaction()
throws PersistenceException;
}
/**
* A Transaction interface. It provides minimal support for
* beginning, committing, and rolling back a transaction.
*/
public interface Transaction
{
public void begin() throws PersistenceException;
public void commit() throws PersistenceException;
public void rollback() throws PersistenceException;
}
/**
* An OJB specific implementation of the PersistenceManager
* class.
*/
public class OJBPersistenceManager extends PersistenceManager
{
private PersistenceBroker broker = null;
public OJBPersistenceManager()
{
broker = PersistenceBrokerFactory.defaultPersistenceBroker();
}
public void makePersistent(Object o) throws PersistenceException
{
try
{
broker.store(o);
}
catch (PersistenceBrokerException e)
{
// rethrow PersistenceException
}
}
public Transaction currentTransaction() throws PersistenceException
{
return new OJBTransaction(broker);
}
}
/**
* An OJB specific implementation of the Transaction
* interface.
*/
public class OJBTransaction implements Transaction
{
private PersistenceBroker broker = null;
public OJBTransaction(PersistenceBroker broker)
{
this.broker = broker;
}
public void begin() throws PersistenceException
{
try
{
broker.beginTransaction();
}
catch(TransactionAbortedException e)
{
// rethrow PersistenceException
}
catch(TransactionInProgressException e)
{
// rethrow PersistenceException
}
}
public void commit() throws PersistenceException
{
try
{
broker.commitTransaction();
}
catch(TransactionAbortedException e)
{
// rethrow PersistenceException
}
catch(TransactionNotInProgressException e)
{
// rethrow PersistenceException
}
}
public void rollback() throws PersistenceException
{
try
{
broker.abortTransaction();
}
catch(TransactionNotInProgressException e)
{
// rethrow PersistenceException
}
}
}
After the above classes are created, it is very simple to convert the test application to use them:
Example 14: Example Using PersistenceManager
and Transaction
Interfaces
PersistenceManager pm = PersistenceManager.getInstance();
Transaction tx = pm.currentTransaction();
tx.begin();
Manager manager = newManager();
manager.setName("John Smith");
manager.setProjectNumber(new Integer(10));
pm.makePersistent(manager);
Employee employee = newEmployee();
employee.setName("David Cosby");
pm.makePersistent(employee);
tx.commit();
It looks surprisingly like JDO, doesn't it? With a little more effort, you can also hide the OJB query mechanism.
Charles Chan is a senior software developer and consultant at Finetix LLC.
Return to ONJava.com.
