BRIDGING
JAVA OBJECTS AND RELATIONAL DATABASES
Author: Thomas Mahler, august 2001
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.
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.
To see if OJB is installed properly run build.sh junit (or build junit under windows).
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.
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
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.
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$