/*
* 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();
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();
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();
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();
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() {
setDirty();
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.setDirty();
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();
}
}
public void setDirty()
{
_isDirty = true;
if (parent != null) {
((NodeImpl) parent).setDirty();
}
}
/* clear dirty flag recursively */
public void reset() {
if (children != null) {
for (int i=0; i<children.size(); i++) {
((NodeImpl) children.get(i)).reset();
}
}
this._isDirty = false;
}
}
|