001: /*
002: * @(#)NodeImpl.java 1.36 02/03/21
003: *
004: * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
005: * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
006: */
007: package org.enhydra.xml;
008:
009: import org.w3c.dom.DOMException;
010: import org.w3c.dom.Document;
011: import org.w3c.dom.NamedNodeMap;
012: import org.w3c.dom.Node;
013: import org.w3c.dom.NodeList;
014: import org.w3c.dom.UserDataHandler;
015:
016: /**
017: * @author Tweety
018: *
019: * A class representing a node in a meta-data tree, which implements
020: * the <a href="../../../../api/org/w3c/dom/Node.html">
021: *
022: * <p> Namespaces are ignored in this implementation. The terms "tag
023: * name" and "node name" are always considered to be synonymous.
024: *
025: * @version 1.0
026: */
027: public class NodeImpl implements Node, NodeList {
028:
029: /**
030: * Owner document.
031: */
032: protected Document ownerDocument;
033:
034: /**
035: * The name (tag) of the node as a <code>String</code>.
036: */
037: protected String nodeName = null;
038:
039: /**
040: * The value of the node as a <code>String</code>.
041: */
042: protected String nodeValue = null;
043:
044: /**
045: * The type of the node as a <code>short</code>.
046: */
047: protected short type = ELEMENT_NODE;
048:
049: /**
050: * The parent node of this node, or <code>null</code> if this node
051: * forms the root of its own tree.
052: */
053: protected NodeImpl parent = null;
054:
055: /**
056: * The number of child nodes.
057: */
058: protected int numChildren = 0;
059:
060: /**
061: * The first (leftmost) child node of this node, or
062: * <code>null</code> if this node is a leaf node.
063: */
064: protected NodeImpl firstChild = null;
065:
066: /**
067: * The last (rightmost) child node of this node, or
068: * <code>null</code> if this node is a leaf node.
069: */
070: protected NodeImpl lastChild = null;
071:
072: /**
073: * The next (right) sibling node of this node, or
074: * <code>null</code> if this node is its parent's last child node.
075: */
076: protected NodeImpl nextSibling = null;
077:
078: /**
079: * The previous (left) sibling node of this node, or
080: * <code>null</code> if this node is its parent's first child node.
081: */
082: protected NodeImpl previousSibling = null;
083:
084: /**
085: * Constructs an empty <code>NodeImpl</code>.
086: */
087: public NodeImpl() {
088: }
089:
090: /**
091: * Constructs a <code>NodeImpl</code> from the given node,
092: * without creating entire children subtree.
093: *
094: * @param node, as a <code>NodeImpl</code>.
095: */
096: public NodeImpl(NodeImpl node) {
097: ownerDocument = node.ownerDocument;
098: nodeName = node.nodeName;
099: nodeValue = node.nodeValue;
100: type = node.type;
101: parent = node.parent;
102: numChildren = node.numChildren;
103: firstChild = node.firstChild;
104: lastChild = node.lastChild;
105: nextSibling = node.nextSibling;
106: previousSibling = node.previousSibling;
107: }
108:
109: /**
110: * Constructs an <code>NodeImpl</code> from a given node (creates the children subtree too),
111: * as a <code>Node</code>
112: *
113: * @param node, as a <code>Node</code>.
114: */
115: public NodeImpl(Node node) {
116: this (node, true);
117: }
118:
119: /**
120: * Constructs an <code>NodeImpl</code> from a given node, as a <code>Node</code>,
121: * and deep as <code>boolean</code>.
122: *
123: * @param node, as a <code>Node</code>.
124: * @param deep if <code>true</code>, recursively clone the subtree
125: * under the specified node; if <code>false</code>, clone only the
126: * node itself.
127: */
128: public NodeImpl(Node node, boolean deep) {
129: this .ownerDocument = node.getOwnerDocument();
130: this .nodeName = node.getNodeName();
131: this .type = node.getNodeType();
132: this .nodeValue = node.getNodeValue();
133: if (deep)
134: this .initNodeImplChildren(node);
135: }
136:
137: /**
138: * Constructs a <code>NodeImpl</code> from the given document owner and node name.
139: *
140: * @param ownerDoc the document owner of the node, as a <code>Document</code>.
141: * @param name the name of the node, as a <code>String</code>.
142: */
143: public NodeImpl(Document ownerDoc, String name) {
144: this .ownerDocument = ownerDoc;
145: // this.nodeName = nodeName;
146: }
147:
148: /**
149: * Constructs an <code>NodeImpl</code> from a given document owner,
150: * node name and node type.
151: *
152: * @param ownerDoc the document owner of the node, as a <code>Document</code>.
153: * @param nodeName the name of the node, as a <code>String</code>.
154: * @param type the type of the node, as a <code>short</code>.
155: */
156: public NodeImpl(Document ownerDoc, String nodeName, short type) {
157: this .ownerDocument = ownerDoc;
158: this .nodeName = nodeName;
159: this .type = type;
160: }
161:
162: /**
163: * Constructs an <code>NodeImpl</code> from a given document owner,
164: * node name, node type and node value.
165: *
166: * @param ownerDoc the document owner of the node, as a <code>Document</code>.
167: * @param nodeName the name of the node, as a <code>String</code>.
168: * @param type the type of the node, as a <code>short</code>.
169: * @param value the value of the node, as a <code>String</code>.
170: */
171: public NodeImpl(Document ownerDoc, String nodeName, short type,
172: String value) {
173: this .ownerDocument = ownerDoc;
174: this .nodeName = nodeName;
175: this .type = type;
176: this .nodeValue = value;
177: }
178:
179: /**
180: * Creates the children subtree and adds to this node.
181: * (this part had to be splited from the constructor)
182: *
183: * @param nodeas a <code>Node</code>.
184: */
185: protected void initNodeImplChildren(Node node) {
186: // add children
187: Node child = node.getFirstChild();
188: while (child != null) {
189: switch (child.getNodeType()) {
190: case Node.ELEMENT_NODE: {
191: this .appendChild(newElementInstance(child));
192: }
193: ;
194: break;
195: case Node.TEXT_NODE: {
196: this .appendChild(newTextInstance(child));
197: }
198: ;
199: break;
200: case Node.COMMENT_NODE: {
201: this .appendChild(newCommentInstance(child));
202: }
203: ;
204: break;
205: default: {
206: this .appendChild(newDefaultInstance(child));
207: }
208: ;
209: }
210: child = child.getNextSibling();
211: }
212: }
213:
214: /**
215: * Creates new instance of the ElementImpl class.
216: *
217: * @param node, as a <code>Node</code>.
218: * @return Node new instance of the ElementImpl class.
219: */
220: protected Node newElementInstance(Node node) {
221: return new ElementImpl(node);
222: }
223:
224: /**
225: * Creates new instance of the TextImpl class.
226: *
227: * @param node, as a <code>Node</code>.
228: * @return Node new instance of the TextImpl class.
229: */
230: protected Node newTextInstance(Node node) {
231: return new TextImpl(node);
232: }
233:
234: /**
235: * Creates new instance of the CommentImpl class.
236: *
237: * @param node, as a <code>Node</code>.
238: * @return Node new instance of the CommentImpl class.
239: */
240: protected Node newCommentInstance(Node node) {
241: return new CommentImpl(node);
242: }
243:
244: /**
245: * Creates new instance of the NodeImpl class.
246: *
247: * @param node, as a <code>Node</code>.
248: * @return Node new instance of the NodeImpl class.
249: */
250: protected Node newDefaultInstance(Node node) {
251: return new NodeImpl(node);
252: }
253:
254: /**
255: * Check that the node is either <code>null</code> or an
256: * <code>NodeImpl</code>.
257: *
258: * @exception DOMException if node is not an instance of <code>NodeImpl</code>.
259: */
260: private void checkNode(Node node) throws DOMException {
261: if (node == null) {
262: return;
263: }
264: if (!(node instanceof NodeImpl))
265: throw new NodeDOMException(DOMException.WRONG_DOCUMENT_ERR,
266: "Node not an NodeImpl!");
267: }
268:
269: // Methods from Node
270:
271: /**
272: * Returns the name associated with this node.
273: *
274: * @return the name, as a <code>String</code>.
275: */
276: public String getNodeName() {
277: return nodeName;
278: }
279:
280: /**
281: * Returns the value associated with this node.
282: *
283: * @return the node value, as a <code>String</code>.
284: */
285: public String getNodeValue() {
286: return nodeValue;
287: }
288:
289: /**
290: * Sets the node value of this node.
291: *
292: * @param nodeValue new node value, as a <code>String</code>.
293: */
294: public void setNodeValue(String nodeValue) {
295: this .nodeValue = nodeValue;
296: }
297:
298: /**
299: * Returns the node type.
300: *
301: * @return the <code>short</code> value node type.
302: */
303: public short getNodeType() {
304: return type;
305: }
306:
307: /**
308: * Returns the parent of this node. A <code>null</code> value
309: * indicates that the node is the root of its own tree. To add a
310: * node to an existing tree, use one of the
311: * <code>insertBefore</code>, <code>replaceChild</code>, or
312: * <code>appendChild</code> methods.
313: *
314: * @return the parent, as a <code>Node</code>.
315: *
316: * @see #insertBefore
317: * @see #replaceChild
318: * @see #appendChild
319: */
320: public Node getParentNode() {
321: return parent;
322: }
323:
324: /**
325: * Returns all child nodes of this node, or <code>null</code> if
326: * the node has no children.
327: *
328: * @return all child nodes of this node, as a <code>Node</code>, or
329: * <code>null</code>.
330: */
331: public NodeList getChildNodes() {
332: return this ;
333: }
334:
335: /**
336: * Returns the first child of this node, or <code>null</code> if
337: * the node has no children.
338: *
339: * @return the first child, as a <code>Node</code>, or
340: * <code>null</code>
341: */
342: public Node getFirstChild() {
343: return firstChild;
344: }
345:
346: /**
347: * Returns the last child of this node, or <code>null</code> if
348: * the node has no children.
349: *
350: * @return the last child, as a <code>Node</code>, or
351: * <code>null</code>.
352: */
353: public Node getLastChild() {
354: return lastChild;
355: }
356:
357: /**
358: * Returns the previous sibling of this node, or <code>null</code>
359: * if this node has no previous sibling.
360: *
361: * @return the previous sibling, as a <code>Node</code>, or
362: * <code>null</code>.
363: */
364: public Node getPreviousSibling() {
365: return previousSibling;
366: }
367:
368: /**
369: * Returns the next sibling of this node, or <code>null</code> if
370: * the node has no next sibling.
371: *
372: * @return the next sibling, as a <code>Node</code>, or
373: * <code>null</code>.
374: */
375: public Node getNextSibling() {
376: return nextSibling;
377: }
378:
379: /**
380: * Returns <code>null</code>, since <code>NodeImpl</code>s
381: * do not belong to any <code>Document</code>.
382: *
383: * @return document owner as <code>Document</code>.
384: */
385: public Document getOwnerDocument() {
386: return ownerDocument;
387: }
388:
389: /**
390: * Inserts the node <code>newChild</code> before the existing
391: * child node <code>refChild</code>. If <code>refChild</code> is
392: * <code>null</code>, insert <code>newChild</code> at the end of
393: * the list of children.
394: *
395: * @param newChild the <code>Node</code> to insert.
396: * @param refChild the reference <code>Node</code>.
397: *
398: * @return the node being inserted.
399: *
400: * @exception IllegalArgumentException if <code>newChild</code> is
401: * <code>null</code>.
402: */
403: public Node insertBefore(Node newChild, Node refChild) {
404: if (newChild == null) {
405: throw new IllegalArgumentException("newChild == null!");
406: }
407:
408: checkNode(newChild);
409: checkNode(refChild);
410:
411: NodeImpl newChildNode = (NodeImpl) newChild;
412: NodeImpl refChildNode = (NodeImpl) refChild;
413:
414: // Siblings, can be null.
415: NodeImpl previous = null;
416: NodeImpl next = null;
417:
418: if (refChild == null) {
419: previous = this .lastChild;
420: next = null;
421: this .lastChild = newChildNode;
422: } else {
423: previous = refChildNode.previousSibling;
424: next = refChildNode;
425: }
426:
427: if (previous != null) {
428: previous.nextSibling = newChildNode;
429: }
430: if (next != null) {
431: next.previousSibling = newChildNode;
432: }
433:
434: newChildNode.parent = this ;
435: newChildNode.previousSibling = previous;
436: newChildNode.nextSibling = next;
437:
438: // N.B.: O.K. if refChild == null
439: if (this .firstChild == refChildNode) {
440: this .firstChild = newChildNode;
441: }
442: ++numChildren;
443: return newChildNode;
444: }
445:
446: /**
447: * Replaces the child node <code>oldChild</code> with
448: * <code>newChild</code> in the list of children, and returns the
449: * <code>oldChild</code> node.
450: *
451: * @param newChild the <code>Node</code> to insert.
452: * @param oldChild the <code>Node</code> to be replaced.
453: *
454: * @return the node replaced.
455: *
456: * @exception IllegalArgumentException if <code>newChild</code> is
457: * <code>null</code>.
458: */
459: public Node replaceChild(Node newChild, Node oldChild) {
460: if (newChild == null) {
461: throw new IllegalArgumentException("newChild == null!");
462: }
463:
464: checkNode(newChild);
465: checkNode(oldChild);
466:
467: NodeImpl newChildNode = (NodeImpl) newChild;
468: NodeImpl oldChildNode = (NodeImpl) oldChild;
469:
470: NodeImpl previous = oldChildNode.previousSibling;
471: NodeImpl next = oldChildNode.nextSibling;
472:
473: if (previous != null) {
474: previous.nextSibling = newChildNode;
475: }
476: if (next != null) {
477: next.previousSibling = newChildNode;
478: }
479:
480: newChildNode.parent = this ;
481: newChildNode.previousSibling = previous;
482: newChildNode.nextSibling = next;
483:
484: if (firstChild == oldChildNode) {
485: firstChild = newChildNode;
486: }
487: if (lastChild == oldChildNode) {
488: lastChild = newChildNode;
489: }
490:
491: oldChildNode.parent = null;
492: oldChildNode.previousSibling = null;
493: oldChildNode.nextSibling = null;
494:
495: return oldChildNode;
496: }
497:
498: /**
499: * Removes the child node indicated by <code>oldChild</code> from
500: * the list of children, and returns it.
501: *
502: * @param oldChild the <code>Node</code> to be removed.
503: *
504: * @return the node removed.
505: *
506: * @exception IllegalArgumentException if <code>oldChild</code> is
507: * <code>null</code>.
508: */
509: public Node removeChild(Node oldChild) {
510: if (oldChild == null) {
511: throw new IllegalArgumentException("oldChild == null!");
512: }
513: checkNode(oldChild);
514:
515: NodeImpl oldChildNode = (NodeImpl) oldChild;
516:
517: NodeImpl previous = oldChildNode.previousSibling;
518: NodeImpl next = oldChildNode.nextSibling;
519:
520: if (previous != null) {
521: previous.nextSibling = next;
522: }
523: if (next != null) {
524: next.previousSibling = previous;
525: }
526:
527: if (this .firstChild == oldChildNode) {
528: this .firstChild = next;
529: }
530: if (this .lastChild == oldChildNode) {
531: this .lastChild = previous;
532: }
533:
534: oldChildNode.parent = null;
535: oldChildNode.previousSibling = null;
536: oldChildNode.nextSibling = null;
537:
538: --numChildren;
539: return oldChildNode;
540: }
541:
542: /**
543: * Adds the node <code>newChild</code> to the end of the list of
544: * children of this node.
545: *
546: * @param newChild the <code>Node</code> to insert.
547: *
548: * @return the node added.
549: *
550: * @exception IllegalArgumentException if <code>newChild</code> is
551: * <code>null</code>.
552: */
553: public Node appendChild(Node newChild) {
554: if (newChild == null) {
555: throw new IllegalArgumentException("newChild == null!");
556: }
557: checkNode(newChild);
558:
559: // insertBefore will increment numChildren
560: return insertBefore(newChild, null);
561: }
562:
563: /**
564: * Returns <code>true</code> if this node has child nodes.
565: *
566: * @return <code>true</code> if this node has children.
567: */
568: public boolean hasChildNodes() {
569: return numChildren > 0;
570: }
571:
572: /**
573: * Returns a duplicate of this node. The duplicate node has no
574: * parent (<code>getParentNode</code> returns <code>null</code>).
575: * If a shallow clone is being performed (<code>deep</code> is
576: * <code>false</code>), the new node will not have any children or
577: * siblings. If a deep clone is being performed, the new node
578: * will form the root of a complete cloned subtree.
579: *
580: * @param deep if <code>true</code>, recursively clone the subtree
581: * under the specified node; if <code>false</code>, clone only the
582: * node itself.
583: *
584: * @return the duplicate node.
585: */
586: public Node cloneNode(boolean deep) {
587: return new NodeImpl(this , deep);
588: }
589:
590: /**
591: * Does nothing, since <code>NodeImpl</code>s do not
592: * contain <code>Text</code> children.
593: */
594: public void normalize() {
595: }
596:
597: /**
598: * Returns <code>false</code> since DOM features are not
599: * supported.
600: *
601: * @return <code>false</code>.
602: *
603: * @param feature a <code>String</code>, which is ignored.
604: * @param version a <code>String</code>, which is ignored.
605: */
606: public boolean isSupported(String feature, String version) {
607: return false;
608: }
609:
610: /**
611: * Returns <code>null</code>, since namespaces are not supported.
612: *
613: * @return <code>null</code>.
614: *
615: * @see #setPrefix
616: */
617: public String getPrefix() {
618: return null;
619: }
620:
621: /**
622: * Does nothing, since namespaces are not supported.
623: *
624: * @param prefix a <code>String</code>, which is ignored.
625: *
626: * @see #getPrefix
627: */
628: public void setPrefix(String prefix) {
629: }
630:
631: /**
632: * Equivalent to <code>getNodeName</code>.
633: *
634: * @return the node name, as a <code>String</code>.
635: */
636: public String getLocalName() {
637: return nodeName;
638: }
639:
640: /**
641: * Returns all attribute nodes of this node.
642: *
643: * @return all attribute nodes of this node.
644: */
645: public NamedNodeMap getAttributes() {
646: return null;
647: }
648:
649: /**
650: * Returns <code>true</code>, if this node has attributes, otherwise
651: * <code>false</code>.
652: *
653: * @return <code>true</code> if node has attributes, otherwise <code>false</code>..
654: */
655: public boolean hasAttributes() {
656: return false;
657: }
658:
659: // Methods from NodeList
660:
661: /**
662: * Returns number of child nodes.
663: *
664: * @return all number of child nodes.
665: */
666: public int getLength() {
667: return numChildren;
668: }
669:
670: /**
671: * Returns child node with the given index.
672: *
673: * @return child node with the given index.
674: */
675: public Node item(int index) {
676: if (index < 0) {
677: return null;
678: }
679:
680: Node child = getFirstChild();
681: while (child != null && index-- > 0) {
682: child = child.getNextSibling();
683: }
684: return child;
685: }
686:
687: // String methodes
688:
689: /**
690: * Returns <code>String</code> representation of this node.
691: *
692: * @return <code>String</code> representation of this node.
693: */
694: public String toString() {
695: return toString(Indent.DEFAULT_TAB);
696: }
697:
698: /**
699: * Returns <code>String</code> representation of this node.
700: *
701: * @param tab tab for node indentation.
702: *
703: * @return <code>String</code> representation of this node.
704: */
705: public String toString(String tab) {
706: StringBuffer sb = new StringBuffer();
707: this .allToString(sb, new Indent(0, tab));
708: return sb.toString();
709: }
710:
711: /**
712: * Method beginToString should be redefined in extended classes.
713: * Each type of node has its own <code>beginToString and
714: * <code>endToString</code>. This was added to support
715: * writing of the xml file. The <code>Element</code>
716: * type of node: it writes the beginning tag, then calls
717: * the child's <code>toString</code>, and then writes the ending tag.
718: *
719: * @param sb string buffer to add resulting string.
720: * @param indent used in formating the output.
721: */
722: protected void beginToString(StringBuffer sb, Indent indent) {
723: }
724:
725: /**
726: * Method endToString should be redefined in extended classes.
727: * Each type of node has its own <code>beginToString and
728: * <code>endToString</code>. This was added to support
729: * writing of the xml file. The <code>Element</code>
730: * type of node: it writes the beginning tag, then calls
731: * the child's <code>toString</code>, and then writes the ending tag.
732: *
733: * @param sb string buffer to add resulting string.
734: * @param indent used in formating the output.
735: */
736: protected void endToString(StringBuffer sb, Indent indent) {
737: }
738:
739: private void allToString(StringBuffer sb, Indent indent) {
740: this .beginToString(sb, indent);
741: Node child = getFirstChild();
742: while (child != null) {
743: ((NodeImpl) child).allToString(sb, indent);
744: child = child.getNextSibling();
745: }
746: this .endToString(sb, indent);
747: }
748:
749: /* (non-Javadoc)
750: * @see org.w3c.dom.Node#getBaseURI()
751: */
752: public String getBaseURI() {
753: // TODO Auto-generated method stub
754: return null;
755: }
756:
757: /* (non-Javadoc)
758: * @see org.w3c.dom.Node#compareDocumentPosition(org.w3c.dom.Node)
759: */
760: public short compareDocumentPosition(Node arg0) throws DOMException {
761: // TODO Auto-generated method stub
762: return 0;
763: }
764:
765: /* (non-Javadoc)
766: * @see org.w3c.dom.Node#getTextContent()
767: */
768: public String getTextContent() throws DOMException {
769: // TODO Auto-generated method stub
770: return null;
771: }
772:
773: /* (non-Javadoc)
774: * @see org.w3c.dom.Node#setTextContent(java.lang.String)
775: */
776: public void setTextContent(String arg0) throws DOMException {
777: // TODO Auto-generated method stub
778:
779: }
780:
781: /* (non-Javadoc)
782: * @see org.w3c.dom.Node#isSameNode(org.w3c.dom.Node)
783: */
784: public boolean isSameNode(Node arg0) {
785: // TODO Auto-generated method stub
786: return false;
787: }
788:
789: /* (non-Javadoc)
790: * @see org.w3c.dom.Node#lookupPrefix(java.lang.String)
791: */
792: public String lookupPrefix(String arg0) {
793: // TODO Auto-generated method stub
794: return null;
795: }
796:
797: /* (non-Javadoc)
798: * @see org.w3c.dom.Node#isDefaultNamespace(java.lang.String)
799: */
800: public boolean isDefaultNamespace(String arg0) {
801: // TODO Auto-generated method stub
802: return false;
803: }
804:
805: /* (non-Javadoc)
806: * @see org.w3c.dom.Node#lookupNamespaceURI(java.lang.String)
807: */
808: public String lookupNamespaceURI(String arg0) {
809: // TODO Auto-generated method stub
810: return null;
811: }
812:
813: /* (non-Javadoc)
814: * @see org.w3c.dom.Node#isEqualNode(org.w3c.dom.Node)
815: */
816: public boolean isEqualNode(Node arg0) {
817: // TODO Auto-generated method stub
818: return false;
819: }
820:
821: /* (non-Javadoc)
822: * @see org.w3c.dom.Node#getFeature(java.lang.String, java.lang.String)
823: */
824: public Object getFeature(String arg0, String arg1) {
825: // TODO Auto-generated method stub
826: return null;
827: }
828:
829: /* (non-Javadoc)
830: * @see org.w3c.dom.Node#setUserData(java.lang.String, java.lang.Object, org.w3c.dom.UserDataHandler)
831: */
832: public Object setUserData(String arg0, Object arg1,
833: UserDataHandler arg2) {
834: // TODO Auto-generated method stub
835: return null;
836: }
837:
838: /* (non-Javadoc)
839: * @see org.w3c.dom.Node#getUserData(java.lang.String)
840: */
841: public Object getUserData(String arg0) {
842: // TODO Auto-generated method stub
843: return null;
844: }
845:
846: /* (non-Javadoc)
847: * @see org.w3c.dom.Node#getNamespaceURI()
848: */
849: public String getNamespaceURI() {
850: // TODO Auto-generated method stub
851: return null;
852: }
853:
854: }
|