PageBox for Java: Web application deployment using Java PageBox

for
 PageBox for Java 
 API 
 Demo 
 Background 
Presentation User guide Token API Active naming Extensions Implementation Token implementation

Token API and Active Naming Implementation

Foreword

Objective

This document presents the implementation of the Token API, measurement facility and Active Naming in PageBox for Java.

Audience

Programmers who want:

  1. To participate to the PageBox development

  2. To adapt or extend PageBox for their needs

Token API

PageBox implements a token ring using the PageBox Web services:

  • DeployIF for the PageBox agent

  • RepoQueryIF for the Repository

The implementation uses the mechanism presented on the Token API page. It is designed as a set of components with very few interactions with the rest of PageBox, which means that

  • It can be tested and updated almost independently of the rest of PageBox

  • If it is not used it has a marginal impact on PageBox performance and footprint

Web services

DeployIF

The DeployIF interface extends a TokenIF interface defined like this:

interface TokenIF {

DeployIF.Status frameSend(TokenFrame frame) throws RemoteException;

}

This TokenIF interface defines a frameSend method that sends a frame to the next PageBox on the ring or to the Repository when the PageBox is the last PageBox on the ring. This method takes one parameter, which is the frame to send.

The frame is an object of TokenFrame class:

class TokenFrame implements Serializable {

String repUrl;

int nb;

LinkedList adjacencyList;

LinkedList msgList;

/** Methods */

}

The TokenFrame class implements methods that we describe later. Here we only present its data, which are:

  • repUrl: the URL of the RepoQueryIF Web service of the Repository

  • nb: the frame number

  • adjacencyList: a list of PageBoxInfo objects describing the PageBoxes on the ring

  • msgList: the list of the message sets carried by the frame. A message set contains messages with the same origin, destination and Web archive and is stored in a TokenMsg object.

The order of the PageBoxes in the adjacency list is the order of the PageBoxes on the ring:

The PageBoxInfo class is defined like this:

class PageBoxInfo implements Serializable {

String url;

String user;

String password;

}

Where:

  • url is the URL of the DeployIF Web service of the PageBox

  • user is the user account to use to call the DeployIF Web service of the PageBox

  • password is the password to use to call the DeployIF Web service of the PageBox

The TokenMsg class is defined like this:

class TokenMsg implements Serializable {

String origin;

String target;

String archive;

HashMap msgs;

/** Methods */

}

The TokenMsg class implements methods that we describe later. Here we only present its data, which are:

  • origin: URL of the Deploy Web service of the origin PageBox

  • target: URL of the Deploy Web service of the target PageBox, null in case of broadcast

  • archive: name of the Web archive

  • msgs: map whose key is the correlation ID and value is a Message object

The Message class is defined like this:

class Message implements Serializable {

String type;

byte[] data;

HashMap codes = null;

}

Where:

  • type is the message type setup by the Web archive in its send request

  • data is the message itself serialized by TokenSerializer

  • codes is a response map whose key is the URL of the Deploy Web service of the answering PageBox and value is the Web application answer

The DeployIF Web service is implemented in the DeployImpl class. DeployImpl extends a TokenImpl class that implements the TokenIF methods.

RepoQueryIF

The RepoQueryIF interface extends a RepoTokenIF interface defined like this:

interface RepoTokenIF extends PageBoxLib.TokenIF {

void tokenRegister(String subscriber) throws RemoteException;

void tokenUnregister(String subscriber) throws RemoteException;

}

This RepoTokenIF interface extends the TokenIF interface described above and defines two additional methods:

  • tokenRegister: adds a new PageBox to the ring. This method takes one parameter, which is the URL of the DeployIF Web service of the added PageBox.

  • tokenUnregister: removes a PageBox from the ring. This method takes one parameter, which is the URL of the DeployIF Web service of the added PageBox.

In this case the TokenIF method, frameSend, sends a frame to the first PageBox on the ring.

The RepoQueryIF Web service is implemented in the RepoQueryImpl class. RepoQueryImpl extends a RepoTokenImpl class that implements the RepoTokenIF methods.

APIImpl

As described in the token API user guide PageBoxAPI implements two methods:

  • registerCallback to register a TokenCallbackIF object

  • unregisterCallback to un-register a TokenCallbackIF object

The actual implementation of PageBoxAPI is in the APIImpl class. This class contains a member of type TokenCallbackImpl. PageBoxAPI.registerCallback calls the registerCallback method of this object and PageBoxAPI.unregisterCallback calls the unregisterCallback method of this object.

Components

Common

These classes are used on the Repository as well as on the PageBox agent. These classes are:

  • TokenFrame

  • TokenMsg

  • Message

  • TokenSerializer

PageBox agent

  • TokenImpl

  • TokenCallbackImpl

Repository

  • RepoTokenImpl

TokenCallbackImpl

TokenCallbackImpl has two members of interest:

  • callbacks whose key is the URL of the RepoQuery Web service of a Repository and value is a RepositoryReg object

  • msgList: a list of TokenMsg objects queued before the frame reception

RepositoryReg is a class embedded in TokenCallbackImpl that has two functions:

  1. To store a callbacks map whose key is the archive name and value is a TokenCallbackIF object provided by the Web application stored in the archive

  2. To implement the invocation of the tokenRegister and tokenUnregister methods of a Repository RepoQuery Web service. Its register method calls tokenRegister and its unregister method calls tokenUnregister.

TokenCallbackImpl also imbeds a Sender class that implements the TokenSendIF. Its send method adds the message passed in parameter to the msgs map of the proper TokenMsg. If this TokenMsg doesn’t exist send creates a new TokenMsg and adds it to msgList.

registerCallback

This method gets called when a Web archive calls the homonymous method of PageBoxAPI. However the registerCallback method of TokenCallbackImpl has a second parameter, the name of the Web archive. This parameter was set up by PageBoxAPI.

If a RepositoryReg instance doesn’t exist yet for the Repository where the Web archive was downloaded in the callbacks map registerCallback:

  • Creates a new RepositoryReg

  • Calls its register method to register the PageBox on this Repository ring

Otherwise registerCallback retrieves the RepositoryReg instance from the callbacks map.

Then registerCallback sets the TokenCallbackIF object of the archive in RepositoryReg.callbacks and creates a Sender object.

unregisterCallback

This method gets called when a Web archive calls the homonymous method of PageBoxAPI. However the unregisterCallback method of TokenCallbackImpl has a parameter, the name of the Web archive. This parameter was set up by PageBoxAPI.

unregisterCallback removes the archive from the RepositoryReg.callbacks map. If then RepositoryReg.callbacks is empty (if there is not anymore Web applications handling messages on this PageBox) unregisterCallback calls the unregister method of RepositoryReg to remove the PageBox from the Repository ring.

processFrame

processFrame is called by TokenImpl to handle frames received by the PageBox.

processFrame enumerates the callbacks map of the RepositoryReg instance that manages the frame Repository. For each archive (Web application) found processFrame retrieves its TokenCallbackIF instance, calls the processResponse and processMessage methods of the frame and the poll method of the TokenCallbackIF instance.

Then processFrame calls a cleanup method of the frame to remove messages that came back to their issuer and adds messages in msgList to the frame.

TokenImpl

TokenImpl implements the TokenIF method of the DeployIF Web service, frameSend.

Steps:

  1. The previous PageBox on the ring calls the frameSend method of the DeployIF Web service

  2. The frameSend method of TokenImpl calls the processFrame method of TokenCallbackImpl to handle message whose target was this PageBox and to add messages sent by this PageBox

  3. The frameSend method queues the updated frame to the TokenImpl thread (TokenThread class)

  4. The run method of the TokenImpl thread calls the frameForward method to send the updated frame to the next PageBox on the ring

The context of TokenImpl is stored in a TokenImpl.Context object defined like this:

class Context {

TokenThread tt = null;

TokenFrame lastFrame = null;

}

Where

  • tt is an instance of a TokenThread class responsible for sending frames to the next station on the ring

  • lastFrame is the last frame sent by TokenImpl

frameSend

frameSend calls the processFrame method of TokenCallbackImpl to handle message whose target was this PageBox and to add messages sent by this PageBox, queues the updated frame and notifies the TokenThread instance that there is a new frame to process.

TokenThread

TokenThread extends Thread. In this thread TokenThread dequeues and forwards the frames queued by the frameSend method to the next PageBox on the ring.

run

The run method is the main method of the TokenThread thread. It waits for a notification or for a timeout. If it was notified by frameSend it calls the frameForward method to send the updated frame to the next PageBox on the ring. In case of timeout run checks if the repository is alive by sending it a special "ping" frame. If the repository is dead run calls a generateToken method.

generateToken

generateToken wait for a random amount of time to:

  1. call the processFrame method of TokenCallbackImpl to add messages sent by this PageBox;

  2. call to frameForward method to forward this updated frame to the next station on the ring.

frameForward

frameForward finds the next PageBox in the adjacency list and calls its DeployIF Web service to send the frame. In case of failure it calls the DeployIF Web service of the next PageBox up to the time it succeeds (finds a running PageBox). When there is no more PageBox frameForward calls the RepoQueryIF Web service of the Repository.

In both the run and the frameForward methods failed PageBoxes are removed from the adjacency list and the RepoQueryIF.tokenUnregister method of the Repository is called to remove the failed PageBoxes from the ring.

TokenFrame

TokenFrame implements trace methods and three methods called by the processFrame method of TokenCallbackImpl:

  • processMessage

  • processResponse

  • cleanup

processMessage

processMessage retrieves from the frame msgList the TokenMsg objects whose archive is the archive passed in parameter and target is this PageBox or null (broadcast).

processMessage enumerates the Message instances in the msgs map of these TokenMsg objects. For each Message processMessage invokes the call method of the Web application’s TokenCallbackIF object.

processResponse

processResponse retrieves from the frame msgList the TokenMsg objects whose archive is the archive passed in parameter and origin is this PageBox.

processResponse enumerates the Message instances in the msgs map of these TokenMsg objects. For each Message processResponse invokes the response method of the Web application’s TokenCallbackIF object.

cleanup

There are two versions of the cleanup method:

  • A version called by TokenCallbackImpl.processFrame on PageBox agents with a parameter that removes TokenMsg objects that came back to their issuer

  • A version called by RepoTokenImpl.frameSend on Repository without parameter that removes TokenMsg objects whose origin or destination is no longer in the adjacency list

RepoTokenImpl

RepoTokenImpl is the Repository equivalent of TokenImpl.

RepoTokenImpl implements the RepoTokenIF methods of the RepoQueryIF Web service. Because RepoTokenIF extends TokenIF RepoTokenImpl implements frameSend. Therefore like TokenImpl RepoTokenImpl and creates a separate RepoTokenThread thread that forwards the updated frame to the first PageBox on the ring. RepoTokenImpl also implements two methods of RepoTokenIF, tokenRegister and tokenUnregister.

The context of RepoTokenImpl is stored in a RepoTokenImpl.Context object defined like this:

class Context {

TokenFrame master = null;

TokenFrame lastFrame = null;

RepoTokenThread rtt = null;

}

Where

  • master is a TokenFrame object sent when the Repository issues a new token. RepoTokenImpl also uses master to keep an up-to-date adjacency list.

  • rtt is a RepoTokenThread object responsible for sending frames to the first station on the ring

  • lastFrame is the last frame sent by RepoTokenImpl.

tokenRegister

If master is null (if a first PageBox joins the ring) tokenRegister instantiates a new TokenFrame with the PageBox in the adjacency list and queues this frame to the RepoTokenImpl thread for sending the frame. Otherwise tokenRegister adds the PageBox to the master adjacency list.

tokenUnregister

tokenUnregister removes the PageBox from the master’s adjacency list. If this PageBox was the last PageBox on the ring tokenUnregister ends the RepoTokenImpl thread and unreferences the master.

frameSend

frameSend

  • Replaces the frame adjacency list by the master adjacency list

  • Calls the cleanup method of TokenFrame to remove messages whose origin or destination is no longer on the ring

  • Queues the updated frame to the RepoTokenThread thread for sending the frame

RepoTokenThread

RepoTokenThread extends Thread. In this thread RepoTokenThread dequeues and forwards the frames queued by the frameSend method to the first PageBox on the ring.

run

The run method is the main method of the RepoTokenThread thread. It waits for a notification or for a timeout. If it was notified by frameSend or tokenRegister run sends the frame to the first running PageBox and calls TokenUnregister to remove the non-running PageBoxes before the first running PageBox from the ring.

In case of timeout run issues a new token (sends a new frame). It addresses the case where the token was lost but also ensures that there are enough tokens on the ring to handle messages fast enough.

When it receives the token earlier than half timeout + the time when it sent this token on the ring, run waits in order for two subsequent frame sends to be separated by half timeout.

TokenSerializer

TokenSerializer addresses a class resolution problem. The Token API allows sending and receiving objects of any Serializable type known by the Web application class loader. TokenFrame that handles messages and responses in its processMessage and processResponse methods is loaded by a different class loader, the PageBoxLib class loader.

To serialize and un-serialize messages the processMessage and processResponse methods load the TokenSerializer class with the Web application class loader, create a TokenSerializer object and use the reflection to invoke the processMessage and processResponse methods of this TokenSerializer object.

TokenSerializer implements three methods for Token handling:

  • processMessage that un-serializes the message object, invokes the call method of the Web application callback and serializes the call response

  • getMessage that returns the error message in case of processMessage failure

  • processResponse that un-serializes the response object

TokenSerializer implements three other methods for Active Naming:

  • mustActive that unserializes the imperative objects of remote Web applications and use the equals method to check if they equal the imperative object passed as parameter

  • niceifActive that unserializes the nice if match objects of remote Web applications and use the compareTo method to measure their distance to the nice if match object passed as parameter

  • serializeActive that serializes objects used for imperative and nice if matching

Measurement facility

The measurement facility measures:

  • The CPU use of a PageBox

  • The memory use of a PageBox

  • The network performance

of a PageBox host.

This facility is modular and extensible to allow supporting new Operating Systems or making better measurements. We describe in the Porting guide how to extend the facility. Collected data are stored in a ResourceUsage class that extends a MemUsage class. Operating system dependent probes are responsible for making measurements. PageBox 0.0.13 embeds a probe for Linux, called LinuxUsageProbe and a probe for Windows NT, 2000 and XP, called WindowsUsageProbe. Probes are instantiated by a UsageFactory class and implement a UsageIF interface defined like this:

interface UsageIF {

ResourceUsage collect();

}

MemUsage

ResourceUsage is just a placeholder for CPU-related data normally set by the probes.

MemUsage is a placeholder for memory and network related data but it also implements an init method.

This init method takes one parameter, netTime, which is the time spent to send a frame to the next station on the ring and sets the MemUsage members in the following way:

Member

Content

netTime

netTime parameter

free

Runtime.getRuntime().freeMemory()

total

Runtime.getRuntime().totalMemory()

max

Runtime.getRuntime().maxMemory()

APIImpl.getResourceUsage calls the init method after it has called the collect method of the probe.

UsageFactory

UsageFactory has a getUsageProbe static method that instantiates the appropriate probe depending on the Operating System. UsageFactory.getUsageProbe is called by APIImpl.getResourceUsage.

LinuxUsageProbe

LinuxUsageProbe implements the collect method of the UsageIF interface. Its collect method reads the /proc/stat file and parses its cpu line.

WindowsUsageProbe

WindowsUsageProbe implements the collect method of the UsageIF interface. Its collect method loads a WindowsCPU dll and calls its getCPU native method. getCPU calls a GetCpuUsage usage method implemented in a GetCpuUsage.cpp file. We didn’t develop this code. We found it on http://www.codeproject.com/system/cpuusage.asp where it is credited to Dudi Avramov. We only added the JNI stuff and converted the exe into a dll.

Active Naming

PageBox implements Active Naming using the Token API and the measurement facility.

The implementation uses the mechanism presented on the Active Naming page. It has no interaction with the rest of PageBox except the Token implementation.

APIImpl

As described in the Active Naming user guide the PageBoxAPI implements seven methods:

  • ActiveNamingLogon to log on Active Naming within a client role

  • ActiveNamingLogoff to log off Active Naming within a client role

  • getEntries to enumerate the logical names of the entry points declared on the ring

  • getCandidate to get the URL (Web service, page) of the most appropriate service instance

  • addEntry to declare an entry point and service instance

  • removeEntry to remove an entry point

  • clearEntries to clear the entry points of a Web application instance

The actual implementation of PageBoxAPI is in the APIImpl class. This class contains a member of type ActiveNaming. PageBoxAPI.ActiveNamingLogon calls the logon method of this object, PageBoxAPI.ActiveNamingLogoff calls the logoff method of this object, PageBoxAPI.getEntries calls the getEntries method of this object, PageBoxAPI.getCandidate calls the getCandidate method of this object, PageBoxAPI.addEntry calls the addEntry method of this object, PageBoxAPI.removeEntry calls the removeEntry method of this object and PageBoxAPI.clearEntries calls the clearEntries method of this object.

APIImpl also contains a getResourceUsage that uses the measurement facility to return a populated ResourceUsage object that describes resource usage on a PageBox host.

Components

Active Naming is implemented in the Active Naming class.

Four other classes store data:

  • ActiveEntry

  • ActiveMessage

  • MatchingEntry

  • ActiveResult

Active Naming also contains an ActiveComparable interface.

ActiveEntry

ActiveEntry is defined like this:

class ActiveEntry implements Serializable {

String url;

byte[] must;

byte[] niceif;

transient public int distance;

}

ActiveEntry describes a service instance. url is the page or Web service URL. must is the imperative matching object serialized by TokenSerializer. niceif is the nice if match object serialized by TokenSerializer.

ActiveEntry objects are inserted in ActiveMessage objects, which are themselves inserted in Token ring frames. Therefore ActiveEntry implements Serializable.

ActiveMessage

ActiveMessage is defined like this:

class ActiveMessage implements Serializable {

public HashMap entries = null;

public ResourceUsage usage = null;

}

ActiveMessage is the token ring message used to send Active Naming data. Because ActiveMessage objects are inserted in Token ring frames ActiveMessage implements Serializable. entries is a map whose keys are entry names and values are ActiveEntry objects.

MatchingEntry

MatchingEntry is defined like this:

class MatchingEntry {

ActiveEntry ae;

ResourceUsage ru;

int distance;

}

distance is the distance between the service instance and a niceif object passed by the getCandidate method. This distance is setup by the niceifActive method of TokenSerializer.

MatchingEntry is used by ActiveNaming.getCandidate to communicate with TokenSerializer.

ActiveResult

ActiveResult is used by the mustActive and niceifActive methods of TokenSerializer to return their response. ActiveResult is defined like this:

class ActiveResult {

public int max = -1;

public ArrayList entries = new ArrayList();

public String msg = "no entry found";

}

Where

  • max contains the maximum distance between an service instance and a niceif object passed by the getCandidate method when ActiveResult is returned by niceifActive. max contains 0 when ActiveResult is returned by mustActive. max contains -1 in case of error in both mustActive and niceifActive

  • entries contains MatchingEntry objects

  • msg contains an error message valid when max == -1

ActiveComparable

ActiveComparable is the interface that nice if match object must implement. These objects must be serializable because nice if match objects must be serialized into ActiveEntry.niceif and implement a compareTo method to measure the distance between two nice if match objects. Therefore ActiveComparable is defined like this:

interface ActiveComparable extends Serializable {

int compareTo(Object o, ResourceUsage usage);

}

ActiveNaming

ActiveNaming implements:

  • The TokenCallbackIF interface, the methods of interest for this discussion being call and send

  • The methods called by PageBoxAPI, logon, logoff, getEntries, getCandidate, addEntry, removeEntry and clearEntries.

ActiveNaming has three members of interest:

  1. localEntries that contains service instances declared by the Web application acting as a server. localEntries is a HashMap whose key is the logical name of an entry point and value is an ActiveEntry object.

  2. foreignEntries that contains service instances declared by the Web application clones deployed from the same repository. foreignEntries is a HashMap whose key is the URL of the DeployIf Web service of a deploying PageBox and value is another HashMap whose key is the logical name of an entry point and value is an ActiveMessage object.

  3. isRegistered, a Boolean set to true by logon and to false by logoff

logon

ActiveNaming may register on the ring for two reasons:

  1. When the Web application acts as a client because logon has been called

  2. When the Web application acts as a server because it has declared service instances. In this case localEntries is not empty.

Therefore logon checks if localEntries is empty. When it is the case logon registers its ActiveNaming instance as a Token API callback with the registerCallback method of the PageBox API.

The Token API allows only one callback per archive. To allow using the Active Naming and the Token API at the same time Active Naming registers a pseudo archive name made of the actual archive suffixed by ".an".

logoff

logoff unregisters from the ring only if localEntries is empty (if the Web application has no more service instances to advertise).

getEntries

getEntries enumerates foreignEntries to build a list of logical names of entry points.

getCandidate

getCandidate is called with three parameters:

  • name: logical name of an entry point

  • must: imperative matching object

  • niceif: nice if match object

getCandidate:

  1. Enumerates foreignEntries to build a first list of services instances whose logical name of entry point is "name"

  2. If "must" is not null, creates a TokenSerializer instance with the "must" class loader to compare the "must" parameter to the must member of service instances in the first list and build a second list with only service instances whose must member matches the "parameter"

  3. If "niceif" is not null, creates a TokenSerializer instance with the "niceif" class loader to measure the distance between the "niceif" member of service instances in the second list and build a third list of service instances

  4. Build a fourth list with each service instance represented (maximum distance - instance distance to "niceif" + 2) times when the service instance had a non-null niceif member and only once otherwise

  5. Return a randomly chosen service instance in the fourth list

addEntry

addEntry adds a new ActiveEntry object to the localEntries map. If the localEntries was empty before and if logon had not been called (isRegistered == false) addEntry registers its ActiveNaming instance as a Token API callback with the registerCallback method of the PageBox API.

To populate the ActiveEntry object addEntry creates a TokenSerializer instance with the "must" class loader to serialize the "must" parameter and creates a TokenSerializer instance with the "niceif" class loader to serialize the "niceif" parameter.

removeEntry

removeEntry removes the service instance identified by the logical name of entry point from the localEntries map. If then localEntries is empty and if logon had not been called (isRegistered == false) removeEntry un-registers its ActiveNaming instance with the unregisterCallback method of the PageBox API.

clearEntries

clearEntries clears the localEntries map. Then if logon had not been called (isRegistered == false) clearEntries un-registers its ActiveNaming instance with the unregisterCallback method of the PageBox API.

call

From each remote instance call receives an ActiveMessage and adds this object to the foreignEntries map.

poll

poll build an ActiveMessage with the localEntries map and the ResourceUsage returned by APIImpl.getResourceUsage and sends this ActiveMessage to remote instances.

Contact:support@pagebox.net
©2002-2004 Alexis Grandemange. Last modified .