0001: /**
0002: * Changes for Persistent DOM running with ozone are
0003: * Copyright 1999 by SMB GmbH. All rights reserved.
0004: */package org.ozoneDB.xml.dom;
0005:
0006: import java.util.*;
0007: import java.io.*;
0008: import org.ozoneDB.*;
0009: import org.ozoneDB.xml.dom.iterator.*;
0010: import org.w3c.dom.*;
0011:
0012: public abstract class NodeImpl extends OzoneObject implements
0013: NodeProxy, Externalizable {
0014:
0015: final static long serialVersionUID = 1;
0016:
0017: // public Object invoke (String methodName, String sig, Object[] args)
0018: // throws Exception {
0019: // if (methodName.equals ("getNodeName")
0020: // return
0021: // }
0022:
0023: public boolean supports(java.lang.String feature,
0024: java.lang.String version) {
0025: throw new DOMExceptionImpl(DOMException.NOT_SUPPORTED_ERR,
0026: "Node.supports(): ozone's persistent DOM doesn't support DOM level 2 yet.");
0027: }
0028:
0029: public void normalize() {
0030: throw new DOMExceptionImpl(DOMException.NOT_SUPPORTED_ERR,
0031: "Node.normalize(): ozone's persistent DOM doesn't support DOM level 2 yet.");
0032: }
0033:
0034: public java.lang.String getNamespaceURI() {
0035: // FIXME:
0036: // throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
0037: // "Node.getNamespaceURI(): ozone's persistent DOM doesn't support DOM level 2 yet." );
0038: return null;
0039: }
0040:
0041: public java.lang.String getPrefix() {
0042: throw new DOMExceptionImpl(DOMException.NOT_SUPPORTED_ERR,
0043: "Node.getPrefix(): ozone's persistent DOM doesn't support DOM level 2 yet.");
0044: }
0045:
0046: public void setPrefix(java.lang.String prefix) throws DOMException {
0047: throw new DOMExceptionImpl(DOMException.NOT_SUPPORTED_ERR,
0048: "Node.setPrefix(): ozone's persistent DOM doesn't support DOM level 2 yet.");
0049: }
0050:
0051: public java.lang.String getLocalName() {
0052: throw new DOMExceptionImpl(DOMException.NOT_SUPPORTED_ERR,
0053: "Node.getLocalName(): ozone's persistent DOM doesn't support DOM level 2 yet.");
0054: }
0055:
0056: /**
0057: * Abstract method must be implemented by each node class.
0058: *
0059: * @see org.w3c.dom.Node#getNodeType
0060: */
0061: public abstract short getNodeType();
0062:
0063: /**
0064: * Returns the name of the node, set from the constructor. Some derived classes
0065: * do not have the notion of a name, and will return the same name each time.
0066: * They should do so by setting the default name (e.g. <TT>"#comment"</TT>)
0067: * in the constructor. This value is never null.
0068: *
0069: * @see org.w3c.dom.Node#getNodeName
0070: */
0071: public final String getNodeName() {
0072: return _nodeName;
0073: }
0074:
0075: /**
0076: */
0077: public final void setNodeName(String nodeName) {
0078: _nodeName = nodeName;
0079: }
0080:
0081: /**
0082: * Returns the value of the node. Depending on the node type, this value
0083: * is either the node value (e.g. the text in {@link org.w3c.dom.Text}),
0084: * or always null is node has no notion of a value (e.g. {@link
0085: * org.w3c.dom.Element}). For complete list of which node types will return
0086: * what, see {@link #setNodeValue}.
0087: *
0088: * @return Value of node, null if node has no value
0089: */
0090: public final String getNodeValue() {
0091: return _nodeValue;
0092: }
0093:
0094: /**
0095: * Changes the value of the node. Not all node types support the notion of
0096: * a value. If the value is not supported by a particular node type, it will
0097: * throw an exception when calling this method. The following table specifies
0098: * which node types support values:
0099: * <PRE>
0100: * Element Not supported
0101: * Attr Value supported
0102: * Text Value supported
0103: * CDATASection Value supported
0104: * EntityReference Not supported
0105: * Entity Not supported
0106: * ProcessingInstruction Value supported
0107: * Comment Value supported
0108: * Document Not supported
0109: * DocumentType Not supported
0110: * DocumentFragment Not supported
0111: * Notation Not supported
0112: * </PRE>
0113: * For most node types, if the value is set to null, {@link #getNodeValue}
0114: * will return an empty string instead.
0115: *
0116: * @param value New value of node
0117: * @throws org.w3c.dom.DOMExceptionImpl <TT>NO_MODIFICATION_ALLOWED_ERR</TT>
0118: * Node is read-only and cannot be modified
0119: * @throws org.w3c.dom.DOMExceptionImpl <TT>NO_DATA_ALLOWED_ERR</TT>
0120: * This node does not support a value
0121: */
0122: public void setNodeValue(String value) {
0123: if (isReadOnly()) {
0124: throw new DOMExceptionImpl(
0125: DOMException.NO_MODIFICATION_ALLOWED_ERR);
0126: }
0127: _nodeValue = value == null ? "" : value;
0128: }
0129:
0130: /**
0131: * Returns the parent node of this node. Node may not necessarily have a
0132: * parent node. If node has been created but not added to any other node,
0133: * it will be parentless. The {@link org.w3c.dom.Document} node is always
0134: * parentless.
0135: *
0136: * @return Parent node of this node
0137: */
0138: public Node getParentNode() {
0139: return _parent;
0140: }
0141:
0142: /**
0143: */
0144: public void setParentNode(Node newParent) {
0145: _parent = (NodeProxy) newParent;
0146: }
0147:
0148: /**
0149: * Called to notify all the iterators created from this node that a
0150: * child of this node has been removed. Iterators that point at this
0151: * child might choose to select another child to point to. This method
0152: * is called before the child is removed.
0153: * <P>
0154: * The removed node is a direct child of this node. Affected iterators
0155: * are those that point at the document tree directly below this node,
0156: * or the tree below one of its parents. Other iterators are not affected
0157: * by the change. This method also performs a notification on all the
0158: * parents of this node.
0159: *
0160: * @param removedChild The child node being removed
0161: */
0162: protected void notifyIterators(Node removedChild) {
0163: /*
0164: FIXME
0165: NodeProxy node;
0166: int i;
0167:
0168: node = this;
0169: while ( node != null ) {
0170: if ( node._iterators != null )
0171: for ( i = node._iterators.length ; i -- > 0 ; )
0172: ( (NodeIteratorListener) node._iterators[ i ] ).removeNode( removedChild );
0173: node = (NodeProxy) node.getParentNode();
0174: }
0175: */
0176: }
0177:
0178: /**
0179: * Returns a {@link org.w3c.dom.NodeList} object that can be used to traverse
0180: * this node's children. The node list is live, so every change to this node
0181: * is reflected in it.
0182: * <P>
0183: * If children are not supported by the derived class, an exception is thrown.
0184: *
0185: * @return {@link org.w3c.dom.NodeList} on this node
0186: * @throws org.w3c.dom.DOMException HIERARCHY_REQUEST_ERR Childern not supported
0187: * by this node type
0188: * @see org.w3c.dom.NodeList
0189: * @see NodeListImpl
0190: */
0191: public NodeList getChildNodes() {
0192: // Throw exception if children not supported by derived class.
0193: if (!supportsChildern()) {
0194: throw new DOMExceptionImpl(
0195: DOMException.HIERARCHY_REQUEST_ERR,
0196: "No childern supported by this node type.");
0197: }
0198: return (NodeList) new org.ozoneDB.xml.dom.NodeListImpl(this );
0199: }
0200:
0201: /**
0202: * Returns the first child of the node. If node has no children, returns null.
0203: *
0204: * @return First child or null
0205: */
0206: public final Node getFirstChild() {
0207: return _firstChild;
0208: }
0209:
0210: /**
0211: * Returns the last child of the node. If node has no children, returns null.
0212: *
0213: * @return Last child or null
0214: */
0215: public final Node getLastChild() {
0216: return _lastChild;
0217: }
0218:
0219: /**
0220: * Returns the previous sibling of this node. If node has no previous siblings,
0221: * returns null.
0222: *
0223: * @return Previous sibling or null
0224: */
0225: public Node getPreviousSibling() {
0226: return _prevNode;
0227: }
0228:
0229: /**
0230: */
0231: public void setPreviousSibling(Node prevNode) {
0232: _prevNode = (NodeProxy) prevNode;
0233: }
0234:
0235: /**
0236: * Returns the next sibling of this node. If node has no next siblings,
0237: * returns null.
0238: *
0239: * @return Next sibling or null
0240: */
0241: public Node getNextSibling() {
0242: return _nextNode;
0243: }
0244:
0245: /**
0246: */
0247: public void setNextSibling(Node nextNode) {
0248: _nextNode = (NodeProxy) nextNode;
0249: }
0250:
0251: /**
0252: * Return attributes of node. Returns null unless node is of type {@link
0253: * org.w3c.dom.Element}, in which case the returned {@link
0254: * org.w3c.dom.NamedNodeMap} will provide access to all the element's
0255: * attributes.
0256: *
0257: * @return Attributes of node or null
0258: */
0259: public NamedNodeMap getAttributes() {
0260: return null;
0261: }
0262:
0263: public boolean hasAttributes() {
0264: throw new DOMExceptionImpl(DOMException.NOT_SUPPORTED_ERR,
0265: "ozone's persistent DOM doesn't support DOM level 2 yet.");
0266: }
0267:
0268: public final Document getOwnerDocument() {
0269: if (_ownerDocument != this ) {
0270: return _ownerDocument;
0271: } else {
0272: return null;
0273: }
0274: }
0275:
0276: /**
0277: * Return true if there are any childern to this node. Less intensive than
0278: * calling {#link getChildNodes}.
0279: *
0280: * @return True if node has any children
0281: */
0282: public final boolean hasChildNodes() {
0283: return _firstChild != null;
0284: }
0285:
0286: /**
0287: * Insert <TT>newChild</TT> as the last child of this parent.
0288: * <P>
0289: * If <TT>newChild</TT> is null, <TT>newChild</TT> does not belong to this DOM,
0290: * or childern are not supported by this node type, an exception is thrown.
0291: * <P>
0292: * <TT>newChild</TT> is removed from its original parent before adding to this
0293: * parent. If <TT>newChild</TT> is a {@link org.w3c.dom.DocumentFragment}, all
0294: * its children are inserted one by one into this parent.
0295: *
0296: * @param newChild The new child to add
0297: * @return The newly inserted child
0298: * @throws org.w3c.dom.DOMException <TT>NO_MODIFICATION_ALLOWED_ERR</TT>
0299: * Node is read-only and cannot be modified
0300: * @throws org.w3c.dom.DOMException <TT>HIERARCHY_REQUEST_ERR</TT>
0301: * Children are not supported by this node type, or <TT>newChild</TT> is not
0302: * a compatible type for this node
0303: * @see #castNewChild
0304: * @see #castOldChild
0305: */
0306: public synchronized final Node appendChild(Node newChild) {
0307: // Node arguments must be casted to NodeEx in order to operate on them.
0308: NodeProxy newChildX;
0309:
0310: // Make sure the node is not read-only.
0311: // Throw exception if children not supported by derived class.
0312: if (isReadOnly()) {
0313: throw new DOMExceptionImpl(
0314: DOMException.NO_MODIFICATION_ALLOWED_ERR);
0315: }
0316: if (!supportsChildern()) {
0317: throw new DOMExceptionImpl(
0318: DOMException.HIERARCHY_REQUEST_ERR,
0319: "No childern supported by this node type.");
0320: }
0321:
0322: // Cast newChild to NodeImpl and make sure it can be inserted to this node.
0323: newChildX = (NodeProxy) castNewChild(newChild);
0324:
0325: // We're going to mess with this child node, so make sure no other thread
0326: // is touching it
0327: synchronized (newChild) {
0328: // If the newChild is already a child or some node, remove it first
0329: // before becoming child of this node. Make sure that parent is not
0330: // read-only.
0331: if (newChildX.getParentNode() != null) {
0332: if (((NodeProxy) newChildX.getParentNode())
0333: .isReadOnly()) {
0334: throw new DOMExceptionImpl(
0335: DOMException.NO_MODIFICATION_ALLOWED_ERR);
0336: }
0337: newChildX.getParentNode().removeChild(newChildX);
0338: }
0339:
0340: // Special case: newChild is a DocumentFragment and instead of adding
0341: // itself, all of its childs are added one by one.
0342: if (newChildX instanceof DocumentFragment) {
0343: NodeProxy nextChild;
0344:
0345: newChildX = (NodeProxy) newChildX.getFirstChild();
0346: while (newChildX != null) {
0347: nextChild = (NodeProxy) newChildX.getNextSibling();
0348: appendChild(newChildX);
0349: newChildX = nextChild;
0350: }
0351: return newChild;
0352: }
0353:
0354: // Node becomes child of this parent and part of this document.
0355: // Note that this code comes after the test for a DocumentFragment.
0356: // A fragment does not become part of this node, only its children.
0357: // The fragment becomes parent-less and child-less.
0358: // newChildX._parent = this;
0359: newChildX.setParentNode(this );
0360: if (_ownerDocument != null) {
0361: newChildX.setOwnerDocument(_ownerDocument);
0362: }
0363:
0364: // If the list has no end (it is empty) then newChild is added as the
0365: // only child in it.
0366: if (_lastChild == null) {
0367: _lastChild = newChildX;
0368: _firstChild = newChildX;
0369: newChildX.setPreviousSibling(null);
0370: newChildX.setNextSibling(null);
0371: } else {
0372: // newChild becomes the new end of the list, adjusting the previous
0373: // last child.
0374: _lastChild.setNextSibling(newChildX);
0375: newChildX.setPreviousSibling(_lastChild);
0376: newChildX.setNextSibling(null);
0377: _lastChild = newChildX;
0378: }
0379: // Keep this count accurate at all times.
0380: ++_childsCount;
0381: }
0382: return newChild;
0383: }
0384:
0385: /**
0386: * Remove <TT>oldChild</TT> from this parent. If <TT>oldChild</TT> is not
0387: * a direct child of this parent, or childern are not supported by this node
0388: * type, an exception is thrown.
0389: *
0390: * @param oldChild The child to remove
0391: * @return The removed child
0392: * @throws org.w3c.dom.DOMException <TT>NO_MODIFICATION_ALLOWED_ERR</TT>
0393: * Node is read-only and cannot be modified
0394: * @throws org.w3c.dom.DOMException <TT>HIERARCHY_REQUEST_ERR</TT>
0395: * Children are not supported by this node type
0396: * @throws org.w3c.dom.DOMException <TT>NOT_FOUND_ERR</TT>
0397: * <TT>oldChild</TT> is not a direct child of this node
0398: * @see #castOldChild
0399: */
0400: public synchronized final Node removeChild(Node oldChild)
0401: throws DOMException {
0402: NodeProxy oldChildX;
0403: int i;
0404:
0405: // Make sure the node is not read-only.
0406: // Throw exception if children not supported by derived class.
0407: if (isReadOnly()) {
0408: throw new DOMExceptionImpl(
0409: DOMException.NO_MODIFICATION_ALLOWED_ERR);
0410: }
0411: if (!supportsChildern()) {
0412: throw new DOMExceptionImpl(
0413: DOMException.HIERARCHY_REQUEST_ERR,
0414: "No childern supported by this node type.");
0415: }
0416:
0417: // Cast refChild to NodeImpl, making sure it is a child of this node.
0418: oldChildX = (NodeProxy) castOldChild(oldChild);
0419:
0420: // We're going to mess with this child node, so make sure no other thread
0421: // is touching it
0422: synchronized (oldChild) {
0423: // Need to tell all the iterators that might be observing the
0424: // child node that the child node is removed from the current
0425: // tree. The iterators will reflect the changed by selecting
0426: // a different child to point to. Interesting iterators are
0427: // those the observer the tree underneath this node and all its
0428: // parents.
0429: notifyIterators(oldChild);
0430:
0431: // Child becomes orphan. It is no longer first or last child of this
0432: // node. Removed from linked list.
0433: oldChildX.setParentNode(null);
0434:
0435: if (_firstChild != null && _firstChild.equals(oldChildX)) {
0436: _firstChild = (NodeProxy) oldChildX.getNextSibling();
0437: }
0438:
0439: if (_lastChild != null && _lastChild.equals(oldChildX)) {
0440: _lastChild = (NodeProxy) oldChildX.getPreviousSibling();
0441: }
0442:
0443: if (oldChildX.getPreviousSibling() != null) {
0444: ((NodeProxy) oldChildX.getPreviousSibling())
0445: .setNextSibling(oldChildX.getNextSibling());
0446: }
0447:
0448: if (oldChildX.getNextSibling() != null) {
0449: ((NodeProxy) oldChildX.getNextSibling())
0450: .setPreviousSibling(oldChildX
0451: .getPreviousSibling());
0452: }
0453:
0454: oldChildX.setPreviousSibling(null);
0455: oldChildX.setNextSibling(null);
0456:
0457: // Keep this count accurate at all times.
0458: --_childsCount;
0459:
0460: }
0461: return oldChild;
0462: }
0463:
0464: /**
0465: * Replace <TT>oldChild</TT> with <TT>newChild</TT>, adding the new child and
0466: * removing the old one.
0467: * <P>
0468: * If <TT>newChild</TT> does not belong to this DOM, <TT>oldChild</TT> is not
0469: * a direct child of this parent, or childern are not supported by this node
0470: * type, an exception is thrown.
0471: * <P>
0472: * <TT>newChild</TT> is removed from its original parent before adding to this
0473: * parent. If <TT>newChild</TT> is a {@link org.w3c.dom.DocumentFragment}, all
0474: * its children are inserted one by one into this parent.
0475: *
0476: * @param newChild The new child to add
0477: * @param oldChild The old child to take away
0478: * @return The old child
0479: * @throws org.w3c.dom.DOMException <TT>NO_MODIFICATION_ALLOWED_ERR</TT>
0480: * Node is read-only and cannot be modified
0481: * @throws org.w3c.dom.DOMException <TT>HIERARCHY_REQUEST_ERR</TT>
0482: * Children are not supported by this node type, or <TT>newChild</TT> is not
0483: * a compatible type for this node
0484: * @throws org.w3c.dom.DOMException <TT>NOT_FOUND_ERR</TT>
0485: * <TT>oldChild</TT> is not a direct child of this node
0486: * @see #castNewChild
0487: * @see #castOldChild
0488: */
0489: public synchronized final Node replaceChild(Node newChild,
0490: Node oldChild) throws DOMException {
0491: // Node arguments must be casted to NodeEx in order to operate on them.
0492: NodeProxy newChildX;
0493: NodeProxy oldChildX;
0494:
0495: // Make sure the node is not read-only.
0496: // Throw exception if children not supported by derived class.
0497: if (isReadOnly()) {
0498: throw new DOMExceptionImpl(
0499: DOMException.NO_MODIFICATION_ALLOWED_ERR);
0500: }
0501: if (!supportsChildern()) {
0502: throw new DOMExceptionImpl(
0503: DOMException.HIERARCHY_REQUEST_ERR,
0504: "No childern supported by this node type.");
0505: }
0506:
0507: // Cast newChild to NodeImpl and make sure it can be inserted to this node.
0508: // Cast oldChild to NodeImpl, making sure it is a child of this node.
0509: if (newChild != null) {
0510: newChildX = (NodeProxy) castNewChild(newChild);
0511: }
0512: oldChildX = (NodeProxy) castOldChild(oldChild);
0513:
0514: // We're going to mess with this child node, so make sure no other thread
0515: // is touching it
0516: synchronized (oldChild) {
0517: if (newChild != null) {
0518: // .. or this
0519: synchronized (newChild) {
0520: // Lazy implementation adds newChild before oldChild and then takes
0521: // oldChild away. Might be a touch slowed, but is way more reliable.
0522: insertBefore(newChild, oldChild);
0523: removeChild(oldChild);
0524: }
0525: } else {
0526: // The case of just removing the old child, when the new one
0527: // is null.
0528: removeChild(oldChild);
0529: }
0530: }
0531: return oldChild;
0532: }
0533:
0534: /**
0535: * Insert <TT>newChild</TT> in this parent, before the existing child
0536: * <TT>refChild</TT>. If <TT>refChild</TT> is null, insert <TT>newChild</TT>
0537: * as the last child of this parent, akin to calling {@link #appendChild}.
0538: * <P>
0539: * If <TT>newChild</TT> is null, <TT>newChild</TT> does not belong to this DOM,
0540: * <TT>refChild</TT> is not a direct child of this node, or childern are not
0541: * supported by this node type, an exception is thrown.
0542: * <P>
0543: * <TT>newChild</TT> is removed from its original parent before adding to this
0544: * parent. If <TT>newChild</TT> is a {@link org.w3c.dom.DocumentFragment}, all
0545: * its children are inserted one by one into this parent.
0546: *
0547: * @param newChild The new child to add
0548: * @param refChild Insert new child before this child, or insert at the end
0549: * if this child is null
0550: * @return The newly inserted child
0551: * @throws org.w3c.dom.DOMException <TT>NO_MODIFICATION_ALLOWED_ERR</TT>
0552: * Node is read-only and cannot be modified
0553: * @throws org.w3c.dom.DOMException <TT>HIERARCHY_REQUEST_ERR</TT>
0554: * Children are not supported by this node type, or <TT>newChild</TT> is not
0555: * a compatible type for this node
0556: * @throws org.w3c.dom.DOMException <TT>NOT_FOUND_ERR</TT>
0557: * <TT>oldChild</TT> is not null and not a direct child of this node
0558: * @see #castNewChild
0559: * @see #castOldChild
0560: */
0561: public synchronized final Node insertBefore(Node newChild,
0562: Node refChild) throws DOMException {
0563: // Node arguments must be casted to NodeEx in order to operate on them.
0564: NodeProxy newChildX;
0565: NodeProxy refChildX;
0566:
0567: // Make sure the node is not read-only.
0568: // Throw exception if children not supported by derived class.
0569: if (isReadOnly()) {
0570: throw new DOMExceptionImpl(
0571: DOMException.NO_MODIFICATION_ALLOWED_ERR);
0572: }
0573: if (!supportsChildern()) {
0574: throw new DOMExceptionImpl(
0575: DOMException.HIERARCHY_REQUEST_ERR,
0576: "No childern supported by this node type.");
0577: }
0578:
0579: // If refChild is null, act as if appendChild was called.
0580: if (refChild == null) {
0581: return appendChild(newChild);
0582: }
0583:
0584: // Cast newChild to NodeImpl and make sure it can be inserted to this node.
0585: // Cast refChild to NodeImpl, making sure it is a child of this node.
0586: newChildX = (NodeProxy) castNewChild(newChild);
0587: refChildX = (NodeProxy) castOldChild(refChild);
0588:
0589: // We're going to mess with this child node, so make sure no other thread
0590: // is touching it
0591: synchronized (newChild) {
0592: // .. or this
0593: synchronized (refChild) {
0594: // If the newChild is already a child or some node, remove it first
0595: // before becoming child of this node. Make sure that parent is not
0596: // read-only.
0597: if (newChildX.getParentNode() != null) {
0598: if (((NodeProxy) newChildX.getParentNode())
0599: .isReadOnly()) {
0600: throw new DOMExceptionImpl(
0601: DOMException.NO_MODIFICATION_ALLOWED_ERR);
0602: }
0603: newChildX.getParentNode().removeChild(newChildX);
0604: }
0605:
0606: // Special case: newChild is a DocumentFragment and instead of
0607: // inserting itself, all of its childs are inserted one by one.
0608: if (newChildX instanceof DocumentFragment) {
0609: NodeProxy nextChild;
0610:
0611: newChildX = (NodeProxy) newChildX.getFirstChild();
0612: while (newChildX != null) {
0613: nextChild = (NodeProxy) newChildX
0614: .getNextSibling();
0615: insertBefore(newChildX, refChild);
0616: newChildX = nextChild;
0617: }
0618: return newChild;
0619: }
0620:
0621: // Node becomes child of this parent and part of this document.
0622: // Note that this code comes after the test for a DocumentFragment.
0623: // A fragment does not become part of this node, only its children.
0624: // The fragment becomes parent-less and child-less.
0625: newChildX.setParentNode(this );
0626: newChildX.setOwnerDocument(_ownerDocument);
0627:
0628: // If refChild is the first child, newChild becomes the first
0629: // child on the list.
0630: if (_firstChild.equals(refChildX)) {
0631: _firstChild = newChildX;
0632: }
0633: // refChild is not the first child, so adjust the previous child
0634: // to point at newChild instead.
0635: if (refChildX.getPreviousSibling() != null) {
0636: newChildX.setPreviousSibling(refChildX
0637: .getPreviousSibling());
0638: ((NodeProxy) refChildX.getPreviousSibling())
0639: .setNextSibling(newChildX);
0640: }
0641: // Adjust the refChild to point at this child and vice versa.
0642: refChildX.setPreviousSibling(newChildX);
0643: newChildX.setNextSibling(refChildX);
0644: // Keep this count accurate at all times.
0645: ++_childsCount;
0646: }
0647: }
0648: return newChild;
0649: }
0650:
0651: /**
0652: * Checks whether <TT>newChild</TT> can be added to this node as a child, and
0653: * if so, performs a necessary cast. <TT>newChild</TT> cannot be null and must
0654: * belong to this DOM. It is impossible to transfer nodes between different
0655: * DOM implementations.
0656: * <P>
0657: * The following rules govern the allowed <TT>newChild</TT> types:
0658: * <UL>
0659: * <LI>Parent is an {@link org.w3c.dom.Attr}, <TT>newChild</TT> must be either
0660: * a {@link org.w3c.dom.Text} or an {@link org.w3c.dom.EntityReference}
0661: * <LI>Parent is a {@link org.w3c.dom.DocumentType}, <TT>newChild</TT> must be
0662: * either an {@link org.w3c.dom.Entity} or a {@link org.w3c.dom.Notation}.
0663: * <LI>Parnet is any other node type, <TT>newChild</TT> must be an {@link
0664: * org.w3c.dom.Element}, a {@link org.w3c.dom.CharacterData} derived type,
0665: * a {@link org.w3c.dom.DocumentFragment}, an {@link
0666: * org.w3c.dom.EntityReference} or a {@link org.w3c.dom.ProcessingInstruction}.
0667: * </UL>
0668: * Any deviation will throw an exception.
0669: *
0670: * @param newChild New child node
0671: * @return <TT>newChild</TT> cast to type {@link NodeImpl}
0672: * @throws org.w3c.dom.DOMException <TT>HIERARCHY_REQUEST_ERR</TT>
0673: * <TT>newChild</TT> is null, does not belong to this DOM, or its node type
0674: * is not supported for this parent
0675: */
0676: protected Node castNewChild(Node newChild) throws DOMException {
0677: if (newChild == null) {
0678: throw new DOMExceptionImpl(
0679: DOMException.HIERARCHY_REQUEST_ERR,
0680: "Child reference is null.");
0681: }
0682:
0683: // newChild must be Element, CDATASection, Text, Comment (all three
0684: // derived from CharacterData), DocumentFragment, EntityReference,
0685: // or ProcessingInstruction.
0686: if (!(newChild instanceof Node)) {
0687: throw new DOMExceptionImpl(
0688: DOMException.HIERARCHY_REQUEST_ERR,
0689: "Child is not a compatible type for this node.");
0690: }
0691: if (!(newChild instanceof Element
0692: || newChild instanceof CharacterData
0693: || newChild instanceof DocumentFragment
0694: || newChild instanceof EntityReference || newChild instanceof ProcessingInstruction)) {
0695: throw new DOMExceptionImpl(
0696: DOMException.HIERARCHY_REQUEST_ERR,
0697: "Child is not a compatible type for this node.");
0698: }
0699: return (Node) newChild;
0700: }
0701:
0702: /**
0703: * Checks whether <TT>oldChild</TT> is a direct child of this node, and if so,
0704: * performs a necessary cast. <TT>oldChild</TT> cannot be null.
0705: *
0706: * @param oldChild Old child node
0707: * @return <T>oldChild</TT> cast to type {@link NodeImpl}
0708: * @throws org.w3c.dom.DOMException <TT>NOT_FOUND_ERR</TT>
0709: * <TT>oldChild</TT> is null, or not a direct child of this node
0710: */
0711: protected final Node castOldChild(Node oldChild)
0712: throws DOMException {
0713: if (oldChild == null
0714: || !(oldChild instanceof NodeProxy)
0715: || !((OzoneProxy) oldChild.getParentNode()).remoteID()
0716: .equals(container().id())) {
0717: throw new DOMExceptionImpl(DOMException.NOT_FOUND_ERR,
0718: "Not a direct child of this node.");
0719: }
0720: return (Node) oldChild;
0721: }
0722:
0723: /**
0724: * This clone method is called after a new node has been constructed to copy
0725: * the contents of this node into the new one. It clones in contents but not
0726: * in context, and guarantees that the cloned node will pass the equality
0727: * test (see {@link #equals}).
0728: * <P>
0729: * <TT>into</TT> must be a valid node of the exact same class as this one.
0730: * <TT>deep</TT> is true if deep cloning (includes all children nodes) is to
0731: * be performed. If <TT>deep</TT> is false, the clone might not pass the
0732: * equality test.
0733: * <P>
0734: * Derived classes override and call this method to add per-class variable
0735: * copying. This method is called by {@link #cloneNode} and the default
0736: * {@link java.lang.Object#clone} method.
0737: * <P>
0738: * Contents cloning duplicates the node's name and value, and its children.
0739: * It does not duplicate it's context, that is, the node's parent or sibling.
0740: * Initially a clone node has no parents or siblings. However, the node does
0741: * belong to the same document, since all nodes must belong to some document.
0742: * The cloned node is never read-only.
0743: *
0744: * @param into A node into which to duplicate this one
0745: * @param deep True if deep cloning is required
0746: */
0747: public synchronized void cloneInto(NodeProxy into, boolean deep) {
0748: NodeProxy child;
0749:
0750: // falko: this expression cannot be true in ozone so I commented this
0751: // out
0752: // Make sure no function messed up with the class types.
0753: // if (this.getClass() != into.getClass()) {
0754: // throw new IllegalArgumentException( "Argument 'into' not same type as this node." );
0755: // }
0756:
0757: // Duplicate node name and value.
0758: into.setNodeName(_nodeName);
0759: String nodeValue = getNodeValue();
0760: if (nodeValue != null) {
0761: into.setNodeValue(nodeValue);
0762: }
0763: into.setOwnerDocument(_ownerDocument);
0764: if (deep) {
0765: child = (NodeProxy) getFirstChild();
0766: while (child != null) {
0767: into.appendChild((Node) child.cloneNode(true));
0768: child = (NodeProxy) child.getNextSibling();
0769: }
0770: }
0771: }
0772:
0773: public synchronized void setOwnerDocument(Document owner) {
0774: Node node;
0775:
0776: if (owner == null) {
0777: _ownerDocument = null;
0778: } else {
0779: if (!(owner instanceof DocumentProxy)) {
0780: throw new IllegalArgumentException(
0781: "Argument 'owner' not of compatible DOM class.");
0782: }
0783: _ownerDocument = (DocumentProxy) owner;
0784: }
0785: node = getFirstChild();
0786: while (node != null) {
0787: ((NodeProxy) node).setOwnerDocument(owner);
0788: node = node.getNextSibling();
0789: }
0790: }
0791:
0792: /**
0793: * Renders this node read only, preventing it's contents from being modified.
0794: * Attempts to modify the node's contents will throw an exception. The node's
0795: * children are also made read-only.
0796: */
0797: public synchronized final void setReadOnly() {
0798: NodeProxy child;
0799:
0800: _readOnly = true;
0801: // Make all children read-only as well: this allows us to lock a branch
0802: // but, for example, move it to a different tree.
0803: child = (NodeProxy) getFirstChild();
0804: while (child != null) {
0805: child.setReadOnly();
0806: child = (NodeProxy) child.getNextSibling();
0807: }
0808: }
0809:
0810: /**
0811: * Returns true if node is read-only and cannot be modified, or if node
0812: * belongs to a read-only document.
0813: *
0814: * @return True if node is read-only and cannot be modified
0815: * @see #setReadOnly
0816: */
0817: public final boolean isReadOnly() {
0818: return _readOnly;
0819: }
0820:
0821: /**
0822: * Returns true if this node supports children. Other methods query this to
0823: * determine whether to properly support childern, return null or throw an
0824: * exception in response. The default method returns false.
0825: *
0826: * @return True if childern supported by this node type
0827: */
0828: boolean supportsChildern() {
0829: return false;
0830: }
0831:
0832: /**
0833: * Returns the <TT>index</TT>-th child of this node. This method is used
0834: * exclusively by {@link NodeListImpl}.
0835: *
0836: * @param index Index of child to retrieve
0837: * @return The child node or null
0838: * @see NodeListImpl#item(int)
0839: */
0840: public synchronized final Node getChild(int index) {
0841: NodeProxy node;
0842:
0843: if (index < 0 || index > _childsCount) {
0844: return null;
0845: }
0846: node = (NodeProxy) getFirstChild();
0847: while (node != null && index > 0) {
0848: node = (NodeProxy) node.getNextSibling();
0849: --index;
0850: }
0851: return node;
0852: }
0853:
0854: /**
0855: * Returns the number of children in this node. This method is used
0856: * exclusively by {@link NodeListImpl}.
0857: *
0858: * @return Number of childern in this node
0859: * @see NodeListImpl#getLength
0860: */
0861: public final int getChildCount() {
0862: return _childsCount;
0863: }
0864:
0865: /**
0866: * Hidden constructor creates a new node. Only one constructor is supported,
0867: * although cloning is also supported. Owner document must be supplied except
0868: * for {@link DocumentImpl} in which case the document itself becomes its
0869: * owner. Name must be supplied, either dynamic or static (e.g. "#document#").
0870: * <P>
0871: * If <TT>checkName</TT> is true, the supplied named is assumed to be a valid
0872: * XML name token, one that can contain any Unicode letter and digit, must
0873: * start with a letter, and may also contain hyphen, underscore, digit or colon.
0874: *
0875: * @param owner Document owner of this node, or null
0876: * @param name Name of node
0877: * @param value Initial value of node or null
0878: * @param checkName True if name is an XML name token
0879: * @throws org.w3c.dom.DOMException <TT>INVALID_CHARACTER_ERR</TT>
0880: * Node name cannot contain whitespaces or non-printable characters
0881: */
0882: protected NodeImpl(DocumentImpl owner, String name, String value,
0883: boolean checkName) throws DOMException {
0884: init(owner, name, value, checkName);
0885: }
0886:
0887: protected NodeImpl() {
0888: }
0889:
0890: public final void init(DocumentProxy owner, String name,
0891: String value, boolean checkName) throws DOMException {
0892: char ch;
0893: int i;
0894:
0895: if (name == null) {
0896: throw new NullPointerException("Argument 'name' is null.");
0897: }
0898:
0899: _nodeName = name;
0900: _ownerDocument = owner;
0901: // Check the node name one character at a time to assure that no
0902: // illegal characters are used. Node name must conform to Name token
0903: // as defined in XML spec, including use of all Unicode letters and
0904: // digits.
0905: if (checkName && name.length() > 0) {
0906: ch = name.charAt(0);
0907: if (!Character.isLetter(ch) && ch != '_' && ch != ':') {
0908: throw new DOMExceptionImpl(
0909: DOMException.INVALID_CHARACTER_ERR);
0910: }
0911: for (i = 1; i < name.length(); ++i) {
0912: ch = name.charAt(1);
0913: if (!Character.isLetterOrDigit(ch) && ch != '_'
0914: && ch != ':' && ch != '-' && ch != '.') {
0915: throw new DOMExceptionImpl(
0916: DOMException.INVALID_CHARACTER_ERR);
0917: }
0918: }
0919: }
0920: if (value != null) {
0921: setNodeValue(value);
0922: }
0923: }
0924:
0925: /**
0926: * Element declaration node. Not part of the DOM, identifies an element
0927: * declaration node appearing in the DTD.
0928: */
0929: public final static short ELEMENT_DECL_NODE = 13;
0930:
0931: /**
0932: * Attributes list declaration node. Not part of the DOM, identifies an
0933: * attributes list declaration node appearing in the DTD..
0934: */
0935: public final static short ATTLIST_DECL_NODE = 14;
0936:
0937: /**
0938: * Parameter entity declaration node. Not part of the DOM, identifies an
0939: * internal or external parameter entity declaration node appearing in the
0940: * DTD (see {@link org.openxml.dom.ParamEntity}).
0941: */
0942: public final static short PARAM_ENTITY_NODE = 15;
0943:
0944: /**
0945: * This node ia part of a double-linked list that belongs to its parent.
0946: * This reference identifies the next child in the list. Class access
0947: * required by derived classes.
0948: */
0949: NodeProxy _nextNode;
0950:
0951: /**
0952: * This node ia part of a double-linked list that belongs to its parent.
0953: * This reference identifies the previous child in the list. Class access
0954: * required by derived classes.
0955: */
0956: NodeProxy _prevNode;
0957:
0958: /**
0959: * The parent of this node or null if the node has no parent. Class access
0960: * required by derived classes.
0961: */
0962: NodeProxy _parent;
0963:
0964: /**
0965: * The document owner of this node, or the document itself. If the node belongs
0966: * to any document, this will point to that document. For a document this will
0967: * point at the document itself ({@link #getOwnerDocument} will return null,
0968: * though). Class access required by derived classes.
0969: */
0970: DocumentProxy _ownerDocument;
0971:
0972: /**
0973: * The name of this node. All nodes have names, some are dynamic (e.g. the
0974: * tag name of an element), others are static (e.g. "#document").
0975: */
0976: private String _nodeName;
0977:
0978: /**
0979: * The value of this node. Not all nodes support values and this might be
0980: * null for some nodes.
0981: */
0982: private String _nodeValue;
0983:
0984: /**
0985: * The children of this node are arranged in a doubly linked lists.
0986: * This reference identifies the first child in the list.
0987: */
0988: private NodeProxy _firstChild;
0989:
0990: /**
0991: * The children of this node are arranged in a doubly linked lists.
0992: * This reference identifies the last child in the list.
0993: */
0994: private NodeProxy _lastChild;
0995:
0996: /**
0997: * Counts how many children nodes belong to this parent. Used to speed up
0998: * some checks.
0999: */
1000: private int _childsCount;
1001:
1002: /**
1003: * True if this node is read-only and its contents cannot be modified.
1004: */
1005: private boolean _readOnly;
1006:
1007: /**
1008: * Holdes a list of iterators that are observing this node of its
1009: * childern.
1010: */
1011: private NodeIteratorListener[] _iterators;
1012:
1013: /**
1014: */
1015: public void writeExternal(ObjectOutput out) throws IOException {
1016: out.writeObject(_nextNode);
1017: out.writeObject(_prevNode);
1018: out.writeObject(_parent);
1019: out.writeObject(_ownerDocument);
1020:
1021: //out.writeObject (_nodeName);
1022: if (_nodeName != null) {
1023: out.writeByte(1);
1024: out.writeUTF(_nodeName);
1025: } else {
1026: out.writeByte(-1);
1027: }
1028:
1029: // out.writeObject (_nodeValue);
1030: if (_nodeValue != null) {
1031: out.writeByte(1);
1032: out.writeUTF(_nodeValue);
1033: } else {
1034: out.writeByte(-1);
1035: }
1036:
1037: out.writeObject(_firstChild);
1038: out.writeObject(_lastChild);
1039: out.writeInt(_childsCount);
1040: out.writeBoolean(_readOnly);
1041:
1042: if (_iterators != null) {
1043: int len = _iterators.length;
1044: out.writeInt(len);
1045: for (int i = 0; i < len; i++) {
1046: out.writeObject(_iterators[i]);
1047: }
1048: } else {
1049: out.writeInt(-1);
1050: }
1051: }
1052:
1053: /**
1054: */
1055: public void readExternal(ObjectInput in) throws IOException,
1056: ClassNotFoundException {
1057: _nextNode = (NodeProxy) in.readObject();
1058: _prevNode = (NodeProxy) in.readObject();
1059: _parent = (NodeProxy) in.readObject();
1060: _ownerDocument = (DocumentProxy) in.readObject();
1061:
1062: int n = in.readByte();
1063: if (n > 0) {
1064: _nodeName = in.readUTF();
1065: } else {
1066: _nodeName = null;
1067: }
1068:
1069: //_nodeValue = (String)in.readObject();
1070: n = in.readByte();
1071: if (n > 0) {
1072: _nodeValue = in.readUTF();
1073: } else {
1074: _nodeValue = null;
1075: }
1076:
1077: _firstChild = (NodeProxy) in.readObject();
1078: _lastChild = (NodeProxy) in.readObject();
1079: _childsCount = in.readInt();
1080: _readOnly = in.readBoolean();
1081:
1082: int len = in.readInt();
1083: if (len > -1) {
1084: _iterators = new NodeIteratorListener[len];
1085: for (int i = 0; i < len; i++) {
1086: _iterators[i] = (NodeIteratorListener) in.readObject();
1087: }
1088: } else {
1089: _iterators = null;
1090: }
1091: }
1092:
1093: public boolean isSupported(String s, String s1) {
1094: throw new DOMExceptionImpl(DOMException.NOT_SUPPORTED_ERR,
1095: "Node.getLocalName(): ozone's persistent DOM doesn't support DOM level 2 yet.");
1096: }
1097: }
|