Tải bản đầy đủ (.pdf) (50 trang)

Tài liệu XML, XSLT, Java, and JSP: A Case Study in Developing a Web Application- P11 ppt

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (167.56 KB, 50 trang )

482
Appendix C Source Code for bonForum Web Application
C.15 Filename: Projects\bonForum\src\
BonForumRobot.java
/*<Imports>*/
import java.io.*;
import java.net.*;
import java.util.*;
import java.applet.*;
import java.awt.Font;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Component; // temp
/*</Imports>*/
/** BonForumRobot repeatedly invokes showDocument method of applet.
* It can be used from a frame display to request a different frameset.
* It can also be used to continually refresh one frame from another.
* The applet parameters are:
* target, document, increment, limit, message and refresh.
* <p>For further information visit the open source
* <A HREF=””>BonForum Project on SourceForge</A>
* @author <A HREF=”mailto://”>Westy Rockwell</A>
*/
public class BonForumRobot extends Applet {
URL codeBase = null;
String document = “”;
String target = “”;
String messageLineOne = “”;
String messageLineTwo = “”;
String message = “”;
boolean refresh = false;


boolean continueRunning = true;
int increment = 0;
int limit = 0;
int counter = 0;
Font font = new Font(“TimesRoman”, Font.ITALIC,24);
public void init() {
System.out.println(“init()”);
// get other plugin parameters
target = getParameter(“target”, “_self”);
document = getParameter(“document”, “”);
increment = getParameter(“increment”, 20000);
limit = getParameter(“limit”, 10000);
message = getParameter(“message”, “BonForumRobot applet”);
refresh = getParameter(“refresh”, false);
// see these debugging messages on the Java Console
codeBase = this.getCodeBase();
System.out.println(“documentBase:” + this.getDocumentBase().toString());
System.out.println(“codeBase:” + codeBase.toString());
15 1089-9 XC 6/26/01 7:40 AM Page 482
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
483
C.15 Filename: Projects\bonForum\src\BonForumRobot.java
System.out.println(“refresh:” + this.refresh);
System.out.println(“target:” + this.target);
System.out.println(“document:” + this.document);
System.out.println(“increment:” + this.increment);
System.out.println(“limit:” + this.limit);
System.out.println(“message:” + this.message);
// forces application global error displays not to be in a frame:
if(document.indexOf(“forum_error”) > -1) {

if(!target.equals(“_top”)) {
target = “_top”;
System.out.println(“changed to forum_error target:” +
this.target);
}
}
}
public void start() {
// kick off thread to do the dirty work
setBackground(Color.cyan);
System.out.println(“start()”);
if (refresh) {
RefreshThread thread = new
RefreshThread(Long.toString(System.currentTimeMillis()), codeBase);
thread.start();
}
}
public void stopRunning() {
stop();
}
public void stop() {
System.out.println(“stop()”);
continueRunning = false;
}
public void paint(Graphics graphics) {
graphics.setFont(font);
graphics.setColor(Color.black);
if(message.equalsIgnoreCase(“debug”)) {
graphics.drawString(messageLineOne,10,20);
graphics.drawString(messageLineTwo,10,40);

graphics.drawString(target,10,60);
graphics.drawString(document,10,80);
graphics.drawString(new Boolean(refresh).toString(), 10, 100);
graphics.drawString(Integer.toString(increment), 10, 120);
graphics.drawString(Integer.toString(limit), 10, 140);
}
else {
graphics.drawString(messageLineOne,10,20);
graphics.drawString(messageLineTwo,10,40);
}
15 1089-9 XC 6/26/01 7:40 AM Page 483
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
484
Appendix C Source Code for bonForum Web Application
}
private String getParameter(String name, String defaultValue){
String retval = getParameter(name);
if (retval == null || retval.trim() == “”){
retval = defaultValue;
}
return retval;
}
private int getParameter(String name, int defaultValue){
int retval = defaultValue;
String tmp = getParameter(name);
if (tmp != null && tmp.trim() != “”){
try {
retval = Integer.parseInt(tmp);
} catch (NumberFormatException nfe) {
// don’t do anything.

// it’s still assigned to the defaultValue!
}
}
return retval;
}
private boolean getParameter(String name, boolean defaultValue){
boolean retval = defaultValue;
String tmp = getParameter(name);
if (tmp != null){
if (tmp.equalsIgnoreCase(“true”)) retval = true;
if (tmp.equals(“1”)) retval = true;
if (tmp.equalsIgnoreCase(“false”)) retval = false;
if (tmp.equals(“0”)) retval = false;
}
return retval;
}
public class RefreshThread extends Thread {
private URL codeBase;
public RefreshThread(String s, URL cb){
super(s);
codeBase = cb;
}
public void run() {
String uncachedDocument = “”;
String errorDocument = codeBase.toString() + “../forum_error.jsp”;
messageLineOne = “”;
messageLineTwo = “”;
// These are two behaviors that depend on the “target” parameter:
//
// 1. target = “_top”

//
// This means we are using the applet to break out of a frameset on
the browser.
//
// 2. target <> “_top”
15 1089-9 XC 6/26/01 7:40 AM Page 484
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
485
C.15 Filename: Projects\bonForum\src\BonForumRobot.java
//
// This means we are using the applet to periodically refresh a
document within a frame
//
//
// The code below here makes this applet repeat an action
(showDocument)
// roughly every increment seconds, with a maximum controlled by
the limit parameter.
// However, note that if target is “_top” no repetition of
showDocument occurs.
counter = 1;
while (continueRunning) {
// put it to sleep for “increment” milliseconds
messageLineOne = “”;
getAppletContext().showStatus(“bonForumRobot”);
repaint();
try { sleep(3*(increment/4)); } catch (InterruptedException e)
{continue;}
// put it back to sleep for a “yellow light”
messageLineOne = “refreshing...”;

repaint();
try { sleep(increment/4); } catch (InterruptedException e)
{continue;}
// are all iterations done?
if(counter > limit) {
System.out.println(“counter:” + counter + “ over limit:”
+ limit);
stopRunning();
continue;
}
// no, do it
counter++;
String millis = Long.toString(System.currentTimeMillis());
// LATER: we will somehow refresh content only if stale
if( (document.indexOf(“forum_error”) > -1)
|| (document.indexOf(“forum_login”) > -1)
|| (document.indexOf(“visitor_joins_chat”) > -1)
|| (document.indexOf(“visitor_starts_chat”) > -1)
|| (document.indexOf(“guest_executes_chat”) > -1)
|| (document.indexOf(“guest_exits_chat”) > -1)
|| (document.indexOf(“guest_executes_command”) > -1)
|| (document.indexOf(“guest_exits_command”) > -1)
|| (document.indexOf(“host_executes_chat”) > -1)
|| (document.indexOf(“host_exits_chat”) > -1)
|| (document.indexOf(“host_executes_command”) > -1)
|| (document.indexOf(“host_exits_command”) > -1)) {
//
// We fixup the filename as a unique filename to prevent
browser from
// retrieving the last result for a jsp uri request from

15 1089-9 XC 6/26/01 7:40 AM Page 485
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
486
Appendix C Source Code for bonForum Web Application
its cache.
//
// For example,
//
“http://localhost:8080/bonForum/jsp/forum/visitor_joins_chat.jsp#entry47”
// will become something like this:
//
“http://localhost:8080/bonForum/jsp/forum/visitor_joins_chat.jsp#entry47.962066767
851.tfe”
//
// The “millis” value added will create a unique
filename, so the browser will fetch the jsp
//
// The “.tfe” at the end of the uncached URL will map to
the BonForumEngine servlet.
//
// One drawback is that although the browser will look
for none of these unique names in the cache,
// it will nevertheless cache them, and cache them, and
cache them! Filling the cache with them!
//
uncachedDocument = document + millis + “.tfe”;
System.out.println(“Created name for uncachedDocument:” +
uncachedDocument);
}
else {

// NOTE: applet code must be in subfolder (e.g.,
“applet”) of folder with forum_login.jsp
// so this creates something like
“http://freedom:8080/bonForum/jsp/forum/forum_login.jsp”
uncachedDocument = errorDocument + millis + “.tfe”;
System.out.println(“Document not in list, using an error
document:” + uncachedDocument);
target = “_top”;
message = “Unknown destination, new login required!”;
}
if(target.equals(“_top”)) {
stopRunning(); // after this loop
getAppletContext().showStatus(message);
}
messageLineOne = “loading...”;
messageLineTwo = message;
repaint();
try {
getAppletContext().showDocument(new
URL(uncachedDocument), target);
} catch(MalformedURLException ee) {
System.out.println(“MalformedURLException:” +
ee.getMessage());
System.out.println(“MalformedURLException,
uncachedDocument:” + uncachedDocument);
15 1089-9 XC 6/26/01 7:40 AM Page 486
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
487
C.16 Filename: Projects\bonForum\src\de\tarent\forum\BonForumEngine.java
document = “”; // force errorDocument next time

}
messageLineTwo = “”;
}
}
} //End of Inner Class
}
C.16 Filename: Projects\bonForum\src\de\
tarent\forum\BonForumEngine.java
package de.tarent.forum;
/*<Imports>*/
import java.io.*;
import java.util.Hashtable;
import javax.servlet.*;
import javax.servlet.http.*;
/*</Imports>*/
/** BonForumEngine is the central servlet of bonForum web application.
* At present, it implements a chat. Its purpose is experimentation.
* It is described fully in the book:
* <i>XML, XSLT, Java and JSP - A Case Study in Developing a Web Application</i>,
* by Westy Rockwell, published by <A HREF=””>New
Riders</A>.
* Translation to German published by <A
HREF=””>Galileo Press</A>.
* <p>For further information visit the open source
* <A HREF=””>BonForum Project on SourceForge</A>
* @author <A HREF=”mailto://”>Westy Rockwell</A>
*/
public class BonForumEngine extends HttpServlet {
// holds and gives access to the data for the forum
private static BonForumStore bonForumStore = new BonForumStore();

// ensures nicknames are unique
private static Hashtable nicknameRegistry = new Hashtable();
// logs debugging information
private static BonLogger logBFE = null;
// controls logger output
private static String logging = null;
// false until logger ready
private static boolean loggingInitialized = false;
/** Initializes a BonForumEngine instance.
* Also sets its logging value from application init param.
* Also creates its logger if not done before.
*
*/
public void init() throws ServletException {
System.err.println(“ENTERING BonForumEngine init”);
if(!loggingInitialized) {
15 1089-9 XC 6/26/01 7:40 AM Page 487
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
488
Appendix C Source Code for bonForum Web Application
System.err.println(“BonForumEngine init loggingInitialized:” +
loggingInitialized);
logging = getServletContext().getInitParameter(“Logging”);
System.err.println(“BonForumEngine init logging:” + logging);
if(logging != null) {
logBFE = new BonLogger(“BonForumEngineLog.txt”, logging);
System.err.println(“BonForumEngine init logBFE:” + logBFE);
loggingInitialized = true;
System.err.println(“BonForumEngine init loggingInitialized:” +
loggingInitialized);

getBonForumStore().setLogging(logging);
System.err.println(“BonForumEngine init
getBonForumStore().setLogging(logging)”);
}
}
System.err.println(“LEAVING BonForumEngine init”);
}
/** Gets the BonForumStore from this BonForumEngine.
*
* @return BonForumStore
*/
public BonForumStore getBonForumStore() {
return bonForumStore;
}
private void log(String sessionId, String where, String what) {
if(logging != null) {
logBFE.logWrite(System.currentTimeMillis(), sessionId, where,
what);
}
}
/** Processes requests in context of web application rules.
* Called from BonForumEngine service method.
* Customizes the HttpServlet based engine as a web application
* (a chat in this case).
*
* @param request HttpServletRequest argument from service method
* @param response HttpServletResponse argument from service
method
* @param session HttpSession current
* @param bonForumCommand String routes request to next destination

* @return String bonForumCommand parameter, maybe changed by this method,
maybe not.
*
* @throws IOException
*/
protected String processRequest(HttpServletRequest request,
HttpServletResponse response,
HttpSession session,
String bonForumCommand)
throws IOException {
BonNode chatNode = null;
15 1089-9 XC 6/26/01 7:40 AM Page 488
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
489
C.16 Filename: Projects\bonForum\src\de\tarent\forum\BonForumEngine.java
Object obj = null;
String actorNickname = “”;
String actorAge = “”;
String xalanVersion = “”;
String sessionMaxInactiveMinutes = “”;
String actorRatingType = “”;
String chatModerated = “”;
String chatTopic = “”;
String chatSubject = “”;
String chatItem = “”;
String chatGuest = “”;
String chatMessage = “”;
String chatMessagesNavigator = “”;
String chatMessagesPageSize = “”;
String nameAndAttributes = “”;

String content = “”;
String forestHashtableName = “”;
String chatNodeKeyKey = “”;
request.setAttribute(“serviceStatus”, “InProcessRequestMethod”);
String sessionId = session.getId();
// using sessionId for now, later it will be
// replaced with userId, when user manager is implemented.
bonForumStore.initialize(sessionId);
// See if bonForumStore instance is bound to this ServletContext
// If not, bind bonForumStore so it can be found elsewhere in web app
// Then, you can use code like the following from other classes, to
// have access to the methods of the bonForumStore:
//
// BonForumStore bonForumStore =
// (bonForumStore)application.getAttribute(“bonForumStore”);
//
// Or, from a JSP page:
//
// if (pageContext.getServletContext().getAttribute(“bonForumStore”)
!= null) {
// BonForumStore bFS =
//
(bonForumStore)(pageContext.getServletContext().getAttribute(
// “bonForumStore”));
// }
//
// Of course, to use properties, it is simpler to do this:
//
// <jsp:useBean id=”bonForumStore”
// class=”de.tarent.forum.BonForumStore”

// scope=”application”/>
//
Object temp = getServletContext().getAttribute(“bonForumStore”);
if (temp == null) {
getServletContext().setAttribute(“bonForumStore”,
getBonForumStore());
15 1089-9 XC 6/26/01 7:40 AM Page 489
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
490
Appendix C Source Code for bonForum Web Application
}
// bonForumCommand selects the next state of the application
// Its value will be used to create a JSP filename.
// If it has no value here, construct one from bonCommand
// request parameter, or else, from other request parameters.
bonForumCommand = normalize(bonForumCommand).trim();
if(bonForumCommand.length() < 1) {
// As a second alternative the engine uses
// the bonCommand request parameter
// to tell where to forward the request
String bonCommand =
normalize((String)request.getParameter(“bonCommand”)).trim();
if(bonCommand.length() > 0) {
bonForumCommand = bonCommand;
}
else {
// As a third alternative, the engine can use any combination
// of one to three other parameters (actor, action, thing)
// to construct the bonForumCommand described above
String actorStatus =

normalize((String)request.getParameter(“actorStatus”)).trim();
String actionStatus =
normalize((String)request.getParameter(“actionStatus”)).trim();
String thingStatus =
normalize((String)request.getParameter(“thingStatus”)).trim();
if((actorStatus.length() > 0) ||
(actionStatus.length() > 0) ||
(thingStatus.length() > 0)) {
bonForumCommand = actorStatus + “_” + actionStatus + “_”
+ thingStatus;
// later, trim off leading and trailing underscore chars,
if any
}
else {
bonForumCommand = “forum_error”;
request.setAttribute(“serviceStatus”,
“ForwardToErrorPage”);
log(sessionId, “err”, “No bonForumCommand! Forwarding To
Error Page!”);
}
}
}
// used for debugging only:
session.setAttribute(“bonForumCommand”, bonForumCommand);
//
// NOTES: ADDING ELEMENTS to bonForumXML ForestHashtable using
BonForumStore
//
// The BonForumStore.add() method automatically finds parent nodeKey
three ways:

//
15 1089-9 XC 6/26/01 7:40 AM Page 490
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
491
C.16 Filename: Projects\bonForum\src\de\tarent\forum\BonForumEngine.java
// 1. If the parent is one of the intrinsic system elements then that
// element’s name (“bonForum”, “”actors”, “actions”, “things”, “system”,
etc.)
// is the key in the nodeNameHashtable for the parent nodeKey.
//
// 2. If the parent is not one of the intrinsic system elements
// (for example, a “message” element inside the “things” element)
// then the key in the nodeKeyHashtable is made up of the following:
// <sessionId> + “_” + <nodeKey.aKey> + “:” <elementName>.
// (for example: “54w5d31sq1_985472754824:message”)
// NOTE: there is also an option to leave out the nodeKey.aKey portion
of
// the key, for a selected list of node names (see ForestHashtable,
property
// UniqueNodeKeyKeyList. That reduces the size requirements of the
// nodeKeyHashtable (for example, by not storing all the message nodeKey
keys).
//
// 3. If the parent is one of certain elements that are loaded into
// the bonForumXML (like the “subjects” subtree loaded with the
// loadForumXML command, for example), then the nodeKey is in the
// corresponding hashtable for that upload.
// (For example, subjects elements are in the pathNameHashtable with
// a key made from the path from root to the node whose nodeKey is
saved.

// An example of a subject key is
“bonForum.things.subjects.Vehicles.Motorcycles”)
// NOTE: EACH add() method call also returns an object
// that can be cast to a NodeKey
//
// 1) YOU CAN USE THESE TO RE-CREATE THE nodeKeyHashtable nodeKey key.
//
// 2) YOU CAN ALSO USE THESE TO RECALL ELEMENTS BY NodeKey.
//
// With the cast returned object, you can keep a reference to any
// nodeKey around. For the message element just added, we could keep
// its nodeKey as follows:
//
// NodeKey messageNodeKey = (NodeKey)obj;
//
// Then, using the aKey member of the NodeKey, together with the
sessionId
// and the name of the node, you can recreate the key for the NodeKey in
the
// nodeKeyHashTable, and use it to add children to the node. For an
example,
// see below how we add hostKey to chat. That example uses two different
// cast returned objects, one to get the hostNodeKey as a String,
// the other to get the chatNodeKeyKey for adding a node (hostKey) with
that
// String as content to the chat node. That same hostKey value will be
15 1089-9 XC 6/26/01 7:40 AM Page 491
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
492
Appendix C Source Code for bonForum Web Application

used
// to stamp all messages from that host to that chat.
//
// We also use the NodeKey cast return object to get access to its
contents
//
// Notice, however, that the add() method involves extra overhead in the
// example just cited, where hostKey is added to chat, and elsewhere.
// The add() method in BonForumStore wraps the addChildNodeToNonRootNode
// method in ForestHashtable, which can be used instead, if parent
nodeKey
// is known. Having just one method adding nodes does have advantages
though.
// PROCESSING OF MANY FORUM COMMANDS IS NEXT
// This extra bonForum variable is available on most JSP form,
// It can be used later for setting options for bonForumCommand, or
whatever.
String actorReturning =
normalize((String)request.getParameter(“actorReturning”));
if(actorReturning.trim().length() > 0) {
session.setAttribute(“actorReturning”, actorReturning);
}
else {
session.setAttribute(“actorReturning”, “”);
}
// Incoming request parameters are used as “bonForum variables”
// (including actor data, GUI settings, chat messages, etc.).
// The parameter values are processed and/or set in attributes.
// Most are set in session attributes, but at least two in application
attributes.

// They can also be added to the bonForumXML “database” (chat messages
are, for example)
// These if clauses are roughly prioritized by frequency of access,
// and grouped by application state, (except for “_executes_chat”
commands)
if(bonForumCommand.indexOf(“host_executes_chat_controls”) > -1 ||
bonForumCommand.indexOf(“guest_executes_chat_controls”) > -1) {
//handle chatMessagesNavigator
chatMessagesNavigator =
normalize((String)request.getParameter(“chatMessagesNavigator”));
if(chatMessagesNavigator.trim().length() > 0) {
session.setAttribute(“chatMessagesNavigator”,
chatMessagesNavigator);
}
// handle chatMessage
// If we have a message save it as child of things,
// and the messageKey to the chat element.
chatMessage =
normalize((String)request.getParameter(“chatMessage”));
if(chatMessage.trim().length() > 0) {
// add message child to things element
15 1089-9 XC 6/26/01 7:40 AM Page 492
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
493
C.16 Filename: Projects\bonForum\src\de\tarent\forum\BonForumEngine.java
// get itemKey from session Attribute
String itemKey =
normalize((String)session.getAttribute(“itemKey”));
if(itemKey.trim().length() < 1) {
itemKey = “”;

log(sessionId, “err”, “processRequest() ERROR: session
has no itemKey!”);
}
// NOTE: make sure attribute name=value items are separated by
a space
// and that there are no spaces next to the “=” between
name and value
// You can have quotes inside the value string, but only
using \” to escape them
// to optimize speed, attributes ordered by frequency of
access using getAttributeValue()
nameAndAttributes = “message”;
nameAndAttributes = nameAndAttributes + “ itemKey=\”” +
itemKey + “\””;
// date and time stamp for message
nameAndAttributes = nameAndAttributes + “ timeMillis=\”” +
BonForumUtils.timeMillis() + “\””;
nameAndAttributes = nameAndAttributes + “ dateStamp=\”” +
BonForumUtils.getLastDate() + “\””;
// Try to get hostKey from session Attribute
// If it is not there get guestKey instead
// LATER: add systemKey to this also!
String actorKeyValue =
normalize((String)session.getAttribute(“hostKey”));
if(actorKeyValue.trim().length() < 1) {
actorKeyValue =
normalize((String)session.getAttribute(“guestKey”));
if(actorKeyValue.trim().length() < 1) {
log(sessionId, “err”, “no hostKey or guestKey for
message!!!!!!!!!!”);

actorKeyValue = “”;
}
else {
nameAndAttributes = nameAndAttributes + “
guestKey=\”” + actorKeyValue + “\””;
}
}
else {
nameAndAttributes = nameAndAttributes + “ hostKey=\”” +
actorKeyValue + “\””;
}
chatNodeKeyKey =
normalize((String)session.getAttribute(“chatNodeKeyKey”));
/* THESE ARE DEBUGGING TESTS
// test value with escaped quote (xml error)
15 1089-9 XC 6/26/01 7:40 AM Page 493
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
494
Appendix C Source Code for bonForum Web Application
nameAndAttributes = nameAndAttributes + “
type=\”te\\\”st\\\”ing\””;
// test unclosed quotes in value (xml error)
nameAndAttributes = nameAndAttributes + “ test1=\”” + “hello
test1!”;
*/
// if no actor key or no chatNodeKeyKey just silently omits
message
if(!actorKeyValue.equals(“”) && !chatNodeKeyKey.equals(“”)) {
// who said what in message
content =

normalize((String)session.getAttribute(“actorNickname”));
content += “::” + chatMessage;
// add message element as child of “things” in
bonForumXML, a ForestHashtable
forestHashtableName = “bonForumXML”;
obj = bonForumStore.add(“bonAddElement”, “things”,
nameAndAttributes, content, forestHashtableName, “nodeNameHashtable”, sessionId);
NodeKey messageNodeKey = (NodeKey)obj;
// get messageKey as String
//String messageKey = messageNodeKey.aKey + “.” +
messageNodeKey.bKey + “.” + messageNodeKey.cKey;
String messageKey = messageNodeKey.toString();
// add messageKey to chat
nameAndAttributes = “messageKey”;
//content = messageKey;
content = messageKey;
forestHashtableName = “bonForumXML”;
obj = bonForumStore.add(“bonAddElement”, chatNodeKeyKey,
nameAndAttributes, content, forestHashtableName, “nodeNameHashtable”, sessionId);
session.setAttribute(“messageKey”, messageKey);
}
}// end of chat message processing
}
else if(bonForumCommand.equals(“host_executes_chat”)) {
boolean haveSubject = true;
boolean haveTopic = true;
boolean actorIsHostInChat = false;
boolean actorIsGuestInChat = false;
boolean chatExistsForSubjectAndTopic = false;
boolean actorRestartingCurrentChat = false;

// get chat topic chosen by host
chatTopic =
normalize((String)session.getAttribute(“chatTopic”)).trim();
// if no topic, prevent chat start
if(chatTopic.length() < 1) {
log(sessionId, “err”, “ERROR: SESSION HAS NO chatTopic,
forwarding back to get it!”);
haveTopic = false;
}
else if(chatTopic.equalsIgnoreCase(“NONE”)) {
15 1089-9 XC 6/26/01 7:40 AM Page 494
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
495
C.16 Filename: Projects\bonForum\src\de\tarent\forum\BonForumEngine.java
log(sessionId, “err”, “ERROR: SESSION HAS chatTopic=NONE,
forwarding back to get it!”);
haveTopic = false;
}
// get chat Subject chosen by host
chatSubject =
normalize((String)session.getAttribute(“chatSubject”)).trim();
// if no subject, prevent chat start
if(chatSubject.length() < 1) {
log(sessionId, “err”, “ERROR: SESSION HAS NO chatSubject,
forwarding back to get it!”);
haveSubject = false;
}
else if(chatSubject.equalsIgnoreCase(“NONE”)) {
log(sessionId, “err”, “ERROR: SESSION HAS chatSubject=NONE,
forwarding back to get it!”);

haveSubject = false;
}
// Note: here we must synchronize two things:
// 1. the check to see subject+topic is taken
// 2. the addition of new chats.
// If we do not do that, two threads with same subject+topic
// can go through here very close together, and this can happen:
// - The first checked subject+topic and is about to add chat, but
hasn’t.
// - The second checks it subject+topic and finds it clear to use.
// - The first adds its chat with the same subject+topic.
// - The second adds its chat with the same subject+topic
// Problems! Using subject+topic to find chat again can only find
one!
//
// The first thread (thus session) that enters the synchronized
block
// gets a lock on bonForumStore object.
// The synchronized block is then closed to all other threads.
// Automatically blocked by Java, they must wait until they can
// get the lock on the bonForumStore object before they can enter.
// Thus the synchronization functions as a FIFO for the threads.
//
// this almost works, needs something else synchronized?
//synchronized(bonForumStore.bonForumXML) {
synchronized(bonForumStore) {
// If subject and topic are ok, see if that chat exists.
// If so, check for two things:
// 1. Is it the current chat for session and actor is trying to
restart it,

// 2. Is it a chat the actor is already in either as host or as
guest.
// (The third alternative is that it is a new chat to start.)
if(haveSubject && haveTopic) {
// see if subject+topic combination exists as a chat
15 1089-9 XC 6/26/01 7:40 AM Page 495
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
496
Appendix C Source Code for bonForum Web Application
String fakeChatItem = chatSubject + “_[“ + chatTopic + “]”;
// replace all ‘.’ with ‘_’ which is separator in chatItem
// ‘.’ is separator in pathNameHashtable
fakeChatItem = fakeChatItem.replace(‘.’, ‘_’);
String foundChatNodeKeyKey =
getBonForumStore().getBonForumChatNodeKeyKey(fakeChatItem);
if((foundChatNodeKeyKey != null) &&
(foundChatNodeKeyKey.length() > 0)) {
// a chat exists with chosen subject and topic
chatExistsForSubjectAndTopic = true;
// see if actor wants to restart current chat for session
// (that information may come in useful later for user
messages, preferences
String newChatSubject =
normalize((String)session.getAttribute(“newChatSubject”));
String newChatTopic =
normalize((String)session.getAttribute(“newChatTopic”));
if(!newChatTopic.equals(“yes”) &&
!newChatSubject.equals(“yes”)) {
// actor trying to re-start current chat for this
session

// see if current chat for session exists
chatNodeKeyKey =
normalize((String)session.getAttribute(“chatNodeKeyKey”));
if(chatNodeKeyKey.trim().length() > 0) {
// session has a chat
// see if it is the right one for subject and
topic
if(chatNodeKeyKey.equals(foundChatNodeKeyKey)) {
actorRestartingCurrentChat = true;
}
else {
//CHAT GONE! WILL RESTART ONE FOR SUBJECT &
TOPIC
chatExistsForSubjectAndTopic = false;
actorRestartingCurrentChat = false;
}
}
}
// see if actor is a host in chat found with requested
subject and topic
String actorKeyValue =
normalize((String)session.getAttribute(“hostKey”));
if(actorKeyValue.trim().length() > 0) {
actorIsHostInChat =
getBonForumStore().isHostInChat(actorKeyValue, foundChatNodeKeyKey);
}
if(!actorIsHostInChat) {
// if not, see if actor is a guest in current chat
actorKeyValue =
normalize((String)session.getAttribute(“guestKey”));

15 1089-9 XC 6/26/01 7:40 AM Page 496
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
497
C.16 Filename: Projects\bonForum\src\de\tarent\forum\BonForumEngine.java
if(actorKeyValue.trim().length() > 0) {
actorIsGuestInChat =
getBonForumStore().isGuestInChat(actorKeyValue, foundChatNodeKeyKey);
}
}
}
// If actor will rejoin existing chat,
// route actor there using a bonForumCommand,
// which determines next JSP destination.
// when engine forwards request.
boolean actorWillRejoinChat = false;
if(chatExistsForSubjectAndTopic) {
// cannot start chat, it exists already
haveTopic = false;
// Here later implement a user preference, using session
attributes.
// Choices can be offered for behavior of “visitor starts
chat” when chat exists
// 1. always warn user and ask again for new subject
and/or new topic
// 2 if actor was in it, always join with previous
status, else warn and ask again
// 3. if actor was in it, always join as guest, else warn
and ask again
// All these choices can be modified re
actorRestartingCurrentChat value

// For now, we implement choice #2
if(actorIsHostInChat) {
bonForumCommand = “host_executes_chat”;
actorWillRejoinChat = true;
else if(actorIsGuestInChat) {
bonForumCommand = “guest_executes_chat”;
actorWillRejoinChat = true;
}
else {
// cannot start existing chat
// set attribute for using on
visitor_starts_chat.jsp
// to trigger user message that chat exists:
session.setAttribute(
“chatSubjectAndTopicTaken”, fakeChatItem);
chatTopic = “”;
session.setAttribute(
“chatTopic”, “”);
session.setAttribute(
“newChatTopic”, “no”);
bonForumCommand = “visitor_starts_chat”;
}
}
// If actor will rejoin existing chat,
// need to set session attributes that
15 1089-9 XC 6/26/01 7:40 AM Page 497
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
498
Appendix C Source Code for bonForum Web Application
// are usually set when actor starts new chat.

//
if(actorWillRejoinChat) {
// nodeNameHashtable key for the chat node key is needed
for:
// 1. adding messages to chat later.
// 2. seeing if a chat is the current chat
session.setAttribute(“chatNodeKeyKey”,
foundChatNodeKeyKey);
// host session doesn’t need this,
// but if rejoining chat as guest, might?
session.setAttribute(“chatItem”, fakeChatItem);
// set the itemKey for this chat into a session attribute
// item key is added as a message attribute later
// it is needed for finding messages (temporarily)
// and for any guest session to find chat
String foundChatItemKey =
getBonForumStore().getBonForumChatItemNodeKey(fakeChatItem).toString();
session.setAttribute(“itemKey”, foundChatItemKey);
}
}
if(haveSubject && haveTopic) {
// actor starts chat
// Each actorNickname is unique in bonForum,
// Only one host node is allowed per actorNickname
actorNickname =
normalize((String)session.getAttribute(“actorNickname”));
// Try getting key to a host node
// for current actor’s nickname
NodeKey hostNicknameNodeKey =
getBonForumStore().getActorNicknameNodeKey( actorNickname, “host” );

NodeKey hostNodeKey = null;
if(hostNicknameNodeKey != null) {
BonNode hostNicknameNode =
getBonForumStore().getBonForumXML().getBonNode( hostNicknameNodeKey);
hostNodeKey = hostNicknameNode.parentNodeKey;
}
if(hostNodeKey == null) {
// If a host node key does not exist,
// then current actor is not yet a host,
// so add a new host node,
// with actorNickname,
// actorAge and
// actorRating children,
// to the “actors” root-child node
// of bonForumXML
nameAndAttributes = “host”;
content = “”;
forestHashtableName = “bonForumXML”;
obj = bonForumStore.add( “bonAddElement”, “actors”,
nameAndAttributes, content, forestHashtableName, “nodeNameHashtable”, sessionId );
15 1089-9 XC 6/26/01 7:40 AM Page 498
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
499
C.16 Filename: Projects\bonForum\src\de\tarent\forum\BonForumEngine.java
hostNodeKey = (NodeKey)obj;
String creationTimeMillis = hostNodeKey.aKey;
String hostNodeKeyKey = sessionId + “_” +
creationTimeMillis + “:host”;
// Make nodeNameHashtable key
// for the hostNodeKeyKey

// available to session.
// It gives quick access to last host nodeKey for session
session.setAttribute( “hostNodeKeyKey”, hostNodeKeyKey );
nameAndAttributes = “actorNickname”;
content = actorNickname;
forestHashtableName = “bonForumXML”;
obj = bonForumStore.add( “bonAddElement”, hostNodeKeyKey,
nameAndAttributes, content, forestHashtableName, “nodeNameHashtable”, sessionId );
//NOTICE: the commented-out line here is more efficient
than the above line.
// and does not require the hostNodeKeyKey to be
reconstructed!
// However, we may want the hostNodeKeyKey in a session
attribute for later?
// Also, if we use this next statement, then we are using
two ways to add
// data to the XML. It may be better if all adding goes
throught the
// wrapper method? Still trying to decide. Performance
difference may decide this?
// There are other similar lines that could be faster.
// They are in host handling, but not in message or guest
handling.
//bonForumStore.getBonForumXML().addChildNodeToNonRootNode(“actorNickname”, “”,
content, hostNodeKey, “nodeNameHashtable”, sessionId);
nameAndAttributes = “actorAge”;
content = normalize((String)session.getAttribute(
“actorAge” ));
forestHashtableName = “bonForumXML”;
obj = bonForumStore.add( “bonAddElement”, hostNodeKeyKey,

nameAndAttributes, content, forestHashtableName, “nodeNameHashtable”, sessionId );
nameAndAttributes = “actorRating”;
content = normalize((String)session.getAttribute(
“actorRating” ));
if(content.length() < 1) {
content = “5”;
}
forestHashtableName = “bonForumXML”;
obj = bonForumStore.add( “bonAddElement”, hostNodeKeyKey,
nameAndAttributes, content, forestHashtableName, “nodeNameHashtable”, sessionId );
}
// Add a chat node to the “things”
// root-child node of bonForumXML,
// with a chatModerated attribute,
15 1089-9 XC 6/26/01 7:40 AM Page 499
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
500
Appendix C Source Code for bonForum Web Application
// and no text content.
chatModerated = normalize((String)session.getAttribute(
“chatModerated” ));
if (chatModerated.equalsIgnoreCase(“yes”)) {
nameAndAttributes = “chat moderated=\”yes\””;
}
else {
nameAndAttributes = “chat moderated=\”no\””;
}
content = “”;
forestHashtableName = “bonForumXML”;
obj = bonForumStore.add( “bonAddElement”, “things”,

nameAndAttributes, content, forestHashtableName, “nodeNameHashtable”, sessionId );
NodeKey chatNodeKey = (NodeKey)obj;
// Add a hostKey to the new chat node,
// its text content is the key to the host node
String creationTimeMillis = chatNodeKey.aKey;
chatNodeKeyKey = sessionId + “_” + creationTimeMillis +
“:chat”;
nameAndAttributes = “hostKey”;
content = hostNodeKey.toString();
forestHashtableName = “bonForumXML”;
obj = bonForumStore.add( “bonAddElement”, chatNodeKeyKey,
nameAndAttributes, content, forestHashtableName, “nodeNameHashtable”, sessionId );
// Make the hostKey available to this session.
// It is later used for these things:
// 1. finding out if an actor is a host in a chat
// 2. branding messages with a host as sender
session.setAttribute(“hostKey”, content);
// Make nodeNameHashtable key
// for the chat node key
// available to session.
// It is useful later for these things:
// 1. adding messages to chat
// 2. finding the chat node
// (to add nodes or attributes)
// 3. determining if a chat is the current chat
session.setAttribute( “chatNodeKeyKey”, chatNodeKeyKey );
// Add a “chatItem” child
// to the selected chat subject element.
// That selected element is
// the chat subject category

// in bonForumXML.
// The name of the new child is “sessionID_” +
// the sessionId of
// the visitor starting the chat +
// the time the chat node was created in millis.
// The time suffix allows more than one chat
// to exist per session.
// Also add an attribute called chatTopic,
// with the (escaped) chatTopic
15 1089-9 XC 6/26/01 7:40 AM Page 500
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
501
C.16 Filename: Projects\bonForum\src\de\tarent\forum\BonForumEngine.java
// input by the visitor.
// The sessionId (recoverable from
// the name of the new child) can
// be used later to quickly find the chat nodeKey.
// That is useful for example
// when a visitor joins a chat
// Note: when adding the sessionId
// element, its parent is found
// using the pathNameHashtable.
// The parent nodeKey is there
// with a key which is its pathName
// (and equal to chatSubject)
nameAndAttributes = “sessionID_”;
nameAndAttributes += sessionId;
nameAndAttributes += “_”;
nameAndAttributes += creationTimeMillis;
nameAndAttributes += “ chatTopic=\””;

nameAndAttributes += chatTopic;
nameAndAttributes += “\””;
content = “”;
forestHashtableName = “bonForumXML”;
obj = bonForumStore.add( “bonAddElement”, chatSubject,
nameAndAttributes, content, forestHashtableName, “pathNameHashtable”, sessionId );
NodeKey itemNodeKey = (NodeKey)obj;
// set itemKey to itemNodeKey as a string
String itemKey = itemNodeKey.toString();
// Add the key to the chatItem element (itemKey)
// to the chat element as an attribute
// The itemKey connects a chat
// to its subject, topic and messages!
String attributeName = “itemKey”;
String attributeValue = itemKey;
NodeKey nk = bonForumStore.addChatNodeAttribute(
chatNodeKeyKey, attributeName, attributeValue );
// Make the itemKey available to the session
session.setAttribute(“itemKey”, itemKey);
}
if((!chatExistsForSubjectAndTopic) && (!haveSubject ||
!haveTopic)) {
// missing information, must return to get it
// LATER: set attribute to trigger message to user
bonForumCommand = “visitor_starts_chat”;
}
} // end of synchronized block!
}// end of host_executes_chat processing
else if (bonForumCommand.equals(“guest_executes_chat”)) {
// assume visitor will join chat

boolean haveChatItem = true;
boolean chatExistsForSubjectAndTopic = false;
// get chat Subject/Topic pair chosen by guest
chatItem =
15 1089-9 XC 6/26/01 7:40 AM Page 501
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.

×