1 28 29 package com.opencms.template; 30 31 import org.opencms.file.CmsFile; 32 import org.opencms.file.CmsObject; 33 import org.opencms.main.CmsException; 34 import org.opencms.main.CmsLog; 35 import org.opencms.main.OpenCms; 36 37 import com.opencms.legacy.CmsLegacyException; 38 import com.opencms.legacy.CmsXmlTemplateLoader; 39 import com.opencms.workplace.CmsWorkplaceDefault; 40 41 import java.io.ByteArrayInputStream ; 42 import java.io.ByteArrayOutputStream ; 43 import java.io.InputStream ; 44 import java.io.OutputStream ; 45 import java.io.StringReader ; 46 import java.io.StringWriter ; 47 import java.io.Writer ; 48 import java.lang.reflect.InvocationTargetException ; 49 import java.lang.reflect.Method ; 50 import java.util.Enumeration ; 51 import java.util.Hashtable ; 52 import java.util.Vector ; 53 54 import org.w3c.dom.CDATASection ; 55 import org.w3c.dom.Document ; 56 import org.w3c.dom.Element ; 57 import org.w3c.dom.Node ; 58 import org.w3c.dom.NodeList ; 59 import org.w3c.dom.Text ; 60 61 94 public abstract class A_CmsXmlContent implements I_CmsXmlContent { 95 96 97 public static final Class [] C_PARAMTYPES_HANDLING_METHODS = new Class [] {Element .class, Object .class, Object .class}; 98 99 100 public static final Class [] C_PARAMTYPES_USER_METHODS = new Class [] {CmsObject.class, String .class, A_CmsXmlContent.class, Object .class}; 101 102 103 public static final String C_MINIMUM_CLASSNAME = "com.opencms.template.A_CmsXmlContent"; 104 105 106 public static final String C_TEMPLATE_EXTENSION = ""; 107 108 109 public static final String C_ERR_NODATABLOCK = "? UNKNOWN DATABLOCK "; 110 111 112 protected CmsObject m_cms; 113 114 115 protected Vector m_knownTags = new Vector (); 116 117 123 protected Hashtable m_firstRunTags = new Hashtable (); 124 125 131 protected Hashtable m_mainProcessTags = new Hashtable (); 132 133 134 protected static final int C_REGISTER_FIRST_RUN = 1; 135 136 137 protected static final int C_REGISTER_MAIN_RUN = 2; 138 139 140 private static final boolean C_DEBUG = false; 141 142 143 private Document m_content; 144 145 146 private String m_filename; 147 148 149 private Hashtable m_blocks = new Hashtable (); 150 151 152 private Vector m_includedTemplates = new Vector (); 153 154 155 private static Hashtable m_filecache = new Hashtable (); 156 157 158 private static I_CmsXmlParser m_parser = new CmsXmlXercesParser(); 159 160 private String m_newEncoding; 161 162 163 public A_CmsXmlContent() { 164 registerAllTags(); 165 } 166 167 181 protected Object callUserMethod(String methodName, String parameter, Object callingObject, Object userObj, boolean resolveMethods) throws CmsException { 182 Object [] params = new Object [] {m_cms, parameter, this, userObj}; 183 Object result = null; 184 185 if (callingObject == null) { 187 throwException("You are trying to call the user method \"" + methodName + "\" without giving an object containing this method. " + "Please select a callingObject in your getProcessedData or getProcessedDataValue call.", CmsLegacyException.C_XML_NO_USER_METHOD); 188 } 189 190 if (CmsXmlTemplateLoader.isElementCacheEnabled() && !resolveMethods) { 194 try { 195 if (callingObject.getClass().getMethod("getMethodCacheDirectives", new Class [] {CmsObject.class, String .class}).invoke(callingObject, new Object [] {m_cms, methodName}) != null) { 196 return null; 197 } 198 } catch (NoSuchMethodException e) { 199 throwException("Method getMethodeCacheDirectives was not found in class " + callingObject.getClass().getName() + ".", CmsLegacyException.C_XML_NO_USER_METHOD); 200 } catch (InvocationTargetException targetEx) { 201 202 Throwable e = targetEx.getTargetException(); 205 if (!(e instanceof CmsException)) { 206 throwException("Method getMethodeCacheDirectives throwed an exception. " + e, CmsLegacyException.C_UNKNOWN_EXCEPTION); 208 } else { 209 throw (CmsException) e; 211 } 212 } catch (Exception exc2) { 213 throwException("Method getMethodeCacheDirectives was found but could not be invoked. " + exc2, CmsLegacyException.C_XML_NO_USER_METHOD); 214 } 215 } 216 217 try { 219 result = getUserMethod(methodName, callingObject).invoke(callingObject, params); 221 } catch (NoSuchMethodException exc) { 222 throwException("User method " + methodName + " was not found in class " + callingObject.getClass().getName() + ".", CmsLegacyException.C_XML_NO_USER_METHOD); 223 } catch (InvocationTargetException targetEx) { 224 225 Throwable e = targetEx.getTargetException(); 228 if (!(e instanceof CmsException)) { 229 throwException("User method " + methodName + " throwed an exception. " + e, CmsLegacyException.C_UNKNOWN_EXCEPTION); 231 } else { 232 throw (CmsException) e; 235 } 236 } catch (Exception exc2) { 237 throwException("User method " + methodName + " was found but could not be invoked. " + exc2, CmsLegacyException.C_XML_NO_USER_METHOD); 238 } 239 if ((result != null) && (!(result instanceof String || result instanceof CmsProcessedString || result instanceof Integer || result instanceof NodeList || result instanceof byte[]))) { 240 throwException("User method " + methodName + " in class " + callingObject.getClass().getName() + " returned an unsupported Object: " + result.getClass().getName(), CmsLegacyException.C_XML_PROCESS_ERROR); 241 } 242 return (result); 243 } 244 245 248 public static void clearFileCache() { 249 if (CmsLog.getLog(A_CmsXmlContent.class).isInfoEnabled()) { 250 CmsLog.getLog(A_CmsXmlContent.class).info("Clearing XML file cache."); 251 } 252 m_filecache.clear(); 253 } 254 255 260 public static void clearFileCache(A_CmsXmlContent doc) { 261 if (doc != null) { 262 String currentProject = doc.m_cms.getRequestContext().currentProject().getName(); 263 String filename = doc.m_cms.getRequestContext().addSiteRoot(doc.getAbsoluteFilename()); 264 m_filecache.remove(currentProject + ":" + filename); 265 } 266 } 267 268 273 public static void clearFileCache(String key) { 274 m_filecache.remove(key); 275 } 276 277 282 public Object clone() throws CloneNotSupportedException { 283 try { 284 A_CmsXmlContent newDoc = (A_CmsXmlContent) getClass().newInstance(); 285 newDoc.init(m_cms, (Document ) m_content.cloneNode(true), m_filename); 286 return newDoc; 287 } catch (Exception e) { 288 if (CmsLog.getLog(this).isErrorEnabled()) { 289 CmsLog.getLog(this).error("Error while trying to clone object " + this.getClass().getName()); 290 } 291 throw new CloneNotSupportedException (e.toString()); 292 } 293 } 294 295 302 private Hashtable concatData(Hashtable data1, Hashtable data2) { 303 Hashtable retValue = (Hashtable ) data1.clone(); 304 Enumeration keys = data2.keys(); 305 Object key; 306 while (keys.hasMoreElements()) { 307 key = keys.nextElement(); 308 retValue.put(key, data2.get(key)); 309 } 310 return retValue; 311 } 312 313 325 public void createNewFile(CmsObject cms, String filename, String documentType) throws CmsException { 326 if (!filename.startsWith("/")) { 327 328 this.throwException("Cannot create new file. Bad name.", CmsLegacyException.C_BAD_NAME); 330 } 331 int pos = filename.lastIndexOf("/") + 1; 332 String folder = filename.substring(0, pos); 333 int type = OpenCms.getResourceManager().getResourceType(documentType).getTypeId(); 334 cms.createResource(folder + filename, type); 335 cms.lockResource(filename); 336 m_cms = cms; 337 m_filename = filename; 338 try { 339 m_content = m_parser.createEmptyDocument(getXmlDocumentTagName()); 340 } catch (Exception e) { 341 throwException("Cannot create empty XML document for file " + m_filename + ". ", CmsLegacyException.C_XML_PARSING_ERROR); 342 } 343 write(); 344 } 345 346 362 protected void fastSetData(String tag, String data) { 363 364 tag = tag.toLowerCase(); 366 Element originalBlock = (Element ) (m_blocks.get(tag)); 367 while (originalBlock.hasChildNodes()) { 368 originalBlock.removeChild(originalBlock.getFirstChild()); 369 } 370 originalBlock.appendChild(m_content.createTextNode(data)); 371 } 372 373 378 public String getAbsoluteFilename() { 379 return m_filename; 380 } 381 382 386 protected Hashtable getAllData() { 387 return m_blocks; 388 } 389 390 396 public abstract String getContentDescription(); 397 398 405 protected Element getData(String tag) throws CmsException { 406 Object result = m_blocks.get(tag.toLowerCase()); 407 if (result == null) { 408 String errorMessage = "Unknown Datablock " + tag + " requested."; 409 throwException(errorMessage, CmsLegacyException.C_XML_UNKNOWN_DATA); 410 } else { 411 if (!(result instanceof Element )) { 412 String errorMessage = "Unexpected object returned as datablock. Requested Tagname: " + tag + ". Returned object: " + result.getClass().getName() + "."; 413 throwException(errorMessage, CmsLegacyException.C_XML_CORRUPT_INTERNAL_STRUCTURE); 414 } 415 } 416 return (Element ) m_blocks.get(tag.toLowerCase()); 417 } 418 419 427 protected String getDataValue(String tag) throws CmsException { 428 Element dataElement = getData(tag); 429 return getTagValue(dataElement); 430 } 431 432 437 public String getFilename() { 438 return m_filename.substring(m_filename.lastIndexOf("/") + 1); 439 } 440 441 448 protected Element getProcessedData(String tag) throws CmsException { 449 return getProcessedData(tag, null, null); 450 } 451 452 460 protected Element getProcessedData(String tag, Object callingObject) throws CmsException { 461 return getProcessedData(tag, callingObject, null); 462 } 463 464 476 protected Element getProcessedData(String tag, Object callingObject, Object userObj) throws CmsException { 477 Element dBlock = (Element ) getData(tag).cloneNode(true); 478 processNode(dBlock, m_mainProcessTags, null, callingObject, userObj); 479 return dBlock; 480 } 481 482 495 protected Element getProcessedData(String tag, Object callingObject, Object userObj, OutputStream stream) throws CmsException { 496 Element dBlock = (Element ) getData(tag).cloneNode(true); 497 processNode(dBlock, m_mainProcessTags, null, callingObject, userObj, stream); 498 return dBlock; 499 } 500 501 509 protected String getProcessedDataValue(String tag) throws CmsException { 510 return getProcessedDataValue(tag, null, null, null); 511 } 512 513 522 protected String getProcessedDataValue(String tag, Object callingObject) throws CmsException { 523 return getProcessedDataValue(tag, callingObject, null, null); 524 } 525 526 539 protected String getProcessedDataValue(String tag, Object callingObject, Object userObj) throws CmsException { 540 return getProcessedDataValue(tag, callingObject, userObj, null); 541 } 542 543 558 protected String getProcessedDataValue(String tag, Object callingObject, Object userObj, OutputStream stream) throws CmsException { 559 registerTag("METHOD", A_CmsXmlContent.class, "handleMethodTagForSure", C_REGISTER_MAIN_RUN); 561 Element data = getProcessedData(tag, callingObject, userObj, stream); 562 registerTag("METHOD", A_CmsXmlContent.class, "handleMethodTag", C_REGISTER_MAIN_RUN); 563 return getTagValue(data); 564 } 565 566 574 protected String getTagValue(Element n) { 575 StringBuffer result = new StringBuffer (); 576 if (n != null) { 577 NodeList childNodes = n.getChildNodes(); 578 Node child = null; 579 if (childNodes != null) { 580 int numchilds = childNodes.getLength(); 581 for (int i = 0; i < numchilds; i++) { 582 child = childNodes.item(i); 583 String nodeValue = child.getNodeValue(); 584 585 if (nodeValue != null) { 586 if (child.getNodeType() == Node.CDATA_SECTION_NODE) { 588 result.append(nodeValue); 590 } else { 591 if (child.getNodeType() == Node.TEXT_NODE) { 592 nodeValue = nodeValue.trim(); 594 if (!"".equals(nodeValue)) { 596 result.append(nodeValue); 598 } 599 } 600 } 601 } 602 } 603 } 604 } 605 return result.toString(); 606 } 607 608 616 private Method getUserMethod(String methodName, Object callingObject) throws NoSuchMethodException { 617 if (methodName == null || "".equals(methodName)) { 618 619 throw (new NoSuchMethodException ("method name is null or empty")); 621 } 622 return callingObject.getClass().getMethod(methodName, C_PARAMTYPES_USER_METHODS); 623 } 624 625 634 protected Document getXmlDocument() { 635 return m_content; 636 } 637 638 643 public abstract String getXmlDocumentTagName(); 644 645 649 public static I_CmsXmlParser getXmlParser() { 650 return m_parser; 651 } 652 653 658 public String getXmlText() { 659 StringWriter writer = new StringWriter (); 660 getXmlText(writer); 661 return writer.toString(); 662 } 663 664 670 public void getXmlText(Writer out) { 671 m_parser.getXmlText(m_content, out); 672 } 673 674 681 public void getXmlText(Writer out, Node n) { 682 Document tempDoc = (Document ) m_content.cloneNode(false); 683 tempDoc.appendChild(m_parser.importNode(tempDoc, n)); 684 m_parser.getXmlText(tempDoc, out); 685 } 686 687 693 public void getXmlText(OutputStream out) { 694 m_parser.getXmlText(m_content, out, m_newEncoding); 695 } 696 697 704 public void getXmlText(OutputStream out, Node n) { 705 Document tempDoc = (Document ) m_content.cloneNode(false); 706 tempDoc.appendChild(m_parser.importNode(tempDoc, n)); 707 m_parser.getXmlText(tempDoc, out, m_newEncoding); 708 } 709 710 717 public String getXmlText(Node n) { 718 StringWriter writer = new StringWriter (); 719 getXmlText(writer, n); 720 return writer.toString(); 721 } 722 723 731 protected void callAllUncalledMethodsSoThatEclipseDoesntComplainAboutThem() throws CmsException { 732 this.handleDataTag(null, null, null); 733 this.handleIncludeTag(null, null, null); 734 this.handleLinkTag(null, null, null); 735 this.handleMethodTag(null, null, null); 736 this.handleMethodTag(null, null, null); 737 this.handleMethodTagForSure(null, null, null); 738 this.handleProcessTag(null, null, null); 739 this.replaceTagByComment(null, null, null); 740 } 741 742 752 private void handleDataTag(Element n, Object callingObject, Object userObj) { 753 String blockname; 754 String bestFit = null; 755 String parentname = null; 756 Node parent = n.getParentNode(); 757 while (parent != null && parent.getNodeType() == Node.ELEMENT_NODE) { 758 759 761 763 if (parent.getNodeName().equals("DATA")) { 765 blockname = ((Element ) parent).getAttribute("name"); 766 } else { 767 blockname = parent.getNodeName(); 768 String secondName = ((Element ) parent).getAttribute("name"); 769 if (!"".equals(secondName)) { 770 blockname = blockname + "." + secondName; 771 } 772 } 773 blockname = blockname.toLowerCase(); 774 if (parentname == null) { 775 parentname = blockname; 776 } else { 777 parentname = blockname + "." + parentname; 778 } 779 if (m_blocks.containsKey(parentname)) { 780 bestFit = parentname; 781 } 782 parent = parent.getParentNode(); 783 } 784 785 787 if (n.getNodeName().equals("DATA")) { 789 blockname = n.getAttribute("name"); 790 } else { 791 blockname = n.getNodeName(); 792 String secondName = n.getAttribute("name"); 793 if (!"".equals(secondName)) { 794 blockname = blockname + "." + secondName; 795 } 796 } 797 blockname = blockname.toLowerCase(); 798 799 if (bestFit != null) { 801 blockname = bestFit + "." + blockname; 802 } 803 if (CmsLog.getLog(this).isDebugEnabled() && C_DEBUG) { 804 CmsLog.getLog(this).debug("Reading datablock " + blockname); 805 } 806 807 m_blocks.put(blockname, n); 809 810 } 812 813 819 private Object handleIncludeTag(Element n, Object callingObject, Object userObj) throws CmsException { 820 A_CmsXmlContent include = null; 821 String tagcontent = getTagValue(n); 822 include = readIncludeFile(tagcontent); 823 return include.getXmlDocument().getDocumentElement().getChildNodes(); 824 } 825 826 832 private Object handleLinkTag(Element n, Object callingObject, Object userObj) throws CmsException { 833 Element dBlock = (Element ) n.cloneNode(true); 835 processNode(dBlock, m_mainProcessTags, null, callingObject, userObj, null); 836 String link = getTagValue(dBlock); 837 return OpenCms.getLinkManager().substituteLink(m_cms, link); 838 } 839 840 851 private Object handleMethodTag(Element n, Object callingObject, Object userObj) throws CmsException { 852 processNode(n, m_mainProcessTags, null, callingObject, userObj); 853 String tagcontent = getTagValue(n); 854 String method = n.getAttribute("name"); 855 Object result = null; 856 try { 857 result = callUserMethod(method, tagcontent, callingObject, userObj, false); 858 } catch (Throwable e1) { 859 if (e1 instanceof CmsException) { 860 throw (CmsException) e1; 861 } else { 862 throwException("handleMethodTag() received an exception from callUserMethod() while calling \"" + method + "\" requested by class " + callingObject.getClass().getName() + ": " + e1); 863 } 864 } 865 return result; 866 } 867 868 882 private Object handleMethodTagForSure(Element n, Object callingObject, Object userObj) throws CmsException { 883 processNode(n, m_mainProcessTags, null, callingObject, userObj); 884 String tagcontent = getTagValue(n); 885 String method = n.getAttribute("name"); 886 Object result = null; 887 try { 888 result = callUserMethod(method, tagcontent, callingObject, userObj, true); 889 } catch (Throwable e1) { 890 if (e1 instanceof CmsException) { 891 throw (CmsException) e1; 892 } else { 893 throwException("handleMethodTagForSure() received an exception from callUserMethod() while calling \"" + method + "\" requested by class " + callingObject.getClass().getName() + ": " + e1); 894 } 895 } 896 return result; 897 } 898 899 908 private Object handleProcessTag(Element n, Object callingObject, Object userObj) { 909 String blockname = getTagValue(n).toLowerCase(); 910 Element datablock = null; 911 if (CmsLog.getLog(this).isDebugEnabled() && C_DEBUG) { 912 CmsLog.getLog(this).debug("Request for datablock \"" + blockname + "\""); 913 } 914 datablock = ((Element )m_blocks.get(blockname)); 915 if (datablock == null) { 916 if (CmsLog.getLog(this).isErrorEnabled()) { 917 String logUri = ""; 918 try { 919 logUri = " RequestUri is " + m_cms.getRequestContext().getFolderUri() + m_cms.getRequestContext().getUri() + "."; 920 } catch (Exception e) { 921 } 923 CmsLog.getLog(this).error("Requested datablock \"" + blockname + "\" not found in " + m_filename + " - " + logUri); 924 } 925 return C_ERR_NODATABLOCK + blockname; 926 } else { 927 return datablock.getChildNodes(); 928 } 929 } 930 931 936 protected boolean hasData(String key) { 937 return m_blocks.containsKey(key.toLowerCase()); 938 } 939 940 947 public void init(CmsObject cms, CmsFile file) throws CmsException { 948 String filename = cms.getSitePath(file); 949 String currentProject = cms.getRequestContext().currentProject().getName(); 950 Document parsedContent = null; 951 m_cms = cms; 952 m_filename = filename; 953 parsedContent = loadCachedDocument(cms.getRequestContext().addSiteRoot(filename)); 954 if (parsedContent == null) { 955 byte[] fileContent = file.getContents(); 956 if (fileContent == null || fileContent.length <= 1) { 957 file = cms.readFile(filename); 960 fileContent = file.getContents(); 961 } 962 if (fileContent == null || fileContent.length <= 1) { 963 try { 966 parsedContent = getXmlParser().createEmptyDocument(getXmlDocumentTagName()); 967 } catch (Exception e) { 968 throwException("Could not initialize now XML document " + filename + ". " + e, CmsLegacyException.C_XML_PARSING_ERROR); 969 } 970 } else { 971 parsedContent = parse(fileContent); 972 } 973 m_filecache.put(currentProject + ":" + cms.getRequestContext().addSiteRoot(filename), parsedContent.cloneNode(true)); 974 fileContent = null; 975 } 976 init(cms, parsedContent, filename); 977 } 978 979 988 public void init(CmsObject cms, String filename, String content) throws CmsException { 989 m_cms = cms; 990 m_filename = filename + com.opencms.core.I_CmsConstants.C_XML_CONTROL_FILE_SUFFIX; 991 init(cms, parse(content.getBytes()), filename); 992 } 993 994 1008 public void init(CmsObject cms, String filename) throws CmsException { 1009 1010 if (!filename.startsWith("/")) { 1011 throw new CmsLegacyException("A relative path has entered the A_CmsXmlContent class. filename=" + filename + ""); 1012 } 1013 String currentProject = cms.getRequestContext().currentProject().getName(); 1014 Document parsedContent = null; 1015 m_cms = cms; 1016 m_filename = filename; 1017 parsedContent = loadCachedDocument(cms.getRequestContext().addSiteRoot(filename)); 1018 if (parsedContent == null) { 1019 CmsFile file = cms.readFile(filename); 1020 1021 parsedContent = parse(file.getContents()); 1022 m_filecache.put(currentProject + ":" + cms.getRequestContext().addSiteRoot(filename), parsedContent.cloneNode(true)); 1023 } else { 1024 1025 cms.readResource(filename); 1028 } 1029 1030 if (C_PRINTNODES) { 1031 if (filename.indexOf(CmsWorkplaceDefault.C_VFS_DIR_LOCALES) != -1) { 1032 System.err.println("\n" + filename); 1033 this.printNode(parsedContent, 0, ""); 1034 } 1035 } 1036 1037 init(cms, parsedContent, filename); 1038 } 1039 1040 1041 private static final boolean C_PRINTNODES = false; 1042 1043 1058 private void printNode(Node node, int depth, String path) { 1059 1060 if (C_PRINTNODES) { 1061 final String badChars = "\n"; 1063 1064 final String [] goodChars = {"\\n"}; 1066 1067 int nodeType = node.getNodeType(); 1068 1069 if (nodeType == Node.ELEMENT_NODE) { 1070 String nodeName = node.getNodeName(); 1071 1072 if (!"".equals(nodeName)) { 1073 if (depth > 2) { 1074 path += "."; 1075 } 1076 if (depth > 1) { 1077 path += nodeName; 1078 } 1079 } 1080 } else if (nodeType == Node.TEXT_NODE) { 1081 String nodeValue = node.getNodeValue(); 1082 1083 if (!"".equals(nodeValue)) { 1084 int nodeValueLength = nodeValue.length(); 1085 String nodeValueNoBadChars = ""; 1086 1087 for (int i = 0; i < nodeValueLength; i++) { 1088 int index = 0; 1089 1090 if ((index = badChars.indexOf(nodeValue.charAt(i))) != -1) { 1091 nodeValueNoBadChars += goodChars[index]; 1092 } else { 1093 nodeValueNoBadChars += nodeValue.charAt(i); 1094 } 1095 } 1096 1097 if (node.getPreviousSibling() == null) { 1098 System.out.print(path + "="); 1099 } 1100 1101 System.out.print(nodeValueNoBadChars); 1102 1103 if (node.getNextSibling() == null) { 1104 System.out.print("\n"); 1105 } 1106 } 1107 } else if (nodeType == Node.CDATA_SECTION_NODE) { 1108 CDATASection cdata = (CDATASection ) node; 1109 String nodeValue = cdata.getData(); 1110 1111 if (!"".equals(nodeValue)) { 1112 int nodeValueLength = nodeValue.length(); 1113 String nodeValueNoBadChars = ""; 1114 1115 for (int i = 0; i < nodeValueLength; i++) { 1116 int index = 0; 1117 1118 if ((index = badChars.indexOf(nodeValue.charAt(i))) != -1) { 1119 nodeValueNoBadChars += goodChars[index]; 1120 } else { 1121 nodeValueNoBadChars += nodeValue.charAt(i); 1122 } 1123 } 1124 1125 if (node.getPreviousSibling() == null) { 1126 System.out.print(path + "="); 1127 } 1128 1129 System.out.print(nodeValueNoBadChars); 1130 1131 if (node.getNextSibling() == null) { 1132 System.out.print("\n"); 1133 } 1134 } 1135 } 1136 1137 NodeList nodeChildren = node.getChildNodes(); 1138 if (nodeChildren != null) { 1139 for (int i = 0; i < nodeChildren.getLength(); i++) { 1140 printNode(nodeChildren.item(i), depth + 1, path); 1141 } 1142 } 1143 } 1144 } 1145 1146 1153 public void init(CmsObject cms, Document content, String filename) throws CmsException { 1154 m_cms = cms; 1155 m_content = content; 1156 m_filename = filename; 1157 1158 Element docRootElement = m_content.getDocumentElement(); 1160 String docRootElementName = docRootElement.getNodeName().toLowerCase(); 1161 if (!docRootElementName.equals(getXmlDocumentTagName().toLowerCase())) { 1162 1163 1165 removeFromFileCache(); 1167 m_content = null; 1168 String errorMessage = "XML document " + getAbsoluteFilename() + " is not of the expected type. This document is \"" + docRootElementName + "\", but it should be \"" + getXmlDocumentTagName() + "\" (" + getContentDescription() + ")."; 1169 throwException(errorMessage, CmsLegacyException.C_XML_WRONG_CONTENT_TYPE); 1170 } 1171 1172 1174 try { 1176 processNode(m_content, m_firstRunTags, A_CmsXmlContent.class.getDeclaredMethod("handleDataTag", C_PARAMTYPES_HANDLING_METHODS), null, null); 1177 } catch (CmsException e) { 1178 if (CmsLog.getLog(this).isWarnEnabled()) { 1179 CmsLog.getLog(this).warn("Error while scanning for DATA and INCLUDE tags in file " + getAbsoluteFilename(), e); 1180 } 1181 throw e; 1182 } catch (NoSuchMethodException e2) { 1183 String errorMessage = "XML tag process method \"handleDataTag\" could not be found"; 1184 throwException(errorMessage, CmsLegacyException.C_XML_NO_PROCESS_METHOD); 1185 } 1186 } 1187 1188 1205 private void insertNewDatablock(String tag, Element data) { 1206 1207 String nameAttr = data.getAttribute("name"); 1211 String workTag = null; 1212 if ((!data.getNodeName().toLowerCase().equals("data")) && nameAttr != null && (!"".equals(nameAttr))) { 1213 workTag = tag.substring(0, tag.lastIndexOf(".")); 1215 } else { 1216 workTag = tag; 1217 } 1218 Element importedNode = (Element ) m_parser.importNode(m_content, data); 1220 1221 if (workTag.indexOf(".") == -1) { 1223 m_content.getDocumentElement().appendChild(importedNode); 1225 m_blocks.put(tag, importedNode); 1226 } else { 1227 boolean found = false; 1230 String match = "." + workTag; 1231 int dotIndex = match.lastIndexOf("."); 1232 Vector newBlocks = new Vector (); 1233 while ((!found) && (dotIndex > 1)) { 1234 match = match.substring(0, dotIndex); 1235 if (hasData(match.substring(1))) { 1236 found = true; 1237 } else { 1238 dotIndex = match.lastIndexOf("."); 1239 newBlocks.addElement(match.substring(dotIndex + 1)); 1240 } 1241 } 1242 String datablockPrefix = ""; 1246 if (found) { 1247 datablockPrefix = match.substring(1) + "."; 1248 } 1249 int numNewBlocks = newBlocks.size(); 1251 Element newElem = null; 1253 Element lastElem = null; 1255 for (int i = numNewBlocks - 1; i >= 0; i--) { 1257 newElem = m_content.createElement("DATA"); 1258 newElem.setAttribute("name", (String ) newBlocks.elementAt(i)); 1259 m_blocks.put(datablockPrefix + (String ) newBlocks.elementAt(i), newElem); 1260 if (lastElem != null) { 1261 lastElem.appendChild(newElem); 1262 } else { 1263 lastElem = newElem; 1264 } 1265 } 1266 if (lastElem != null) { 1269 lastElem.appendChild(importedNode); 1270 } else { 1271 lastElem = importedNode; 1272 } 1273 m_blocks.put(datablockPrefix + tag, importedNode); 1274 1275 if (found) { 1281 Element parent = (Element ) m_blocks.get(match.substring(1)); 1282 parent.appendChild(lastElem); 1283 } else { 1284 m_content.getDocumentElement().appendChild(lastElem); 1285 } 1286 } 1287 } 1288 1289 1295 private Document loadCachedDocument(String filename) { 1296 Document cachedDoc = null; 1297 String currentProject = m_cms.getRequestContext().currentProject().getName(); 1298 Document lookup = (Document ) m_filecache.get(currentProject + ":" + filename); 1299 if (lookup != null) { 1300 try { 1301 cachedDoc = (Document ) lookup.cloneNode(true); 1303 } catch (Exception e) { 1304 lookup = null; 1305 cachedDoc = null; 1306 } 1307 } 1308 if (CmsLog.getLog(this).isDebugEnabled() && cachedDoc != null) { 1309 CmsLog.getLog(this).debug("Reused previously parsed XML file " + getFilename()); 1310 } 1311 return cachedDoc; 1312 } 1313 1314 1323 private NodeList replaceTagByComment(Element n, Object callingObject, Object userObj) { 1324 Element tempNode = (Element ) n.cloneNode(false); 1325 while (tempNode.hasChildNodes()) { 1326 tempNode.removeChild(tempNode.getFirstChild()); 1327 } 1328 tempNode.appendChild(m_content.createComment("removed " + n.getNodeName())); 1329 return tempNode.getChildNodes(); 1330 } 1331 1332 1341 protected Document parse(byte[] content) throws CmsException { 1342 return parse(new ByteArrayInputStream (content)); 1343 } 1344 1345 1354 protected Document parse(InputStream content) throws CmsException { 1355 Document parsedDoc = null; 1356 1357 try { 1360 parsedDoc = m_parser.parse(content); 1361 } catch (Exception e) { 1362 String errorMessage = "Cannot parse XML file \"" + getAbsoluteFilename() + "\". " + e; 1365 throwException(errorMessage, CmsLegacyException.C_XML_PARSING_ERROR); 1366 } 1367 if (parsedDoc == null) { 1368 String errorMessage = "Unknown error. Parsed DOM document is null."; 1369 throwException(errorMessage, CmsLegacyException.C_XML_PARSING_ERROR); 1370 } 1371 1372 try { 1380 Class elementClass = Class.forName("org.w3c.dom.Element"); 1381 Method normalizeMethod = elementClass.getMethod("normalize", new Class [] {}); 1382 normalizeMethod.invoke(parsedDoc.getDocumentElement(), new Object [] {}); 1383 } catch (Exception e) { 1384 throwException("Normalizing the XML document failed. Possibly you are using concurrent versions of " + "the XML parser with different DOM levels. ", e, CmsLegacyException.C_XML_PARSING_ERROR); 1387 } 1388 Node loop = parsedDoc.getDocumentElement(); 1391 while (loop != null) { 1392 Node next = treeWalker(parsedDoc.getDocumentElement(), loop); 1393 if (loop.getNodeType() == Node.TEXT_NODE) { 1394 Node leftSibling = loop.getPreviousSibling(); 1395 Node rightSibling = loop.getNextSibling(); 1396 if (leftSibling == null || rightSibling == null || (leftSibling.getNodeType() == Node.ELEMENT_NODE && rightSibling.getNodeType() == Node.ELEMENT_NODE)) { 1397 if ("".equals(loop.getNodeValue().trim())) { 1398 loop.getParentNode().removeChild(loop); 1399 } 1400 } 1401 } 1402 loop = next; 1403 } 1404 return parsedDoc; 1405 } 1406 1407 1416 protected void processDocument(Hashtable keys, Method defaultMethod, Object callingObject, Object userObj) throws CmsException { 1417 processNode(m_content.getDocumentElement(), keys, defaultMethod, callingObject, userObj); 1418 } 1419 1420 1444 protected void processNode(Node n, Hashtable keys, Method defaultMethod, Object callingObject, Object userObj) throws CmsException { 1445 processNode(n, keys, defaultMethod, callingObject, userObj, null); 1446 } 1447 1448 1473 protected void processNode(Node n, Hashtable keys, Method defaultMethod, Object callingObject, Object userObj, OutputStream stream) throws CmsException { 1474 1475 Node child = null; 1477 1478 String childName = null; 1480 1481 Node nextchild = null; 1483 1484 NodeList newnodes = null; 1486 1487 Node insert = null; 1489 1490 Method callMethod = null; 1492 1493 Object methodResult = null; 1495 1496 boolean newnodesAreAlreadyProcessed = false; 1498 1499 Node startingNode = n; 1501 1502 if (n != null && n.hasChildNodes()) { 1504 child = n.getFirstChild(); 1505 while (child != null) { 1506 childName = child.getNodeName().toLowerCase(); 1507 1508 nextchild = treeWalker(startingNode, child); 1510 1511 1513 if (child.getNodeType() == Node.ELEMENT_NODE) { 1515 newnodes = null; 1516 callMethod = null; 1517 newnodesAreAlreadyProcessed = false; 1518 if (keys.containsKey(childName)) { 1519 1520 callMethod = (Method ) keys.get(childName); 1522 } else { 1523 if (!m_knownTags.contains(childName)) { 1524 1525 callMethod = defaultMethod; 1528 } 1529 } 1530 if (callMethod != null) { 1531 methodResult = null; 1532 try { 1533 if (C_DEBUG && CmsLog.getLog(this).isDebugEnabled()) { 1534 CmsLog.getLog(this).debug("<" + childName + "> tag found. Value: " + child.getNodeValue()); 1535 CmsLog.getLog(this).debug("Tag will be handled by method [" + callMethod.getName() + "]. Invoking method NOW."); 1536 } 1537 1538 methodResult = callMethod.invoke(this, new Object [] {child, callingObject, userObj}); 1540 } catch (Exception e) { 1541 if (e instanceof InvocationTargetException ) { 1542 Throwable thrown = ((InvocationTargetException ) e).getTargetException(); 1543 1544 if (thrown instanceof CmsException) { 1547 throw (CmsException) thrown; 1548 } else { 1549 throwException("processNode received an exception while handling XML tag \"" + childName + "\" by \"" + callMethod.getName() + "\" for file " + getFilename() + ": " + e, CmsLegacyException.C_XML_PROCESS_ERROR); 1550 } 1551 } else { 1552 throwException("processNode could not invoke the XML tag handling method " + callMethod.getName() + "\" for file " + getFilename() + ": " + e, CmsLegacyException.C_XML_PROCESS_ERROR); 1553 } 1554 } 1555 1556 if (methodResult == null) { 1560 newnodes = null; 1561 } else { 1562 if (methodResult instanceof NodeList ) { 1563 newnodes = (NodeList ) methodResult; 1564 } else { 1565 if (methodResult instanceof String ) { 1566 newnodes = stringToNodeList((String ) methodResult); 1567 } else { 1568 if (methodResult instanceof CmsProcessedString) { 1569 newnodes = stringToNodeList(((CmsProcessedString) methodResult).toString()); 1570 newnodesAreAlreadyProcessed = true; 1571 } else { 1572 if (methodResult instanceof Integer ) { 1573 newnodes = stringToNodeList(((Integer ) methodResult).toString()); 1574 } else { 1575 if (methodResult instanceof byte[]) { 1576 newnodes = stringToNodeList(new String ((byte[]) methodResult)); 1577 } else { 1578 1579 if (CmsLog.getLog(this).isErrorEnabled()) { 1581 CmsLog.getLog(this).error("Return type of method " + callMethod.getName() + " not recognized, can not insert value"); 1582 } 1583 newnodes = null; 1584 } 1585 } 1586 } 1587 } 1588 } 1589 } 1590 1591 if (newnodes != null) { 1595 int numNewChilds = newnodes.getLength(); 1603 if (numNewChilds > 0) { 1604 1605 for (int j = 0; j < numNewChilds; j++) { 1608 1609 insert = m_parser.importNode(child.getOwnerDocument(), newnodes.item(j)); 1611 if (j == 0 && !newnodesAreAlreadyProcessed) { 1612 nextchild = insert; 1613 } 1614 1615 child.getParentNode().insertBefore(insert, child); 1617 1618 } 1620 1621 if (newnodesAreAlreadyProcessed) { 1622 nextchild = treeWalkerWidth(startingNode, child); 1625 } 1626 1627 } else { 1628 1629 nextchild = treeWalkerWidth(startingNode, child); 1634 } 1635 1636 child.getParentNode().removeChild(child); 1638 } 1639 } 1640 } else if (stream != null) { 1641 1644 String streamResults = null; 1645 if (child.getNodeType() == Node.CDATA_SECTION_NODE) { 1646 streamResults = child.getNodeValue(); 1647 } else { 1648 if (child.getNodeType() == Node.TEXT_NODE) { 1649 String s = child.getNodeValue().trim(); 1650 if (!"".equals(s)) { 1651 streamResults = child.getNodeValue(); 1652 } 1653 } 1654 } 1655 if (streamResults != null) { 1656 try { 1657 stream.write(streamResults.getBytes(m_cms.getRequestContext().getEncoding())); 1658 } catch (Exception e) { 1659 throw new CmsLegacyException(CmsLegacyException.C_UNKNOWN_EXCEPTION, e); 1660 } 1661 } 1662 } 1663 child = nextchild; 1664 } 1665 } 1666 } 1667 1668 1675 public void readIncludeFile(A_CmsXmlContent include) throws CmsException { 1676 m_includedTemplates.addElement(include); 1677 m_blocks = concatData(m_blocks, include.getAllData()); 1678 } 1679 1680 1688 public A_CmsXmlContent readIncludeFile(String filename) throws CmsException { 1689 A_CmsXmlContent include = null; 1690 if (CmsLog.getLog(this).isDebugEnabled() && C_DEBUG) { 1691 CmsLog.getLog(this).debug("Including file: " + filename); 1692 } 1693 try { 1694 include = (A_CmsXmlContent) getClass().newInstance(); 1695 include.init(m_cms, filename); 1696 } catch (Exception e) { 1697 if (CmsLog.getLog(this).isErrorEnabled()) { 1698 CmsLog.getLog(this).error("Error include file: " + filename, e); 1699 } 1700 } 1701 readIncludeFile(include); 1702 return include; 1703 } 1704 1705 1719 private void registerAllTags() { 1720 1721 registerTag("INCLUDE", A_CmsXmlContent.class, "handleIncludeTag", C_REGISTER_FIRST_RUN); 1723 registerTag("DATA", A_CmsXmlContent.class, "handleDataTag", C_REGISTER_FIRST_RUN); 1724 1725 registerTag("METHOD", A_CmsXmlContent.class, "handleMethodTag", C_REGISTER_MAIN_RUN); 1727 registerTag("PROCESS", A_CmsXmlContent.class, "handleProcessTag", C_REGISTER_MAIN_RUN); 1728 registerTag("LINK", A_CmsXmlContent.class, "handleLinkTag", C_REGISTER_MAIN_RUN); 1729 registerTag("INCLUDE", A_CmsXmlContent.class, "replaceTagByComment", C_REGISTER_MAIN_RUN); 1730 registerTag("DATA", A_CmsXmlContent.class, "replaceTagByComment", C_REGISTER_MAIN_RUN); 1731 registerTag(getXmlDocumentTagName()); 1732 } 1733 1734 1741 public void registerTag(String tagname) { 1742 if (!(m_knownTags.contains(tagname.toLowerCase()))) { 1743 m_knownTags.addElement(tagname.toLowerCase()); 1744 } 1745 } 1746 1747 1765 public void registerTag(String tagname, Class c, String methodName, int runSelector) { 1766 Hashtable selectedRun = null; 1767 switch (runSelector) { 1768 case C_REGISTER_FIRST_RUN : 1769 selectedRun = m_firstRunTags; 1770 break; 1771 1772 case C_REGISTER_MAIN_RUN : 1773 default: 1774 selectedRun = m_mainProcessTags; 1775 break; 1776 } 1777 try { 1778 selectedRun.put(tagname.toLowerCase(), c.getDeclaredMethod(methodName, C_PARAMTYPES_HANDLING_METHODS)); 1779 } catch (Exception e) { 1780 if (CmsLog.getLog(this).isWarnEnabled()) { 1781 CmsLog.getLog(this).warn("Exception in register tag ", e); 1782 } 1783 } 1784 registerTag(tagname); 1785 } 1786 1787 1792 protected void removeData(String tag) { 1793 Element e = (Element ) m_blocks.get(tag.toLowerCase()); 1794 if (e != null) { 1795 m_blocks.remove(tag.toLowerCase()); 1796 Element parent = (Element ) e.getParentNode(); 1797 if (parent != null) { 1798 parent.removeChild(e); 1799 } 1800 } 1801 } 1802 1803 1806 public void removeFromFileCache() { 1807 String currentProject = m_cms.getRequestContext().currentProject().getName(); 1808 m_filecache.remove(currentProject + ":" + m_cms.getRequestContext().addSiteRoot(getAbsoluteFilename())); 1809 } 1810 1811 1818 protected void setData(String tag, String data) { 1819 String attribute = tag; 1821 int dotIndex = tag.lastIndexOf("."); 1822 if (dotIndex != -1) { 1823 attribute = attribute.substring(dotIndex + 1); 1824 } 1825 Element newElement = m_content.createElement(attribute); 1826 if (data == null || "".equals(data)) { 1827 setData(tag, newElement); 1830 } else { 1831 newElement.appendChild(m_content.createTextNode(data.trim())); 1835 setData(tag, newElement); 1836 } 1837 } 1838 1839 1845 protected void setData(String tag, Element data) { 1846 1847 if (data == null) { 1850 setData(tag, ""); 1851 } else { 1852 tag = tag.toLowerCase(); 1854 Element newElement = (Element ) data.cloneNode(true); 1855 if (CmsLog.getLog(this).isDebugEnabled() && C_DEBUG) { 1856 CmsLog.getLog(this).debug("Putting datablock " + tag + " into internal Hashtable"); 1857 } 1858 if (!(m_blocks.containsKey(tag))) { 1859 insertNewDatablock(tag, newElement); 1862 } else { 1863 if (CmsLog.getLog(this).isDebugEnabled() && C_DEBUG) { 1866 CmsLog.getLog(this).debug("Datablock existed before, replacing"); 1867 } 1868 Element originalBlock = (Element ) (m_blocks.get(tag)); 1870 while (originalBlock.hasChildNodes()) { 1871 originalBlock.removeChild(originalBlock.getFirstChild()); 1872 } 1873 NodeList newNodes = data.getChildNodes(); 1875 int len = newNodes.getLength(); 1876 for (int i = 0; i < len; i++) { 1877 Node newElement2 = newNodes.item(i).cloneNode(true); 1878 originalBlock.appendChild(m_parser.importNode(originalBlock.getOwnerDocument(), newElement2)); 1879 } 1880 } 1881 } 1882 } 1883 1884 1892 public void setParsedData(String tag, String data) throws CmsException { 1893 1894 StringBuffer tempXmlString = new StringBuffer (); 1895 tempXmlString.append("<?xml version=\"1.0\"?>\n"); 1896 tempXmlString.append("<" + getXmlDocumentTagName() + ">"); 1897 tempXmlString.append("<" + tag + ">\n"); 1898 tempXmlString.append("<![CDATA["); 1899 tempXmlString.append(data); 1900 tempXmlString.append("]]>"); 1901 tempXmlString.append("</" + tag + ">\n"); 1902 tempXmlString.append("</" + getXmlDocumentTagName() + ">\n"); 1903 StringReader parserReader = new StringReader (tempXmlString.toString()); 1904 Document tempDoc = null; 1905 try { 1906 tempDoc = m_parser.parse(parserReader); 1907 } catch (Exception e) { 1908 throwException("PARSING ERROR! " + e.toString(), CmsLegacyException.C_XML_PARSING_ERROR); 1909 } 1910 Element templateNode = (Element ) tempDoc.getDocumentElement().getFirstChild(); 1911 setData(tag, templateNode); 1912 } 1913 1914 1920 private NodeList stringToNodeList(String s) { 1921 Element tempNode = m_content.createElement("TEMP"); 1922 Text text = m_content.createTextNode(s); 1923 tempNode.appendChild(text); 1924 return tempNode.getChildNodes(); 1925 } 1926 1927 1934 protected void throwException(String errorMessage) throws CmsException { 1935 throwException(errorMessage, CmsLegacyException.C_UNKNOWN_EXCEPTION); 1936 } 1937 1938 1946 protected void throwException(String errorMessage, int type) throws CmsLegacyException { 1947 if (CmsLog.getLog(this).isErrorEnabled()) { 1948 CmsLog.getLog(this).error(errorMessage); 1949 } 1950 throw new CmsLegacyException(errorMessage, type); 1951 } 1952 1953 1961 protected void throwException(String errorMessage, Exception e) throws CmsException { 1962 throwException(errorMessage, e, CmsLegacyException.C_UNKNOWN_EXCEPTION); 1963 } 1964 1965 1974 protected void throwException(String errorMessage, Exception e, int type) throws CmsException { 1975 if (CmsLog.getLog(this).isErrorEnabled()) { 1976 CmsLog.getLog(this).error(errorMessage, e); 1977 } 1978 if (e instanceof CmsException) { 1979 throw (CmsException) e; 1980 } else { 1981 throw new CmsLegacyException(errorMessage, type, e); 1982 } 1983 } 1984 1985 1989 public String toString() { 1990 StringBuffer output = new StringBuffer (); 1991 output.append("[XML file]: "); 1992 output.append(getFilename()); 1993 output.append(", content type: "); 1994 output.append(getContentDescription()); 1995 return output.toString(); 1996 } 1997 1998 2007 protected Node treeWalker(Node root, Node n) { 2008 Node nextnode = null; 2009 if (n.hasChildNodes()) { 2010 nextnode = n.getFirstChild(); 2013 } else { 2014 nextnode = treeWalkerWidth(root, n); 2017 } 2018 return nextnode; 2019 } 2020 2021 2028 protected Node treeWalkerWidth(Node root, Node n) { 2029 if (n == root) { 2030 return null; 2031 } 2032 Node nextnode = null; 2033 Node parent = null; 2034 nextnode = n.getNextSibling(); 2035 parent = n.getParentNode(); 2036 while (nextnode == null && parent != null && parent != root) { 2037 2038 nextnode = parent.getNextSibling(); 2042 parent = parent.getParentNode(); 2043 } 2044 return nextnode; 2045 } 2046 2047 2051 public void write() throws CmsException { 2052 ByteArrayOutputStream os = new ByteArrayOutputStream (); 2053 getXmlText(os); 2054 byte[] xmlContent = os.toByteArray(); 2055 2056 String filename = getAbsoluteFilename(); 2058 CmsFile file = m_cms.readFile(filename); 2059 2060 file.setContents(xmlContent); 2062 m_cms.writeFile(file); 2063 xmlContent = null; 2064 2065 String currentProject = m_cms.getRequestContext().currentProject().getName(); 2067 m_filecache.put(currentProject + ":" + m_cms.getRequestContext().addSiteRoot(filename), m_content.cloneNode(true)); 2068 } 2069 2070 2074 public String getEncoding() { 2075 return m_parser.getOriginalEncoding(m_content); 2076 } 2077 2078 2082 public void setEncoding(String encoding) { 2083 m_newEncoding = encoding; 2084 } 2085 2086} 2087 | Popular Tags |