ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Prevalence: Transparent, Fault-Tolerant Object Persistence

by Jim Paterson
06/08/2005

When people talk about object persistence, they usually mean the storage of objects or their states in a database. This will usually be a relational database, or possibly an alternative, in the form of an object database such as db4objects, described in a previous article.

For most applications, interfacing with a DBMS is desirable, necessary, or both. However, it is possible to achieve object persistence without using a database at all. The requirements are that it is acceptable to have a very close coupling between the data and the application, and that the amount of data involved is small enough to fit into working memory.

In fact, Java already has a well-established, built-in persistence mechanism in the form of serialization. However, serialization is limited in terms of ability to query specific data, and, crucially, in its lack of fault tolerance. The first problem is not an issue if the entire data set for an application can be held in memory--and querying an in-memory data set will usually be faster than a database query. However, this is not of much use if the system experiences a failure while running--the state of the data on restart will be the last serialized data set, and any changes to the data since then will be lost.

A prevalent system makes use of serialization, and is again useful only when an in-memory data set is feasible. A serialized snapshot of a working system can be taken at regular intervals as a first-line storage mechanism. Fault-tolerance and data consistency are provided by the use of command objects to perform all transactions that change the state of the data. All commands are stored using serialization.

If a fault occurs, an up-to-date data set can be rebuilt by taking the last snapshot and applying all of the subsequent commands to it. Consistency is assured as each command represents a transaction--no changes to the data can be made to the data without using such a transaction, and transactions are applied sequentially. This clearly requires that the behavior of all business objects is deterministic.

Persistence using a prevalent system is transparent, as transactions are applied directly to the business objects with no need to use SQL either directly or through object-relational mappings.

Tools for Creating a Prevalent System

In this article, I will show how to create a simple prevalent system in Java using open source tools. The main tool you need is the popular Prevayler framework. Prevayler, created by Klaus Wuestefeld, provides a prevalence layer for Java. Prevayler 1.0 was awarded a JOLT Productivity award in 2004. The recent version, 2.0, has many improvements, including a simpler API.

Prevayler itself is really all that is required to build a prevalent system. However, the task is made easier by the Preclipse plugin for Eclipse, which provides extensive support for Prevayler in terms of code generation, refactorings, and visualization. The current version of Preclipse is based on Prevayler 2.0.

Note that there are also prevalence tools available or under development for other languages, such as Bamboo for .NET.

The Component Parts of the System

The example code on the Preclipse site shows the creation of a basic system with a GUI interface. The system described here deals with a slightly more complex domain model. Before we look at any code, we need to define what the component parts of our system are. There are three components:

  • The prevalent system--a single class that acts as a container for business objects and handles snapshots.
  • Business Object (BO) classes.
  • Transactions that can modify the prevalent system and that are logged to disk.

The business objects in this example represent customer Orders, and Items that can be added to Orders. An Order comprises OrderLines, each of which contains a reference to an Item and a quantity. Just to make things a bit more interesting, Items can be of different types (BookItem, SoftwareItem) or can contain other items (MultipackItem). Mapping this composite hierarchy to a relational database would require a bit of effort, but the prevalent system will handle this easily. The class diagram for the business classes is shown in Figure 1.

Business classes
Figure 1. Business classes

A wide range of transactions on these classes would be possible. The following transactions that will be implemented here:

  • Add a new Item to the system.
  • Restock a specified Item.
  • Create a new Order.
  • Add a new Orderline to an Order.

Now that you know what the component parts of the system will be, you are ready to start creating some code.

Creating the Prevalent System

Before you can use Preclipse, you need to download and install Eclipse 3.0. To install the plugin, use the Software Updates feature in Eclipse and go to the Preclipse download center. When you create a new project in Eclipse, you should now have the option to create a New Prevayler-based Project, as shown in Figure 2. Select this option and follow the steps of the wizard to create a new project.

Creating a new Prevayler-based project
Figure 2. Creating a new Prevayler-based project

Call the project ordersystem and accept the defaults for Java settings. The final step allows you to create a skeleton, which consists of a basic prevalent system class and a main class that kicks off an instance of the prevalent system. Enter the values shown in Figure 3. For simplicity, I have chosen here not to put source files into a separate folder.

Creating the skeleton
Figure 3. Creating the skeleton

Click Finish and the project structure shown in Figure 4 should be created. Note that the Prevayler library is included.

Initial project structure
Figure 4. Initial project structure

At this point, PrevalentOrderSystem doesn't have much code in it, as no business objects have been defined. Main contains code to simply start a new thread that creates an instance of PrevalentOrderSystem, and takes a snapshot of it at intervals specified in the project wizard (see Figure 3).

package ordersystem;

import org.prevayler.Prevayler;
import org.prevayler.PrevaylerFactory;

import java.io.IOException;

public class Main {

    public final static String DATA_FOLDER = "data";

    public Main() {
    super();
    }

    public static void main(String[] ignored)
                                throws Exception {
    final Prevayler prevayler =
        PrevaylerFactory.createPrevayler(
            new PrevalentOrderSystem(), DATA_FOLDER);
    Thread snapShotThread = new Thread() {
        public void run() {
        while (true) {
            try {
                Thread.sleep(500);
                prevayler.takeSnapshot();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        }
    };
    snapShotThread.start();
    }
}

Pages: 1, 2, 3, 4, 5

Next Pagearrow