Prevalence: Transparent, Fault-Tolerant Object Persistence
by Jim Paterson06/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.

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
Itemto the system. - Restock a specified
Item. - Create a new
Order. - Add a new
Orderlineto anOrder.
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.

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.

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.

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();
}
}