C.16 Filename: Projects\bonForum\src\de\tarent\forum\BonForumEngine.java 491
// 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:
// + “_” + + “:” .
// (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

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

C.16 Filename: Projects\bonForum\src\de\tarent\forum\BonForumEngine.java 495
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