OpenSubsystems

Business Components for Java Applications

Open Core

Implementing Support for a New Database

Last modified

$Author: bastafidli $
$Date: 2006/08/27 07:51:37 $
$Revision: 1.11 $
$RCSfile: implementation_newdb.html,v $

Open Core supports out of the box many databases. If the database you are interested in is not yet supported by Open Core it is a straigh forward process to implement such support. This document describes in detail steps required to add support for a new database into Open Core.

Adding New Libraries

Open Core is Java based framework. The default implementation of the persistence layer for already supported databases utilizes JDBC API. Regardless of your choice of communication API (e.g. JDBC or some other technology), you will need Java libraries (e.g. JDBC driver, custom database utilities) exposing such API to client programs. Most databases provide such library by default and there are also several third-party vendors of JDBC drivers for the most popular databases. Sun Microsystems also maintains database of available JDBC drivers.

If the libraries you have decided to use for your implementation are freely redistributable, we recommend to make them part of OpenSubsystems Externals and place them into

OpenSubsystems/external/[new database name]

directory. For example

OpenSubsystems/external/mysql

contains MySQL Connector/J libraries, which were tested to work with OpenSubsystems. It is also recommended that you rename all required files so that the filename doesn't contain version number of the particular release. This will make future upgrades easier since only the files will need to be updated and no other references will have to be modified.

Once the directory is created and all files are located inside, compress this directory into a single package

[new database name].zip

and commit this package into OpenSubsystems CVS. Do not commit the uncompressed directory into CVS to prevent issues related to maintaining many individual externaly supplied files. Add this directory into .cvsignore file located in OpenSubsystems/external directory and commit this file into CVS.

For more information about adding new libraries read the following article.

Setting up Classpath

Once the libraries are located, it is important to include them on a classpath so that OpenSubsystems can access them. If you decide to use just a regular JDBC driver, you need to include it only on your Eclipse runtime classpath. You can follow article describing how to run your application for a step by step instructions.

If you are using any custom libraries that you need to refer to in your code, you will need to include them on your project classpath. In Eclipse you can do so by going to Project menu and selecting Properties menu item. In the Project properties dialog select Java Build Path section from the list on the left and then on the Libraries tab you can add your custom libraries using Add JARs or Add External JARs buttons.

Open Core provides support for desktop applications and provide set of shell scripts to make launching such applications easier. It is recommended that you include the required libraries on the classpath set in these scripts to make them available for the application. Modify all files starting with coreclasspath to include the required libraries. For example for Windows you need to modify script coreclasspath.bat View source

Implementation

org.opensubsystems.core.persist.db.Database

Each supported database has to be uniquely identified by constants defined in the Database interface. The identification consists of numeric constant and a string, which will be used to construct full names of database dependent classes. Choose carefully especially the string constant since later on you will have to use it as part of class names and therefore it should follow OpenSubsystems coding conventions. For example HSQLDB database is defined as

   /**
    * The current database is HSQLDB
    */
   int HSQLDB_DATABASE_TYPE = 1;
   
   /**
    * The current database is HSQLDB
    */
   String HSQLDB_DATABASE_TYPE_IDENTIFIER = "HsqlDB";
               
org.opensubsystems.core.persist.db.[dbidentifier].[DbIdentifier]DatabaseImpl

Each supported database has some behavior that is different from other databases. This behavior may include for example way how to create database user or a name of a function call to find out current time. This database specific behavior is encapsulated in a class that implements

org.opensubsystems.core.persist.db.Database View source

interface. Create new class

org.opensubsystems.core.persist.db.[dbidentifier].[DbIdentifier]DatabaseImpl

in the

\OpenSubsystems\sources\code\java

directory derived from

org.opensubsystems.core.persist.db.DatabaseImpl View source

class where the dbidentifier is the string constant you have added in the Database interface in the previous step. Implement all methods required by the interface and the base class. Override any methods from the base class that require different behavior for your database. For example behavior specific to HSQLDB database is implemented in class

org.opensubsystems.core.persist.db.hsqldb.HsqlDBDatabaseImpl View source

org.opensubsystems.core.persist.db.DatabaseImpl

At this point you have defined unique identifier for your database and implemented any database specific behavior needed by OpenSubsystems. At this time the key step is to tell OpenSubsystems when to use the newly defined database class. This is in general done based on the database specific JDBC driver or url defined in the configuration file. First, define substring of JDBC driver class name or url, which can uniquely identify your database. For example for HSQLDB the substring of JDBC driver class name is

   /**
    * String used to identify HSQLDB JDBC driver
    */
   private static final String HSQLDB_DRIVER_IDENTIFIER = ".hsqldb.";
                  
Next modify the getInstance() method in this class and add condition to check for the uniquely identifying substring. Once the substring was identified, set the default database instance to instance of your newly defined database specific class. For example for HSQLDB the condition is
   if (strDriver.indexOf(HSQLDB_DRIVER_IDENTIFIER) != -1)
   {
      setInstance(new HsqlDBDatabaseImpl());
   }
               
org.opensubsystems.core.persist.db.[dbidentifier].[DbIdentifier]VersionedDatabaseSchema

Open Core uses table with default name BF_SCHEMA to track what database schemas software system built on top of it contains. This table is by default created by

org.opensubsystems.core.persist.db.VersionedDatabaseSchema View source

class. If your database requires non standard way or syntax to create database tables you will have to create class

org.opensubsystems.core.persist.db.[dbidentifier].[DbIdentifier]VersionedDatabaseSchema

derived from the default VersionedDatabaseSchema class. In the create() method of this class you will have to create the schema tracking table. For example Microsoft SQL Server specific implementation is in

org.opensubsystems.core.persist.db.mssql.MSSQLVersionedDatabaseSchema View source

org.opensubsystems.core.persist.db.[dbidentifier].[DbIdentifier]DataUtils

Architecture of OpenSubsystems suggests that unique identifiers of data objects should be database generated. Open Core also uses database generated timestamp to implement optimistic locking. It is advisable to implement set of utility methods to simplify these operations for writing persistence logic for your database. For example Microsoft SQL Server specific implementation of such functionality is in

org.opensubsystems.core.persist.db.mssql.MSSQLDataUtils View source

Configuration

oss.properties

OpenSubsystems is by default using oss.properties View source as it's main configuration file when running production applications. Edit this file and add here all properties required by OpenSubsystems to access your database. When configuring database url and user credentials to access the database you should consider using different values than those used for testing. Before committing this file into CVS make sure that all the newly added properties are commented out unless your database becomes the default OpenSubsystems database.

osstest.properties

OpenSubsystems is by default using osstest.properties View source as it's main configuration file when running JUnit tests. Edit this file and add here all properties required by OpenSubsystems to access your database during test. When configuring database url and user credentials to access the database you should consider using different values than those used for production. Before committing this file into CVS make sure that all the newly added properties are commented out unless your database becomes the default OpenSubsystems database.

osstest[dbidentifier].properties

Copy file osstest.properties into a new file

OpenSubsystems\sources\config\osstest[dbidentifier].properties

This file will be used when running all OpenSubsystems JUnit tests against your database. Delete from this file all sections related to other databases except the one added in the previous step. Uncomment the recently added section, which should be the only set of database related properties left in this file before commiting it into CVS. For example configuration file for HSQLDB is in the

\OpenSubsystems\sources\config\osstesthsqldb.properties View source

JUnit Tests

org.opensubsystems.[DbIdentifier]Tests

Create new class

org.opensubsystems.[DbIdentifier]Tests

in the

\OpenSubsystems\sources\tests\java

directory. This class will be used to conveniently run all OpenSubsystems JUnit tests against your database without having to modify any configuration files when working with multiple databases at the same time. Use one of the existing classes located in the same directory as an example. As a parameter to the setPropertyFileName call use name of the

osstest[dbidentifier].properties

file you have created in the previous step. For example tests for HSQLDB can be conveniently run using class

org.opensubsystems.HsqlDBTests View source

org.opensubsystems.core.persist.db.driver.[dbidentifier].[DbIdentifier]DatabaseTestSchema

Open Core comes with about 150 JUnit tests that can be immediately used to test its functionality with your new database. In order for these tests to function properly you will have to create database schema class. The responsibility of the database schema is to abstract the database specific functionality in order to make the tests generic but implement it in a database specific way. Create class

org.opensubsystems.core.persist.db.driver.[dbidentifier].[DbIdentifier]DatabaseTestSchema

in the

\OpenSubsystems\sources\tests\java

directory. This class must be derived from the

org.opensubsystems.core.persist.db.driver.DatabaseTestSchema View source

class and implement all the unimplemented methods. It may also need to override some already defined methods to provide database specific implementation. Use as an example one of the existing classes for other supported databases located in sibling directories. For example database schema for HSQLDB tests is implemented in class

org.opensubsystems.core.persist.db.driver.hsqldb.HsqlDBDatabaseTestSchema View source

org.opensubsystems.core.persist.db.DatabaseSchemaClassFactoryTest

You will have to modify every test in JUnit test case

org.opensubsystems.core.persist.db.DatabaseSchemaClassFactoryTest View source

to take into account your new database. This test case is testing if your newly defined test database schema can be correctly instantiated when Open Core detects that your new database is active. Add new case statement into every switch in a similar fashion as the existing case statemens in that test.

org.opensubsystems.core.persist.db.DatabaseSchemaManagerTest

You will have to modify every test in JUnit test case

org.opensubsystems.core.persist.db.DatabaseSchemaManagerTest View source

to take into account your new database. This is another test case testing if your newly defined test database schema can be correctly instantiated when Open Core detects that your new database is active. Add new case statement into every switch in a similar fashion as the existing case statemens in that test.