PageBox for Java: Web application deployment using Java PageBox

for
 PageBox for Java 
 API 
 Demo 
 Background 
Presentation Download User guide Implementation Epimetheus euroLCC Prometheus

Prometheus

Objective

This document explains how to use the Prometheus Web archive and presents the Prometheus implementation.

Assumptions

In this document we assume that you have installed:

  • Java JDK 1.4

  • Java Web Services Developer pack (WSDP) 1.2 or 1.3, which includes Tomcat 5 or Tomcat 4.1/Tomcat 5 with Axis 1.1

  • PageBox for Java version 0.0.12 or above

Principle

Prometheus 0.0.2 is an example that illustrates the use of the Token API and of Active Naming in PageBox.

Token API

Function

This part of Prometheus is a simple chat application.

The user enters a pseudo and a set of metadata to enter a chat session. Then she can see messages from others and send messages to the other participants to the session. The key difference with a traditional chat system is that participants are distributed across multiple server sides. A distributed Prometheus constellation should be able to handle an unlimited number of participants. Because the number of participants can be huge Prometheus allows sending messages to subsets of the participant population.

Protocol

A Prometheus instance stores the names and metadata of its registered participants in a user map.

When a participant sends a new message the Prometheus instance checks the message destination.

If the message targets one or many participants in other Prometheus instances Prometheus stores the message in a foreignMessages map. Otherwise the Prometheus instance adds the message to a received map.

When it is notified about the arrival of the token frame the Prometheus instance adds the following items to the frame using the send method:

  • Its user map

  • A list of messages targeting all Prometheus instances

  • Message lists targeting a specific Prometheus instance

Active Naming

This part of Prometheus is a simple illustration of Active Naming. It is independent of the Token API part.

On an entries form the user creates entries with a name, a must parameter that requestors must match, a niceif parameter to which requestors must be as close as possible and a URL.

A JSP provided as a target page for routing displays the entry name, the must and the niceif parameters and a parm parameter of the query string.

A routing page allows setting requested entry name, must and niceif parameters and uses Active Naming to redirect to a page that can be the JSP page.

This example is enough to test and illustrate Active Naming. However in a real application the entry name would probably be hard-coded and the must and niceif parameters would be fields or data meaningful for the application. Furthermore Active Naming is flexible: the URL can include a query string. The application can generate entry names on the fly and doesn’t have to setup the must or niceif parameter.

Setting

To test Prometheus you need:

  1. To setup a PageBox

  2. To subscribe the PageBox to the Repository

  3. To publish the Prometheus archive on a Repository

See the PageBox installation guide to setup the PageBox.

Subscription

To subscribe your PageBox to the Repository follow the following steps:

  1. Go on the subscribe form of the Repository

  2. Logon with the subscriber account defined in the PageBox’s rules.xml

  3. Enter the URL of the PageBox’s deploy Web service, the user ID and password of your PageBox and click on the subscribe button

Publication

To publish Prometheus on the Repository:

  1. Go on the publish page of the Repository and log on with a Publisher account

  2. Click on the Browse button and select the prometheus.war archive. Then enter the documentation URL if you want and check the "Run application server installer" checkbox.

Use

Token API

Start your browser.

Let’s assume that you configured your PageBox with this rule.xml file:

<rules>

<repositories>

<repository>

<subscriber>

<name>subscriber</name>

<password>subscriber</password>

</subscriber>

<name>https://localhost:8443/Repository/repoquery</name>

<allow>copy</allow>

<deployer-class>PageBoxLib.JWSDPDeployer</deployer-class>

<querier-class>PageBoxLib.JWSDPQuerier</querier-class>

<publishers>

<publisher>

<name>publisher</name>

<allow>install</allow>

</publisher>

</publishers>

</repository>

<default>

<allow>none</allow>

</default>

</repositories>

<target>PageBox\deployed</target>

<root-path>/pb1</root-path>

<dbcreate>C:\deployed\dbcreate.bat</dbcreate>

<dbdrop>C:\deployed\dbdrop.bat</dbdrop>

<driver>com.mysql.jdbc.Driver</driver>

<url>jdbc:mysql://localhost/</url>

<user>pageboxa</user>

<password>pagebox</password>

</rules>

Prometheus will be installed in PageBox\deployed on the file system and under /pb1 on the Application server. Assuming that the Application server runs locally and is configured to listen on port 8443 (SSL) you can display the login form of Prometheus with https://localhost:8443/pb1/prometheus/login. You should get this:

Enter:

  • A user (pseudo) name

  • A user location that can be the city name or the country name of the user or whatever can is defined on this Prometheus constellation to locate users

  • Areas of interest, for instance camping, java or the name of a novel

Click on the Login button to log in. Once you are logged in you may click on the Message link to send messages and display messages of others.

The Login form contains two other buttons:

  • Refresh to refresh the display and check if for instance the session has not expired

  • Unlog to un-log the user. If you don’t click on this button once you have completed your chat work your user will be removed only after the session expiration.

The Message form looks like that:

On the top right the user name is displayed.

The form contains two parts. The top part displays the received messages. The bottom part allows sending messages.

The user drop-down list displays logged-in users. If a user is logged on the same PageBox the user string is user_name@local. If a user is logged on another PageBox the user string is user_name@PageBox_url where PageBox_url is the URL of the DeployIF Web service of the PageBox where the user is logged in.

The PageBox drop-down list displays the DeployIF Web service’s URL of the PageBox where users are connected.

To send a message put the message text in the text area. To send a broadcast message, just click on the Send button. To send a message to all users on a PageBox, select the PageBox on the PageBox drop-down list and click on the send button. To send a message to a user, select the user on the user drop-down list and click on the send button. You can also send a message to all users that match a criterion that you enter on the filter area. This filter can be loc/user_location or sub/user_area_of_interest where user_location is the location entered by the user on the Login form and user_area_of_interest is an area of interest entered by the user on the Login form. You can also send a message to all users of a PageBox that match a criterion. In this case select the PageBox on the PageBox drop-down list and enter a filter string.

Active Naming

Assuming the same setting as with the Token API you can declare a service instance on this page:

In this case two services instances are already declared. The name is the logical name of the entry. On a Prometheus instance an entry is served by only one service instance but many Prometheus instance can declare the same entry point. For a given entry point routing and load balancing take place between the service instances declared with this entry point. The must is the first parameter used for routing. This instance can only be selected if the request has a must parameter with the same value. The niceif is the second parameter used for routing. This instance has more chances to be selected if the request has a niceif parameter close to this instance.

Let’s take the case of entry1. Let’s assume that another Prometheus instance declared entry1 with niceif=mmmmm and a third instance declared entry1 with niceif=zzzzz. If the request has a niceif that equals aaaba, the first instance is the closest. Therefore it has more chances to be chosen. The second instance has fewer chances to be chosen and the third one even fewer chances because it has the farthest niceif.

The last URL is the service instance URL. We declared here the URL of redirect.jsp on this Prometheus instance with a query string parm=entry1 in case of entry1 because redirect.jsp displays parm.

We can do the same kind of declaration on other Prometheus instances installed from the same repository.

Then we can display the routing page on any Prometheus instance installed from the same repository:

On this form we are displayed a drop-down list where all entry points declared on the constellation for the Prometheus Web archive are displayed. We select one of these entry points and we enter the must and the niceif parameters of the request.

When we click on the send button we are redirected on the target URL, redirected.jsp in our case, which displays:

Implementation

Design choices

  • Model View Controller (MVC) architecture where LoginCtrl.java, PrometheusCtrl, EntriesCtrl and RoutingCtrl are the controllers, login.jsp, prometheus.jsp, entries.jsp and routing.jsp are the views and LoginBean, PrometheusBean and EntriesBean are the models

  • Messages kept in memory for the Token API part

Prometheus is made of the following components:

Name

Function

Install.java

Installation class. Updates the prometheus web.xml.

login.jsp

Displays a form where the user enters or display her pseudo, location and areas of interest (login view)

prometheus/LoginCtrl.java

Handles login requests (controller servlet)

prometheus/LoginBean.java

Stores the user pseudo, location and areas of interest (model)

prometheus.jsp

Displays a form where the user displays messages and can submit new messages (message view)

prometheus/PrometheusCtrl.java

Handles message sending (controller servlet)

prometheus/PrometheusBean.java

Returns PageBox instances in the constellation, users and messages from PrometheusCallback

prometheus/PrometheusCallback.java

Implements the Token API, receives and send messages.

prometheus/Message.java

Contains the actual message.

prometheus/UserInfo.java

Describes a user.

prometheus/UserManager.java

Used to remove users whose session was invalidated

entries.jsp

Displays a form where the user declares service instances

prometheus/EntriesCtrl.java

Handles service instance declarations

prometheus/EntriesBean.java

Store service instance data and uses Active Naming

routing.jsp

Displays a routing page where the user enters an entry name and the must and niceif parameters

prometheus/RoutingCtrl.java

Handles routing requests and returns a redirect page when applicable. Uses EntriesBean as model.

prometheus/Entry.java

Describes a service instance

prometheus/NiceIf.java

Wrapper for a niceif string that implements the ActiveComparable interface

redirected.jsp

Example of target page

Install

Install.java is a stripped-down version of the generic installation demonstrated in euroLCC that onlyreplaces the first <!--Install_wordir--> place holder in web.xml by the installation directory of the archive.

LoginCtrl

LoginCtrl implements three methods:

  • The servlet’s init method that sets some variables

  • The servlet’s doGet method that displays login.jsp

  • The servlet’s doPost method that handles the request parameters, creates the PrometheusCallback and LoginBean session instances and displays login.jsp

LoginBean

LoginBean contains four member variables:

  • User pseudo name

  • Location

  • Array of area of interest

  • The PrometheusCallback instance bound to the application context

LoginBean implements the HttpSessionBindingListener interface. Because LoginCtrl binds LoginBean instances to sessions (with the HttpSession.setAttribute method) the LoginBean’s valueUnbound method is called when the session is invalidated either thank to user action (unlog button) or because the session has expired. valueUnbound calls the removeUser method of PrometheusCallback.

PrometheusCtrl

PrometheusCtrl implements three methods:

  • The servlet’s init method that sets some variables

  • The servlet’s doGet method that displays prometheus.jsp

  • The servlet’s doPost method that handles the request parameters, creates the PrometheusBean session instance and displays prometheus.jsp

PrometheusBean

PrometheusBean implements three methods of interest:

  • getUser that returns the user logged in this session

  • getMessages that formats in HTML the messages received by the logged user

  • getUsers that formats in HTML the users logged on the constellation

  • getPageboxes that formats in HTML the URLs of the constellation PageBoxes

PrometheusCallback

PrometheusCallback implements the TokenCallbackIF and HttpSessionListener interfaces.

PrometheusCallback also implements methods called by LoginCtrl:

  • addUser

  • removeUser

PrometheusCallback also implements methods called by LoginCtrl:

  • send

  • sendTo

  • sendFiltered

PrometheusCallback has five member objects of interest:

  • users: a map that describes local users. The key is the user name and the value is a UserInfo object.

  • foreignUsers: a map that describes users defined on other PageBoxes on the ring. The key is the URL of the DeployIF Web service of the PageBox and the value is a HashMap whose key is the user name and value is a UserInfo object.

  • messages: a map that contains messages to send to other PageBoxes on the ring. The key is the URL of the DeployIF Web service of the target PageBox or all if the message is a broadcast message. The value is a Message object.

  • received: a map that contains received messages. The key is the user name and the value is a TreeMap. The key in this TreeMap is the URL of the DeployIF Web service of the origin PageBox or "local" if the message was sent by a user on the same Prometheus instance. The value in this TreeMap is another TreeMap whose key is the message timestamp and value is the message itself.

  • sender: object to use to send messages to other PageBoxes on the ring

A user in users and foreignUsers is represented by a UserInfo object. The UserInfo class is defined like this:

class UserInfo implements Serializable {

String location = null;

String[] aoi = null;

}

Where

  • location is the location entered by the user on the login.jsp form

  • the aoi entries are the user areas of interest entered by this user on the login.jsp form

Message is defined like this:

class Message implements Serializable {

String user = null;

String timestamp = null;

String from = null;

String msg = null;

}

Where

  • user is either a user name or "all" or ! followed by a filter string. A filter string has a syntax [loc/location] [sub/area_of_interest]* where location and area_of_interest are string entered by the sender on the prometheus.jsp form.

  • timestamp contains the time when the message was sent

  • from is the name of the user who sent the message

  • msg is the message entered by the sender on the prometheus.jsp form

setSender

The setSender of TokenCallbackIF is called when Prometheus calls the registerCallback method of the PageBox API to insert into the ring. setSender stores the sender object in the sender member variable.

call

The call method of TokenCallbackIF is called when the PageBox receives a frame. This frame may contain:

  • "prometheus" messages: type PrometheusCallback.Message; messages issued by other Prometheus instances

  • "users" messages: type HashMap; users maps of other Prometheus instances

When it is called with type = "prometheus" call adds the message to the received map.

When it is called with type = "user" calls adds the user map of the foreign Prometheus instance to the foreignUsers map.

Then call adds a message of "prometheus" type to the frame (with the sender.send method) for every entry found in the messages map.

Eventually call adds a message of "users" type to the frame (with the sender.send method) for its users map.

addUser

addUser adds a user to the users map except if this user name is "all", which is the broadcast user or the user name starts with "!", which is used for filters.

removeUser

removeUser removes a user from the users map except if this user name is "all", which is the broadcast user or the user name starts with "!", which is used for filters.

send

There are three flavors of the send method

  • The send method with two parameters, the user who sends the message and a message string is a broadcast version. It sends a message to all users. This version calls the addLocalMessage method to send the message to the "all" local user and add the message to the messages map with a "all" target.

  • The send method with three parameters, the name of the target user, the user who sends the message and the message string. It sends a message to the target user. It this user is local this send method calls the addLocalMessage method to add the message to the received map. Otherwise this send method adds the message to the messages map with the user PageBox as target PageBox.

  • The send method with four parameters, the target PageBox, a filter string, the user who sends the message and the message string. It sends a message to the users defined on the target PageBox that match the filter string. If the target PageBox is "local" this send method calls the addLocalMessage method to add the message to the received map. Otherwise this send method adds the message to the message map with the target PageBox as target and "!" filter string as user name.

addLocalMessage

addLocalMessage adds the message to the received map with a "local" key.

sendTo

The sendTo method sends a message to all users on a specified PageBox. If the PageBox is "local" sendTo calls the addLocalMessage method to send the message to the "all" local user. Otherwise sendTo adds the message to the message map with the designated PageBox as target and "all" as user name.

sendFiltered

The sendFiltered method sends a message to users that match a filter string on a specified PageBox. If the PageBox is "local" sendFiltered calls the addLocalMessage method to send the message to a "!" filter string local user. Otherwise sendFiltered adds the message to the message map with the designated PageBox as target and "!" filter string as user name.

getUserMessages

getUserMessages is called by PrometheusBean.getMessage to return messages of interest for a user, which are:

  1. Messages targeting this specific user

  2. Broadcast messages

  3. Messages whose filtering criteria match the user location and areas of interest


getUserMessages returns null if there is no message for this user or a TreeMap that it builds in the following way:

  1. getUserMessages enumerates the entries in the received map

  2. If the target user is this user getUserMessages adds the entry content to the returned TreeMap

  3. If the target user is "all" getUserMessages adds the entry content to the returned TreeMap

  4. If the target user is a filter (starts with "!") and if this user matches filtering criteria (matchingFilter(filter, user) returns true) getUserMessages adds the entry content to the returned TreeMap

matchingFilter

matchingFilter is called by getUserMessages to check if a message target is a filter and matches the user location and areas of interest.

matchingFilter parses the filter string and checks

  • When the filter contains a location if the user location is the same as specified in the filter. If it is not the same matchingFilter returns false.

  • For each area of interest defined in the filter if the user has this area of interest. If the user doesn’t have this area of interest matchingFilter returns false.


Therefore matchingFilter returns true only if when the user fulfills all criteria in the filter.

UserManager

UserManager is normally redundant with the HttpSessionBindingListener implementation of LoginBean. Its attributeRemoved method is called like the valueUnbound method of LoginBean when the session is invalidated.

UserManager implements the HttpSessionAttributeListener interface to be called when an attribute is added to or removed from the session. The container calls the HttpSessionAttributeListener methods when the UserManager class is declared as a listener in web.xml:

<listener>

<listener-class>prometheus.UserManager</listener-class>

</listener>

The attributeRemoved method calls the removeUser method of PrometheusCallback.

EntriesCtrl

EntriesCtrl implements three methods:

  • The servlet’s init method that sets some variables

  • The servlet’s doGet method that displays entries.jsp

  • The servlet’s doPost method that handles the request parameters, creates if it doesn’t exist yet the EntriesBean application instance, calls the addEntry method of the EntriesBean instance and displays entries.jsp

EntriesBean

EntriesBean has the following members of interest:

  • A handle to a PageBoxAPI instance

  • A isInitialized boolean. When isInitialized is false EntriesCtrl.doPost and RoutingCtrl.init call the init method that set this boolean to true.

  • A entries map whose keys are entry logical names and values are Entry objects.

The Entry class is defined like this:

class Entry {

String must;

NiceIf niceif;

	String url;

}

It contains essentially the same data as the ActiveEntry class of PageBoxLib. This map of entries is filled by addEntries and used by the getEntries method to display the service instances declared locally.

init

init creates the PageBox instance and calls its ActiveNamingLogon method.

addEntry

addEntry adds a new entry to the entries map and calls the addEntry method of the PageBoxAPI instance.

end

end is called by the destroy method of EntriesCtrl when the Prometheus application is unloaded.

end calls the clearEntries and the ActiveNamingLogoff methods of the PageBoxAPI instance.

getEntries

getEntries is called by entries.jsp to display the service instances declared locally.

getEntries enumerates the entries to return a set of HTML rows that displays the service instances.

getNames

getNames is called by routing.jsp to display a drop down list of the entry points declared in the constellation. getNames calls the getEntries method of the PageBoxAPI instance and returns the response formatted in HTML select options.

redirect

redirect is called by RoutingCtrl.doPost with a handle to the servlet output writer.

redirect calls the getCandidate method of the PageBoxAPI instance that returns the service URL.

Then redirects writes on the servlet output writer:

<html>

<body onload="javascript:document.parmSend.submit();">

<form name="parmSend" method="post" action="service URL">

<input type="hidden" name="name" value="entry logical name" />

<input type="hidden" name="must" value="must parameter" />

<input type="hidden" name="niceif" value="niceif parameter" />"

</form>

</body></html>

When this page is loaded in the browser it automatically redirects to the service page with a POST request that contains the entry logical name, the must and the niceif parameters. When the service page is redirect.jsp it displays these data.

RoutingCtrl

RoutingCtrl implements three methods:

  • The servlet’s init method that sets some variables and creates if it doesn’t exist yet the EntriesBean application instance

  • The servlet’s doGet method that displays routing.jsp

  • The servlet’s doPost method that handles the request parameters and calls the redirect method of the EntriesBean instance

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