Persistent Objects in Java Code
Status: Alpha
Brought to you by:
guenne
Persistent Objects for Java
===========================
License: GNU Lesser General Public License
Requirements
------------
- Java version 1.5 or newer
- GNU Getopt for Java (included -- see lib/README)
- JDBC driver
Additional requirements for the PObjForm/PObjSearch library
-----------------------------------------------------------
- Servlet Java Classes
Additional requirements for compilation
---------------------------------------
- Apache Ant 1.6 or newer
- Checkstyle (included -- see lib/README)
Optional requirements
---------------------
- Apache DBCP (for de.mguennewig.pobjects.optional.BasicContainerPool)
Table of Contents
=================
1. Introduction
2. Basic Concepts
3. Examples
4. Package Overview
5. Compiling from Source
6. Thread-safety and concurrency
7. References
1. Introduction
===============
Persistent Objects for Java is a framework for storing object data
in a RDBMS. Or, if one starts with a database, a framework that
presents relational data as a set of objects. It consists of a thin
library ("thin" because aspects of RDBMS shine through in parts) and a
code generator that provides the glue code bridging the gap from
internal to external data representation. For the most part, the
"glue" are get and set methods on otherwise hidden record fields
within classes representing table rows.
A number of basic assumptions guide the design and implementation of
the persistence layer:
* The goal is to make the use of persistent objects in a program as
convenient as possible. Developers should be able to operate on
persistent objects similar to normal objects.
* Referential integrity between table rows is preserved in memory.
That is, all foreign key references to a particular row in the
relational database are mapped to pointers to a single object in
memory, and vice versa.
* Access is provided to table data, views, and arbitrary selects. The
API provides a similar interface for all of these variants. A
subset of SQL is made available to the application as a simple query
language. Depending on the type of application, the scope of this
subset is powerful enough to cover a large part of the queries it
needs to run. If an application manipulates symbolic data, then all
of its queries can typically formulated in this simple language. On
the other hand, for an application including number crunching, the
aggregation of data must be done with manually crafted SQL selects.
* The framework offers sufficient flexibility to tune the tradeoff
between convenience and performance. For example, the running time
of most applications is determined by the number of interactions
between client program and database server. Accordingly, the
library offers ability to change from fine grained access to single
objects to coarse grained data access internalizing thousands of
objects with a single `select' statement.
* PObjects does not provide an object oriented view on *any* SQL
database schema. The persistence layer supports a limited number of
mappings between relational data and objects.
* For the persistence mechanism to work, classes must be explicitly
programmed for it. That is, the library is not a mechanism that
magically allows to store existing classes in a database. Instead,
the persistence capable classes must be derived from a common base
class, `de.mguennewig.pobjects.Record'.
* Not all aspects of persistence are hidden from the developer.
Persistent objects differ in some details from normal objects. For
example, concurrency is not an issue if an object is under the full
control of a program, but becomes very important if object data is
serialized in a database, where several applications and users may
access it simultaneously. The persistence layer exposes details of
the lower level database access if these details cannot be
abstracted away without loss of control. Most notably, the
application must deal with transactions.
The project is based on a port I made of the `libpobj' library that
is part of the `Optimizing Oberon-2 Compiler' [5].
2. Basic Concepts
=================
Three basic concepts summarize the operation of the persistent
object abstraction layer:
1. Every table corresponds to a class.
2. Every table row corresponds to an instance of the table's class.
3. Every attribute in a table row corresponds to a member of the
table's class.
As far as the application is concerned, the database is a container
of objects
* from which it can retrieve objects that were made persistent
earlier,
* where it can create new objects or can make changes to objects
persistent, and
* which it can query for lists of objects satisfying a given set of
criteria.
The authoritative source of persistent data is always the database.
In general, it must be assumed that multiple processes are reading and
writing to the same database at the same time. This means, that all
objects and their state held locally be the application are only
copies of the original data, and may become out of date immediately
after they were taken from the database. (This is another aspect of a
shared database that is _not_ abstracted away by PObjects, although
some features of its implementation try to lessen the impact of this
fact.)
As far as possible, data items from the database are presented to the
application in a format suitable for easy access by the programming
language. For example, a table attribute like `VARCHAR(n)' is mapped
onto String objects, while a foreign key constraint is translated into
a object reference (aka pointer) representing the row of the key's
target table.
3. Examples
===========
The most basic example assumes a table representing a person. It has
two data columns, `firstName' and `lastName', both of type string.
Additionally, it has an integer primary key column (implicitly named
`id') that is fed from a database sequence `Seq_Person'.
Class definition in the meta-data file:
<class name="Person">
<idField sequenceName="Seq_Person" />
<field name="firstName" schemaName="first_name">
<string size="128" />
</field>
<field name="lastName" schemaName="last_name">
<string size="128" />
</field>
</class>
The table definition for our RDBMS system (Postgres in this case)
looks like this:
CREATE SEQUENCE Seq_Person;
CREATE TABLE Person (
id INTEGER CONSTRAINT nn_Person_id NOT NULL,
CONSTRAINT pk_Person PRIMARY KEY(id),
first_name VARCHAR(64) CONSTRAINT nn_Person_first_name NOT NULL,
last_name VARCHAR(64) CONSTRAINT nn_Person_last_name NOT NULL
);
Now to application's view on this table and its rows. First, create
our object container `cnt' on top of the database connection `conn'
and start a transaction:
cnt = new PostgreSQLContainer(conn);
cnt.beginTransaction();
Add an object to the database table `Person':
person = new Person("Michael", "van Acken");
cnt.makePersistent(person);
person.store();
Retrieve all `Person' objects from the corresponding table:
q = cnt.newQuery();
q.addTableExpr(Person.cdeclPerson, false);
res = q.execute();
At this place, `res[0,0]' holds the first object, `res[1,0]' the
second, and so on. To retrieve a subset of all persons matching a
particular pattern, one needs to add a filter predicate to the query:
q = cnt.newQuery();
q.addTableExpr(Person.cdeclPerson, false);
q.addConj(Predicate.like(new Member(0, Person.attrFirstName),
new Literal("Mich%")));
res = q.execute();
This returns all `Person' objects whose first name begins with `Mich'.
Removing a table row:
person.delete();
person.store();
And finally, closing the transaction:
cnt.commitTransaction();
4. Package Overview
===================
de.mguennewig.pobjects
The base library for PObjects.
de.mguennewig.pobjects.metadata
The metadata related part of the PObjects library.
de.mguennewig.pobjects.demo
A very simple investment related demo that uses the PObjects library.
See InvestmentDemo.xml for the metadata declaration.
de.mguennewig.pobjects.event
A simple event interface that can be used to listen to database
changes, for example within a Swing application.
de.mguennewig.pobjects.filesystem
A simple container implementation that maps the file system tree
onto a Record.
de.mguennewig.pobjects.jdbc
Contains PObject container implementations which use JDBC.
de.mguennewig.pobjects.memdb
A simple container implementation that just keeps all objects in
memory instead of a persistent database.
de.mguennewig.pobjects.optional
Contains classes and packages that provide optional features.
de.mguennewig.pobjtool
The code generator for the "glue" code.
de.mguennewig.pobjtool.ddl
This contains database specific "metadata" classes for the SQL
code generator.
de.mguennewig.pobjform
A PObjects based framework for Swing dialogs and HTML forms.
de.mguennewig.pobjform.html
The HTML form implementation of the PObjForm framework.
de.mguennewig.pobjform.swing
The Swing dialog implementation of the PObjForm framework.
de.mguennewig.pobjimport
A toolkit to import and export PObject databases from/into XML files.
de.mguennewig.pobjsearch
An generic search framework based on PObjForm.
5. Compiling from Source
========================
The project is compiled using `Apache Ant' [1] by just starting in
the source root (where this file residences):
ant
or
ant dist
6. Thread-safety and concurrency
================================
The library is not thread-safe.
7. References
=============
1. Apache Ant
http://ant.apache.org/
2. Checkstyle
http://checkstyle.sourceforge.net/
3. GNU Getopt for Java
http://www.urbanophile.com/arenn/hacking/download.html
4. MySQL
http://www.mysql.com/
5. Optimizing Oberon-2 Compiler
http://ooc.sourceforge.net/
6. Oracle Database
http://www.oracle.com/database/
7. PostgreSQL
http://www.postgresql.org/
8. Servlet Java Classes
http://java.sun.com/products/servlet/