| /* |
| * Copyright 2001-2004 The Apache Software Foundation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.axis.message; |
| |
| import org.apache.axis.components.logger.LogFactory; |
| import org.apache.axis.encoding.SerializationContext; |
| import org.apache.axis.i18n.Messages; |
| import org.apache.commons.logging.Log; |
| import org.w3c.dom.Attr; |
| import org.w3c.dom.CDATASection; |
| import org.w3c.dom.CharacterData; |
| import org.w3c.dom.Comment; |
| import org.w3c.dom.DOMException; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.NamedNodeMap; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import org.w3c.dom.Text; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.helpers.AttributesImpl; |
| |
| import javax.xml.soap.SOAPElement; |
| import javax.xml.soap.SOAPException; |
| import java.io.Serializable; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| |
| /** |
| * This is our implementation of the DOM node |
| */ |
| public class NodeImpl implements org.w3c.dom.Node, javax.xml.soap.Node, |
| Serializable, Cloneable { |
| |
| protected static Log log = |
| LogFactory.getLog(NodeImpl.class.getName()); |
| |
| protected String name; |
| protected String prefix; |
| protected String namespaceURI; |
| protected transient Attributes attributes = NullAttributes.singleton; |
| |
| protected Document document = null; |
| protected NodeImpl parent = null; |
| protected ArrayList children = null; |
| |
| // ...or as DOM |
| protected CharacterData textRep = null; |
| |
| protected boolean _isDirty = false; |
| private static final String NULL_URI_NAME = "intentionalNullURI"; |
| |
| /** |
| * empty constructor |
| */ |
| public NodeImpl() { |
| } |
| |
| /** |
| * constructor which adopts the name and NS of the char data, and its text |
| * @param text |
| */ |
| public NodeImpl(CharacterData text) { |
| textRep = text; |
| namespaceURI = text.getNamespaceURI(); |
| name = text.getLocalName(); |
| } |
| |
| /** |
| * A code representing the type of the underlying object, as defined above. |
| */ |
| public short getNodeType() { |
| if (this.textRep != null) { |
| if (textRep instanceof Comment) { |
| return COMMENT_NODE; |
| } else if (textRep instanceof CDATASection) { |
| return CDATA_SECTION_NODE; |
| } else { |
| return TEXT_NODE; |
| } |
| } else if (false) { |
| return DOCUMENT_FRAGMENT_NODE; |
| } else if (false) { |
| return Node.ELEMENT_NODE; |
| } else { // most often but we cannot give prioeity now |
| return Node.ELEMENT_NODE; |
| } |
| } |
| |
| /** |
| * Puts all <code>Text</code> nodes in the full depth of the sub-tree |
| * underneath this <code>Node</code>, including attribute nodes, into a |
| * "normal" form where only structure (e.g., elements, comments, |
| * processing instructions, CDATA sections, and entity references) |
| * separates <code>Text</code> nodes, i.e., there are neither adjacent |
| * <code>Text</code> nodes nor empty <code>Text</code> nodes. This can |
| * be used to ensure that the DOM view of a document is the same as if |
| * it were saved and re-loaded, and is useful when operations (such as |
| * XPointer lookups) that depend on a particular document tree |
| * structure are to be used.In cases where the document contains |
| * <code>CDATASections</code>, the normalize operation alone may not be |
| * sufficient, since XPointers do not differentiate between |
| * <code>Text</code> nodes and <code>CDATASection</code> nodes. |
| */ |
| public void normalize() { |
| //TODO: Fix this for SAAJ 1.2 Implementation |
| } |
| |
| /** |
| * Returns whether this node (if it is an element) has any attributes. |
| * |
| * @return <code>true</code> if this node has any attributes, |
| * <code>false</code> otherwise. |
| * @since DOM Level 2 |
| */ |
| public boolean hasAttributes() { |
| return attributes.getLength() > 0; |
| } |
| |
| /** |
| * Returns whether this node has any children. |
| * |
| * @return <code>true</code> if this node has any children, |
| * <code>false</code> otherwise. |
| */ |
| public boolean hasChildNodes() { |
| return (children != null && !children.isEmpty()); |
| } |
| |
| /** |
| * Returns the local part of the qualified name of this node. |
| * <br>For nodes of any type other than <code>ELEMENT_NODE</code> and |
| * <code>ATTRIBUTE_NODE</code> and nodes created with a DOM Level 1 |
| * method, such as <code>createElement</code> from the |
| * <code>Document</code> interface, this is always <code>null</code>. |
| * |
| * @since DOM Level 2 |
| */ |
| public String getLocalName() { |
| return name; |
| } |
| |
| /** |
| * The namespace URI of this node, or <code>null</code> if it is |
| * unspecified. |
| * <br>This is not a computed value that is the result of a namespace |
| * lookup based on an examination of the namespace declarations in |
| * scope. It is merely the namespace URI given at creation time. |
| * <br>For nodes of any type other than <code>ELEMENT_NODE</code> and |
| * <code>ATTRIBUTE_NODE</code> and nodes created with a DOM Level 1 |
| * method, such as <code>createElement</code> from the |
| * <code>Document</code> interface, this is always <code>null</code>.Per |
| * the Namespaces in XML Specification an attribute does not inherit |
| * its namespace from the element it is attached to. If an attribute is |
| * not explicitly given a namespace, it simply has no namespace. |
| * |
| * @since DOM Level 2 |
| */ |
| public String getNamespaceURI() { |
| return (namespaceURI); |
| } |
| |
| /** |
| * The name of this node, depending on its type; see the table above. |
| */ |
| public String getNodeName() { |
| return (prefix != null && prefix.length() > 0) ? |
| prefix + ":" + name : name; |
| } |
| |
| /** |
| * The value of this node, depending on its type; see the table above. |
| * When it is defined to be <code>null</code>, setting it has no effect. |
| * |
| * @throws org.w3c.dom.DOMException NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly. |
| * @throws org.w3c.dom.DOMException DOMSTRING_SIZE_ERR: Raised when it would return more characters than |
| * fit in a <code>DOMString</code> variable on the implementation |
| * platform. |
| */ |
| public String getNodeValue() throws DOMException { |
| if (textRep == null) { |
| return null; |
| } else { |
| return textRep.getData(); |
| } |
| } |
| |
| /** |
| * The namespace prefix of this node, or <code>null</code> if it is |
| * unspecified. |
| * <br>Note that setting this attribute, when permitted, changes the |
| * <code>nodeName</code> attribute, which holds the qualified name, as |
| * well as the <code>tagName</code> and <code>name</code> attributes of |
| * the <code>Element</code> and <code>Attr</code> interfaces, when |
| * applicable. |
| * <br>Note also that changing the prefix of an attribute that is known to |
| * have a default value, does not make a new attribute with the default |
| * value and the original prefix appear, since the |
| * <code>namespaceURI</code> and <code>localName</code> do not change. |
| * <br>For nodes of any type other than <code>ELEMENT_NODE</code> and |
| * <code>ATTRIBUTE_NODE</code> and nodes created with a DOM Level 1 |
| * method, such as <code>createElement</code> from the |
| * <code>Document</code> interface, this is always <code>null</code>. |
| * |
| * @throws org.w3c.dom.DOMException INVALID_CHARACTER_ERR: Raised if the specified prefix contains an |
| * illegal character, per the XML 1.0 specification . |
| * <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. |
| * <br>NAMESPACE_ERR: Raised if the specified <code>prefix</code> is |
| * malformed per the Namespaces in XML specification, if the |
| * <code>namespaceURI</code> of this node is <code>null</code>, if the |
| * specified prefix is "xml" and the <code>namespaceURI</code> of this |
| * node is different from "http://www.w3.org/XML/1998/namespace", if |
| * this node is an attribute and the specified prefix is "xmlns" and |
| * the <code>namespaceURI</code> of this node is different from " |
| * http://www.w3.org/2000/xmlns/", or if this node is an attribute and |
| * the <code>qualifiedName</code> of this node is "xmlns" . |
| * @since DOM Level 2 |
| */ |
| public String getPrefix() { |
| return (prefix); |
| } |
| |
| /** |
| * The value of this node, depending on its type; see the table above. |
| * When it is defined to be <code>null</code>, setting it has no effect. |
| * |
| * @throws org.w3c.dom.DOMException NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly. |
| * @throws org.w3c.dom.DOMException DOMSTRING_SIZE_ERR: Raised when it would return more characters than |
| * fit in a <code>DOMString</code> variable on the implementation |
| * platform. |
| */ |
| public void setNodeValue(String nodeValue) throws DOMException { |
| throw new DOMException(DOMException.NO_DATA_ALLOWED_ERR, |
| "Cannot use TextNode.set in " + this); |
| } |
| |
| /** |
| * The namespace prefix of this node, or <code>null</code> if it is |
| * unspecified. |
| * <br>Note that setting this attribute, when permitted, changes the |
| * <code>nodeName</code> attribute, which holds the qualified name, as |
| * well as the <code>tagName</code> and <code>name</code> attributes of |
| * the <code>Element</code> and <code>Attr</code> interfaces, when |
| * applicable. |
| * <br>Note also that changing the prefix of an attribute that is known to |
| * have a default value, does not make a new attribute with the default |
| * value and the original prefix appear, since the |
| * <code>namespaceURI</code> and <code>localName</code> do not change. |
| * <br>For nodes of any type other than <code>ELEMENT_NODE</code> and |
| * <code>ATTRIBUTE_NODE</code> and nodes created with a DOM Level 1 |
| * method, such as <code>createElement</code> from the |
| * <code>Document</code> interface, this is always <code>null</code>. |
| * |
| * @throws org.w3c.dom.DOMException INVALID_CHARACTER_ERR: Raised if the specified prefix contains an |
| * illegal character, per the XML 1.0 specification . |
| * <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. |
| * <br>NAMESPACE_ERR: Raised if the specified <code>prefix</code> is |
| * malformed per the Namespaces in XML specification, if the |
| * <code>namespaceURI</code> of this node is <code>null</code>, if the |
| * specified prefix is "xml" and the <code>namespaceURI</code> of this |
| * node is different from "http://www.w3.org/XML/1998/namespace", if |
| * this node is an attribute and the specified prefix is "xmlns" and |
| * the <code>namespaceURI</code> of this node is different from " |
| * http://www.w3.org/2000/xmlns/", or if this node is an attribute and |
| * the <code>qualifiedName</code> of this node is "xmlns" . |
| * @since DOM Level 2 |
| */ |
| public void setPrefix(String prefix) { |
| this.prefix = prefix; |
| } |
| |
| /** |
| * Set the owner document |
| * |
| * @param doc |
| */ |
| public void setOwnerDocument(Document doc) { |
| document = doc; |
| } |
| |
| /** |
| * The <code>Document</code> object associated with this node. This is |
| * also the <code>Document</code> object used to create new nodes. When |
| * this node is a <code>Document</code> or a <code>DocumentType</code> |
| * which is not used with any <code>Document</code> yet, this is |
| * <code>null</code>. |
| */ |
| public Document getOwnerDocument() { |
| if(document == null) { |
| NodeImpl node = getParent(); |
| if (node != null) { |
| return node.getOwnerDocument(); |
| } |
| } |
| return document; |
| } |
| |
| /** |
| * A <code>NamedNodeMap</code> containing the attributes of this node (if |
| * it is an <code>Element</code>) or <code>null</code> otherwise. |
| */ |
| public NamedNodeMap getAttributes() { |
| // make first it is editable. |
| makeAttributesEditable(); |
| return convertAttrSAXtoDOM(attributes); |
| } |
| |
| /** |
| * The first child of this node. If there is no such node, this returns |
| * <code>null</code>. |
| */ |
| public Node getFirstChild() { |
| if (children != null && !children.isEmpty()) { |
| return (Node) children.get(0); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * The last child of this node. If there is no such node, this returns |
| * <code>null</code>. |
| */ |
| public Node getLastChild() { |
| if (children != null && !children.isEmpty()) { |
| return (Node) children.get(children.size() - 1); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * The node immediately following this node. If there is no such node, |
| * this returns <code>null</code>. |
| */ |
| public Node getNextSibling() { |
| SOAPElement parent = getParentElement(); |
| if (parent == null) { |
| return null; |
| } |
| Iterator iter = parent.getChildElements(); |
| Node nextSibling = null; |
| while (iter.hasNext()) { |
| if (iter.next() == this) { |
| if (iter.hasNext()) { |
| return (Node) iter.next(); |
| } else { |
| return null; |
| } |
| } |
| } |
| return nextSibling; // should be null. |
| } |
| |
| /** |
| * The parent of this node. All nodes, except <code>Attr</code>, |
| * <code>Document</code>, <code>DocumentFragment</code>, |
| * <code>Entity</code>, and <code>Notation</code> may have a parent. |
| * However, if a node has just been created and not yet added to the |
| * tree, or if it has been removed from the tree, this is |
| * <code>null</code>. |
| */ |
| public Node getParentNode() { |
| return (Node) getParent(); |
| } |
| |
| /** |
| * The node immediately preceding this node. If there is no such node, |
| * this returns <code>null</code>. |
| */ |
| public Node getPreviousSibling() { |
| SOAPElement parent = getParentElement(); |
| if (parent == null) { |
| return null; |
| } |
| NodeList nl = parent.getChildNodes(); |
| int len = nl.getLength(); |
| int i = 0; |
| Node previousSibling = null; |
| while (i < len) { |
| if (nl.item(i) == this) { |
| return previousSibling; |
| } |
| previousSibling = nl.item(i); |
| i++; |
| } |
| return previousSibling; // should be null. |
| } |
| |
| /** |
| * Returns a duplicate of this node, i.e., serves as a generic copy |
| * constructor for nodes. The duplicate node has no parent; ( |
| * <code>parentNode</code> is <code>null</code>.). |
| * <br>Cloning an <code>Element</code> copies all attributes and their |
| * values, including those generated by the XML processor to represent |
| * defaulted attributes, but this method does not copy any text it |
| * contains unless it is a deep clone, since the text is contained in a |
| * child <code>Text</code> node. Cloning an <code>Attribute</code> |
| * directly, as opposed to be cloned as part of an <code>Element</code> |
| * cloning operation, returns a specified attribute ( |
| * <code>specified</code> is <code>true</code>). Cloning any other type |
| * of node simply returns a copy of this node. |
| * <br>Note that cloning an immutable subtree results in a mutable copy, |
| * but the children of an <code>EntityReference</code> clone are readonly |
| * . In addition, clones of unspecified <code>Attr</code> nodes are |
| * specified. And, cloning <code>Document</code>, |
| * <code>DocumentType</code>, <code>Entity</code>, and |
| * <code>Notation</code> nodes is implementation dependent. |
| * |
| * @param deep If <code>true</code>, recursively clone the subtree under |
| * the specified node; if <code>false</code>, clone only the node |
| * itself (and its attributes, if it is an <code>Element</code>). |
| * @return The duplicate node. |
| */ |
| public Node cloneNode(boolean deep) { |
| return new NodeImpl(textRep); |
| } |
| |
| /** |
| * A <code>NodeList</code> that contains all children of this node. If |
| * there are no children, this is a <code>NodeList</code> containing no |
| * nodes. |
| */ |
| public NodeList getChildNodes() { |
| if (children == null) { |
| return NodeListImpl.EMPTY_NODELIST; |
| } else { |
| return new NodeListImpl(children); |
| } |
| } |
| |
| /** |
| * Tests whether the DOM implementation implements a specific feature and |
| * that feature is supported by this node. |
| * |
| * @param feature The name of the feature to test. This is the same name |
| * which can be passed to the method <code>hasFeature</code> on |
| * <code>DOMImplementation</code>. |
| * @param version This is the version number of the feature to test. In |
| * Level 2, version 1, this is the string "2.0". If the version is not |
| * specified, supporting any version of the feature will cause the |
| * method to return <code>true</code>. |
| * @return Returns <code>true</code> if the specified feature is |
| * supported on this node, <code>false</code> otherwise. |
| * @since DOM Level 2 |
| */ |
| public boolean isSupported(String feature, String version) { |
| return false; //TODO: Fix this for SAAJ 1.2 Implementation |
| } |
| |
| /** |
| * Adds the node <code>newChild</code> to the end of the list of children |
| * of this node. If the <code>newChild</code> is already in the tree, it |
| * is first removed. |
| * |
| * @param newChild The node to add.If it is a |
| * <code>DocumentFragment</code> object, the entire contents of the |
| * document fragment are moved into the child list of this node |
| * @return The node added. |
| * @throws org.w3c.dom.DOMException HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not |
| * allow children of the type of the <code>newChild</code> node, or if |
| * the node to append is one of this node's ancestors or this node |
| * itself. |
| * <br>WRONG_DOCUMENT_ERR: Raised if <code>newChild</code> was created |
| * from a different document than the one that created this node. |
| * <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly or |
| * if the previous parent of the node being inserted is readonly. |
| * |
| */ |
| public Node appendChild(Node newChild) throws DOMException { |
| if (newChild == null) { |
| throw new DOMException |
| (DOMException.HIERARCHY_REQUEST_ERR, |
| "Can't append a null node."); |
| } |
| initializeChildren(); |
| // per DOM spec - must remove from tree. If newChild.parent == null, |
| // detachNode() does nothing. So this shouldn't hurt performace of |
| // serializers. |
| ((NodeImpl) newChild).detachNode(); |
| children.add(newChild); |
| ((NodeImpl) newChild).parent = this; |
| setDirty(true); |
| return newChild; |
| } |
| |
| /** |
| * Removes the child node indicated by <code>oldChild</code> from the list |
| * of children, and returns it. |
| * |
| * @param oldChild The node being removed. |
| * @return The node removed. |
| * @throws org.w3c.dom.DOMException NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. |
| * <br>NOT_FOUND_ERR: Raised if <code>oldChild</code> is not a child of |
| * this node. |
| */ |
| public Node removeChild(Node oldChild) throws DOMException { |
| if (removeNodeFromChildList((NodeImpl) oldChild)) { |
| setDirty(true); |
| return oldChild; |
| } |
| throw new DOMException(DOMException.NOT_FOUND_ERR, |
| "NodeImpl Not found"); |
| } |
| |
| private boolean removeNodeFromChildList(NodeImpl n) { |
| boolean removed = false; |
| initializeChildren(); |
| final Iterator itr = children.iterator(); |
| while (itr.hasNext()) { |
| final NodeImpl node = (NodeImpl) itr.next(); |
| if (node == n) { |
| removed = true; |
| itr.remove(); |
| } |
| } |
| return removed; |
| } |
| |
| /** |
| * Inserts the node <code>newChild</code> before the existing child node |
| * <code>refChild</code>. If <code>refChild</code> is <code>null</code>, |
| * insert <code>newChild</code> at the end of the list of children. |
| * <br>If <code>newChild</code> is a <code>DocumentFragment</code> object, |
| * all of its children are inserted, in the same order, before |
| * <code>refChild</code>. If the <code>newChild</code> is already in the |
| * tree, it is first removed. |
| * |
| * @param newChild The node to insert. |
| * @param refChild The reference node, i.e., the node before which the |
| * new node must be inserted. |
| * @return The node being inserted. |
| * @throws org.w3c.dom.DOMException HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not |
| * allow children of the type of the <code>newChild</code> node, or if |
| * the node to insert is one of this node's ancestors or this node |
| * itself. |
| * <br>WRONG_DOCUMENT_ERR: Raised if <code>newChild</code> was created |
| * from a different document than the one that created this node. |
| * <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly or |
| * if the parent of the node being inserted is readonly. |
| * <br>NOT_FOUND_ERR: Raised if <code>refChild</code> is not a child of |
| * this node. |
| */ |
| public Node insertBefore(Node newChild, Node refChild) throws DOMException { |
| initializeChildren(); |
| int position = children.indexOf(refChild); |
| if (position < 0) { |
| position = 0; |
| } |
| children.add(position, newChild); |
| setDirty(true); |
| return newChild; |
| } |
| |
| /** |
| * Replaces the child node <code>oldChild</code> with <code>newChild</code> |
| * in the list of children, and returns the <code>oldChild</code> node. |
| * <br>If <code>newChild</code> is a <code>DocumentFragment</code> object, |
| * <code>oldChild</code> is replaced by all of the |
| * <code>DocumentFragment</code> children, which are inserted in the |
| * same order. If the <code>newChild</code> is already in the tree, it |
| * is first removed. |
| * |
| * @param newChild The new node to put in the child list. |
| * @param oldChild The node being replaced in the list. |
| * @return The node replaced. |
| * @throws org.w3c.dom.DOMException HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not |
| * allow children of the type of the <code>newChild</code> node, or if |
| * the node to put in is one of this node's ancestors or this node |
| * itself. |
| * <br>WRONG_DOCUMENT_ERR: Raised if <code>newChild</code> was created |
| * from a different document than the one that created this node. |
| * <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node or the parent of |
| * the new node is readonly. |
| * <br>NOT_FOUND_ERR: Raised if <code>oldChild</code> is not a child of |
| * this node. |
| */ |
| public Node replaceChild(Node newChild, Node oldChild) throws DOMException { |
| initializeChildren(); |
| int position = children.indexOf(oldChild); |
| if (position < 0) { |
| throw new DOMException(DOMException.NOT_FOUND_ERR, |
| "NodeImpl Not found"); |
| } |
| children.remove(position); |
| children.add(position, newChild); |
| setDirty(true); |
| return oldChild; |
| } |
| |
| /** |
| * Returns the the value of the immediate child of this <code>Node</code> |
| * object if a child exists and its value is text. |
| * |
| * @return a <code>String</code> with the text of the immediate child of |
| * this <code>Node</code> object if (1) there is a child and |
| * (2) the child is a <code>Text</code> object; |
| * <code>null</code> otherwise |
| */ |
| public String getValue() { |
| return textRep.getNodeValue(); |
| } |
| |
| /** |
| * Sets the parent of this <code>Node</code> object to the given |
| * <code>SOAPElement</code> object. |
| * |
| * @param parent the <code>SOAPElement</code> object to be set as |
| * the parent of this <code>Node</code> object |
| * @throws javax.xml.soap.SOAPException if there is a problem in setting the |
| * parent to the given element |
| * @see #getParentElement() getParentElement() |
| */ |
| public void setParentElement(SOAPElement parent) throws SOAPException { |
| if (parent == null) |
| throw new IllegalArgumentException( |
| Messages.getMessage("nullParent00")); |
| try { |
| setParent((NodeImpl) parent); |
| } catch (Throwable t) { |
| throw new SOAPException(t); |
| } |
| } |
| |
| /** |
| * Returns the parent element of this <code>Node</code> object. |
| * This method can throw an <code>UnsupportedOperationException</code> |
| * if the tree is not kept in memory. |
| * |
| * @return the <code>SOAPElement</code> object that is the parent of |
| * this <code>Node</code> object or <code>null</code> if this |
| * <code>Node</code> object is root |
| * @throws UnsupportedOperationException if the whole tree is not kept in memory |
| * @see #setParentElement(javax.xml.soap.SOAPElement) setParentElement(javax.xml.soap.SOAPElement) |
| */ |
| public SOAPElement getParentElement() { |
| return (SOAPElement) getParent(); |
| } |
| |
| /** |
| * Removes this <code>Node</code> object from the tree. Once |
| * removed, this node can be garbage collected if there are no |
| * application references to it. |
| */ |
| public void detachNode() { |
| if (parent != null) { |
| parent.removeChild(this); |
| parent = null; |
| } |
| } |
| |
| /** |
| * Notifies the implementation that this <code>Node</code> |
| * object is no longer being used by the application and that the |
| * implementation is free to reuse this object for nodes that may |
| * be created later. |
| * <P> |
| * Calling the method <code>recycleNode</code> implies that the method |
| * <code>detachNode</code> has been called previously. |
| */ |
| public void recycleNode() { |
| //TODO: Fix this for SAAJ 1.2 Implementation |
| } |
| |
| /** |
| * If this is a Text node then this method will set its value, otherwise it |
| * sets the value of the immediate (Text) child of this node. The value of |
| * the immediate child of this node can be set only if, there is one child |
| * node and that node is a Text node, or if there are no children in which |
| * case a child Text node will be created. |
| * |
| * @param value the text to set |
| * @throws IllegalStateException if the node is not a Text node and |
| * either has more than one child node or has a child node that |
| * is not a Text node |
| */ |
| public void setValue(String value) { |
| if (this instanceof org.apache.axis.message.Text) { |
| setNodeValue(value); |
| } else if (children != null) { |
| if (children.size() != 1) { |
| throw new IllegalStateException( "setValue() may not be called on a non-Text node with more than one child." ); |
| } |
| javax.xml.soap.Node child = (javax.xml.soap.Node) children.get(0); |
| if (!(child instanceof org.apache.axis.message.Text)) { |
| throw new IllegalStateException( "setValue() may not be called on a non-Text node with a non-Text child." ); |
| } |
| ((javax.xml.soap.Text)child).setNodeValue(value); |
| } else { |
| appendChild(new org.apache.axis.message.Text(value)); |
| } |
| } |
| |
| /** |
| * make the attributes editable |
| * |
| * @return AttributesImpl |
| */ |
| protected AttributesImpl makeAttributesEditable() { |
| if (attributes == null || attributes instanceof NullAttributes) { |
| attributes = new AttributesImpl(); |
| } else if (!(attributes instanceof AttributesImpl)) { |
| attributes = new AttributesImpl(attributes); |
| } |
| return (AttributesImpl) attributes; |
| } |
| |
| /** |
| * The internal representation of Attributes cannot help being changed |
| * It is because Attribute is not immutible Type, so if we keep out value and |
| * just return it in another form, the application may chnae it, which we cannot |
| * detect without some kind back track method (call back notifying the chnage.) |
| * I am not sure which approach is better. |
| */ |
| protected NamedNodeMap convertAttrSAXtoDOM(Attributes saxAttr) { |
| try { |
| org.w3c.dom.Document doc = org.apache.axis.utils.XMLUtils.newDocument(); |
| AttributesImpl saxAttrs = (AttributesImpl) saxAttr; |
| NamedNodeMap domAttributes = new NamedNodeMapImpl(); |
| for (int i = 0; i < saxAttrs.getLength(); i++) { |
| String uri = saxAttrs.getURI(i); |
| String qname = saxAttrs.getQName(i); |
| String value = saxAttrs.getValue(i); |
| if (uri != null && uri.trim().length() > 0) { |
| // filterring out the tricky method to differentiate the null namespace |
| // -ware case |
| if (NULL_URI_NAME.equals(uri)) { |
| uri = null; |
| } |
| Attr attr = doc.createAttributeNS(uri, qname); |
| attr.setValue(value); |
| domAttributes.setNamedItemNS(attr); |
| } else { |
| Attr attr = doc.createAttribute(qname); |
| attr.setValue(value); |
| domAttributes.setNamedItem(attr); |
| } |
| } |
| return domAttributes; |
| } catch (Exception ex) { |
| log.error(Messages.getMessage("saxToDomFailed00"),ex); |
| |
| return null; |
| } |
| } |
| |
| /** |
| * Initialize the children array |
| */ |
| protected void initializeChildren() { |
| if (children == null) { |
| children = new ArrayList(); |
| } |
| } |
| |
| /** |
| * get the parent node |
| * @return parent node |
| */ |
| protected NodeImpl getParent() { |
| return parent; |
| } |
| |
| /** |
| * Set the parent node and invoke appendChild(this) to |
| * add this node to the parent's list of children. |
| * @param parent |
| * @throws SOAPException |
| */ |
| protected void setParent(NodeImpl parent) throws SOAPException { |
| if (this.parent == parent) { |
| return; |
| } |
| if (this.parent != null) { |
| this.parent.removeChild(this); |
| } |
| if (parent != null) { |
| parent.appendChild(this); |
| } |
| this.parent = parent; |
| } |
| |
| /** |
| * print the contents of this node |
| * @param context |
| * @throws Exception |
| */ |
| public void output(SerializationContext context) throws Exception { |
| if (textRep == null) |
| return; |
| boolean oldPretty = context.getPretty(); |
| context.setPretty(false); |
| if (textRep instanceof CDATASection) { |
| context.writeString("<![CDATA["); |
| context.writeString(((org.w3c.dom.Text) textRep).getData()); |
| context.writeString("]]>"); |
| } else if (textRep instanceof Comment) { |
| context.writeString("<!--"); |
| context.writeString(((CharacterData) textRep).getData()); |
| context.writeString("-->"); |
| } else if (textRep instanceof Text) { |
| context.writeSafeString(((Text) textRep).getData()); |
| } |
| context.setPretty(oldPretty); |
| } |
| |
| /** |
| * get the dirty bit |
| * @return |
| */ |
| public boolean isDirty() { |
| return _isDirty; |
| } |
| |
| /** |
| * set the dirty bit. will also set our parent as dirty, if there is one. |
| * Note that clearing the dirty bit does <i>not</i> propagate upwards. |
| * @param dirty new value of the dirty bit |
| */ |
| public void setDirty(boolean dirty) |
| { |
| _isDirty = dirty; |
| if (_isDirty && parent != null) { |
| ((NodeImpl) parent).setDirty(true); |
| } |
| } |
| } |