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

232
Chapter 8 Java Servlet and Java Bean: BonForumEngine and BonForumStore
Table 8.7 JSP Transitions vs. Actor-Chat Relationships
Chat Exists Already Chat DoesNot
Exist
Actor Is Not Actor Is Actor Is
in Chat Host Guest
visitor guest host guest host executes
starts chat executes chat(1) executes chat(1) executes chat(1)(2) chat
visitor guest executes host guest forum
joins chat chat executes chat(3) executes chat error
Here are some notes for this table:
n
Numbered table items are optional, to be set by user preferences in a command,
with alternatives as follows:
1. visitor starts chat
2. host executes chat, if multihosted chat allowed
3. guest executes chat
n
If the actor is a host or a guest, the actor is rejoining the chat.
Rejoining Existing Chats
As you can see, if a chat with the requested subject and topic combination does not
exist, the visitor will become the host of a new chat for that combination. If the
requested chat exists already, then what happens depends upon an option setting. One
option is that the user will be taken back to “visitor starts chat” to try again with a dif-
ferent subject, topic, or both. (Actually, in the release of bonForum for this book, this
and other options listed in the notes are not yet available!)
As seen in the table cells for the “visitor starts chat” row, the outcome when a
requested chat already exists can be made to depend upon whether the visitor is
already a host or a guest in that chat. If not, the visitor becomes a new guest in the
chat. If the visitor already a member of the chat, the visitor rejoins as a host or a guest,

set bonForumCommand to guest_executes_chat
endif
endif
However, the code that actually exists is not that simple. Are the subject and the topic
okay? If not, the user is sent back to reinput them. If the subject and the topic are
okay, the code determines whether they have already been taken by an existing chat. If
they are available, then a new chat will be started now. If they are taken, the code finds
out even more. Is the visitor trying to restart the current chat for the session? (In the
future, that information can be used for user messages or to control user preferences.)
Is the actor already in the chat as a host or as a guest? If so, will the actor be joining or
rejoining an existing chat? If so, the code must set some session attributes with the
right values so that they reflect the chat.
Some of the methods and variables used by this code might not become clear until
later in the section. Here is the code, excerpted from the
processRequest()
method,
with one part of it substituted by comments that show the pseudocode for the omit-
ted source:
if(haveSubject && haveTopic) {
String fakeChatItem = chatSubject + “_[“;
fakeChatItem = fakeChatItem + chatTopic + “]”;
// ‘_’ is separator in a chatItem
// ‘.’ is separator in pathNameHashtable keys
fakeChatItem = fakeChatItem.replace(‘.’, ‘_’);
// example fakeChatItem:
// Animals_Bird_Hawk_[Medieval falconry]
String foundChatNodeKeyKey = getBonForumStore().getBonForumChatNodeKeyKey(

fakeChatItem );
if((foundChatNodeKeyKey != null) && (foundChatNodeKeyKey.length() > 0)) {

“hostKey” ));
if(actorKeyValue.trim().length() > 0) {
actorIsHostInChat = getBonForumStore().isHostInChat(

actorKeyValue, foundChatNodeKeyKey );
}
if(!actorIsHostInChat) {
actorKeyValue = normalize((String)session.getAttribute(

“guestKey” ));
if(actorKeyValue.trim().length() > 0) {
actorIsGuestInChat = getBonForumStore().isGuestInChat(

actorKeyValue, foundChatNodeKeyKey );
}
}
}
boolean actorWillRejoinChat = false;
if(chatExistsForSubjectAndTopic) {
// cannot start an existing chat
haveTopic = false;
if(actorIsHostInChat) {
bonForumCommand = “host_executes_chat”;
actorWillRejoinChat = true;
}
else if(actorIsGuestInChat) {
bonForumCommand = “guest_executes_chat”;
actorWillRejoinChat = true;
else {
// set attribute to trigger

// and for guest sessions to find chat.
String foundChatItemKey =

getBonForumStore().getBonForumChatItemNodeKey( fakeChatItem ).toString();
session.setAttribute( “itemKey”, foundChatItemKey );
}
}
Setting
haveTopic
(or
haveSubject
) to
false
sends the user back to the “visitor starts
chat” bonForum state.
Starting a Chat
In our discussion of the
processRequest()
method, we have come to a very important
block of code, the one that transforms a bonForum visitor into a chat host. It adds
quite a few elements to the XML data: a host element (if the visitor has none yet), a
chat element, and a
chatItem
element (that relates the chat to its subject and contains
its topic).The method also adds the key to the new
chatItem
as an XML attribute in
the new chat element, which will relate the chat to its
chatItem
and later to its mes-

// 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”;
08 1089-9 CH08 6/26/01 7:33 AM Page 236
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
237
8.1 The BonForumEngine Servlet

// we are using two ways to add data to the
// XML, and it may be better to only use the
// wrapper method. Still trying to decide.
// There are other similar lines below!
// 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”;
08 1089-9 CH08 6/26/01 7:33 AM Page 237
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
238
Chapter 8 Java Servlet and Java Bean: BonForumEngine and BonForumStore
content = normalize((String)session.getAttribute( “actorRating” ));

if(content.length() < 1) {
content = “5”;
}
forestHashtableName = “bonForumXML”;

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.
// Example key: ofl37sijm1_987195762494:chat
08 1089-9 CH08 6/26/01 7:33 AM Page 238
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
239
8.1 The BonForumEngine Servlet
// 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

NodeKey itemNodeKey = (NodeKey)obj;
// set itemKey to itemNodeKey as a string
08 1089-9 CH08 6/26/01 7:33 AM Page 239
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
240
Chapter 8 Java Servlet and Java Bean: BonForumEngine and BonForumStore
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(!(haveSubject && haveTopic)) {
// missing information, must return to get it
// LATER: set attribute to trigger message to user
bonForumCommand = “visitor_starts_chat”;
}
Adding a Host Actor
Recall that in the bonForum XML data, a child of the root node is called
actors
.For
a chat, two important children of
actors

:
getActorNicknameNodeKey()
with the nickname and
host
as arguments.The returned
nickname
nodeKey
, if any, is used to get the nickname node itself, using the
getBonNode()
method of
ForestHashtable
.The
parentNodeKey
member of the nick-
name node is the host
nodeKey
.
Actually, if the
getActorNicknameNodeKey()
method fails to return a
nodeKey
,we
know already that there is no host node for the nickname.Then why continue on to
get the node itself and its
parentNodeKey
? Because we will need this host
nodeKey
as a
string (
hostKey

earlier set by the
processRequest
method (see Section 8.1.14, “The
processRequest()
Method: Overall View”).
Note the following statements from the “add a host” part of the previous long
source code listing:
hostNodeKey = (NodeKey)obj;
String creationTimeMillis = hostNodeKey.aKey;
String hostNodeKeyKey = sessionId + “_” + creationTimeMillis + “:host”;
The
hostNodeKey
is obtained by casting the returned object from the
add()
method of
BonForumStore
.The next two lines re-create the
nodeNameHashtable
key for the host
nodeKey
stored there.That is needed by the next
add()
method invocation to directly
add child nodes to the host node, without searching for it in the XML data.
The
aKey
is available from the return value after casting (as it is from any
NodeKey
).
The

and guests associated with each session object. Before this timestamp part of the
nodeKeyKey
was implemented (for this edition of the book), bonForum users could be
a host or a guest in only one chat per browser instance. Now, a host and a guest can
enter and leave chats at will. Before, if a user started two or more different chats in the
same session, a visitor could join only the latest one, although all would appear to be
available.This small change made a big difference in the usability of bonForum.
The same session ID and timestamp mechanism just described applies also to
chatNodeKeyKey
and
guestNodeKeyKey
, as you will see in the following sections. Of
course, these longer timestamped keys take up memory space and entries in the
nodeNameHashtable
, so we have included an option to suppress them when they are
08 1089-9 CH08 6/26/01 7:33 AM Page 241
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
242
Chapter 8 Java Servlet and Java Bean: BonForumEngine and BonForumStore
not needed. Message nodes, for example, use a shorter
nodeNameHashtable
key such as
ofl37sijm1:messageKey
so that only the last message
nodeKey
(
messageKey
) for each
session is kept in the
nodeNameHashtable

nodeKey
key and the lookup in the
nodeNameHashtable
.
String name = “actorNickname”;
String attributes = “”;
content = actorNickname;
forestHashtableName = “bonForumXML”;
bonForumStore.getBonForumXML().addChildNodeToNonRootNode(name, attributes,

content, hostNodeKey, “nodeNameHashtable”, sessionId);
The main reason that we use only the
add()
method is so that we will have just one
method adding elements to the XML data in the host threads, the guest threads, and
the chat message threads.When we later discuss “visitor joins chat” handling and chat
message handling, you will see why we sometimes really do need the
add()
method,
with its second argument (
hostNodeKeyKey
,
chatNodeKeyKey
, and so on).
Adding a Chat Element
In the next part of the long source code listing in the previous section “Starting a
Chat,” a new chat element is added to the XML data.The element has an attribute to
keep the user’s answer to the “Will you moderate this chat?” question on the browser
page.That answer is retrieved from a session attribute, where it was earlier set from a
request parameter in the

is immediately useful for adding the
hostKey
to the chat ele-
ment. It is added as a string value in the text node of the chat element.That string
value is also set in a session attribute named
hostKey
. Of course, it looks something
like this:
987195762454.987195735516.987195735486
We make the
hostKey
available to the session so that it can later be used for two
things:
n
To find out if the session actor is the host in a chat
n
To brand messages with the host that sent them
The first use was discussed previously in the section “Rejoining Existing Chats.”The
second use of
hostKey
is discussed later, in Section 8.1.22, “The
processRequest()
Method: Handling Chat Messages.”
The last step in adding a chat to bonForum is to make the newly created
chatNodeKeyKey
available to the session as its attribute.That will come in handy for the
following uses:
n
To determine whether a chat is the current chat
n

the concatenation of the
chatSubject
and
chatTopic
that a visitor selects to join a
chat, and that is sent in the request as a request parameter.That can be confusing, but
they are related: One refers to them in the tree, and the other refers to them in
words.)
The
nodeKey
of the new
chatItem
element, called the
itemKey
, is saved in the new
chat node.
A very important part of the new
chatItem
element is its name.The name given to
the new child is always something like the following example:
sessionID_ofl37sijm1_987195762494
After being concatenated with a (escaped)
chatTopic
in a
nameAndAttributes
string
for the
add()
method, it comes out something like this:
sessionID_ofl37sijm1_987195762494 chatTopic=”love”

nodeKeyKey
values and
the
chatItem
element name.This next example is more current:
<sessionID_12rjpmlbj1_987109690411

nodeKey=”987109690431.987109600301.987109600251” chatTopic=”flying fish
recipes”>
</sessionID_12rjpmlbj1_987109690411>
08 1089-9 CH08 6/26/01 7:33 AM Page 244
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
245
8.1 The BonForumEngine Servlet
Again, adding the timestamp to the name of the
chatItem
element allowed us to pro-
vide direct access to multiple chats per session by creating unlimited unique key values
for the
nodeNameHashtable
.
You will see in the next section why we have these strange names for the
chatItem
elements.The
chatNodeKeyKey
can be reverse-engineered from the element name to
find a chat from a different session, as must be done when a visitor later joins a chat.
Meanwhile, let’s continue with the discussion of “host executes chat” handling.
After the
nameAndAttributes

child element, but instead as an attribute of the chat element.That is done using the
addChatNodeAttribute()
method of
BonForumStore
. It requires the very handy
chatNodeKeyKey
. No need, this time, to get it from a session attribute because we still
have it from adding the chat node.
We are going to need the
itemKey
value elsewhere in this session. It connects a chat
to its subject and topic. It also connects a chat to its messages and connects a message
to its subject. Here then, we are finally arriving at the end of the code that handles the
host_executes_chat bonForumCommand
.
Before leaving the “host executes chat” handler, each thread checks to see if either
haveSubject
or
haveTopic
has been set to
false
; in this case,
bonForumCommand
will be
set to
visitor_starts_chat
.That value will take the user back to where the missing
information can be supplied.
At this point, we have also completed the two steps that need synchronization, so
the next statement closes the thread-safe block of code:

We can call this the ”guest executes chat” handler. Its job is to process a visiting actor’s
request to join a chat, transforming the actor from a visitor to a guest. First, let’s set the
scene by recapitulating events up to this point. (If you think that you already know
what these events must have been, you can safely skip ahead to the section “Getting
the
chatItem
.”)
When the thread reaches the “guest executes chat” handler, the visitor has already
chosen a
chatItem
, which describes one available chat. As you can see in Table 8.5,
“bonForum Variables: Priority, Name, Origin,Type,” that
chatItem
variable value orig-
inated in an HTML select element displayed (using the XSLT processor) by the JSP
visitor_joins_chat_frame.jsp.
That
chatItem
value included in itself both the subject and topic of the chosen
chat, and arrived at the
BonForumEngine
servlet as a request parameter looking some-
thing like this example:
Animals_Bird_Hawk_[prehistoric falconry]
Furthermore, the
processRequest()
method has already processed the
chatItem
in the
“visitor joins chat” frame handler within its

That JSP set up some applet parameter values in its request parameters, including
one for a target of _top, and another for a document with the full URI for the JSP
guest_executes_chat.jsp.
08 1089-9 CH08 6/26/01 7:33 AM Page 246
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
247
8.1 The BonForumEngine Servlet
Next, the _ready JSP executed this action, obviously as its last act:
<jsp:forward page=”actor_leaves_frameset_robot.jsp.tfe”/>
That request was servlet-mapped, so it arrived at the
BonForumEngine
, where it was
handled by the servlet-mapped request processor block discussed earlier.With the
highest priority, and without being serviced by
processRequest()
, the request was for-
warded to the JSP actor_leaves_frameset_robot.jsp.
The
BonForumRobot
applet in the Java plug-in on that JSP got its applet parameters
from the request parameters. It dressed up the document name before asking its applet
context object to have it shown in the _top frame. Now the request URI looked
something like the following:
http://chatterbox:8080/bonForum/jsp/forum/guest_executes_chat.jsp987195879833.tfe
That was no static HTML document name but was yet another .tfe URI, again
servlet-mapped to the
BonForumEngine
. Arriving there, its
requestURI
now looked like

is retrieved from the session attribute, where it was safely held
through a chain of events involving several different request objects. Here is the
statement:
chatItem = normalize((String)session.getAttribute(“chatItem”)).trim();
If the
chatItem
is empty or is set to the special value
NONE
, then the
haveChatItem
flag
is set to
false
, which causes the request to be forwarded back to the “visitor joins
chat” state for new input.
Synchronizing the XML Database for the Chat
Just as in the “host executes chat” handler discussed previously, we need for synchro-
nization to enable thread-safe execution of code that shares a common resource: the
XML data. For general information about synchronization, refer to the previous
08 1089-9 CH08 6/26/01 7:33 AM Page 247
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
248
Chapter 8 Java Servlet and Java Bean: BonForumEngine and BonForumStore
section, “The Need for Thread Synchronization“. Here, we will get specific about the
current need.
When a visitor joins a chat, we need to synchronize these two steps:
1. Checking to see whether a chat for
chatItem
(subject+topic) exists
2. The visitor joining that chat

synchronized(bonForumStore.bonForumXML) {
// thread-safe critical section
// 1. step one
// 2. step two
}
That way, a thread arriving at the synchronized block would get a lock on the static
ForestHashtable
member of the static
BonForumStore
member of the
BonForumEngine
instance.That would still allow multiple threads to access other nonsynchronized
08 1089-9 CH08 6/26/01 7:33 AM Page 248
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
249
8.1 The BonForumEngine Servlet
methods of
bonForumStore
. However, this preferred synchronization needs more test-
ing and might require adding other synchronized methods or blocks.We are instead
using the following, more severe, lock:
synchronized(bonForumStore) {
It does takes a while to rule out problems related to undersynchronization.Thread
clashes are a bit like motor vehicle accidents:They’re not easy to stage.
Finding a Chat and the Actor Status in It
The thread is now ready to fulfill the “visitor joins chat” action leading to the “guest
executes chat” state. First, it searched for the chat with the
chatItem
that was requested
by the visitor. (Does this sound familiar? This is similar to what was done in the “host

In the case of “visitor joins chat,” if a chat with the requested subject and topic combi-
nation does not exist, the visitor will certainly not be able to join it! If the requested
chat does exist, then what happens will depend upon an option setting. One option is
08 1089-9 CH08 6/26/01 7:33 AM Page 249
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
250
Chapter 8 Java Servlet and Java Bean: BonForumEngine and BonForumStore
that a visitor will join the chat as a guest, unless the visitor is already a host in the
chat; in this case, that host role will resume.The other option (not yet implemented) is
that the visitor will always enter the chat as a guest.This last option will allow a host
in a chat to re-enter the chat as a guest.
A user preference setting can later offer a choice of options for the behavior of
“visitor joins chat” when the visitor is found already in the chat as a host or guest:
1. Always join it with the previous status.
2. Always join as a guest.
3. Always offer a choice if the visitor already is a host.
At this time, the transitions given in Table 8.8 itself are implemented, and the options
given in the notes are not yet implemented.We decided to tackle the harder ones first.
In the previous section “Finding a Chat and the Actor Status in It,” where this table
first appeared, we showed a simple way to implement the transitions for the “visitor
starts chat” row. Here, we do the same for the “visitor joins chat” row:
if chat exists
if actor is not host in chat
set bonForumCommand to guest_executes_chat
else
set bonForumCommand to host_executes_chat
endif
else
set haveChatItem false //error
endif

In the previous section “Adding a Host Actor,” we discussed the structure of keys in
the
nodeNameHashtable
and showed how they could be reverse-engineered in the fol-
lowing general manner:
nodeKeyKey = sessionId + “_” + nodeKey.aKey +”:” + nodeName;
We also showed that we did not really have to do that while adding elements to a new
host element because whenever we have a
nodeKey
to get the
aKey
from, we already
have the key to find the node.We wanted to use only the
add()
method of
BonForumStore
, however, which requires a
nodeKeyKey
argument, and we also wanted
the
nodeKeyKey
anyway, to put in a session attribute for other purposes.
However, getting back to the code for joining a chat (we can call it the guest
thread), we really could use a
nodeKeyKey
for the chat, for two reasons: to see if the
chat exists and to add elements to it.This time, we do not have the
chatNodeKey
, and
having a

hostNodeKeyKey
.
As you no doubt know by now, this problem of passing information between
sessions is the reason that we gave the chat subject marker elements in the XML
(
chatItem
nodes) a name that is made from the
chatNodeKeyKey
.When a visitor
chooses a chat to join (a
chatItem
variable), we can get from that choice the node that
marks the subject and the topic (the
chatItem
node), that node’s name, and thus the
chatNodeKeyKey
.Then, instead of searching through all the XML for the chat node, we
can find it using its
nodeKey
from the
nodeKeyHashtable
, which we get with the
chatNodeKeyKey
.
Some of you who are waiting patiently for more standard ways to use XML in a
Web application (a book in itself!) are perhaps saying, “Wait! Isn’t that cheating?”Well,
indeed it is, and for a good reason. Ensuring direct access to an object that you are
going to require again in a different context looks good compared to some of the
alternatives.
08 1089-9 CH08 6/26/01 7:33 AM Page 251


Nhờ tải bản gốc

Tài liệu, ebook tham khảo khác

Music ♫

Copyright: Tài liệu đại học © DMCA.com Protection Status