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


AddThis Social Bookmark Button

Web Services and the Search for Really Big Prime Numbers
Pages: 1, 2, 3, 4, 5

Adding a Persistence Mechanism

In case of a server restart, the current Mersenne numbers being factored need to be persisted. To achieve this, a memento pattern is used. This is in conjunction with a Caretaker object, which manages and persists the Memento objects. The Memento objects represent the state of the Factor objects currently being computed, and the Caretaker object manages and persists these objects. On startup, the Caretaker checks if all of the previous Factor objects have finished. Unfinished Factor objects are reinitialized and their calculations restarted. In a later iteration, the stage of factorization will also be persisted.

Example 4. Caretaker interface

 * A simple implementation of the Caretaker interface. This Caretaker 
 * implementation is used to persist Factor objects by keeping a list of 
 * Memento representing the state of the current Factor instance. 
 * It writes that list to disk using a a JDO DAO object
 * @author Eoin Lane
 * @version 1.0
public class SimpleCaretaker implements ICaretaker {
    /** The current list of Memento objects */
    private Vector currentList;

    /** The initalisign list of factor objects */
    private Vector factors;

     * @link dependency
     * @label mementos

    /*# IMemento lnkIMemento; */

     * Initialise the caretaker load Memento object using 
     * JDO from disk if necessary
     * @param a vector of factory objects
    public SimpleCaretaker(Vector factors) {
        this.currentList = new Vector();
        this.factors = factors;
        System.out.println("Loading Memento 
                  objects using JDO from if necessary disk");

    /** Clears the current Vector list */
    public void clear(Vector factor) {
        currentList = new Vector();
        this.factors = factors;

    /** Adds an element */
    public void addElement(Object obj) {

    /** Removes an element */
    public void removeElement(Object obj) {

    private void remove(IMemento obj) {
        IMemento m = (IMemento)obj;
        m.restore(); //and restore the old position

The persistence mechanism used here is the new Java Data Object (JDO) mechanism. A JDO data access object (DAO) is used to encapsulate the persistence mechanism and the Caretaker object uses the JDODOA object to persist the object graph of Memento objects (these Memento objects contain the state of the Factor objects currently in memory).

Use Case 2: Calculate a Perfect Number From a Mersenne Prime

This use is also defined in the IPerfectCalc interface and implemented in PerfectCalc. As a reminder, there are two methods declared in IPerfectCalc. See the above section for more information about these methods.

As is evident from the service description, this service takes a Mersenne prime and returns the corresponding perfect number. Here are the sequence diagrams and class diagram for this use case.

The Patterns

This server-side architecture uses a number of GOF patterns, which are detailed below.

A stateless facade service class is exposed to the client via a Web service. This facade calls the FactorFactory (which is a factory class, a mediator, and a singleton) to create Factor stateful objects. Potentially, there will be many of these objects, depending on the number of client requests for factorization. The Factor stateful object uses a strategy pattern to find the factors of the Mersenne number and informs the FactorFactory of the state change using an observer pattern. The FactorFactory will then email the result. Finally, the FactorFactoryalso uses a memento pattern to persist the state of the Mersenne number factorization calculation, so it may be reinstated in case of a server restart.

Here is a list of and references to the GOF patterns used:

  1. The facade pattern (the stateless service exposes a simple interface of checkMersenne number to the client).
  2. The factory method (a FactorFactory object for creating Factor (or any other type of object implementing the IFactor interface) at runtime),
  3. The singleton pattern is used for the FactorFactory object to ensure that there is only one object creating and managing Factor objects.
  4. The strategy pattern (for factorizing the MersenneNumber, decoupling the Factor object from how it factors).
  5. The mediator pattern is used in the FactorFactory again to control and manage the lifecycle of the Factor objects that it is responsible for creating.
  6. The observer pattern (a callback to the FactorFactory object that the stateful Factor object has finished factoring and the results should be emailed to the calling client).
  7. The memento pattern to persist the state of the Factor object in case of a server restart.

Grid Computing

Where does the notion of grid computing come into all of this? In the above example, an instance of the strategy pattern -- the LLFactorer -- has been looked at. Another potential factorization algorithm uses the Elliptic Curve Method (ECM) to check for primality. This can be another implementation of the IFactorer interface called ECMFactorer. Numerous other algorithms exist that could be used for this; a comprehensive list can be found here.

For grid computing, the algorithm must be capable of breaking this problem down into nonsequential units of work that can be run in a simultaneous, or parallel, manner. The LL algorithm cannot be parallelized very well, but the ECM algorithm can. Thus, a master Web service could accept a potential Mersenne number for primality testing, only to de-convolute the problem into multiple, paralleled problems that can be farmed out to other Web services from the ECMFactorer strategy implementation.

Idle processes, within an Intranet exposing an algorithm service as WSDL, for example, could be looked up using UDDI and invoked using SOAP/HTTP. Care should be taken here in long-running blocking transactions, and in extreme cases, a more flexible non-blocking protocol like SOAP/JMS or SOAP/SMTP could be used.

Therefore, our choice of algorithmic implementation dictates the usefulness of applying the problem to a grid solution. The easy infrastructure that Web services provide for solving this sort of computationally-intense problem is unattainable in any other middleware solution currently available.


The combination of Web services and grid computing provides a powerful duo for tackling computationally difficult problems. The three amigos of Web services -- WSDL, UDDI, and SOAP -- provide a framework on which a grid can flourish.

It remains to be seen how effective this will be in terms of providing solutions in realistic timeframes. Other standards within the Web services domain will need to mature in order for this to be a true robust enterprise solution. However, this type of grid computing is already being actively developed by Sun and HP, and applications may not be far off.

Eoin Lane is a Principal Technologist with Cape Clear Software. He offers advice and consultancy to Cape Clear clients in the design and implementation of Web services projects.

Return to ONJava.com.