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

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

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

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, whichever was the case before. (Again, in the book release of bonForum, the options within the table cells are the only options!) In a later release of bonForum, we will implement user preference settings using session attributes. Choices can be offered for the behavior of “visitor starts chat” when the requested chat already exists, as follows: 1. Always warn the user and request a new subject or new topic. 2. If the actor was in the chat, always join it with the previous status; otherwise, warn and ask again. 3. If the actor was in the chat, always join as a guest; otherwise, warn and ask again. 08 1089-9 CH08 6/26/01 7:33 AM Page 232 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 233 8.1 The BonForumEngine Servlet All these choices can be modified further according to whether the actor is restarting the current chat. Until these preference settings are added, bonForum implements only the second choice. Looking at the table again, it is very easy to cause the various outcomes of this desired logic to happen.You simply need to set the bonForumCommand value to the cor- responding value in the table cell (or optional value, when that is implemented). Implementing the logic can also be quite simple.We leave the “visitor joins chat” part aside until Section 8.1.21, “The processRequest() Method: Handling ‘Guest Executes Chat.’” Also leaving aside the numbered options (in the table notes), we could suggest the following pseudocode: set bonForumCommand to host_executes_chat if chat exists if actor is not host in chat 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)) { ➥ chatExistsForSubjectAndTopic = true; // 08 1089-9 CH08 6/26/01 7:33 AM Page 233 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 234 Chapter 8 Java Servlet and Java Bean: BonForumEngine and BonForumStore // There is more code here, not shown! // It does the following: // // if subject and topic are not new // (requested chat is the current chat) { // if chatNodeKeyKey exists // (current chat exists) { // if foundChatNodeKeyKey is // chatNodeKeyKey { // set actorRestartingCurrentChat // true; // } else { // set // chatExistsForSubjectAndTopic // false; // set actorRestartingCurrentChat // false; // endif // endif // endif // String actorKeyValue = normalize((String)session.getAttribute( ➥ “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 08 1089-9 CH08 6/26/01 7:33 AM Page 234 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 235 8.1 The BonForumEngine Servlet // user message that chat exists: session.setAttribute( “chatSubjectAndTopicTaken”, fakeChatItem ➥ ); chatTopic = “”; session.setAttribute( “chatTopic”, “” ); session.setAttribute( “newChatTopic”, “no” ); bonForumCommand = “visitor_starts_chat”; } } if(actorWillRejoinChat) { // set session attributes // usually set when actor starts new chat. // // nodeNameHashtable key // for the chat node key, 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); // itemKey for this chat // is added as message attributes later, // is needed for finding messages // (temporarily), // 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- sage elements. In addition, some important session attributes are set: the key to the host element, the key to the chat nodeKey in the nodeNameHashtable , and the itemKey . 08 1089-9 CH08 6/26/01 7:33 AM Page 235 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 236 Chapter 8 Java Servlet and Java Bean: BonForumEngine and BonForumStore All this sounds more complex than it is.The hardest part is showing how simple it is in this book. You can follow it with the source code to BonForumEngine , also in Appendix C. Finally, we suggest using an XML viewer, such as Microsoft’s free XMLpad, to follow the discussion using one of the XSLT output files that contains the complete bonForumXML contents. First, use bonForum a while from a couple of browser instances. Start a chat in one, join it in another, and send some messages from both browsers.Then use the Output bonForum XML Data option on the System Commands page (reachable from the start of bonForum).You should then be able to view the file TOMCAT_HOME\webapps\ bonForum\mldocs\bonForumIdentityTransform.xml. The following listing shows the entire block of code that starts a chat in processRequest() . After the listing, you will find a discussion of the code. 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”; 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 content = “”; forestHashtableName = “bonForumXML”; obj = bonForumStore.add( “bonAddElement”, “actors”, nameAndAttributes, ➥ content, forestHashtableName, “nodeNameHashtable”, sessionId ); 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 below here // is more efficient than the above line. // It does not require the reconstructed // hostNodeKeyKey. However, we may want that // 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, 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”; 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, // 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 // example: 987195762454.987195735516.987195735486 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. // 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 // 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 // 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 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 are host and guest .When processRequest() handles the host_executes_chat bonForumCommand , which originates in the “visitor starts chat” state, it must decide whether to add the visitor to the XML data as a host element, a child of actors . It finds out by using the visitor’s nickname, actorNickname . Nicknames used by bonForum users (actors) must be unique.That is enforced by storing them as keys in a hashtable , the nicknameRegistry . Here, we make sure that each nickname has no more than one host element related to it. A user can host more than one chat, but all the chats share one host node. The code gets the nickname for the current request from a session attribute, where it was stored after input, by processRequest() .To find out whether a host node exists for the current nickname, the code first invokes a method of BonForumStore : 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 ) later, to add to the new chat and to a session attribute as well (see the section “Adding a Chat Element”). 08 1089-9 CH08 6/26/01 7:33 AM Page 240 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 241 8.1 The BonForumEngine Servlet If no host nodeKey is found for the nickname, then a new host node is added to the actors child of the XML root node, using the add() method of BonForumStore , which wraps the ForestHashtable addChildNodeToNonRootNode() method.The add() method returns the nodeKey of the newly added host node, which is useful for the next three steps: adding the actorNickname , actorAge , and actorRating children of the host node.The values for these three are found in session attributes, where they were 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 aKey was given a value using the system clock time in milliseconds.That hap- pened when the NodeKey was used to store the host node.The NodeKey for the host node (as a string) was then stored in the nodeNameHashtable with a key that looked something like this: ofl37sijm1_987195762454:host The first part, before the underscore character, is the session ID for the thread that added the host.The part between the underscore and the colon character is the same system clock value that was used for the aKey in the host nodeKey when the host node was stored.That happened deep in the bowels of the ForestHashtable class, in a state- ment like this: nodeKeyKey = sessionId + “_” + nodeKey.aKey +”:” + nodeName; The nodeKey.aKey acts as a timestamp allowing multiple keys per session in nodeNameHashtable . It is used whenever we need to be able to find multiple nodes with the same name for one session. It allows bonForum to have multiple chats, hosts, 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. [...]... that as the “XML database” because the purpose of the class is to model a database containing XML As you recall, a BonForumEngine object has a static member called bonForumStore As an instance of the BonForumStore class, it contains two instances of the ForestHashtable class, both static, and therefore acts as an interface between the BonForumEngine servlet and the XML data.The data for the chat application... ForestHashtable) Initializes the XML database for use as a chat Web app Loads XML files into a database using its methods Dumps the content of the database as XML in a string Provides access to the database as a property Has methods to edit, add, and remove XML database nodes BonForumStore BonForumEngine, providing n n n n n n Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark... it is okay to add a guest node and its children: actorNickname, actorAge, and actorRating elements.That should happen only if the actor has never joined a chat as a guest (In the prototype, we can add to that during the current session.) Adding a Guest Actor The code for adding a guest node and its children is nearly identical to that for adding a host node.This makes you wonder if the two actions... processor, as shown in the following excerpt (The chatMessagesNavigator parameters originate on the same pages as the chatMessage ones, so they are also handled here.) if(bonForumCommand.indexOf(“host_executes_chat_controls”) > -1) ➥(bonForumCommand.indexOf(“guest_executes_chat_controls”) { // handle chatMessagesNavigator // handle chatMessage } || The first thing done is to get the message value that was input... 7:33 AM Page 250 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. .. second argument, in these cases, is not the key to the parent node, but a path in the XML data (the chatSubject, in this case) , which could be this: Animals.Fish.FlyingFish This brings our discussion to the last act involved in adding a chat Adding an itemKey to a Chat The return value from the add() method is again cast to a NodeKey, as itemNodeKey As a string, it becomes itemKey.This time we want to add... 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... replace any of those books for you in the remainder of this chapter 8.2.2 Purpose of the BonForumStore Class wraps the XML data for the chat Web application controlled by access to the data in the context of the application.This includes methods to get data into and out of the XML, and methods to change the data that is there In the prototype so far implemented, we have modeled that database as an instance... 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... you can see in Table 8.5, “bonForum Variables: Priority, Name, Origin,Type,” that chatItem variable value originated 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 something like this example: . chat, always join it with the previous status; otherwise, warn and ask again. 3. If the actor was in the chat, always join as a guest; otherwise, warn and. 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.

Ngày đăng: 14/12/2013, 22:15

Từ khóa liên quan

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan