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

advertisement

AddThis Social Bookmark Button

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

Understanding the Server-Side Architecture

The server-side architecture can be taught as two use cases. The first is to find the factor of a Mersenne number to check if it is a Mersenne prime or not. The second it to take a Mersenne prime number and calculate the corresponding perfect number.



Use Case 1: Factorizing a Mersenne Number.

This is by far the more complicated of the two use cases, and can be thought of in terms of a number of sub-use cases. It involves taking a Mersenne number and finding its factors; since this is computationally a very intensive process, the client is informed of the result asynchronously by email when the calculation is finished.

Furthermore, this now involves the notion of state, since with multiple client invocations, each Mersenne number, and its corresponding email address and factors (once it has finished factorizing), must be remembered. Since Web services are largely stateless services (a consequence of using stateless HTTP as the protocol), they must impersonate some type of stateful service. The client must also be informed of the results, so there must be the ability to email the results to the calling client. Finally, some sort of state-lifecycle management is also desirable. On a server restart, a Mersenne number that is not finished factorizing should, at a minimum, be restarted. The sub-use cases can therefore be listed as follows:

  1. The basic service
  2. Making a stateless service stateful
  3. Informing the client
  4. Making the calculation
  5. Adding a persistence mechanism

These use cases are discussed in more detail below; however, before discussing them individually, it is worth looking at an overview of the sequence diagrams and class diagrams for this use case.

The Basic Service

The basic service is the PerfectCalc interface (here is the WSDL). It defines the two methods listed below; however, the second method belongs to the second use case and will be addressed as part of that discussion.

public boolean checkMersenneNumber(MersenneNumber k, String email)

takes a Mersenne number (which is not necessarily a prime number) and an email address of the invoker, factors the Mersenne number, and emails the result to the invoker. If the Mersenne number has no factor other than itself and one, then it is a Mersenne prime.

public PerfectNumber calcPerfectNumber(MersennePrime MersennePrime)

takes a Mersenne prime and calculates the corresponding perfect number.

Making a Stateless Service Stateful

The FactorFactory object is a factory pattern responsible for making the stateless PerfectCalc service stateful. The FactorFactory object is also a singleton with a protected constructor and a public static initializer. Example 1 gives the code for the FactorFactory object.

Example 1. FactorFactory

/**
 * A Factory class that is also a singleton object for creating multiple 
 * instances of the stateful Factor class
 * @testcase test.TestFactorFactory
 * @version 1.0
 * @author Eoin Lane
 */
public class FactorFactory implements IFactorFactory, Observer {
    /** This contructor is only called once and when it is 
     * the Caretaker is created and initalised 
     */
    protected FactorFactory() {
        // Initalise the Map
        this.map = new HashMap();
        //factors = new Vector();
        caretaker = new SimpleCaretaker();
        System.out.println("Caretaker created and initialized");
    }

    /**
     * Factory method to create instances of IFactor object
     * @param MersenneNumber number of the form (2^k-1)
     * @param email of the invoking client
     */
    public IFactor getFactor(MersenneNumber MersenneNumber, String email) {
        // Store the Mersenne number k value into the Map
        Double d = new Double(MersenneNumber.getK());
        this.map.put(d, email);
        Factor factor = new Factor(MersenneNumber);
        factor.attach(this);
        factor.factorize();
        // Create a Memento of the newly created factor object
        IMemento memento = new SimpleMemento(MersenneNumber.getK(), email);
        //Tell the caretaker about it
        this.caretaker.addElement(memento);
        return (IFactor)factor;
    }

    /** Returns a one and only one instance of this class */
    public static FactorFactory getInstance() {
        if (instance == null) {
            synchronized(FactorFactory.class) {
                if (instance == null) {
                    instance = new FactorFactory();
                }
            }
        }
        return instance;
    }

    /**
     * The callback method that the subject will call on this listener
     * @param factor the finished Factor class
     */
    public void update(Factor factor) {
        // Get the k value from the Mersenne number in the factor class
        double k_value = factor.getMersenneNumber().getK();
        System.out.println("Observer informed of finished 
                  calculation of Mersenne number: " + k_value);
        // Get the email corrosponding th the Factor's Mersenne k value
        String email = (String)(this.map.get(new Double(k_value)));
        Collection bag = factor.getFactors();
        mail(bag, email, k_value);
        // since this Factor class has now finished process remove 
        // it's corrosponding memento object from the caretaker
        // Create a Memento of the newly created factor object
        IMemento memento = new SimpleMemento(k_value, email);
        this.caretaker.removeElement(factor);
    }
  
    private static FactorFactory instance = null;
    // Looks after and tracks all the created Factor objects
    private ICaretaker caretaker;
    // A map containing the Mersenne number, email value pair
    Map map;
}

The important thing to note is the protected constructor, where a Vector of Factor class is created and initialized. This Vector keeps a record of all of the created Factor classes. The Factor classes are then created with the getFactor(MersenneNumber MersenneNumber) method. This pattern -- using a singleton factory object to create and keep track of the generated Factor object -- allows a stateless facade to be exposed to the outside while internally stateful classes can be created and their lifecycle managed.

Pages: 1, 2, 3, 4, 5

Next Pagearrow