ObJectRelationalBridge
BRIDGING JAVA OBJECTS AND RELATIONAL DATABASES


Getting started with the OJB C/S architecture:

Author: Thomas Mahler, august 2001

abstract

This document presents an overview of the OJB Client/Server architecture. It then shows how to run the demo applications. In a final section I give some hints how to use OJB in real world environments.

architecture

In it's early days OJB was a simple classlibrary for mapping objects to relational databases. It did not cover the handling conflicts between concurrently operating multiple clients. It was also not scalable if it was used within an application server. The usage of OJB classes from a client application is depicted in the following class diagram:






Today OJB ships with a scalable Client/Server architecture that addresses the shortcomings mentioned.

This new architecture splits OJB into two parts: a client, the PersistenceBrokerClient. And on the other Side a PersistenceBrokerServer. The PersistenceBrokerClient implements the PersistenceBroker interface as the single VM PersistenceBrokerImpl. But is does no persistence operations at all. It rather works as a proxy that delegates all calls to the PersistenceBrokerServer.

User Applications using OJB (like the OJB ODMG and JDO implementations) always work against the PersistenceBroker Interface. They use a Factory (PersistenceBrokerFactory) to obtain their PersistenceBroker objects. The usage of factory and interface allow to keep the operating mode (with a local PersistenceBrokerImpl or with a remote PersistenceBrokerServer) complety transparent for the user-applications. The factory is configured by a properties-file.
[side note for pattern enthusiasts: This implementation is a variant of the AbstractFactory pattern. Instead of using a number of concrete factories to pruce different targets types we use only one configurable Factory. I call this the ConfigurableFactory pattern.]

The PersistenceBrokerServer is a TCP/IP based multithreaded Server. The Server maintains a pool of PersistenceBrokerImpl's that do the real database work.

The PersistenceBrokerClient and the PersistenceBrokerServer use a simple protocol for communication. The client sends a ojb.broker.server.Request object to the server. The Request object encapsulates the method call with all parameters and the index of the PersistenceBrokerImpl to be used by the server. The marshalling is done with Java Serialization using an ObjectOutputStream over a socket connection.
The Server delegates all work to threaded RequestProcessors. The RequestProcessor unmarshals the incoming request (reading from an ObjectInputStream). Then it determines the PersistenceBrokerImpl object to be used by the received index. This PersistenceBrokerImpl object then performs the request a specified by the client. The resulting Object (whether a resulting collection, a single object, a null value or an exception) is then sent back to the client. The PersistenceBrokerClient unmarshals the incoming object and returns to the calling application.

The overall design is shown in the following class diagram:





The server's gross layout of dispatching incoming requests to worker threads has been adopted from a simple HTTP server implementation. It is a proven design for servers handling a large number of clients.

The architecture described above allows to run many clients against a single server. But the new OJB architecture even allows to run several PersistenceBrokerServers in parallel. This can be helpful if OJB is to be used within a heavy duty application server scenario.
The PersistenceBrokerClients can be configured to use all available OJB servers in a roundrobin sequence. This results in a loadbalancing between the servers.

Running parallel PersistenceBrokerServers requires additional coordination, as explained by the following example. If a ODMG (or JDO) transaction commits changes to a certain object the changes are made persistent to the underlying RDBMS and they are reflected in the cache of the PersistenceBrokerServer used for this transcation.
But the cache of a second PersistenceBrokerServer in the cluster may still hold an old copy of the changed object. A client requesting the object from the second server would receive an invalid copy which obviously could result in data corruption.
To avoid such problems, OJB provides a cache synchronisation mechanism. On commiting an object to one server all other servers are requested to invalidate this object (i.e. to remove it from theirs caches).

The overall picture how an application may be distributed accross multiple clients, multiple servers and multiple RDBMS backends is shown in the following schema.






running the examples

  1. To see if OJB is installed properly run build.sh junit (or build junit under windows).

  2. Edit the file build/test/ojb/OJB.properties and change the line useServer=false to useServer=true. If you want to run the server on a port different from the default port 2001 you also have to change the line BrokerServers=localhost\:2001 accordingly.
    Run build.sh tests to activate these changes.

  3. To start the OJB server execute the server.sh (or server.bat under windows). By default the server operates on port 2001. If you must use a different port you can edit the script file (see file server2.sh for an example). The server will start up with a screen like this:
    [BOOT] WARN: no port specified, will use default: 2001
    [BOOT] INFO: OJB.properties: /home/tom/ojb/build/test/ojb/OJB.properties
    [BOOT] INFO: PersistenceBrokerServer is accepting connections on port 2001

  4. Now again run the Junit tests by build.sh junit from new terminal window (or dos box). You will notice that all database messages (if any) go to the server terminal and all result messages to the junit terminal.
    You might experiment with the logging settings for the PersistenceBrokerClient and the PersistenceBrokerServer in the OJB.properties file. Change the lines
    # Logger for PersistenceBrokerClient
    ojb.broker.server.PersistenceBrokerClient.LogLevel=WARN
    # Logger for Serverside RequestProcessor
    ojb.broker.server.RequestProcessor.LogLevel=WARN
    to
    # Logger for PersistenceBrokerClient
    ojb.broker.server.PersistenceBrokerClient.LogLevel=DEBUG
    # Logger for Serverside RequestProcessor
    ojb.broker.server.RequestProcessor.LogLevel=DEBUG
    to get an impression on the interaction of client and server. You must again execute build.sh tests to activate these changes.

usage in real world environments

To run OJB in client/server mode with multiple clients and multiple servers you first have to install OJB on all machines (see above). You then have to edit the file OJB.properties on all machines. To learn more about the OJB.properties file follow this link.

Say you have to servers luna and stella with the repository.xml file residing in /usr/local/ojb. The properties file on all machines (all clients and all servers) will have entries like:

#OJB Configuration
#Tue Jun 26 20:31:43 CEST 2001
BrokerServers=stella\:2001,luna\:2001
useServer=true
repositoryFile=/usr/local/ojb/repository.xml

This configuration will allow a loadbalancing of all client requests between luna and stella.


$FOOTER$