blob: 5047b9435e4a650b64e21fb30ad8cdd1743e0200 [file] [log] [blame]
/*
* Copyright 2004,2005 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.axiom.om.impl.dom;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMException;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNode;
import org.apache.axiom.om.impl.OMContainerEx;
import org.apache.axiom.om.impl.OMNodeEx;
import org.apache.axiom.om.impl.traverse.OMChildrenIterator;
import org.apache.axiom.om.impl.traverse.OMChildrenQNameIterator;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.namespace.QName;
import java.util.Iterator;
public abstract class ParentNode extends ChildNode implements OMContainerEx {
protected ChildNode firstChild;
protected ChildNode lastChild;
/**
* @param ownerDocument
*/
protected ParentNode(DocumentImpl ownerDocument, OMFactory factory) {
super(ownerDocument, factory);
}
protected ParentNode(OMFactory factory) {
super(factory);
}
// /
// /OMContainer methods
// /
public void addChild(OMNode omNode) {
this.appendChild((Node) omNode);
}
public void buildNext() {
if (!this.done)
builder.next();
}
public Iterator getChildren() {
return new OMChildrenIterator(this.firstChild);
}
/**
* Returns an iterator of child nodes having a given qname.
*
* @see org.apache.axiom.om.OMContainer#getChildrenWithName
* (javax.xml.namespace.QName)
*/
public Iterator getChildrenWithName(QName elementQName) throws OMException {
return new OMChildrenQNameIterator(getFirstOMChild(), elementQName);
}
/**
* Returns the first OMElement child node.
*
* @see org.apache.axiom.om.OMContainer#getFirstChildWithName
* (javax.xml.namespace.QName)
*/
public OMElement getFirstChildWithName(QName elementQName)
throws OMException {
Iterator children = new OMChildrenQNameIterator(getFirstOMChild(),
elementQName);
while (children.hasNext()) {
OMNode node = (OMNode) children.next();
// Return the first OMElement node that is found
if (node instanceof OMElement) {
return (OMElement) node;
}
}
return null;
}
public OMNode getFirstOMChild() {
while ((firstChild == null) && !done) {
buildNext();
}
return firstChild;
}
public void setFirstChild(OMNode omNode) {
if (firstChild != null) {
((OMNodeEx) omNode).setParent(this);
}
this.firstChild = (ChildNode) omNode;
}
// /
// /DOM Node methods
// /
public NodeList getChildNodes() {
if (!this.done) {
this.build();
}
return new NodeListImpl(this, null, null);
}
public Node getFirstChild() {
return (Node) this.getFirstOMChild();
}
public Node getLastChild() {
if (!this.done) {
this.build();
}
return this.lastChild;
}
public boolean hasChildNodes() {
while ((firstChild == null) && !done) {
buildNext();
}
return this.firstChild != null;
}
/**
* Inserts newChild before the refChild. If the refChild is null then the
* newChild is made the last child.
*/
public Node insertBefore(Node newChild, Node refChild) throws DOMException {
ChildNode newDomChild = (ChildNode) newChild;
ChildNode refDomChild = (ChildNode) refChild;
if (this == newChild || !isAncestor(newChild)) {
throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
DOMMessageFormatter.formatMessage(
DOMMessageFormatter.DOM_DOMAIN,
"HIERARCHY_REQUEST_ERR", null));
}
if (!(this instanceof Document)
&& !(this.ownerNode == newDomChild.getOwnerDocument())) {
throw new DOMException(DOMException.WRONG_DOCUMENT_ERR,
DOMMessageFormatter.formatMessage(
DOMMessageFormatter.DOM_DOMAIN,
"WRONG_DOCUMENT_ERR", null));
}
if (this.isReadonly()) {
throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
DOMMessageFormatter.formatMessage(
DOMMessageFormatter.DOM_DOMAIN,
"NO_MODIFICATION_ALLOWED_ERR", null));
}
if (this instanceof Document) {
if (((DocumentImpl) this).documentElement != null
&& !(newDomChild instanceof CommentImpl)) {
// Throw exception since there cannot be two document elements
throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
DOMMessageFormatter.formatMessage(
DOMMessageFormatter.DOM_DOMAIN,
"HIERARCHY_REQUEST_ERR", null));
} else if (newDomChild instanceof ElementImpl) {
if (newDomChild.parentNode == null) {
newDomChild.parentNode = this;
}
// set the document element
((DocumentImpl) this).documentElement = (ElementImpl) newDomChild;
}
}
if (refChild == null) { // Append the child to the end of the list
// if there are no children
if (this.lastChild == null && firstChild == null) {
this.lastChild = newDomChild;
this.firstChild = newDomChild;
this.firstChild.isFirstChild(true);
newDomChild.setParent(this);
} else {
this.lastChild.nextSibling = newDomChild;
newDomChild.previousSibling = this.lastChild;
this.lastChild = newDomChild;
this.lastChild.nextSibling = null;
}
if (newDomChild.parentNode == null) {
newDomChild.parentNode = this;
}
return newChild;
} else {
Iterator children = this.getChildren();
boolean found = false;
while (children.hasNext()) {
ChildNode tempNode = (ChildNode) children.next();
if (tempNode.equals(refChild)) {
// RefChild found
if (this.firstChild == tempNode) { // If the refChild is the
// first child
if (newChild instanceof DocumentFragmentimpl) {
// The new child is a DocumentFragment
DocumentFragmentimpl docFrag =
(DocumentFragmentimpl) newChild;
this.firstChild = docFrag.firstChild;
docFrag.lastChild.nextSibling = refDomChild;
refDomChild.previousSibling =
docFrag.lastChild.nextSibling;
} else {
// Make the newNode the first Child
this.firstChild = newDomChild;
newDomChild.nextSibling = refDomChild;
refDomChild.previousSibling = newDomChild;
this.firstChild.isFirstChild(true);
refDomChild.isFirstChild(false);
newDomChild.previousSibling = null; // Just to be
// sure :-)
}
} else { // If the refChild is not the fist child
ChildNode previousNode = refDomChild.previousSibling;
if (newChild instanceof DocumentFragmentimpl) {
// the newChild is a document fragment
DocumentFragmentimpl docFrag =
(DocumentFragmentimpl) newChild;
previousNode.nextSibling = docFrag.firstChild;
docFrag.firstChild.previousSibling = previousNode;
docFrag.lastChild.nextSibling = refDomChild;
refDomChild.previousSibling = docFrag.lastChild;
} else {
previousNode.nextSibling = newDomChild;
newDomChild.previousSibling = previousNode;
newDomChild.nextSibling = refDomChild;
refDomChild.previousSibling = newDomChild;
}
}
found = true;
break;
}
}
if (!found) {
throw new DOMException(DOMException.NOT_FOUND_ERR,
DOMMessageFormatter.formatMessage(
DOMMessageFormatter.DOM_DOMAIN,
"NOT_FOUND_ERR", null));
}
if (newDomChild.parentNode == null) {
newDomChild.parentNode = this;
}
return newChild;
}
}
/**
* Replaces the oldChild with the newChild.
*/
public Node replaceChild(Node newChild, Node oldChild) throws DOMException {
ChildNode newDomChild = (ChildNode) newChild;
ChildNode oldDomChild = (ChildNode) oldChild;
if (this == newChild || !isAncestor(newChild)) {
throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
DOMMessageFormatter.formatMessage(
DOMMessageFormatter.DOM_DOMAIN,
"HIERARCHY_REQUEST_ERR", null));
}
if (!this.ownerNode.equals(newDomChild.ownerNode)) {
throw new DOMException(DOMException.WRONG_DOCUMENT_ERR,
DOMMessageFormatter.formatMessage(
DOMMessageFormatter.DOM_DOMAIN,
"WRONG_DOCUMENT_ERR", null));
}
if (this.isReadonly()) {
throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
DOMMessageFormatter.formatMessage(
DOMMessageFormatter.DOM_DOMAIN,
"NO_MODIFICATION_ALLOWED_ERR", null));
}
Iterator children = this.getChildren();
boolean found = false;
while (children.hasNext()) {
ChildNode tempNode = (ChildNode) children.next();
if (tempNode.equals(oldChild)) {
if (newChild instanceof DocumentFragmentimpl) {
DocumentFragmentimpl docFrag =
(DocumentFragmentimpl) newDomChild;
ChildNode child = (ChildNode) docFrag.getFirstChild();
child.parentNode = this;
this.replaceChild(child, oldChild);
} else {
if (this.firstChild == oldDomChild) {
newDomChild.parentNode = this;
if(this.firstChild.nextSibling != null) {
this.firstChild.nextSibling.previousSibling = newDomChild;
newDomChild.nextSibling = this.firstChild.nextSibling;
}
//Cleanup the current first child
this.firstChild.parentNode = null;
this.firstChild.nextSibling = null;
//Set the new first child
this.firstChild = newDomChild;
} else {
newDomChild.nextSibling = oldDomChild.nextSibling;
newDomChild.previousSibling = oldDomChild.previousSibling;
oldDomChild.previousSibling.nextSibling = newDomChild;
// If the old child is not the last
if (oldDomChild.nextSibling != null) {
oldDomChild.nextSibling.previousSibling = newDomChild;
} else {
this.lastChild = newDomChild;
}
if (newDomChild.parentNode == null) {
newDomChild.parentNode = this;
}
}
}
found = true;
// remove the old child's references to this tree
oldDomChild.nextSibling = null;
oldDomChild.previousSibling = null;
oldDomChild.parentNode = null;
}
}
if (!found)
throw new DOMException(DOMException.NOT_FOUND_ERR,
DOMMessageFormatter.formatMessage(
DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR",
null));
return oldChild;
}
/**
* Removes the given child from the DOM Tree.
*/
public Node removeChild(Node oldChild) throws DOMException {
// Check if this node is readonly
if (this.isReadonly()) {
throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
DOMMessageFormatter.formatMessage(
DOMMessageFormatter.DOM_DOMAIN,
"NO_MODIFICATION_ALLOWED_ERR", null));
}
// Check if the Child is there
Iterator children = this.getChildren();
boolean childFound = false;
while (children.hasNext()) {
ChildNode tempNode = (ChildNode) children.next();
if (tempNode.equals(oldChild)) {
if (this.firstChild == tempNode) {
// If this is the first child
this.firstChild = null;
this.lastChild = null;
tempNode.parentNode = null;
} else if (this.lastChild == tempNode) {
// not the first child, but the last child
ChildNode prevSib = tempNode.previousSibling;
prevSib.nextSibling = null;
tempNode.parentNode = null;
tempNode.previousSibling = null;
} else {
ChildNode oldDomChild = (ChildNode) oldChild;
ChildNode privChild = oldDomChild.previousSibling;
privChild.nextSibling = oldDomChild.nextSibling;
oldDomChild.nextSibling.previousSibling = privChild;
// Remove old child's references to this tree
oldDomChild.nextSibling = null;
oldDomChild.previousSibling = null;
}
// Child found
childFound = true;
}
}
if (!childFound)
throw new DOMException(DOMException.NOT_FOUND_ERR,
DOMMessageFormatter.formatMessage(
DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR",
null));
return oldChild;
}
private boolean isAncestor(Node newNode) {
// TODO isAncestor
return true;
}
public Node cloneNode(boolean deep) {
ParentNode newnode = (ParentNode) super.cloneNode(deep);
// set owner document
newnode.ownerNode = ownerNode;
// Need to break the association w/ original kids
newnode.firstChild = null;
newnode.lastChild = null;
// Then, if deep, clone the kids too.
if (deep) {
for (ChildNode child = firstChild; child != null;
child = child.nextSibling) {
newnode.appendChild(child.cloneNode(true));
}
}
return newnode;
}
}