Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 50 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
50
Dung lượng
167,03 KB
Nội dung
582 Appendix C Source Code for bonForum Web Application * XML document specification. * ForestHashtable is described fully in the book: * <i>XML, XSLT, Java and JSP - A CaseStudyinDevelopinga Web Application</i>, * by Westy Rockwell, published by * <A HREF=”http://www.newriders.com”>New Riders</A>. * Translation to German published by * <A HREF=”http://www.galileocomputing.de”>Galileo Press</A>. * <p>For further information visit the open source * <A HREF=”http://www.bonForum.org”>BonForum Project on SourceForge</A> * @author <A HREF=”mailto://email@bonforum.org”>Westy Rockwell</A> */ public class ForestHashtable extends java.util.Hashtable { private NodeNameHashtable nodeNameHashtable; private PathNameHashtable pathNameHashtable; private boolean lastRootNodeFound; private boolean lastChildOfRootNodeFound; // next one defined further down for recursion // private boolean lastChildOfNonRootNodeFound; private String currentRootNodeAKey; private String currentRootNodeBKey; private String currentRootNodeCKey; // for debug only private String currentChildOfRootNodeAKey; private String currentChildOfRootNodeBKey; private String currentChildOfRootNodeCKey; // for debug only // next 3 defined further down for recursion // private String currentChildOfNonRootNodeAKey; // private String currentChildOfNonRootNodeBKey; // private String currentChildOfNonRootNodeCKey; private static BonLogger logFH = null; // Controls logger output. private static String logging = null; // False until logger ready. private static boolean loggingInitialized = false; // for logging output, when no sessionId available private static String sessionId = “0000000000”; private static final int NO_NODEKEY_KEY_PREFIX = 0; private static final int SESSION_ID = 1; private static final int SESSION_ID_AND_CREATION_TIME = 2; private String uniqueNodeKeyKeyList = “message;messageKey”; /** Sets uniqueNodeKeyKeyList of node names unique per session * in nodeNameHashtable. Determines key prefix choice. * Node names in list can have one key per session * Node names not in list can have multiple keys per session * This saves space by not storing keys for unused nodeKey entries. * (Note: applies only adding children to non-root nodes.). * */ protected void setUniqueNodeKeyKeyList(String newUniqueNodeKeyKeyList) { uniqueNodeKeyKeyList = newUniqueNodeKeyKeyList; } /** Gets uniqueNodeKeyKeyList setting. 15 1089-9 XC 6/26/01 7:40 AM Page 582 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 583 C.22 Filename: Projects\bonForum\src\de\tarent\forum\ForestHashtable.java * (see set method for details) * * @return String uniqueNodeKeyKeyList */ public String getUniqueNodeKeyKeyList() { return uniqueNodeKeyKeyList; } /** Creates a ForestHashtable with the default capacity. */ public ForestHashtable() { super(); nodeNameHashtable = new NodeNameHashtable(); pathNameHashtable = new PathNameHashtable(); } /** Creates a ForestHashtable of a given capacity. * * @param capacity initialCapacity of parent java.util.Hashtable */ public ForestHashtable(int capacity) { super(capacity); nodeNameHashtable = new NodeNameHashtable(); pathNameHashtable = new PathNameHashtable(); } private void log(String sessionId, String where, String what) { if(logging != null) { logFH.logWrite(System.currentTimeMillis(), sessionId, where, what); } } /** Gets logging setting. * * @return String logging */ public String getLogging() { return logging; } /** Sets logging setting. * * @param String setting for logger logtype (“none”,”all”,”std”,”file”) */ protected void setLogging(String newLogging) { logging = newLogging; synchronized(this) { if(!loggingInitialized) { System.err.println(“ForestHashtable init loggingInitialized:” + loggingInitialized); System.err.println(“ForestHashtable init logging:” + logging); if(logging != null) { logFH = new BonLogger(“ForestHashtableLog.txt”, logging); 15 1089-9 XC 6/26/01 7:40 AM Page 583 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 584 Appendix C Source Code for bonForum Web Application System.err.println(“ForestHashtable init logFH:” + logFH); logFH.setLogging(newLogging); loggingInitialized = true; System.err.println(“ForestHashtable init loggingInitialized:” + loggingInitialized); } } } } /** Gets nodeNameHashtable. * @return NodeNameHashtable nodeNameHashtable */ protected NodeNameHashtable getNodeNameHashtable() { return nodeNameHashtable; } /** Gets pathNameHashtable. * @return PathNameHashtable pathNameHashtable */ protected PathNameHashtable getPathNameHashtable() { return pathNameHashtable; } /** Returns nodeKey from a BonNode, as an object. * * @param bonNode node whose key is returned * @return nodeKey of BonNode cast to an Object */ protected Object nodeKeyFromBonNode(BonNode bonNode) { return (Object)bonNode.nodeKey; } /** Provides a useable NodeKey with a unique default root key value. * * @return NodeKey instance with unique aKey, initialized as a root node key * (to use for non-root nodes, change bKey and cKey values) */ private NodeKey getNextAvailableNodeKey() { long temp = 0; long lastCurrentTimeMillis = System.currentTimeMillis(); NodeKey nodeKey = new NodeKey(); while (temp <= lastCurrentTimeMillis) { temp = System.currentTimeMillis(); } nodeKey.aKey = Long.toString(temp); // initialize other keys to first, // that makes node a root node by default nodeKey.bKey = nodeKey.aKey; nodeKey.cKey = nodeKey.aKey; return nodeKey; } /** Deletes a BonNode given its nodeKey value. 15 1089-9 XC 6/26/01 7:40 AM Page 584 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 585 C.22 Filename: Projects\bonForum\src\de\tarent\forum\ForestHashtable.java * * @param keyOfNodeToDelete nodeKey of BonNode to delete * @return boolean true if deleted, false otherwise */ private boolean doDeleteNode(NodeKey keyOfNodeToDelete) { // LATER: this will just mark node as deleted, // anda separate thread will scavenge deleted nodes. if (this.containsKey(keyOfNodeToDelete)) { this.remove(keyOfNodeToDelete); return true; } else { return false; } } /** Deletes a BonNode and its descendant nodes, given a nodeKey value. * * @param keyOfNodeToDelete nodeKey of BonNode to delete * @return boolean true if at least one node was deleted, false otherwise */ private boolean doDeleteNodeRecursive(NodeKey keyOfNodeToDelete) { // LATER: this will just mark node as deleted, // anda separate thread will scavenge deleted nodes. String parentAKey = keyOfNodeToDelete.aKey; NodeKey nodeKey = new NodeKey(); BonNode bonNode = null; Enumeration enumeration = this.elements(); if(!(enumeration.hasMoreElements())) { return false; // no elements to delete } while(enumeration.hasMoreElements()) { bonNode = (BonNode)enumeration.nextElement(); nodeKey = bonNode.nodeKey; if(nodeKey.bKey.equals(parentAKey)) { // found a child doDeleteNodeRecursive(nodeKey); } } bonNode = this.getBonNode(keyOfNodeToDelete); this.remove(keyOfNodeToDelete); return true; } /** Returns true if a BonNode has child nodes. * * @param parentNodeKey the node being tested for children * @return boolean true if at least one node was deleted, false otherwise */ protected boolean hasAtLeastOneChild(NodeKey parentNodeKey) { // ina ForestHashtable, children have nodeKey.bKey equal to the parent’s nodeKey.aKey 15 1089-9 XC 6/26/01 7:40 AM Page 585 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 586 Appendix C Source Code for bonForum Web Application BonNode bonNode = null; String parentAKey = parentNodeKey.aKey; Enumeration enumeration = this.elements(); while(enumeration.hasMoreElements()) { bonNode = (BonNode)enumeration.nextElement(); if(bonNode.nodeKey.bKey.equals(parentAKey)) { return true; } } return false; } /** Deletes a BonNode and possibly its descendant nodes, given a nodeKey value. * * @param keyOfNodeToDelete nodeKey of BonNode to delete * @param leafOnly boolean true to delete only if node has no children * false to delete node and any descendant nodes * @return boolean true if at least one node was deleted, false otherwise */ public boolean deleteNode(NodeKey keyOfNodeToDelete, boolean leafOnly) { // NodeKey is a three-valued key (ABCTable key). // if leafOnly is True, then Node not deleted if it has one or more child nodes. // if leafOnly is False, then Node and all its descendants are deleted! synchronized(this) { if(this.containsKey(keyOfNodeToDelete)) { if(leafOnly) { if(hasAtLeastOneChild(keyOfNodeToDelete)) { return false; // was not a leaf node, so not deleted } } // delete and report success or failure return doDeleteNodeRecursive(keyOfNodeToDelete); } else { return false; // no such node } } } /** Adds a BonNode (and optionally its nodeKey to another hashtable for fast lookups). * To add nodes, user only calls addRootNode, addChildNodeToRootNode or addChildNodeToNonRootNode. * If nodeKeyHashtableName is “nodeNameHashtable” then these nodeKeyKeyPrefix values are possible: * <UL> * <LI> NO_NODEKEY_KEY_PREFIX makes added node global, visible to all HTTP Sessions, * <LI> SESSION_ID makes node UNIQUE for nodeName in session, and visible 15 1089-9 XC 6/26/01 7:40 AM Page 586 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 587 C.22 Filename: Projects\bonForum\src\de\tarent\forum\ForestHashtable.java only to current session * <LI> SESSION_ID_AND_CREATION_TIME allows multiple nodes with nodeName, and visible only to current session * </UL> * * Note: more values of nodeKeyKeyPrefix will be defined in later versions! * * @param nodeName String naming this node * @param nodeAttributes String containing all attributes concatenated (name=value name=value .) * @param nodeContent String containing text content of node * @param nodeKey NodeKey uniquely identifying and positioning node to be added in hierarchy * @param parentNodeKey NodeKey for parent of node to be added * @param nodeKeyHashtableName String naming hashtable in which to cache key of added node * @param nodeKeyKeyPrefix int = NO_NODEKEY_KEY_PREFIX makes added node global, visible to all HTTP Sessions, * = SESSION_ID makes node UNIQUE for nodeName in session, and visible only to current session * = SESSION_ID_AND_CREATION_TIME allows multiple nodes with nodeName, and visible only to current session * @param sessionId String, ID of HTTP session calling the method * @return BonNode that was added */ private BonNode addNode(String nodeName, String nodeAttributes, String nodeContent, NodeKey nodeKey, NodeKey parentNodeKey, String nodeKeyHashtableName, int nodeKeyKeyPrefix, String sessionId) { BonNode node = new BonNode(); node.deleted = false; node.flagged = false; node.nodeName = nodeName; if(nodeAttributes != null && nodeAttributes.length() > 0) { node.nodeAttributes = “nodeKey=\””+ nodeKey + “\” “ + nodeAttributes; } else { node.nodeAttributes = “nodeKey=\””+ nodeKey + “\””; } node.nodeContent = nodeContent; node.nodeKey = nodeKey; node.parentNodeKey = parentNodeKey; // put in this ForestHashtable // also optionally put nodeKey in nodeNameHashtable // but not if it is a subject element, etc. if(nodeKeyHashtableName.equals(“nodeNameHashtable”)) { // Hashtable is synchronized, but we need to sync two together here: String nodeKeyKey = null; 15 1089-9 XC 6/26/01 7:40 AM Page 587 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 588 Appendix C Source Code for bonForum Web Application synchronized(this) { try { this.put(nodeKey, node); } catch(Exception ee) { log(sessionId, “err”, “EXCEPTION in addNode():” + ee.getMessage()); ee.printStackTrace(); } if(nodeKeyKeyPrefix == SESSION_ID) { // allows only one key per session // use this option to reduce size of table // by not storing key to nodeKeys not needed // (examples: message keys, messageKey keys). nodeKeyKey = sessionId + “:” + nodeName; } else if(nodeKeyKeyPrefix == SESSION_ID_AND_CREATION_TIME) { // the nodeKey.aKey acts as a timestamp // allowing multiple keys per session in nodeNameHashtable // use to find multiple nodes with same name for one session // (example: chat keys, guest keys, host keys) nodeKeyKey = sessionId + “_” + nodeKey.aKey +”:” + nodeName; } else if(nodeKeyKeyPrefix == NO_NODEKEY_KEY_PREFIX) { // use no prefix for elements global to all sessions nodeKeyKey = nodeName; } else { nodeKeyKey = nodeName; // unknown arg value, could complain } // else ifs and/or else can add other prefixes here. // Note: it replaces older entries, if any this.nodeNameHashtable.put(nodeKeyKey, nodeKey); } } // else ifs here can add other hashtables later else { // Hashtable is synchronized, so if you change ancestor class for this, // be sure to sync addition to this here also. this.put(nodeKey, node); } return node; } /** Adds a BonNode as a root node. (Names should be unique among siblings, if nodeKeyHashtable is used) 15 1089-9 XC 6/26/01 7:40 AM Page 588 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 589 C.22 Filename: Projects\bonForum\src\de\tarent\forum\ForestHashtable.java * * @param rootNodeName String naming this node * @param rootNodeAttributes String containing all attributes concatenated (name=value name=value .) * @param rootNodeContent String containing text content of node * @param nodeKeyHashtableName String naming hashtable in which to cache key of added node * @return BonNode that was added */ protected BonNode addRootNode(String rootNodeName, String rootNodeAttributes, String rootNodeContent, String nodeKeyHashtableName) { // Node is an object that points to everything mapped to that node in the tree. // Ina table that holds objects, just stick Node in table. // OTW, you can extract info and write to fields in table. NodeKey nodeKey = getNextAvailableNodeKey(); // initially, nodeKey = An.An.An; // When all three keys are equal, the row is a root node! // An empty parent node key means no parent, because it is a root node. NodeKey emptyParentNodeKey = new NodeKey(); return addNode(rootNodeName, rootNodeAttributes, rootNodeContent, nodeKey, emptyParentNodeKey, nodeKeyHashtableName, NO_NODEKEY_KEY_PREFIX, “”); } /** Adds a BonNode as a child of a root node.(Names should be unique among siblings, if nodeKeyHashtable is used) * * @param childNodeName String naming this node * @param childNodeAttributes String containing all attributes concatenated (name=value name=value .) * @param childNodeContent String containing text content of node * @param childNodeKey NodeKey uniquely identifying a root node * @param nodeKeyHashtableName String naming hashtable in which to cache key of added node * @return BonNode that was added */ protected BonNode addChildNodeToRootNode(String childNodeName, String childNodeAttributes, String childNodeContent, NodeKey rootNodeKey, String nodeKeyHashtableName) { NodeKey childNodeKey = getNextAvailableNodeKey(); // initially, NodeKey = An.An.An; childNodeKey.bKey = rootNodeKey.aKey; childNodeKey.cKey = rootNodeKey.bKey; // when the second and third key are equal, it is child of a root return addNode(childNodeName, childNodeAttributes, childNodeContent, childNodeKey, rootNodeKey, nodeKeyHashtableName, NO_NODEKEY_KEY_PREFIX, “”); } /** Adds a BonNode as a child of a non-root node (and optionally its nodeKey to another hashtable for fast lookups). 15 1089-9 XC 6/26/01 7:40 AM Page 589 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 590 Appendix C Source Code for bonForum Web Application * If “nodeNameHashtable” nodeKeyHashtable is used, sessionId must be passed in to create session-related key for nodeKey. * (for now, caller is responsible for that!) * * @param childNodeName String naming this node * @param childNodeAttributes String containing all attributes concatenated (name=value name=value .) * @param childNodeContent String containing text content of node * @param nonRootNodeKey NodeKey uniquely identifying a non- root node * @param nodeKeyHashtableName String naming hashtable in which to cache key of added node * @param sessionId String id of callers session, if nodeKeyHashtable is used. * @return BonNode that was added */ protected BonNode addChildNodeToNonRootNode(String childNodeName, String childNodeAttributes, String childNodeContent, NodeKey nonRootNodeKey, String nodeKeyHashtableName, String sessionId) { NodeKey childNodeKey = getNextAvailableNodeKey(); // when no keys are equal, its a root grandchild or deeper childNodeKey.bKey = nonRootNodeKey.aKey; childNodeKey.cKey = nonRootNodeKey.bKey; // Assume multiple keys per nodeKey allowed in “nodeNameHashtable” nodeKeyHashtable int nodeKeyKeyPrefix = SESSION_ID_AND_CREATION_TIME; // unless node name to be added is in the “list”. if(uniqueNodeKeyKeyList.trim().length() > 0) { if(uniqueNodeKeyKeyList.indexOf(childNodeName) > -1) { nodeKeyKeyPrefix = SESSION_ID; } } return addNode(childNodeName, childNodeAttributes, childNodeContent, childNodeKey, nonRootNodeKey, nodeKeyHashtableName, nodeKeyKeyPrefix, sessionId); } /** Counts the children of a BonNode. * * @param parentNodeKey NodeKey of node whose children will be counted * @return long number of child nodes */ public long countChildren(NodeKey parentNodeKey) { // ina ForestHashtable, children have nodeKey.bKey equal to the parent’s nodeKey.aKey long counter = 0; BonNode bonNode = null; String parentAKey = parentNodeKey.aKey; Enumeration enumeration = this.elements(); while(enumeration.hasMoreElements()) { bonNode = (BonNode)enumeration.nextElement(); 15 1089-9 XC 6/26/01 7:40 AM Page 590 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 591 C.22 Filename: Projects\bonForum\src\de\tarent\forum\ForestHashtable.java if(bonNode.nodeKey.bKey.equals(parentAKey)) { counter++; } } return counter; } /** Gets from NodeKey ArrayList the first one whose BonNode has a child with given content. * * @param nodeKeys ArrayList of NodeKeys to will be checked * @param childContent String content of child node to look for * @return NodeKey of first BonNode with child node that has childContent as content, or null */ protected NodeKey getNodeKeyByChildNameAndContent(ArrayList nodeKeys, String childName, String childContent) { Iterator iK= nodeKeys.iterator(); while(iK.hasNext()) { NodeKey nodeKey = getNodeKeyForString((String)iK.next()); NodeKey childNodeKey = getChildNodeByNameAndContent(nodeKey, childName, childContent); if(childNodeKey != null) { return nodeKey; // of parent whose child has content } } return null; } /** Gets a new NodeKey whose toString() method returns a given String. * Note: If argument string is empty or null method returns an empty NodeKey. * * @param nodeKeyString String * @return NodeKey for the given nodeKeyString */ protected NodeKey getNodeKeyForString(String nodeKeyString) { //log(sessionId, “”, “getNodeKeyForString() nodeKeyString” + nodeKeyString); NodeKey nodeKey = new NodeKey(); int inx; if((nodeKeyString == null) || (nodeKeyString.equals(“”))) { return nodeKey; } String keyString = nodeKeyString; // 984576125127.984576061235.984576061225 // 1 2 3 // 01234567890123456789012345678901234567 inx = keyString.indexOf(“.”); if(inx > -1) { nodeKey.aKey = keyString.substring(0, inx); keyString = keyString.substring(inx + 1); inx = keyString.indexOf(“.”); 15 1089-9 XC 6/26/01 7:40 AM Page 591 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. [...]... nodeAttributes string * * @param allAttributes String with format used in BonNode nodeAttributes member * (No spaces allowed between attributeName and equals sign * nor between equal sign and attributeValue.) * @param attributeName String naming attribute in allAttributes * whose value is returned * @return null if value has no closing quote or if attributeName not found, * else value as... while(findingClosingQuote) { int inx3 = str2.indexOf(“\””); // find next quotation mark if(inx3 < 0) { str1 = null; break; } // find next escaped quotation mark (if any) int inx4 = str2.indexOf(“\\\””); if(inx4 > -1) { // found one // te\”st\”ing” goal=”961772451582” // | // inx3 // | // inx4 if(inx3 == inx4 + 1) { // same one again // accumulate an index relative to // beginning of attribute value inxAcc += inx3... NodeNameHashtable extends java.util.Hashtable { // wrapped just for access from a tag } /** PathNameHashtable only wraps java.util.Hashtable for access from JSP Custom tag * @author Westy Rockwell (wrockwell@tarent.de) * @version 0.2 */ class PathNameHashtable extends java.util.Hashtable { // wrapped just for access from a tag } Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark 15... * @param attributeName String naming attribute to look for in * allAttributes * @return boolean true if given attribute exists, false otherwise */ public boolean attributeExists(String allAttributes, String attributeName) { if(allAttributes.indexOf(attributeName+”=\””) > -1) { // found name return true; } else { return false; } } /** Gets the value assigned to a given attribute in a nodeAttributes... 7:40 AM Page 595 C.22 Filename: Projects\bonForum\src\de\tarent\forum\ForestHashtable.java 595 attributeName))) { return bonNode; } } } } return null; } /** Finds out if a given attribute exists in a nodeAttributes string * * @param allAttributes String with format used in BonNode nodeAttributes member * (No spaces allowed between attributeName and equals sign * nor between equal sign and attributeValue.)... “OutputDebugInfoTag doInitBody caught IOException”); throw new JspTagException(“OutputDebugInfoTag doInitBody caught IOException”); } } /* Code below here is based on Apache Software Foundation samples */ /** Normalizes the given string, replacing chars with entities * (less than, greater than, ampersand, double quote, return and linefeed) * NOTE: replaces null string with empty string * * @param s String... OutputPathNamesTag extends BodyTagSupport { TreeMap outputTable = null; Iterator iterator = null; private static BonForumStore bonForumStore = null; private static BonLogger logOPNT = null; private static boolean loggingInitialized = false; private static String logging = null; private String docName = “”; private String pathToSubTreeRootNode = “”; private String ancestorReplacer = “”; private String... given attribute name and value pair * * @param parentNodeKey NodeKey of node whose children will be checked * @param attributeName String name of attribute to look for * @param attributeValue String value of named attribute to look for * @return BonNode first child node (only!) with the given attribute name and value */ protected BonNode getChildNodeFromAttributeValue(NodeKey parentNodeKey, String attributeName,... setAttr2( String value ) { if( value.equals( null ) ) { value = “”; } attr2 = value; } /** Sets value of the attr3 attribute * * @param value string to which attr3 attribute is set */ public void setAttr3( String value ) { if( value.equals( null ) ) { value = “”; } attr3 = value; } /** Makes sure the body of the tag is evaluated * * @returns EVAL_BODY_TAG constant that causes... pageContext.getServletContext( ).getInitParameter( “Logging” ); logOCMT = new BonLogger( “OutputChatMessagesTagLog.txt”, logging ); loggingInitialized = true; System.err.println( “OutputChatMessagesTag init logging:” + logging ); } if ( value.equals( null ) ) { value = “bonForumXML”; } command = value; } /** Sets value of the attr1 attribute * * @param value string to which attr1 attribute is set . pathNameHashtable = new PathNameHashtable(); } /** Creates a ForestHashtable of a given capacity. * * @param capacity initialCapacity of parent java.util.Hashtable */ public. Rockwell< /A& gt; */ public class ForestHashtable extends java.util.Hashtable { private NodeNameHashtable nodeNameHashtable; private PathNameHashtable pathNameHashtable;