odeled using foreign keys. (Each object in the database is stored with a unique object ID, derived invisibly by JRB. These object IDs become the unique keys by which objects can be referred to -- and therefore accessed -- by other objects.)
JRB lets you store more than just classes in the database; you can also store Java bytecodes. Consequently, you can store a Java class wholesale in the database, and a JRB application can load the class at run time. The JRB API defines a
DatabaseClassLoader
class for doing this.
However, befo
re your application can store any objects in a JRB-compliant database, you must first import the object's class into the database. You do this with the
jrb_import
tool, which reads the class definition (from a Java source file) and builds the necessary structures in the relational database.
Any classes you intend on importing into a database must implement the
PersistentObject
interface, which defines the methods that JRB applications will ultimately use to store the objects in and retrieve them from the database. When you turn the jrb_import tool loose on the class to be imported, the tool creates a source-code file into which has been written the actual source code needed to manipulate objects of the imported class in the database.
Once you've imported a class into the database, you can begin storing objects in the database. Objects in a JRB application pass through several "states" as the application moves them in and out of the database. Objects can be transient,
shadow, or persistent. A transient object is a "typical" Java object that your application has instantiated from some class. A persistent object is an object that has been stored in the database. (The JRB libraries include a variety of persistent classes from which you must derive all persistent objects.)
A shadow object is a partially loaded persistent object. That is, the shadow object has been instantiated, but its component variables have been initialized by JRB library routines with nulls or zeroes (depending on the variable type). Consequently, a shadow object is a persistent object that has merely been instantiated, and not loaded from the database.
As with the previous OO database systems I've reviewed, access to objects in a JRB database occurs within the bounds of a transaction. (An application can read objects from the database outside of a transaction, but updates and deletes are not allowed.) Shared modification of objects is dealt with through locks, and JRB provides three locking l
evels: shared, update, and exclusive. A JRB application will automatically acquire locks -- in this case, shared locks -- on objects accessed from within a transaction. A shared lock, therefore, serves as a kind of signal to other JRB applications accessing the same database that the object has been accessed from within a transaction. Placing a shared lock on an object, then, prevents the object from being modified by another application. Any number of applications can hold a shared lock on an object.
Next up the locking ladder is the update lock. Only one transaction at a time, and therefore only one application at a time, can hold an update lock on an object. However, an update lock does not exclude a shared lock. A JRB application will place an update lock on an object to signal its intent to modify that object.
To actually modify the object, the transaction must obtain an exclusive lock on the object. Only one transaction can hold an exclusive lock on the object, and an exclusive lock (as its
name suggests) excludes all other locks.
JRB provides a number of avenues a developer can follow to fine-tune an application's performance along the lines of both execution speed and memory consumption. For example, objects that are read from a JRB database are loaded into a cache maintained by the JRB run-time. This improves performance in cases where an unmodified object is reread from the database. The system can simply draw the object out of cache rather than read it from disk. Ordinarily, this cache is invisible to the programmer. However, JRB does allow some limited manipulation of the cache from your application. You can, for example, explicitly delete objects from the cache, allowing the application to run in a smaller memory footprint.
Additionally, JRB includes methods that permit your application to load only a portion of an array object. This allows the application to consume smaller amounts of memory (since less memory is allocated to the array at any given time).
Also, you can
fine-tune the database's space consumption on disk. For example, suppose you've declared a persistent class such that one of the member variables of the class is used for computation only. Since that variable is needed only at run time (and holds no persistent information), storing it in the database is simply wasting disk space. JRB lets you define the member variable as being transient. Transient member variables of persistent objects are not stored in the database and therefore do not waste storage space.
JRB is an interesting implementation of persistent OO technology. Because it consists of a thin Java run-time (most of the heavy work of lock resolution and transaction management is taken over by the back-end database), it is simple to set up and administer. A developer license for JRB is $500 ($1000 for a three-developer license). Contact the company for run-time license details.
Hard-core OO developers will also be interested in Ardent's full-blown OODBMS product, O2. A binding for O2 that
is syntactically equivalent to JRB is available, allowing migration of applications from a relational back-end arrangement to the O2 full OODBMS.
Product Information
Ardent Software
Westboro, MA
Phone: 800-545-4545
Phone: 303-294-0800
Fax: 303-293-8880
Internet: http://objects.unidata.com
illustration_link (21 Kbytes)

Java Relational Binding uses an import tool (jrb_import) to process a class for use by a JRB application.
Rick Grehan (
rgrehan@austin.metrowerks.com
) works for Metrowerks' Discover Products division. He is coauthor of The Client/Server Toolkit (NobleNet, 1996).