ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

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.)

  1. 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
  2. In the OJB_HOME/profile directory, modify the corresponding database profile file. For the Hypersonic database, the file is called hsqldb.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, and databaseUrlvariables are all incorrect in the OJB 0.9.7 distribution. Make sure the URLs are right after string substitutions are done.)

  3. If you have Ant installed, you can simply invoke ant prepare-testdb. Otherwise, OJB_HOME/bin contains both build.sh and build.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 the OJB_HOME/lib directory.)

  4. 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.