protected cfData getXmlTextAndCData() {
    boolean tfirst = true;
    NodeList nl = nodeData.getChildNodes();
    StringBuilder texts = null;
    for (int i = 0; i < nl.getLength(); i++) {
      Node node = nl.item(i);
      short nodeType = node.getNodeType();
      if (nodeType == Node.CDATA_SECTION_NODE || nodeType == Node.TEXT_NODE) {
        if (tfirst) texts = new StringBuilder();
        else texts.append(System.getProperty("line.separator"));
        String nv = "";
        try {
          nv = node.getNodeValue();
        } catch (DOMException ex) {
          // Just log it
          com.nary.Debug.printStackTrace(ex);
        }
        texts.append(nv.trim());
        tfirst = false;
      }
    }

    if (texts != null) return new cfStringData(texts.toString().trim());
    else return new cfStringData("");
  }
  protected cfData getXmlNsPrefix() {
    String oldPrefix = null;
    try {
      oldPrefix = nodeData.getPrefix();
    } catch (DOMException ex) {
      // Just log it
      com.nary.Debug.printStackTrace(ex);
    }

    if (oldPrefix != null) return new cfStringData(oldPrefix.trim());
    else return new cfStringData("");
  }
  public static void onApplicationEnd(cfApplicationData appData) {
    String applicationCfcPath = appData.getApplicationCfcPath();
    if (applicationCfcPath == null) return;

    cfSession session =
        new cfSession(
            new dummyServletRequest(appData.getWebroot()),
            new dummyServletResponse(),
            cfEngine.thisServletContext);
    cfComponentData applicationCfc = null;

    try {
      cfFile applicationFile = session.getRealFile(applicationCfcPath);
      applicationFile.setComponentName("Application");

      applicationCfc =
          new cfComponentData(session, applicationFile, false); // false = don't allow abstract

      List<cfApplicationData> args = new ArrayList<cfApplicationData>();
      args.add(appData); // ApplicationScope

      cfcMethodData methodData = new cfcMethodData(session, ON_APPLICATION_END, args);
      applicationCfc.invokeApplicationFunction(session, methodData);

    } catch (cfmAbortException ignore) {
      // do nothing, we're finished anyway (catch here so it's not caught as Throwable below)
    } catch (cfmRunTimeException e) {
      try {
        session.invokeOnError(applicationCfc, e, ON_APPLICATION_END);
      } catch (cfmRunTimeException ie) {
        cfEngine.log("RunTimeError in onApplicationEnd: " + applicationCfcPath);
        ie.handleException(session);
      }
    } catch (Throwable t) {
      com.nary.Debug.printStackTrace(t);
      new cfmRunTimeException(session, t).handleException(session);
    } finally {
      // Make sure per request connections are closed (bug #3174)
      session.sessionEnd();
    }
  }
  protected cfData getXmlComment() {
    boolean cfirst = true;
    NodeList nl = nodeData.getChildNodes();
    StringBuilder comments = null;
    for (int i = 0; i < nl.getLength(); i++) {
      Node node = nl.item(i);
      if (node.getNodeType() == Node.COMMENT_NODE) {
        if (cfirst) comments = new StringBuilder();
        else comments.append(System.getProperty("line.separator"));
        String nv = "";
        try {
          nv = node.getNodeValue();
        } catch (DOMException ex) {
          // Just log it
          com.nary.Debug.printStackTrace(ex);
        }
        comments.append(nv.trim());
        cfirst = false;
      }
    }

    if (comments != null) return new cfStringData(comments.toString().trim());
    else return new cfStringData("");
  }
  public Object remove(Object key) {
    try {
      if (key.toString().equalsIgnoreCase("XmlNsPrefix")) {
        String oldPrefix = null;
        try {
          oldPrefix = nodeData.getPrefix();
        } catch (DOMException ex) {
          // Just log it
          com.nary.Debug.printStackTrace(ex);
        }
        nodeData.setPrefix(null);
        return oldPrefix;
      } else if (key.toString().equalsIgnoreCase("XmlNsURI")) {
        return null;
      } else if (key.toString().equalsIgnoreCase("XmlText")) {
        // Remove all text nodes
        List<Node> ln = new ArrayList<Node>();
        NodeList nl = nodeData.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
          Node node = nl.item(i);
          if (node.getNodeType() == Node.TEXT_NODE) ln.add(node);
        }

        Iterator<Node> itr = ln.iterator();
        while (itr.hasNext()) nodeData.removeChild(itr.next());
        nodeData.normalize();
        return null;
      } else if (key.toString().equalsIgnoreCase("XmlCData")) {
        // Remove all cdata nodes
        List<Node> ln = new ArrayList<Node>();
        NodeList nl = nodeData.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
          Node node = nl.item(i);
          if (node.getNodeType() == Node.CDATA_SECTION_NODE) ln.add(node);
        }

        Iterator<Node> itr = ln.iterator();
        while (itr.hasNext()) nodeData.removeChild(itr.next());
        nodeData.normalize();
        return null;
      } else if (key.toString().equalsIgnoreCase("XmlComment")) {
        // Remove all comment nodes
        List<Node> ln = new ArrayList<Node>();
        NodeList nl = nodeData.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
          Node node = nl.item(i);
          if (node.getNodeType() == Node.COMMENT_NODE) ln.add(node);
        }

        Iterator<Node> itr = ln.iterator();
        while (itr.hasNext()) nodeData.removeChild((Node) itr.next());
        nodeData.normalize();
        return null;
      } else if (key.toString().equalsIgnoreCase("XmlAttributes")) {
        ((cfXmlDataAttributeStruct) getXmlAttributes()).clear();
        return null;
      } else if (key.toString().equalsIgnoreCase("XmlChildren")) {
        ((cfXmlDataArray) getXmlChildren()).removeAllElements();
        nodeData.normalize();
        return null;
      } else if (key.toString().equalsIgnoreCase("XmlParent")) {
        return null;
      } else if (key.toString().equalsIgnoreCase("XmlNodes")) {
        ((cfXmlDataArray) getXmlNodes()).removeAllElements();
        nodeData.normalize();
        return null;
      } else {
        cfData d = (cfData) get(key);
        if (d != null) {
          if (d instanceof cfXmlData) nodeData.removeChild(((cfXmlData) d).getXMLNode());
          else if (d instanceof cfXmlDataArray) ((cfXmlDataArray) d).removeAllElements();
          nodeData.normalize();
        }
        return null;
      }
    } catch (cfmRunTimeException ex) {
      // Nothing else we can do here
      com.nary.Debug.printStackTrace(ex);
    } catch (DOMException ex) {
      // Nothing else we can do here
      com.nary.Debug.printStackTrace(ex);
    }
    return null;
  }
  public Object put(Object key, Object value) {
    try {
      if (key.toString().equalsIgnoreCase("XmlNsPrefix")) {
        String oldPrefix = null;
        try {
          oldPrefix = nodeData.getPrefix();
        } catch (DOMException ex) {
          // Just log it
          com.nary.Debug.printStackTrace(ex);
        }
        nodeData.setPrefix(((cfData) value).toString());
        return oldPrefix;
      } else if (key.toString().equalsIgnoreCase("XmlNsURI")) {
        // Do nothing
        return null;
      } else if (key.toString().equalsIgnoreCase("XmlText")
          || key.toString().equalsIgnoreCase("XmlCData")) {
        boolean isCDATA = key.toString().equalsIgnoreCase("XmlCData");
        // Remove all text and CDATA nodes, and add 1 new one at the top
        remove("XmlText");
        remove("XmlCData");
        if (!((cfData) value).toString().trim().equals("")) {
          Node t = null;
          if (isCDATA)
            t = nodeData.getOwnerDocument().createCDATASection(((cfData) value).toString());
          else t = nodeData.getOwnerDocument().createTextNode(((cfData) value).toString());
          nodeData.insertBefore(t, nodeData.getFirstChild());
        }
        nodeData.normalize();
        return null;
      } else if (key.toString().equalsIgnoreCase("XmlComment")) {
        // Remove all comment nodes, and add 1 new one at the top
        remove(key);
        if (!((cfData) value).toString().trim().equals("")) {
          Comment c = nodeData.getOwnerDocument().createComment(((cfData) value).toString());
          nodeData.insertBefore(c, nodeData.getFirstChild());
        }
        nodeData.normalize();
        return null;
      } else if (key.toString().equalsIgnoreCase("XmlAttributes")) {
        // Overwrite any existing xml attributes with these new ones
        if (value instanceof cfStructData) {
          cfXmlDataAttributeStruct attribs = (cfXmlDataAttributeStruct) getXmlAttributes();
          cfStructData attribsToAdd = (cfStructData) value;

          Object[] keys = attribsToAdd.keys();
          for (int i = 0; i < keys.length; i++) {
            String str = keys[i].toString();
            cfData valueData = attribsToAdd.getData(str);
            attribs.setData(str, valueData);
          }
        }
        return null;
      } else if (key.toString().equalsIgnoreCase("XmlChildren")) {
        // Do nothing
        return null;
      } else if (key.toString().equalsIgnoreCase("XmlParent")) {
        // Do nothing
        return null;
      } else if (key.toString().equalsIgnoreCase("XmlNodes")) {
        // Do nothing
        return null;
      } else {
        if (value instanceof cfXmlData) {
          Node n = ((cfXmlData) value).getXMLNode();
          if (n.getParentNode() != null) n = n.cloneNode(true);

          cfData d = (cfData) get(key);
          if (d != null) {
            if (d instanceof cfXmlData)
              return nodeData.replaceChild(n, ((cfXmlData) d).getXMLNode());
            else if (d instanceof cfXmlDataArray)
              ((cfXmlDataArray) d)
                  .setData(1, new cfXmlData(n, ((cfXmlData) value).isCaseSensitive()));
          } else {
            nodeData.appendChild(n);
          }
          nodeData.normalize();
        } else if (value instanceof cfStructData) {
          Element e = nodeData.getOwnerDocument().createElement((String) key);
          nodeData.appendChild(e);
          buildParentElement((cfStructData) value, e);
          nodeData.normalize();
        } else if (value instanceof cfStringData) {
          if (((cfData) value).toString().trim().equals("")) {
            cfData d = (cfData) get(key);
            if (d != null) {
              if (d instanceof cfXmlData) nodeData.removeChild(((cfXmlData) d).getXMLNode());
              else if (d instanceof cfXmlDataArray) ((cfXmlDataArray) d).removeAllElements();
              nodeData.normalize();
            }
          }
        } else {
          super.put(key, value);
        }

        return null;
      }
    } catch (cfmRunTimeException ex) {
      // Nothing else we can do here
      com.nary.Debug.printStackTrace(ex);
    } catch (DOMException ex) {
      // Nothing else we can do here
      com.nary.Debug.printStackTrace(ex);
    }
    return null;
  }