PageBox for Java: Web application deployment using Java PageBox

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

Pandora implementation

Foreword

Objective

This document presents the implementation of Pandora.

Pandora is not a comprehensive application. Pandora fully implements aspects specific to a PageBox-enabled application but it doesn’t implements things like an administration and a mean allowing adding new articles. This limitation makes the implementation easier to understand and adapt. Pandora can be used as the skeleton of a real application.

Audience

Programmers who want to implement a PageBox-enabled Web application or adapt an existing application for a PageBox deployment.

Design choices

  1. Model View Controller (MVC) architecture

  2. Data stored in a RDBMS and accessed using JDBC

  3. Authentication by trusted referrers that communicate with Pandora using HTTP POST

  4. SOAP Web service for the communication with the central server

The reference implementation of Pandora uses the MySQL database (tested with MySQL 3.23.53) and the MySQL Connect/J 2 JDBC driver.

Data model

Pandora uses three tables:

  • command

  • item

  • article


article describes the referenced articles. An article has a unique ID, a name and a unit price. The article table also contains the available number of articles (qty) and the number of article sold on this Pandora instance.

command describes the commands. A command has a unique ID, data allowing charging a customer (name), data allowing delivering the command (addr,) the URL of the Payment facility Web service (payment,) the URL of the Delivery facility Web service (delivery) and the date when the command was made. name can contain the user ID, the user name, a billable account or an identifier returned by a payment facility. addr can contain the user address and mail address, the user office # and telephone #. Pandora doesn’t interpret the content of name and addr: the name and addr fields can have different formats on different Pandora instances. The only requirement is that the name format is understood by the payment facility and that the addr format is understood by the delivery facility.

item describes an item of a command. An item is uniquely identified by a command ID and by an article ID. An item has also a number of articles (qty.)

Components

The Pandora deliverables include:

  • The distributed application - the core of the Pandora demo - that implements the user interface

  • The referrer site page that links to Pandora and sends the payment and delivery information

  • The central application that maintains the number of articles available and calls the payment and delivery facilities

  • A mockup of payment and delivery facility

Pandora uses the PageBox API. See the PageBox API documentation for more details.

Use cases

Distributed application

The distributed application implements a user interface that allows customers creating commands, adding, updating or deleting items in the command and committing commands.

Central application

The distributed application periodically sends the filed commands to the central application.

Then the central application issues payment and delivery requests and returns an updated inventory to the distributed application.

Sandbox checking

PageBox version 0.0.7 implement a Java 2 security. With this security a deployed application cannot read and write files everywhere, run commands, use native code or create and use a class loader. Sandbox checking is a working example allowing PageBox administrators to check that the security is properly set. The distributed and the central applications and the payment/delivery mockup call this facility.

CheckSandbox

CheckSandbox exercises the sandbox in its constructor.

The constructor calls the following methods:

  • checkRead to try reading a file

  • checkWrite to try writing a file

  • checkCmd to try running a command

  • checkLoad to try loading and using native code

  • checkClassLoader to try creating a class loader and using it to load a class

checkRead

checkRead tries to read the file whose path was given as parameter and to log lines found in the file.

checkWrite

checkWrite tries to write "CheckSandbox" in the file whose path was given as parameter and then to delete this file.

checkCmd

checkCmd uses the Runtime to try executing the command given as parameter and waiting for its completion.

checkLoad

checkLoads tries calling the static write method of the CheckLoad class.

checkClassLoader

checkClassLoader tries

  1. Instantiating a CheckClassLoader

  2. Using this instance to load pandora.CheckLoaded

  3. Instantiating the pandora.CheckLoaded class

CheckLoad

CheckLoad implements a minimalist native interface:

public class CheckLoad {

private static native void writeLine(String line);

public static void write() {

writeLine("CheckLoad");

}

static {

System.loadLibrary(CheckSandbox.chkLib);

}

}

loadLibrary loads the library defined in CheckSandbox.chkLib when write is called for the first time (when the statics of CheckLoad are created.)

CheckClassLoader

CheckClassLoader extends ClassLoader. Its most important class is loadClass that gets called each time a program (or the JVM) requires a class load. loadClass loads classes from the directory given to the constructor and caches them in a classes map for subsequent requests.

Distributed application

The distributed application contains eight components:

  1. The user interface view, command.jsp

  2. The user interface model, CommandBean.java

  3. The user interface controller, CommandCtrl.java

  4. A component that periodically updates the central application, Publish.java

  5. The installation class, Install.java

  6. A view to display the URLs of the distributed application installed from the same Repository, neighbor.jsp

  7. A model to display the URLs of the distributed application installed from the same Repository, NeighborBean.java

  8. A controller to display the URLs of the distributed application installed from the same Repository, NeighborCtrl.java

CommandCtrl retrieves a CommandBean instance from the Session, parses the user request and updates the CommandBean instance. Then CommandCtrl forwards the request to common.jsp using RequestDispatch.forward.

common.jsp retrieves the CommandBean instance from the Session and calls its properties to display the form.

NeighborCtrl

  1. Calls the getClones method of PageBoxAPI

  2. Creates a NeighborBean with the list returned by getClones

  3. Adds this NeighborBean instance to the request attributes

  4. Forwards the request to neighbor.jsp

neighbor.jsp retrieves the NeighborBean instance from the request attribute and calls its getClones method to display the URLs of the distributed application installed from the same Repository.

command.jsp

command.jsp shows a form that:

  1. Displays the command items

  2. Allows selecting an article on a dropdown list

  3. Allows adding, updating and deleting command items

CommandBean.java

CommandBean implements the following read-only properties for command.jsp:

  • Articles. getArticles returns a set of Javascript instructions price[i]="price_i"; where i is the article ID and price_i is the price of the i article. When the user selects a different article a Javascript snippet in command.jsp uses this array to update the current article price.

  • Options. getOptions returns a set of HTML options <option value="i">name_i</option> where i is the article ID and name_i is the name of the article. Options is used to populate the Article dropdown list.

  • Items. getItems returns a set of HTML rows <tr><td><button name="delete" onClick=del("i")>Delete</button></td><td><button name="update" onClick=upd("i")>Update</button></td><td>name_i</td><td>qty_i</td><td>price_i</td></tr> where i is the article ID, name_i is the name of the article, qty_i is the number of articles i in the command and price_i is unit price of i * qty_i.

  • UpdatedId, Disabled, Qty and Price. These properties are used to handle updates. UpdatedId contains the ID of the updated item and is used by CommandCtrl to interpret the request. Disabled returns disabled="true" in updates to disable the article selection. Qty returns the current number of articles in the command. Price returns the price of the current article.

CommandBean implements its properties using an article map called articles and an item map called items.

CommandCtrl.java

CommandCtrl is a servlet and implements the servlet init, doGet and doPost methods.

Both doGet and doPost implement the object creation logic:

  1. Check if the user is authenticated in the checkReferrer method

  2. Retrieve the distributed application directory

  3. Instantiate PageBoxAPI the first time CommandCtrl.doGet or CommandCtrl.doPost is called

  4. Instantiate Publish the first time CommandCtrl.doGet or CommandCtrl.doPost is called

  5. Instantiate CommandBean in a createCb method when the user enters a new session

createCb uses the PageBox API to read the article list from the database and initiate the CommandBean instance. Then doGet and doPost store the CommandBean instance in the Session object.

The distributed application uses HTTP POST. Therefore doPost must also parse the user request. The user request can be:

  • Adding a new article to a command. In this case doPost calls an add method.

  • Updating (changing the number of articles) a command. In this case doPost calls an update method.

  • Deleting an article from a command. In this case doPost calls a delete method.

  • Committing a command: updating the command and item tables in order to persist the command. Up to the commit the command data are only stored in CommandBean. In this case doPost calls a commit method.

Before looking at these methods we must present how CommandCtrl handles the database tables.

  1. The fields of the command record are set from the authentication data retrieved by the checkReferrer method.

  2. The fields of the item records are set from the items Map of CommandBean. The keys of this Map are the article Ids and the values of this Map are Item objects.

  3. The article records are copied in an articles Map of CommandBean. The keys of this Map are the article IDs and the values of this Map are Article objects.

The Article class is defined like this:

class Article {

String name;

float price;

int qty;

}

Where:

  • name is the article name

  • price is the unit price of the article

  • qty is the number of articles available for sale

Initially the article table and therefore the Articles objects contain what the installation class has set. Then each time it calls the Update Web service Publish gets an updated article list and updates the article table. The distributed application cannot sell more than qty but when concurrent customers ask for the same article in different sessions. See the presentation of the demo for a full explanation of this mechanism.

The Item class is defined like this:

class Item {

int qty;

}

Where qty is the number of articles with a given article ID in the command.

update

update retrieves the Item object corresponding to the selected item and updates its qty field with the number entered by the user. update rejects the update request if the requested quantity is higher than the qty of the article.

add

If there is already an Item object for this article, add adds to its qty the number entered by the user. Add rejects the add request if the total quantity is higher than the qty of the article.

If there is no Item object for this article, add creates an Item object and sets its qty with the number entered by the user. add rejects the add request if the requested quantity is higher than the qty of the article.

delete

delete removes the Item object corresponding to the selected item from the items Map.

checkReferrer

The distributed application doesn’t implement a authentication mechanism of its own or provided by the Application server. Instead it trusted referrer sites that can prove their identity.

CheckReferrer first checks if the user information is already stored in the Session.

User information is made of four fields and four Session attributes:

CommandCtrl field

Session attribute

Meaning

user

user

Data that uniquely identifies the user and allows charging it with the payment facility

addr

addr

Data that uniquely identifies the user and allows to deliver the article to it using the delivery facility

payment

payment

Web service URL of the payment facility

delivery

delivery

Web service URL of the delivery facility

If the user information is not yet stored in the Session checkReferrer assumes that the user is coming from a trusted application that has properly set the user information in HTTP POST data and proven that it is a trustable referrer.

checkReferrer expects that the user request contains six fields:

  1. name (user in the Session and in CommandCtrl)

  2. addr

  3. payment

  4. delivery

  5. certificate: the certificate used to sign the name field

  6. signature: the signature of name with the certificate

checkReferrer verifies that the name is signed with the certificate passed in parameter, which implies that the referrer owns the private key corresponding to the certificate. The referrer site page shows an example of valid link to the distributed application.

Then checkReferrer stores the user information in Session attributes.

Note:

In a production environment you must also check that the certificate was issued by a trusted authority.

commit

commit records the command stored in CommandBean in the command and item tables. It also updates the article table.

commit

  1. Insert a new command record

  2. Retrieves the unique command ID

  3. For each Item object in the items map inserts a new item record and updates the corresponding article record: the quantity sold = former quantity sold + qty and the quantity to sell = former quantity to sell - qty

Publish.java

Publish extends Thread: its run method runs in an independent thread created when Publish is instantiated at the first invocation of CommandCtrl. Publish sends the commands recorded in the command and item tables in batch to the central server using an Update Web service.

The Update Web service implements the UpdateIF interface:

interface UpdateIF extends Remote {

class Item {

int id;

int qty;

}

class Command {

String name;

String address;

String payment;

String delivery;

long date;

Item[] items;

}

class Article {

int id;

String name ;

float price;

int qty;

}

Article[] update(Command[] orders) throws RemoteException;

}

Publish has three methods, its constructor, its run method and an update method.

Publish

The Publish constructor retrieves the URL of the Update Web service in a central.txt file.

Then it instantiates an Update Web service stub, sets its URL and starts the Thread. Then run is called.

run

run calls the update method every period. period is a context parameter.

update

update

  1. Reads the commands from the command table.

  2. For each command creates and sets a Command object

  3. For each item in the item table whose cdid = the command ID creates and sets a Item objects in the items array of the command object

  4. Calls the update method of the Web service

  5. If the update call was successful clears the command and item tables

  6. Update the article table with the Article array returned by the update call

Note:

In a production implementation the article table would probably contain a validity range:

An article would have a price and an available quantity between a date A and a date B.

It would be possible to remove an article.

These functions are easy to implement but wouldn’t improve the clarity of the Pandora example.

Install.java

The Install class implements the InstallIF interface and is called by the PageBox once the archive has been installed on the target Application server and before the archive is dynamically deployed on the Application server. For more information about the Installation interface see the developer guide and the installation guide.

The same installation class is used by all applications. However only the distributed and the central application need a database update. The table below summarizes the use of the installation class features by the applications:

Web application

Database update

web.xml update

Distributed application

yes

yes

Central application

yes

yes

Payment or delivery application

no

yes

If it doesn’t contain the update placeholder the application web.xml file is not updated.

If the PageBox administrator has not configured the JDBC info in rules.xml, the database update is not performed (case of the payment and delivery applications.)

install

The install method is a method of the InstallIF interface. The install method is called by PageBox to perform a post installation.

In case of update the install method of the Pandora installation class drops the article table with the dropArticle method and re-create/populate the article table with the createArticle method.

In case of new installation the install method of the Pandora installation:

  • Updates the archive’s web.xml with the updateWebXml

  • Drops all Pandora tables with the drop method and re-create the tables with the create method

uninstall

The uninstall method is a method of the InstallIF interface. The uninstall method is called by PageBox to perform a de-installation.

In case of de-installation for update uninstall does nothing.

Otherwise uninstall drops all Pandora tables with the drop method.

drop

drop calls dropArticle to drop the article table and drops the command and item tables.

create

create creates the command and item tables and calls the createArticle method to create and populate the article table.

dropArticle

dropArticle drops the article table.

createArticle

createArticle creates the article table. Then it reads an article.csv file from the archive directory.

article.csv must contain four columns separated by commas:

  1. article ID that must be an integer

  2. article name, a string

  3. article price that is parsed as a float: enter it in a format iii.jj

  4. article number that must be an integer

For each row in the article.csv file createArticle inserts a record in the article table.

updateWebXml

updateWebXml illustrates configuration updates in installation classes.

The web.xml is expected to contain a workdir context parameter with an update placeholder:

<context-param>

<param-name>workdir</param-name>

<param-value><!--Install_wordir--></param-value>

</context-param>

updateWebXml replaces <!--Install_wordir--> by the archive directory.

Here is how it works. updateWebXml

  1. Checks that web.xml exists at the expected location archive_directory/WEB-INF/web.xml

  2. Creates a new configuration file web2.xml

  3. Reads web.xml and looks for <!--Install_wordir-->

  4. Rewrites on web2.xml but when it finds <!--Install_wordir-->. In that case updateWebXml writes the path of the archive directory

  5. Renames web2.xml into web.xml

Referrer site pages

The referrer site pages are designed to simulate an actual authentication mechanism.

The referrer environment is made of three components:

  1. login.jsp that allows the user to enter authentication information

  2. link.jsp that implements a link to the distributed application and is the view of the link

  3. LinkBean.java that computes the signature of the referrer site and is the model of the link

login.jsp

login.jsp displays a form with four text area:

  1. name: data that uniquely identifies the user and allows charging it with the payment facility

  2. address: data that uniquely identifies the user and allows to deliver the article to it using the delivery facility

  3. payment: Web service URL of the payment facility

  4. delivery: Web service URL of the delivery facility

When the user clicks on the Login button login.jsp stores these data in Session attributes.

link.jsp

link.jsp implements two mechanisms:

  1. Automatic redirect to the distributed application’s CommandCtrl

  2. Link to the distributed application’s CommandCtrl

When it is called link.jsp retrieves the user name from a Session attribute, instantiates a LinkBean object and sets its name property.

Both mechanisms described above are actually implemented in a goto script and in a PandoraForm hidden form. The automatic redirect is triggered by <body onload="goto();"> whereas the link is triggered by <a onClick="goto();"

goto is implemented like this:

function goto() {

document.PandoraForm.action="command";

document.PandoraForm.submit();

}

action contains the URL of CommandCtrl. In the code above we can set a relative URL because the Referrer site components are packaged in the distributed application. On production systems the referrer site and the distributed applications are not hosted by the same Web application and often even by the same Web site. In these cases the URL has to be a full URL.

To pass the information needed by CommandCtrl.checkReferrer the PandoraForm hidden form is coded like this:

<form name="PandoraForm" method="post">

<input type="hidden" name="msg" value='<%= lb.getMessage() %>' />

<input type="hidden" name="certificate" value='<%= lb.getCert() %>' />

<input type="hidden" name="signature" value='<%= lb.getSignature() %>' />

<input type="hidden" name="name" value='<%= name %>' />

<input type="hidden" name="addr" value='<%= session.getAttribute("PandoraAddr") %>' />

<input type="hidden" name="payment" value='<%= session.getAttribute("PandoraPayment") %>' />

<input type="hidden" name="delivery" value='<%= session.getAttribute("PandoraDelivery") %>'/>

</form>

Where lb is the LinkBean instance.

LinkBean.java

LinkBean implements a constructor, a Name write property and two read properties, Cert and Signature.

LinkBean

The LinkBean constructor takes four parameters:

  1. The name of a key store

  2. The password of this key store

  3. The alias in the key store of the (private key, certificate) to use to prove its identity to the distributed application

  4. The password of this alias

Note:

In a production environment the keystore and the (name, password) uples should not be accessible even in read mode to prevent security and repudiation problems. In the future we plan to support the automated distribution of link pages with PageBox. These pages will then be used in existing Web applications. It can imply some enhancements of the installation process.

Here is an example of invocation from link.jsp:

LinkBean lb = new LinkBean("E:\java\pandora\keystore", "kspasswd", "mycert", "mypasswd");

The constructor loads the key store and retrieves the certificate and private key from the key store.

setName

setName stores the name in a member variable.

getCert

getCert returns the certificate.

getSignature

getSignature signs the name with the private key and returns the signature.

Central application

The central application

  • Implements the Update Web service

  • Uses the same table definitions as the distributed application

  • Uses the PageBox API

Therefore the central application can also be deployed using PageBox and the same installation class as the distributed application.

The main part of the central application is the implementation of the Update Web service, UpdateImpl.

UpdateImpl.java

UpdateImpl implements the UpdateIF and the ServiceLifecycle interfaces.

The main methods of UpdateImpl are init and update.

init

init is a method of the ServiceLifeCycle interface. init is called just before the first Web service invocation.

init retrieves the directory of the Central application from a context variable, workdir.

Then init creates a PageBox API instance and creates a stub for the Query Web service of the payment and delivery facilities.

update

update is the method of the UpdateIF interface (and of the Update Web service.)

update uses the PageBox API to get a database connection.

Then for each Command object in the orders array update:

  1. Sets the URL of the Query Web service to the payment URL of this command

  2. Calls the payment Web service with the name of this command as parameter

  3. Sets the URL of the Query Web service to the delivery URL of this command

  4. Calls the delivery Web service with the name of this command and an items array as parameters

  5. Inserts a new record in the command table

  6. For each item in the items array of the Command object inserts a new record in the item table

  7. Updates an arts Map that contains an Art object for each article included in these commands

The Art class is defined like this:

class Art {

int qty;

int sold;

}

update stores in the arts map the quantity of articles sold and still available for sale.

Next for each article in arts update updates the quantity sold and available in the corresponding record in the article table.

Eventually update reads the article table to build the Article array returned by the Web service.

Payment/delivery

The payment and delivery mockups implement the Query Web service and use the PageBox API. Therefore the payment and delivery mockups can also be deployed using PageBox and the same installation class as the distributed and central applications.

The Query Web service has the following interface:

interface QueryIF extends Remote {

class Item {

int id;

String name;

float price;

int qty;

}

class Status {

int rc;

String msg;

}

Status query(String id, Item[] items) throws RemoteException;

}

Where

  • id is the data that allows charging the customer (payment) or delivering the good

  • Each item object contains the article ID, the name of the article, its unit price and the requested number of articles (qty)

  • rc can contains an error code (< 0) or a tracking number

  • msg can contain additional status information

The main part of the central application is the implementation of the Query Web service, QueryImpl.

QueryImpl.java

QueryImpl implements the QueryIF and the ServiceLifecycle interfaces.

The main methods of QueryImpl are init and query.

init

init is a method of the ServiceLifeCycle interface. init is called just before the first Web service invocation.

init retrieves the directory of the Central application from a context variable, workdir.

Then init creates a PageBox API instance.

query

query is the method of the QueryIF interface (and of the Query Web service.)

In this mockup query simply logs the request and returns a fake status.

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