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

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