/* * */ package xid; import java.util.*; import java.io.*; import javax.xml.parsers.*; import javax.xml.validation.Schema; import org.xml.sax.*; import org.w3c.dom.*; /** * */ public class Presenter { static protected org.apache.log4j.Logger log; static { log = org.apache.log4j.Logger.getLogger (Presenter.class.getName ()); } protected String webappPath; protected String sourceFileName; protected long sourceFileTime; protected Document doc; /* * */ public Presenter () { this.webappPath = null; this.sourceFileName = null; this.sourceFileTime = 0; this.doc = null; } /* * */ public Presenter (String webappPath, String fileName) { this.webappPath = webappPath; this.sourceFileName = fileName; this.sourceFileTime = 0; this.doc = null; } /* * */ public String getWebappPath () { String result; result = this.webappPath; // return (result); } /* * */ public void setSource (String fileName) { this.sourceFileName = fileName; this.sourceFileTime = 0; this.doc = null; } /* * */ public String getSource () { String result; result = this.sourceFileName; // return (result); } /* * */ public StringBuffer doXid (TagsData datas, StringBuffer errorOutput) { StringBuffer result; String sourceFilePath = this.webappPath + File.separator + this.sourceFileName; // Get the good tree. File source = new File (sourceFilePath); if (source == null) { String errorMessage = "source file not defined"; errorOutput.append (errorMessage); log.error (errorMessage); result = null; } else if (!source.exists ()) { String errorMessage = "source file defined but not found (" + sourceFilePath + ")"; errorOutput.append (errorMessage); log.error (errorMessage); result = null; } else if ((this.doc == null) || (this.sourceFileTime != source.lastModified ())) { this.sourceFileTime = source.lastModified (); this.doc = Presenter.fileToTree (sourceFilePath, errorOutput); if (this.doc != null) { Presenter.addMetaTag (doc, "generator", "XID 0.0"); } } // Build the web page. result = Presenter.doXid (doc, datas, this.webappPath, errorOutput); // return (result); } /* * */ static public StringBuffer doXid (String fileName, String webappPath, StringBuffer errorOutput) { StringBuffer result; Document doc = Presenter.fileToTree (fileName, errorOutput); if (doc == null) { result = null; } else { Presenter.addMetaTag (doc, "generator", "XID 0.0"); result = Presenter.doXid (doc, null, webappPath, errorOutput); } // return (result); } /* * */ static public StringBuffer doXid (Document doc, TagsData datas, String webappPath, StringBuffer errorOutput) { StringBuffer result; result = Presenter.process (doc, datas, webappPath, errorOutput); // return (result); } /* * */ static public StringBuffer doXid (String html, TagsData datas, String webappPath, StringBuffer errorOutput) { StringBuffer result; Document doc = null; result = Presenter.process (doc, datas, webappPath, errorOutput); // return (result); } /* * */ static public String getClassAttributeValue (Node node) { String result; NamedNodeMap attributes = node.getAttributes (); if (attributes == null) { result = null; } else { Node nameAttribute = attributes.getNamedItem ("class"); if (nameAttribute == null) { result = null; } else { result = nameAttribute.getNodeValue (); } } // return (result); } /* * */ static protected StringBuffer processChildren (Node node, TagsData datas, String webappPath, StringBuffer errorOutput) { StringBuffer result; result = new StringBuffer (); NodeList children = node.getChildNodes(); if (children == null) { result.append (" "); } else { int childrenCount = children.getLength (); for (int i = 0; i < childrenCount; i++) { result.append (process (children.item(i), datas, webappPath, errorOutput)); } } // return (result); } /** * Includes another HSP file into the current page. * * @param node * @param attrMap * @param idAttr */ static protected StringBuffer processObjectTag (Node node, NamedNodeMap attrMap, Node idAttr, TagsData datas, String webappPath, StringBuffer errorOutput) { StringBuffer result; result = new StringBuffer (); // Find codetype. String codetype; if (attrMap == null) { codetype = null; } else if (attrMap.getNamedItem ("codetype") == null) { codetype = null; } else { codetype = attrMap.getNamedItem ("codetype").getNodeValue (); } // Check tag requirements. if ((attrMap == null) || (codetype == null) || (!codetype.equals ("application/xid")) || (attrMap.getNamedItem ("data") == null)) { // STU: do default action. Presenter.processElementBasically (node, datas, webappPath, errorOutput); } else { log.info ("object action"); result.append (""); // Build the file name. String htmlFileName = webappPath + attrMap.getNamedItem ("data").getNodeValue (); // Load file in tree. Document childDoc = null; try { childDoc = fileToTree (htmlFileName, errorOutput); } catch (Exception ex) { result.append ("unable to build the file tree"); log.info ("unable to build the file tree"); } // Extract the 'body' section. Node body = null; try { NodeList nodes = childDoc.getElementsByTagName ("body"); if (nodes.getLength () == 0) { result.append ("no body tag in include html"); log.info ("no body tag in include html"); } else { body = nodes.item(0); } } catch (Exception e) { result.append ("error getting child"); log.info ("error getting child"); } // Process the body child as part of the primary tree. NodeList bodyChildren = body.getChildNodes (); if (bodyChildren != null) { int childCount = bodyChildren.getLength (); for (int childCounter = 0; childCounter < childCount; childCounter++) { result.append (process (bodyChildren.item (childCounter), datas, webappPath, errorOutput)); } } // result.append (""); } log.info ("end of object action"); // return (result); } /** * Processes a node that has dynamic content. Calls the appropriate code * generator method, depending on the tag. * * @param node * Current node. * @param attrs * The tag attributes. * @param idAttr * The ID. */ static protected StringBuffer processElementWithId (Node node, NamedNodeMap attrs, Node idAttr, TagsData datas, String webappPath, StringBuffer errorOutput) { StringBuffer result; result = new StringBuffer (); String tag = node.getNodeName(); String idValue = idAttr.getNodeValue(); log.info ("tag=" + tag); // Get data of this id. TagData data = datas.get (idAttr.getNodeValue ()); String theClass; if (data == null) { theClass = null; } else { theClass = data.getAttributes ().getAttribute ("class"); } if ((theClass == null) || (!theClass.equals ("xid:nodisplay"))) { if ((tag.equals ("a")) || (tag.equals ("b")) || (tag.equals ("div")) || (tag.equals ("em")) || (tag.equals ("p")) || (tag.equals ("span"))) { // Open the tag. result.append ('<'); result.append (node.getNodeName()); // Build the tag attributes. result.append (processAttributes (attrs, data)); //result.append (attributesFromNode (attrs)); //result.append (attributesFromTagData (data)); result.append ('>'); // Insert data. if ((data == null) || (data.display ().equals (""))) { result.append (processChildren (node, datas, webappPath, errorOutput)); } else { result.append (data.display ()); } // Close the tag. result.append (""); result.append (node.getNodeName()); result.append ('>'); } else if (tag.equals("img")) { // Possibility to merge with previous case if
is a correct tag. // Open the tag. result.append ("<"); result.append (node.getNodeName()); // Build the tag attributes. result.append (processAttributes (attrs, data)); //result.append (attributesFromNode (attrs)); //result.append (attributesFromTagData (data)); result.append ("/>"); } else if (tag.equals("textarea")) { result.append ("[textarea]"); } else if (tag.equals("select")) { result.append ("[select]"); } else if (tag.equals("input")) { result.append ("[input]"); } else if (tag.equals("table")) { result.append ("[table]"); } else if (tag.equals("tbody")) { result.append ("[tbody]"); } else if (tag.equals("object")) { result.append (processObjectTag (node, attrs, idAttr, datas, webappPath, errorOutput)); } else { log.info ("Id on <" + tag + "> not supported."); } } // log.info ("Exit"); return (result); } /** * Recursive method that processes a node and any child nodes. * */ static protected StringBuffer process (Node node, TagsData datas, String webappPath, StringBuffer errorOutput) { log.info ("Enter"); String TRANSITIONAL_DTD = "xhtml1-transitional.dtd"; String TRANSITIONAL_DOCTYPE = "\n"; StringBuffer result; result = new StringBuffer (); // Is there anything to do? if (node != null) { log.info ("nodeName=" + node.getNodeName ()); // Find the name attribute value. String name; name = getClassAttributeValue (node); if ((name == null) || ((name != null) && (!name.equals ("xid:nodisplay")))) { int type = node.getNodeType(); switch (type) { case Node.DOCUMENT_NODE: { log.info ("case Node.DOCUMENT_NODE"); DocumentType dt = ((Document) node).getDoctype(); String publicId = dt.getPublicId(); String systemId = dt.getSystemId(); if (systemId.equals(TRANSITIONAL_DTD)) { result.append(TRANSITIONAL_DOCTYPE); } // Log.write(Log.TRACE,"publicId = " + publicId); // Log.write(Log.TRACE,"systemId = " + systemId); result.append (Presenter.process (((Document) node).getDocumentElement(), datas, webappPath, errorOutput)); break; } case Node.ELEMENT_NODE: { log.info ("case Node.ELEMENT_NODE"); NamedNodeMap attrs = node.getAttributes (); Node idAttr = attrs.getNamedItem ("id"); if (idAttr != null) { result.append (Presenter.processElementWithId (node, attrs, idAttr, datas, webappPath, errorOutput)); } else { result.append (Presenter.processElementBasically (node, datas, webappPath, errorOutput)); } break; } // handle entity reference nodes case Node.ENTITY_REFERENCE_NODE: { log.info ("case Node.ENTITY_REFERENCE_NODE"); result.append ('&'); result.append (node.getNodeName()); result.append (';'); break; } // print cdata sections case Node.CDATA_SECTION_NODE: { log.info ("case Node.CDATA_SECTION_NODE"); result.append (""); break; } // print text case Node.TEXT_NODE: { log.info ("case Node.TEXTE_NODE"); result.append (restoreEntities (new StringBuffer(node.getNodeValue()))); break; } // print processing instruction case Node.PROCESSING_INSTRUCTION_NODE: { log.info ("Node.PROCESSING_INSTRUCTION_NODE"); result.append (""); result.append (node.getNodeName()); String data = node.getNodeValue(); if ((data != null) && (data.length () > 0)) { result.append (' '); result.append (data); } result.append ("?>"); break; } } } } // //log.info ("result=" + result); log.info ("Exit"); return (result); } /* */ static StringBuffer processElementBasically (Node node, TagsData datas, String webappPath, StringBuffer errorOutput) { StringBuffer result; result = new StringBuffer (); // Open the tag. result.append ('<'); result.append (node.getNodeName()); // Build the tag attributes. NamedNodeMap attrs = node.getAttributes (); if (attrs != null) { for (int i = 0; i < attrs.getLength(); i++) { Attr attr = (Attr) attrs.item(i); result.append (' '); result.append (attr.getNodeName()); result.append ("=\""); result.append (restoreEntities(new StringBuffer(attr.getNodeValue()))); result.append ("\""); } // NodeList children = node.getChildNodes(); if (children == null) { result.append(" />"); } else { int childrenCount = children.getLength (); if (childrenCount == 0) { result.append(" />"); } else { result.append('>'); for (int i = 0; i < childrenCount; i++) { result.append (process (children.item(i), datas, webappPath, errorOutput)); } result.append(""); result.append(node.getNodeName()); result.append('>'); } } } // return (result); } /* * */ static protected Document fileToTree (String fileName, StringBuffer errorOutput) { Document result; File source = new File (fileName); if (source == null) { String errorMessage = "source file not defined (null)"; errorOutput.append (errorMessage); log.error (errorMessage); result = null; } else if (!source.exists ()) { String errorMessage = "source file not found (" + fileName + ")"; errorOutput.append (errorMessage); log.error (errorMessage); result = null; } else { try { // Create a DocumentBuilderFactory and configure it. DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance (); // Set various configuration options. dbf.setValidating (true); dbf.setIgnoringComments (true); dbf.setIgnoringElementContentWhitespace (false); dbf.setCoalescing (false); // Keep entity references as they are. dbf.setExpandEntityReferences(false); // Create a DocumentBuilder that satisfies the constraints // specified by the DocumentBuilderFactory. DocumentBuilder db = dbf.newDocumentBuilder (); ParserErrorHandler errorHandler; errorHandler = new ParserErrorHandler(); // Set the error handler. db.setErrorHandler (errorHandler); Schema schema = db.getSchema (); log.info ("schema=" + schema); // Parse the input file. result = db.parse (fileName); if (errorHandler.hasError ()) { errorOutput.append (errorHandler.toString ()); } } catch (ParserConfigurationException exception) { String errorMessage = "Parser configuration exception: " + exception.getMessage (); errorOutput.append (errorMessage); log.error (errorMessage); result = null; } catch (SAXException exception) { String errorMessage = "Error during SAX parsing: " + exception.getMessage (); errorOutput.append (errorMessage); log.error (errorMessage); result = null; } catch (IOException exception) { String errorMessage = "IOError during parsing." + exception.getMessage (); errorOutput.append (errorMessage); log.error (errorMessage); result = null; } } // return (result); } /* * */ static protected void addMetaTag (Document doc, String name, String content) { // Find head tag. Node headNode = Presenter.findHeadNode (doc); Node metaNode = doc.createElement ("meta"); NamedNodeMap attrMap = metaNode.getAttributes(); Node attrNode = doc.createAttribute("name"); attrMap.setNamedItem(attrNode); attrNode.setNodeValue(name); attrNode = doc.createAttribute("content"); attrMap.setNamedItem(attrNode); attrNode.setNodeValue(content); headNode.insertBefore(metaNode, headNode.getFirstChild()); } /** * Finds the node containing the <head> tag. * * @param node * Document node. * @return The head tag node */ static protected Node findHeadNode (Node node) { Node headNode = null; int type = node.getNodeType(); switch (type) { // print document case Node.DOCUMENT_NODE: { headNode = findHeadNode(((Document) node).getDocumentElement()); break; } case Node.ELEMENT_NODE: { String tag = node.getNodeName(); if ("head".equals(tag)) { headNode = node; break; } NodeList children = node.getChildNodes(); int numChildren = 0; if (children != null) numChildren = children.getLength(); for (int i = 0; i < numChildren; i++) { headNode = findHeadNode(children.item(i)); if (headNode != null) break; } break; } } return headNode; } /** * Any ampersand lt;, ampersand gt; and ampersand amp; sequences in text * nodes get read in as symbols. This method converts them back to entities. * * @param s String that is to have the entities restored.. * @return The processed string. */ static public String restoreEntities (StringBuffer s) { String result; if (s == null) { result = null; } else { StringBuffer str = new StringBuffer(); int len = (s != null) ? s.length() : 0; for (int i = 0; i < len; i++) { char ch = s.charAt(i); switch (ch) { case '<': { str.append("<"); break; } case '>': { str.append(">"); break; } case '&': { str.append("&"); break; } default: { str.append(ch); } } } result = str.toString (); } // return (result); } /** * Get the text for an element. Converts new lines to spaces. * * @param node */ static protected String getElementText (Node node) { String result; result = ""; // Grrrr, Java ... NodeList children = node.getChildNodes(); if (children == null) { result = ""; } else { boolean ended = false; int childCounter = 0; int childCount = children.getLength (); while (!ended) { if (childCounter >= childCount) { ended = true; result = ""; } else { Node child = children.item (childCounter); if (child.getNodeType () == Node.TEXT_NODE) { result = newLinesToSpaces (child.getNodeValue ()); // STU (+=, newLines...) ended = true; } else { childCounter += 1; } } } } // return (result); } /** * Converts New Line characters to spaces. This is used when for example * the text in a div tag goes over serveral lines. * * @param text String * @return String */ static protected String newLinesToSpaces (String text) { StringBuffer result = new StringBuffer (text); for (int i = 0; i < result.length(); i++) { if (result.charAt (i) == '\n') { result.setCharAt (i,' '); } } // return (result.toString()); } /* * */ static protected StringBuffer processAttributes (NamedNodeMap attrs, TagData model) { StringBuffer result; result = new StringBuffer (); // Build the original attributes list. HashMap