XML, XSLT, Java, and JSP: A Case Study in Developing a Web Application- P11

Chia sẻ: Thanh Cong | Ngày: | Loại File: PDF | Số trang:50

0
69
lượt xem
32
download

XML, XSLT, Java, and JSP: A Case Study in Developing a Web Application- P11

Mô tả tài liệu
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

XML, XSLT, Java, and JSP: A Case Study in Developing a Web Application- P11: Là một nhà phát triển Web, bạn biết những thách thức trong việc xây dựng các ứng dụng mạnh mẽ trên nhiều nền tảng. Tạo các ứng dụng di động trở nên thật sự có thể bằng cách sử dụng Java cho code và XML để tổ chức và quản lý dữ liệu. "XML, XSLT, Java, và JSP: Một trường hợp học" sẽ giúp bạn tối đa hóa khả năng của XML, XSLT, Java, và JSP trong các ứng dụng web của bạn....

Chủ đề:
Lưu

Nội dung Text: XML, XSLT, Java, and JSP: A Case Study in Developing a Web Application- P11

  1. 482 Appendix C Source Code for bonForum Web Application C.15 Filename: Projects\bonForum\src\ BonForumRobot.java /**/ 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 /**/ /** 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. * For further information visit the open source * BonForum Project on SourceForge * @author Westy Rockwell */ 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());
  2. C.15 Filename: Projects\bonForum\src\BonForumRobot.java 483 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); }
  3. 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”
  4. C.15 Filename: Projects\bonForum\src\BonForumRobot.java 485 // // 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
  5. 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);
  6. C.16 Filename: Projects\bonForum\src\de\tarent\forum\BonForumEngine.java 487 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; /**/ import java.io.*; import java.util.Hashtable; import javax.servlet.*; import javax.servlet.http.*; /**/ /** 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: * XML, XSLT, Java and JSP - A Case Study in Developing a Web Application, * by Westy Rockwell, published by New Riders. * Translation to German published by Galileo Press. * For further information visit the open source * BonForum Project on SourceForge * @author Westy Rockwell */ 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) {
  7. 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;
  8. C.16 Filename: Projects\bonForum\src\de\tarent\forum\BonForumEngine.java 489 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: // // // Object temp = getServletContext().getAttribute(“bonForumStore”); if (temp == null) { getServletContext().setAttribute(“bonForumStore”, getBonForumStore());
  9. 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: //
  10. 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
  11. 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
  12. C.16 Filename: Projects\bonForum\src\de\tarent\forum\BonForumEngine.java 493 // 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)
  13. 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”)) {
  14. 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
  15. 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”));
  16. C.16 Filename: Projects\bonForum\src\de\tarent\forum\BonForumEngine.java 497 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
  17. 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 );
  18. C.16 Filename: Projects\bonForum\src\de\tarent\forum\BonForumEngine.java 499 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,
  19. 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
  20. C.16 Filename: Projects\bonForum\src\de\tarent\forum\BonForumEngine.java 501 // 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 =
Đồng bộ tài khoản