The Apache DB Project
ObJectRelationalBridge

OJB

Downloads

Documentation

Development

Translated (Web)

Deployment

Things needed for deploying OJB

This section enumerates all things needed to deploy OJB.

1. The OJB binary jar archive

You need a db-ojb-<version>.jar file containing the compiled OJB library.
This jar files contains all OJB code neccessary in production level environments. It does not contain any test code. It also does not contain any configuration data. You'll find this file in the lib directory of the binary distribution. If you are working with the source distribution you can assemble the binary jar archive By calling build[.sh] jar . This ant task generates the binary jar to the dist directory.

2. Configuration data

OJB needs two kinds of configuration data:

  1. configuration of the OJB runtime environment. This data is stored in a file named OJB.properties. Learn more about this file here.
  2. Configuration of the MetaData layer. This data is stored in file named repository.xml (and several included files). Learn more about this file here.

These configuration files are read in through ClassLoader resource lookup and must therefore be placed on the classpath.

3. Additional jar archives

OJB depends on several other jar archives. These jar files are shipped in the db-ojb-<version>/lib directory. These jar files are listed here.

Some of these jar files are only used during build-time and need not to be be deployed in runtime environments.
Apart from wasting disk space they do no harm. If you don't care you just take all jars from db-ojb-<version>/lib.
If you do care, here is the list of jars you can omit during runtime:

  • ant.jar
  • antlr.debug.jar
  • antlr_compiletime.jar
  • junit.jar
  • optional.jar
  • xalan.jar
  • crossdb.jar
  • ejb.jar
  • servlet.jar
  • jakarta-regexp-xxx.jar
  • torque-xxx.jar
  • velocity-xxx.jar

4. Don't forget the JDBC driver

The repository.xml defines JDBC Connections to your runtime databases. To use the declared JDBC drivers the respective jar archives must also be present in the classpath. Refer to the documentation of your databases.

In the following sections I will describe how to deploy these items for specific runtime environments.

Deployment in standalone applications

Deploying OJB for standalone applications is most simple. If you follow these four steps your application will be up in a few minutes.

  1. Add db-ojb-<version>.jar to the classpath
  2. place OJB.properties and repository.xml files on the classpath
  3. Add the additional runtime jar archives to the classpath.
  4. Add your JDBC drivers jar archive to the classpath.
Deployment in servlet based applications

Generally speaking the four steps described in the previous section have to be followed also in Servlet / JSP based environments. The exact details may differ for your specific Servlet container, but the general concepts should be quite similar.

  1. Deploy db-ojb-<version>.jar with your servlet applications WAR file.
    The WAR format specifies that application specific jars are to be placed in a directory WEB-INF/lib. Place db-ojb-<version>.jar to this directory.
  2. Deploy OJB.properties and repository.xml with your servlet applications WAR file.
    The WAR format specifies that Servlet classes are to be placed in a directory WEB-INF/classes. The OJB configuration files have to be in this directory.
  3. Add the additional runtime jar archives to WEB-INF/lib too.
  4. Add your JDBC drivers jar archive to WEB-INF/lib.

By executing build[.sh] war you can generate a sample servlet application assembled to a valid WAR file. The resulting ojb-servlet.war file is written to the dist directory. You can deploy this WAR file to your servlet engine or unzip it to have a look at its directory structure.
you can also use the target war as a starting point for your own deployment scripts.

Deployment in EJB based applications

The above mentioned guidelines concerning jar files and placing of the OJB.properties and the repository.xml are valid for EJB environments as well. But apart from these basic steps you'll have to perform some additional configurations to integrate OJB into the container mechanisms.

The instructions to make OJB running within your application server should be similar for all server. So the following instructions for JBoss should be useful for all user. E.g. most OJB.properties file settings are the same for all application server.

There are some topics you should examine very carefully:

  • Connection handling: Lookup DataSource from your AppServer, only these connections will be enlisted in running transactions
  • Caching: Do you need distributed caching?
  • Locking: Do you need distributed locking (e.g. when using odmg-api)?

Example: Instructions for JBoss

The eight step guide to felicity (or insanity in some cases)

1. Get the missed jar files
As a result of different licence models we could not ship all necessary jar files with OJB. Thus you need some extra jar files to make the ejb examples target run:

  • JBoss jar files to support the OJB mbeans (jars depend on used version, so trial and error)
  • jboss-j2ee.jar or use j2ee jars fron SUN
  • XDoclet jar file and modules for generating ejb's and jboss deployment descriptor (modules: jboss, jmx, ejb, web)
Put these jar files in the lib directory of OJB if you want to generate the ejb-examples.

2. Bind OJB api-main classes to JNDI
To make the OJB api's accessible via JNDI, we need to bind them to JNDI. How to do that depends on the used environment. In JBoss you can use mbean classes to do that org.apache.ojb.jboss.PBFactory and org.apache.ojb.jboss.ODMGFactory.
Let JBoss know about the new mbeans, so declare them in a jboss-service.xml file:

<?xml version="1.0" encoding="UTF-8"?>

<server>
    <mbean code="org.apache.ojb.jboss.PBFactory"
        name="DefaultDomain:service=PBAPI,name=ojb/PBAPI">
        <depends>jboss.jca:service=RARDeployer</depends>
        <attribute name="JndiName">ojb/PBAPI</attribute>
    </mbean>

    <mbean code="org.apache.ojb.jboss.ODMGFactory"
    name="DefaultDomain:service=ODMG,name=ojb/defaultODMG">
        <depends>jboss.jca:service=RARDeployer</depends>
        <attribute name="JndiName">ojb/defaultODMG</attribute>
    </mbean>
</server>
These step makes OJB accessible via JNDI. In other application server you should do a similar step and bind the OJB api-main classes to JNDI. The main classes to bind are:
  • org.apache.ojb.broker.core.PersistenceBrokerFactoryFactory for PB-api. Make method PersistenceBrokerFactoryFactory.instance() accessible.
  • org.apache.ojb.odmg.OJBJ2EE_2 for ODMG-api. Make method OJBJ2EE_2.getInstance() accessible.

3. Enclose all libraries OJB depend on and put them into a .sar-directory
Make a ojb.sar directory under [jboss.home]/server/default/deploy
Add a META-INF directory under ojb.sar.
Put a simple MANIFEST.MF file and the jboss-service.xml file in this directory.
To make OJB run and (re-)deployable you have to put all libraries OJB depend on into the ojb.sar directory:

  • The jakarta commons libraries files (all commons-xxx.jar)
  • The antlr jar file (antlr-xxx.jar)
(This was tested with jboss 3.2.2)

4. Prepare OJB code base
With bin\build.bat prepare-jboss jar using windows or
bin/build.sh prepare-jboss jar we rebuild OJB jars including the jboss MBeans.
The prepare-jboss target copy the jboss MBeans to the OJB code base. After running the jar target you could find the new db-ojb-xxx.jar, including the MBeans, in the dist directory.
(If you need a OJB jar file without the MBeans, clean the target directory e.g. by calling the clean ant target and invoke the jar ant target again).
Copy the db-ojb-xxx.jar file into the ojb.sar directory.

5. Copy OJB configuration files into the ojb.sar directory
OJB.properties, repository.dtd, repository.xml, repository_internal.xml, repository_database.xml, repository_ejb.xml (if you want to run the ejb examples). The repository.xml should rather look like:

<?xml version="1.0" encoding="UTF-8"?>
<!-- This is a sample metadata repository for the ObJectBridge
System. Use this file as a template for building your own
mappings-->

<!-- defining entities for include-files -->
<!DOCTYPE descriptor-repository SYSTEM "repository.dtd" [
<!ENTITY database SYSTEM "repository_database.xml">
<!ENTITY internal SYSTEM "repository_internal.xml">
<!ENTITY junit SYSTEM "repository_junit.xml">
<!ENTITY user SYSTEM "repository_user.xml">
<!ENTITY ejb SYSTEM "repository_ejb.xml">
<!ENTITY jdo SYSTEM "repository_jdo.xml">
]>


<descriptor-repository version="1.0"
                    isolation-level="read-uncommitted">

    <!-- include all used database connections -->
    &database;

    <!-- include ojb internal mappings here -->
    &internal;

    <!-- include mappings for the EJB-examples -->
    &ejb;

</descriptor-repository>

6. Adapt OJB.properties file

If the PB-api is the only persistence API being used (no ODMG nor JDO), and it is only being used in a managed environment, it is recommended to use a special PersistenceBrokerFactory class, which enables PersistenceBroker instances to participate in the running JTA transaction (e.g. this makes PBStateListener proper work in managed environments and enables use of 'autoSync' property in ObjectCacheDefaultImpl):

PersistenceBrokerFactoryClass=
org.apache.ojb.broker.core.PersistenceBrokerFactorySyncImpl
Don't use this setting in conjunction with the ODMG-api.

Your OJB.properties file need the following additional settings to work within managed environments (apply to all used api):

...
ConnectionFactoryClass=
org.apache.ojb.broker.accesslayer.ConnectionFactoryManagedImpl

...
OJBTxManagerClass=org.apache.ojb.odmg.JTATxManager

...
JTATransactionManagerClass=
org.apache.ojb.otm.transaction.factory.JBossTransactionManagerFactory

7a. Declare datasources in the repository (repository_database) file and do additional configuration
Do only use DataSource from the application server to connect your databases.
NOTE: We strongly recommend to use JBoss 3.2.2 or higher of the 3.x series of JBoss. With earlier versions of 3.x we got Statement/Connection resource problems when running some ejb stress tests. As workaround we introduce a jboss specific attribute eager-release for version before 3.2.2, but it seems that this attribute can cause side-effects. Again, this problem seems to be fixed in 3.2.2.

<!-- Datasource example -->
<jdbc-connection-descriptor
    jcd-alias="default"
    default-connection="true"
    platform="Sapdb"
    jdbc-level="2.0"
    jndi-datasource-name="java:DefaultDS"
    username="sa"
    password=""
    eager-release="false"
    batch-mode="false"
    useAutoCommit="0"
    ignoreAutoCommitExceptions="false"
>
    <object-cache class="org.apache.ojb.broker.cache.ObjectCacheDefaultImpl">
            <attribute attribute-name="timeout" attribute-value="900"/>
            <attribute attribute-name="autoSync" attribute-value="true"/>
     </object-cache>

    <sequence-manager className=
    "org.apache.ojb.broker.util.sequence.SequenceManagerNextValImpl">
    </sequence-manager>
</jdbc-connection-descriptor>
The attribute useAutoCommit="0" is mandatory in managed environments, because it's in most cases not allowed to change autoCommit state.

In managed environments you can't use the default sequence manager (SequenceManagerHighLowImpl) of OJB. For alternative sequence manager implemetation see here.

7b. Take care of caching
Very important thing is cache synchronization with the database. When using the ODMG-api or PB-api (with special PBF (see 6.) setting) it's possible to use all ObjectCache implementations as long as OJB doesn't run in a clustered mode. When the ObjectCacheDefaultImpl cache implementation was used it's recommended to enable the autoSync mode.
In clustered environments (OJB run on different AppServer nodes) you need a distributed ObjectCache or you should use a local/empty cache like
ObjectCacheClass=org.apache.ojb.broker.cache.ObjectCachePerBrokerImpl
or
ObjectCacheClass=org.apache.ojb.broker.cache.ObjectCacheEmptyImpl. The cache is pluggable, so you can write your own ObjectCache implementation to accomplish your expectations.

More info you can find in clustering and ObjectCache topic.

7c. Take care of locking
If the used api supports Object Locking (e.g. ODMG-api), in clustered environments (OJB run on different AppServer nodes) a distributed lock management is necessary.

[7d. How to deploy ojb test hsqldb database to jboss]
After creating the database with bin\build.bat prepare-testdb or bin/build.sh prepare-testdb.
Take the generated OJB.script file from .../target/test and rename the file to default.script. Replace the jboss default.script file in ...\jboss-3.x.y\server\default\db\hypersonic with this file.

8a. Inside your EJB's you can get a handle on the ODMG like this:

ODMGFactory factory =
(ODMGFactory) context.lookup("java:/ojb/defaultODMG");
odmg = factory.getInstance();

8b. Inside your EJB's you can get a handle on the PB like this:

context = new InitialContext();
pbf = ((PBFactoryIF) context.lookup(
    PBFactoryIF.PBFACTORY_JNDI_NAME)).getInstance();

Check out the ejb's provided in the OJB distro at: [db-ojb]/src/ejb/org/apache/ojb/ejb for an example of working beans.

This solution should be re-deployable in jboss. If you will get any problems, please let me know.

8c. OJB logging within JBoss
Jboss use log4j as standard logging api.
In summary, to use log4j logging with OJB within jBoss,

1) in OJB.properties set

LoggerClass=org.apache.ojb.broker.util.logging.Log4jLoggerImpl
There is no need for a separate log4j.properties file of OJB-specific log4j settings (in fact the OJB.properties setting LoggerConfigFile is ignored). Instead, the jBoss log4j configuration file must be used:

2) in JBOSS_HOME/server/default/conf/log4j.xml,
define appenders and add categories to add or filter logging of desired OJB packages, following the numerous examples in that file. For example,

<category name="org.apache.ojb">
      <priority value="DEBUG" />
      <appender-ref ref="CONSOLE"/>
      <appender-ref ref="FILE"/>
    </category>

<category name="org.apache.ojb.broker.metadata.RepositoryXmlHandler">
      <priority value="ERROR" />
      <appender-ref ref="CONSOLE"/>
      <appender-ref ref="FILE"/>
     </category>

Build the OJB sample session beans

The OJB source distribution was shipped with a bunch of sample beans. We are using xdoclet to build the necessary classes and deployment descriptors.

To run xdoclet properly you need the following xdoclet jar files in [db-ojb]/lib directory (xdoclet version 1.2xx or higher):

    xdoclet-xxx.jar
    xdoclet-ejb-module-xxx.jar
    xdoclet-jboss-module-xxx.jar
    xdoclet-jmx-module-xxx.jar
    xdoclet-web-module-xxx.jar
    xdoclet-xjavadoc-module-xxx.jar

You could find the source code of the beans under
[db-ojb]/src/ejb/org/apache/ojb/ejb
and after running the ejb-examples ant target (see below), you will find the complete sources (including the generated interfaces) under
[db-ojb]/target/srcejb
in three sub-dirs.

Run the following ant target

bin/build.sh ejb-examples
or
bin\build.bat ejb-examples
to generate the the bean and client jars prepared for use in JBoss. If you using a different application server, you have to modifiy the xdoclet ant target in [db-ojb]/build-xdoclet.xml to generate files specified for your application server. See xdoclet documentation for further information.

After running the ant target you will find a db-ojb-XXX-beans.jar and a db-ojb-XXX-client.jar in the [db-ojb]/dist directory. Put the bean jar in the ojb.sar directory.
To run the ejb-example test cases use the org.apache.ojb.ejb.AllTests class.

NOTE:
When using JBoss 3.2.x the generated beans cause start up problems (re-deployment works fine). The problem is that in JBoss 3.2.x an ejb shouldn't be deployed until its declared invokers have started. Thus the jboss.xml file in the generated db-ojb-XXX-beans.jar needs a new element called 'depends' in each session bean declaration:

...
<session>
    <ejb-name>ODMGSessionBean</ejb-name>
    <jndi-name>org.apache.ojb.ejb.ODMGSessionBean</jndi-name>
    <local-jndi-name>org.apache.ojb.ejb.ODMGSessionBeanLocal</local-jndi-name>
    <depends optional-attribute-name="Invoker">jboss:service=invoker,type=jrmp</depends>
</session>
...
We hope with the next version of xdoclet this can be done automatic.
(Many thanks to Alex Bates)

How to run client org.apache.ojb.ejb.AllTests
Numerous jars are required for the client. One possibility is to modify build.bat/build.sh to set this up properly and called it e.g. .\runEJBClient.bat. A sample srict could look like this:

@echo off
REM Please let JAVA_HOME point to your JDK base directory
if "%JAVA_HOME%" == "" set JAVA_HOME=C:\j2sdk1.4.1
set JAVA=%JAVA_HOME%\bin\java
set JBOSS_HOME=D:\jboss-3.0.6
set cp=
for %%i in (%JBOSS_HOME%\client\*.jar) do call bin\cp.bat %%i
for %%i in (dist\*.jar) do call bin\cp.bat %%i
for %%i in (lib\*.jar) do call bin\cp.bat %%i
"%JAVA%" -classpath "%CP%" org.apache.ojb.ejb.AllTests

Instructions for Weblogic

(Thanks Christophe Lombart and Lucy Zhao)

  • Add the OJB jar files and depedencies into the Weblogic classpath
  • Compile the following classes (see at the end of this section) and add them to the weblogic classpath. This allows to access the PB-api via JNDI lookup.
  • Register via the weblogic console the startup class (see OjbPbStartup class below). The JNDI name and the OJB.properties file path can be specified as parameters in this startup class.

    To use the ODMG-api you have to write a similar startup class. This shouldn't be too complicated. Take a look in org.apache.ojb.jboss package (dir src/connector/main). Here you could find the jboss mbeans. All you have to do is bound a similar class to JNDI in weblogic.
    Implement ODMGJ2EEFactory Interface in your class bound this class to JNDI (in the ejb-examples the beans try to lookup the Implementation instance via "java:/ojb/defaultODMG"). Your ODMGFactory class should implement this method
    public Implementation getInstance()
    {
        return OJBJ2EE_2.getInstance();
    }
    
  • As usual create the connection pool and the datasource.
  • Prepare the OJB.properties file. Should be similar to jboss. Expect the following entry:
    ...
    # Weblogic Transaction Manager Factory
    JTATransactionManagerClass=
    org.apache.ojb.odmg.transaction.WeblogicTransactionManagerFactory
    
  • Modify the connection information in the repository.xml (specify the datasource name):
    <jdbc-connection-descriptor
        jcd-alias="default"
        default-connection="true"
           platform="Sapdb"
           jdbc-level="2.0"
           jndi-datasource-name="datasource_demodb"
        eager-release="false"
        batch-mode="false"
        useAutoCommit="0"
        ignoreAutoCommitExceptions="false"
    >
    
        <sequence-manager
            className=
    "org.apache.ojb.broker.util.sequence.SequenceManagerNextValImpl">
          <attribute attribute-name="grabSize" attribute-value="20"/>
        </sequence-manager>
    
    </jdbc-connection-descriptor>
    

Write a session bean similar to thoses provided for the JBOSS samples. It is also possible to use the ejb-example beans doing minor modifications when the JNDI lookup was done.

Write an OJB startup class can look like (I couldn't test this sample class, so don't know if it will work ;-)):

package org.apache.ojb.weblogic;

import javax.naming.*;

import org.apache.ojb.broker.core.PersistenceBrokerFactoryFactory;
import org.apache.ojb.broker.core.PersistenceBrokerFactoryIF;

import weblogic.common.T3ServicesDef;
import weblogic.common.T3StartupDef;
import java.util.Hashtable;

/**
 * This startup class created and binds an instance of a
 * PersistenceBrokerFactoryIF into JNDI.
 */
public class OjbPbStartup
    implements T3StartupDef, OjbPbFactory, Serializable
{
    private String defaultPropsFile =
        "org/apache/ojb/weblogic/OJB.properties";

    public void setServices (T3ServicesDef services)
    {
    }

    public PersistenceBrokerFactoryIF getInstance()
    {
        return PersistenceBrokerFactoryFactory.instance();
    }

    public String startup (String name, Hashtable args)
        throws Exception
    {

        try
        {
            String jndiName = (String)args.get ("jndiname");
            if (jndiName == null || jndiName.length () == 0)
                jndiName = OjbPbFactory.DEFAULT_JNDI_NAME;

            String propsFile = (String)args.get ("propsfile");
            if (propsFile == null || propsFile.length () == 0)
            {
                System.setProperty("OJB.properties", defaultPropsFile  );
            }
            else
            {
                System.setProperty("OJB.properties", propsFile  );
            }

            InitialContext ctx = new InitialContext ();
            bind (ctx, jndiName, this);

            // return a message for logging
            return "Bound OJB PersistenceBrokerFactoryIF to " + jndiName;
        }
        catch (Exception e)
        {
            e.printStackTrace();
            // return a message for logging
            return
            "Startup Class error: impossible to bind OJB PB factory";
        }
    }

    private void bind(Context ctx, String name, Object val)
            throws NamingException
    {
        Name n;
        for (n = ctx.getNameParser("").parse(name);
            n.size() > 1; n = n.getSuffix(1))
        {
            String ctxName = n.get(0);
            try
            {
                ctx = (Context) ctx.lookup(ctxName);
            }
            catch (NameNotFoundException namenotfoundexception)
            {
                ctx = ctx.createSubcontext(ctxName);
            }
        }
        ctx.bind(n.get(0), val);
    }
}
The used OjbPbFactory interface:
package org.apache.ojb.weblogic;

import org.apache.ojb.broker.core.PersistenceBrokerFactoryIF;

public interface OjbPbFactory
{
    public static String DEFAULT_JNDI_NAME = "PBFactory";
    public PersistenceBrokerFactoryIF getInstance();
}


Copyright © 1999-2003, Apache Software Foundation