1/*
2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
3 */
4 /*
5 * Licensed to the Apache Software Foundation (ASF) under one or more
6 * contributor license agreements.  See the NOTICE file distributed with
7 * this work for additional information regarding copyright ownership.
8 * The ASF licenses this file to You under the Apache License, Version 2.0
9 * (the "License"); you may not use this file except in compliance with
10 * the License.  You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21package com.sun.org.apache.xerces.internal.dom;
22
23import java.io.IOException;
24import java.io.ObjectOutputStream;
25import java.io.Serializable;
26import java.util.Map;
27import org.w3c.dom.DOMException;
28import org.w3c.dom.Document;
29import org.w3c.dom.DocumentType;
30import org.w3c.dom.NamedNodeMap;
31import org.w3c.dom.Node;
32import org.w3c.dom.NodeList;
33import org.w3c.dom.UserDataHandler;
34import org.w3c.dom.events.Event;
35import org.w3c.dom.events.EventListener;
36import org.w3c.dom.events.EventTarget;
37
38/**
39 * NodeImpl provides the basic structure of a DOM tree. It is never used
40 * directly, but instead is subclassed to add type and data
41 * information, and additional methods, appropriate to each node of
42 * the tree. Only its subclasses should be instantiated -- and those,
43 * with the exception of Document itself, only through a specific
44 * Document's factory methods.
45 * <P>
46 * The Node interface provides shared behaviors such as siblings and
47 * children, both for consistancy and so that the most common tree
48 * operations may be performed without constantly having to downcast
49 * to specific node types. When there is no obvious mapping for one of
50 * these queries, it will respond with null.
51 * Note that the default behavior is that children are forbidden. To
52 * permit them, the subclass ParentNode overrides several methods.
53 * <P>
54 * NodeImpl also implements NodeList, so it can return itself in
55 * response to the getChildNodes() query. This eliminiates the need
56 * for a separate ChildNodeList object. Note that this is an
57 * IMPLEMENTATION DETAIL; applications should _never_ assume that
58 * this identity exists.
59 * <P>
60 * All nodes in a single document must originate
61 * in that document. (Note that this is much tighter than "must be
62 * same implementation") Nodes are all aware of their ownerDocument,
63 * and attempts to mismatch will throw WRONG_DOCUMENT_ERR.
64 * <P>
65 * However, to save memory not all nodes always have a direct reference
66 * to their ownerDocument. When a node is owned by another node it relies
67 * on its owner to store its ownerDocument. Parent nodes always store it
68 * though, so there is never more than one level of indirection.
69 * And when a node doesn't have an owner, ownerNode refers to its
70 * ownerDocument.
71 * <p>
72 * This class doesn't directly support mutation events, however, it still
73 * implements the EventTarget interface and forward all related calls to the
74 * document so that the document class do so.
75 *
76 * @xerces.internal
77 *
78 * @author Arnaud  Le Hors, IBM
79 * @author Joe Kesselman, IBM
80 * @since  PR-DOM-Level-1-19980818.
81 */
82public abstract class NodeImpl
83    implements Node, NodeList, EventTarget, Cloneable, Serializable{
84
85    //
86    // Constants
87    //
88
89
90    // TreePosition Constants.
91    // Taken from DOM L3 Node interface.
92    /**
93     * The node precedes the reference node.
94     */
95    public static final short TREE_POSITION_PRECEDING   = 0x01;
96    /**
97     * The node follows the reference node.
98     */
99    public static final short TREE_POSITION_FOLLOWING   = 0x02;
100    /**
101     * The node is an ancestor of the reference node.
102     */
103    public static final short TREE_POSITION_ANCESTOR    = 0x04;
104    /**
105     * The node is a descendant of the reference node.
106     */
107    public static final short TREE_POSITION_DESCENDANT  = 0x08;
108    /**
109     * The two nodes have an equivalent position. This is the case of two
110     * attributes that have the same <code>ownerElement</code>, and two
111     * nodes that are the same.
112     */
113    public static final short TREE_POSITION_EQUIVALENT  = 0x10;
114    /**
115     * The two nodes are the same. Two nodes that are the same have an
116     * equivalent position, though the reverse may not be true.
117     */
118    public static final short TREE_POSITION_SAME_NODE   = 0x20;
119    /**
120     * The two nodes are disconnected, they do not have any common ancestor.
121     * This is the case of two nodes that are not in the same document.
122     */
123    public static final short TREE_POSITION_DISCONNECTED = 0x00;
124
125
126    // DocumentPosition
127    public static final short DOCUMENT_POSITION_DISCONNECTED = 0x01;
128    public static final short DOCUMENT_POSITION_PRECEDING = 0x02;
129    public static final short DOCUMENT_POSITION_FOLLOWING = 0x04;
130    public static final short DOCUMENT_POSITION_CONTAINS = 0x08;
131    public static final short DOCUMENT_POSITION_IS_CONTAINED = 0x10;
132    public static final short DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20;
133
134    /** Serialization version. */
135    static final long serialVersionUID = -6316591992167219696L;
136
137    // public
138
139    /** Element definition node type. */
140    public static final short ELEMENT_DEFINITION_NODE = 21;
141
142    //
143    // Data
144    //
145
146    // links
147
148    protected NodeImpl ownerNode; // typically the parent but not always!
149
150    // data
151
152    protected short flags;
153
154    protected final static short READONLY     = 0x1<<0;
155    protected final static short SYNCDATA     = 0x1<<1;
156    protected final static short SYNCCHILDREN = 0x1<<2;
157    protected final static short OWNED        = 0x1<<3;
158    protected final static short FIRSTCHILD   = 0x1<<4;
159    protected final static short SPECIFIED    = 0x1<<5;
160    protected final static short IGNORABLEWS  = 0x1<<6;
161    protected final static short HASSTRING    = 0x1<<7;
162    protected final static short NORMALIZED = 0x1<<8;
163    protected final static short ID           = 0x1<<9;
164
165    //
166    // Constructors
167    //
168
169    /**
170     * No public constructor; only subclasses of Node should be
171     * instantiated, and those normally via a Document's factory methods
172     * <p>
173     * Every Node knows what Document it belongs to.
174     */
175    protected NodeImpl(CoreDocumentImpl ownerDocument) {
176        // as long as we do not have any owner, ownerNode is our ownerDocument
177        ownerNode = ownerDocument;
178    } // <init>(CoreDocumentImpl)
179
180    /** Constructor for serialization. */
181    public NodeImpl() {}
182
183    //
184    // Node methods
185    //
186
187    /**
188     * A short integer indicating what type of node this is. The named
189     * constants for this value are defined in the org.w3c.dom.Node interface.
190     */
191    public abstract short getNodeType();
192
193    /**
194     * the name of this node.
195     */
196    public abstract String getNodeName();
197
198    /**
199     * Returns the node value.
200     * @throws DOMException(DOMSTRING_SIZE_ERR)
201     */
202    public String getNodeValue()
203        throws DOMException {
204        return null;            // overridden in some subclasses
205    }
206
207    /**
208     * Sets the node value.
209     * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR)
210     */
211    public void setNodeValue(String x)
212        throws DOMException {
213        // Default behavior is to do nothing, overridden in some subclasses
214    }
215
216    /**
217     * Adds a child node to the end of the list of children for this node.
218     * Convenience shorthand for insertBefore(newChild,null).
219     * @see #insertBefore(Node, Node)
220     * <P>
221     * By default we do not accept any children, ParentNode overrides this.
222     * @see ParentNode
223     *
224     * @return newChild, in its new state (relocated, or emptied in the case of
225     * DocumentNode.)
226     *
227     * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a
228     * type that shouldn't be a child of this node.
229     *
230     * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a
231     * different owner document than we do.
232     *
233     * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
234     * read-only.
235     */
236    public Node appendChild(Node newChild) throws DOMException {
237        return insertBefore(newChild, null);
238    }
239
240    /**
241     * Returns a duplicate of a given node. You can consider this a
242     * generic "copy constructor" for nodes. The newly returned object should
243     * be completely independent of the source object's subtree, so changes
244     * in one after the clone has been made will not affect the other.
245     * <P>
246     * Note: since we never have any children deep is meaningless here,
247     * ParentNode overrides this behavior.
248     * @see ParentNode
249     *
250     * <p>
251     * Example: Cloning a Text node will copy both the node and the text it
252     * contains.
253     * <p>
254     * Example: Cloning something that has children -- Element or Attr, for
255     * example -- will _not_ clone those children unless a "deep clone"
256     * has been requested. A shallow clone of an Attr node will yield an
257     * empty Attr of the same name.
258     * <p>
259     * NOTE: Clones will always be read/write, even if the node being cloned
260     * is read-only, to permit applications using only the DOM API to obtain
261     * editable copies of locked portions of the tree.
262     */
263    public Node cloneNode(boolean deep) {
264
265        if (needsSyncData()) {
266            synchronizeData();
267        }
268
269        NodeImpl newnode;
270        try {
271            newnode = (NodeImpl)clone();
272        }
273        catch (CloneNotSupportedException e) {
274            // if we get here we have an error in our program we may as well
275            // be vocal about it, so that people can take appropriate action.
276            throw new RuntimeException("**Internal Error**" + e);
277        }
278
279        // Need to break the association w/ original kids
280        newnode.ownerNode      = ownerDocument();
281        newnode.isOwned(false);
282
283        // By default we make all clones readwrite,
284        // this is overriden in readonly subclasses
285        newnode.isReadOnly(false);
286
287        ownerDocument().callUserDataHandlers(this, newnode,
288                                             UserDataHandler.NODE_CLONED);
289
290        return newnode;
291
292    } // cloneNode(boolean):Node
293
294    /**
295     * Find the Document that this Node belongs to (the document in
296     * whose context the Node was created). The Node may or may not
297     * currently be part of that Document's actual contents.
298     */
299    public Document getOwnerDocument() {
300        // if we have an owner simply forward the request
301        // otherwise ownerNode is our ownerDocument
302        if (isOwned()) {
303            return ownerNode.ownerDocument();
304        } else {
305            return (Document) ownerNode;
306        }
307    }
308
309    /**
310     * same as above but returns internal type and this one is not overridden
311     * by CoreDocumentImpl to return null
312     */
313    CoreDocumentImpl ownerDocument() {
314        // if we have an owner simply forward the request
315        // otherwise ownerNode is our ownerDocument
316        if (isOwned()) {
317            return ownerNode.ownerDocument();
318        } else {
319            return (CoreDocumentImpl) ownerNode;
320        }
321    }
322
323    /**
324     * NON-DOM
325     * set the ownerDocument of this node
326     */
327    void setOwnerDocument(CoreDocumentImpl doc) {
328        if (needsSyncData()) {
329            synchronizeData();
330        }
331        // if we have an owner we rely on it to have it right
332        // otherwise ownerNode is our ownerDocument
333        if (!isOwned()) {
334            ownerNode = doc;
335        }
336    }
337
338    /**
339     * Returns the node number
340     */
341    protected int getNodeNumber() {
342        int nodeNumber;
343        CoreDocumentImpl cd = (CoreDocumentImpl)(this.getOwnerDocument());
344        nodeNumber = cd.getNodeNumber(this);
345        return nodeNumber;
346    }
347
348    /**
349     * Obtain the DOM-tree parent of this node, or null if it is not
350     * currently active in the DOM tree (perhaps because it has just been
351     * created or removed). Note that Document, DocumentFragment, and
352     * Attribute will never have parents.
353     */
354    public Node getParentNode() {
355        return null;            // overriden by ChildNode
356    }
357
358    /*
359     * same as above but returns internal type
360     */
361    NodeImpl parentNode() {
362        return null;
363    }
364
365    /** The next child of this node's parent, or null if none */
366    public Node getNextSibling() {
367        return null;            // default behavior, overriden in ChildNode
368    }
369
370    /** The previous child of this node's parent, or null if none */
371    public Node getPreviousSibling() {
372        return null;            // default behavior, overriden in ChildNode
373    }
374
375    ChildNode previousSibling() {
376        return null;            // default behavior, overriden in ChildNode
377    }
378
379    /**
380     * Return the collection of attributes associated with this node,
381     * or null if none. At this writing, Element is the only type of node
382     * which will ever have attributes.
383     *
384     * @see ElementImpl
385     */
386    public NamedNodeMap getAttributes() {
387        return null; // overridden in ElementImpl
388    }
389
390    /**
391     *  Returns whether this node (if it is an element) has any attributes.
392     * @return <code>true</code> if this node has any attributes,
393     *   <code>false</code> otherwise.
394     * @since DOM Level 2
395     * @see ElementImpl
396     */
397    public boolean hasAttributes() {
398        return false;           // overridden in ElementImpl
399    }
400
401    /**
402     * Test whether this node has any children. Convenience shorthand
403     * for (Node.getFirstChild()!=null)
404     * <P>
405     * By default we do not have any children, ParentNode overrides this.
406     * @see ParentNode
407     */
408    public boolean hasChildNodes() {
409        return false;
410    }
411
412    /**
413     * Obtain a NodeList enumerating all children of this node. If there
414     * are none, an (initially) empty NodeList is returned.
415     * <p>
416     * NodeLists are "live"; as children are added/removed the NodeList
417     * will immediately reflect those changes. Also, the NodeList refers
418     * to the actual nodes, so changes to those nodes made via the DOM tree
419     * will be reflected in the NodeList and vice versa.
420     * <p>
421     * In this implementation, Nodes implement the NodeList interface and
422     * provide their own getChildNodes() support. Other DOMs may solve this
423     * differently.
424     */
425    public NodeList getChildNodes() {
426        return this;
427    }
428
429    /** The first child of this Node, or null if none.
430     * <P>
431     * By default we do not have any children, ParentNode overrides this.
432     * @see ParentNode
433     */
434    public Node getFirstChild() {
435        return null;
436    }
437
438    /** The first child of this Node, or null if none.
439     * <P>
440     * By default we do not have any children, ParentNode overrides this.
441     * @see ParentNode
442     */
443    public Node getLastChild() {
444        return null;
445    }
446
447    /**
448     * Move one or more node(s) to our list of children. Note that this
449     * implicitly removes them from their previous parent.
450     * <P>
451     * By default we do not accept any children, ParentNode overrides this.
452     * @see ParentNode
453     *
454     * @param newChild The Node to be moved to our subtree. As a
455     * convenience feature, inserting a DocumentNode will instead insert
456     * all its children.
457     *
458     * @param refChild Current child which newChild should be placed
459     * immediately before. If refChild is null, the insertion occurs
460     * after all existing Nodes, like appendChild().
461     *
462     * @return newChild, in its new state (relocated, or emptied in the case of
463     * DocumentNode.)
464     *
465     * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a
466     * type that shouldn't be a child of this node, or if newChild is an
467     * ancestor of this node.
468     *
469     * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a
470     * different owner document than we do.
471     *
472     * @throws DOMException(NOT_FOUND_ERR) if refChild is not a child of
473     * this node.
474     *
475     * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
476     * read-only.
477     */
478    public Node insertBefore(Node newChild, Node refChild)
479        throws DOMException {
480        throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
481              DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
482                 "HIERARCHY_REQUEST_ERR", null));
483    }
484
485    /**
486     * Remove a child from this Node. The removed child's subtree
487     * remains intact so it may be re-inserted elsewhere.
488     * <P>
489     * By default we do not have any children, ParentNode overrides this.
490     * @see ParentNode
491     *
492     * @return oldChild, in its new state (removed).
493     *
494     * @throws DOMException(NOT_FOUND_ERR) if oldChild is not a child of
495     * this node.
496     *
497     * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
498     * read-only.
499     */
500    public Node removeChild(Node oldChild)
501                throws DOMException {
502        throw new DOMException(DOMException.NOT_FOUND_ERR,
503              DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
504                 "NOT_FOUND_ERR", null));
505    }
506
507    /**
508     * Make newChild occupy the location that oldChild used to
509     * have. Note that newChild will first be removed from its previous
510     * parent, if any. Equivalent to inserting newChild before oldChild,
511     * then removing oldChild.
512     * <P>
513     * By default we do not have any children, ParentNode overrides this.
514     * @see ParentNode
515     *
516     * @return oldChild, in its new state (removed).
517     *
518     * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a
519     * type that shouldn't be a child of this node, or if newChild is
520     * one of our ancestors.
521     *
522     * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a
523     * different owner document than we do.
524     *
525     * @throws DOMException(NOT_FOUND_ERR) if oldChild is not a child of
526     * this node.
527     *
528     * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
529     * read-only.
530     */
531    public Node replaceChild(Node newChild, Node oldChild)
532        throws DOMException {
533        throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
534              DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
535                 "HIERARCHY_REQUEST_ERR", null));
536    }
537
538    //
539    // NodeList methods
540    //
541
542    /**
543     * NodeList method: Count the immediate children of this node
544     * <P>
545     * By default we do not have any children, ParentNode overrides this.
546     * @see ParentNode
547     *
548     * @return int
549     */
550    public int getLength() {
551        return 0;
552    }
553
554    /**
555     * NodeList method: Return the Nth immediate child of this node, or
556     * null if the index is out of bounds.
557     * <P>
558     * By default we do not have any children, ParentNode overrides this.
559     * @see ParentNode
560     *
561     * @return org.w3c.dom.Node
562     * @param Index int
563     */
564    public Node item(int index) {
565        return null;
566    }
567
568    //
569    // DOM2: methods, getters, setters
570    //
571
572    /**
573     * Puts all <code>Text</code> nodes in the full depth of the sub-tree
574     * underneath this <code>Node</code>, including attribute nodes, into a
575     * "normal" form where only markup (e.g., tags, comments, processing
576     * instructions, CDATA sections, and entity references) separates
577     * <code>Text</code> nodes, i.e., there are no adjacent <code>Text</code>
578     * nodes.  This can be used to ensure that the DOM view of a document is
579     * the same as if it were saved and re-loaded, and is useful when
580     * operations (such as XPointer lookups) that depend on a particular
581     * document tree structure are to be used.In cases where the document
582     * contains <code>CDATASections</code>, the normalize operation alone may
583     * not be sufficient, since XPointers do not differentiate between
584     * <code>Text</code> nodes and <code>CDATASection</code> nodes.
585     * <p>
586     * Note that this implementation simply calls normalize() on this Node's
587     * children. It is up to implementors or Node to override normalize()
588     * to take action.
589     */
590    public void normalize() {
591        /* by default we do not have any children,
592           ParentNode overrides this behavior */
593    }
594
595    /**
596     * Introduced in DOM Level 2. <p>
597     * Tests whether the DOM implementation implements a specific feature and
598     * that feature is supported by this node.
599     * @param feature The package name of the feature to test. This is the same
600     * name as what can be passed to the method hasFeature on
601     * DOMImplementation.
602     * @param version This is the version number of the package name to
603     * test. In Level 2, version 1, this is the string "2.0". If the version is
604     * not specified, supporting any version of the feature will cause the
605     * method to return true.
606     * @return boolean Returns true if this node defines a subtree within which
607     * the specified feature is supported, false otherwise.
608     * @since WD-DOM-Level-2-19990923
609     */
610    public boolean isSupported(String feature, String version)
611    {
612        return ownerDocument().getImplementation().hasFeature(feature,
613                                                              version);
614    }
615
616    /**
617     * Introduced in DOM Level 2. <p>
618     *
619     * The namespace URI of this node, or null if it is unspecified. When this
620     * node is of any type other than ELEMENT_NODE and ATTRIBUTE_NODE, this is
621     * always null and setting it has no effect. <p>
622     *
623     * This is not a computed value that is the result of a namespace lookup
624     * based on an examination of the namespace declarations in scope. It is
625     * merely the namespace URI given at creation time.<p>
626     *
627     * For nodes created with a DOM Level 1 method, such as createElement
628     * from the Document interface, this is null.
629     * @since WD-DOM-Level-2-19990923
630     * @see AttrNSImpl
631     * @see ElementNSImpl
632     */
633    public String getNamespaceURI()
634    {
635        return null;
636    }
637
638    /**
639     * Introduced in DOM Level 2. <p>
640     *
641     * The namespace prefix of this node, or null if it is unspecified. When
642     * this node is of any type other than ELEMENT_NODE and ATTRIBUTE_NODE this
643     * is always null and setting it has no effect.<p>
644     *
645     * For nodes created with a DOM Level 1 method, such as createElement
646     * from the Document interface, this is null. <p>
647     *
648     * @since WD-DOM-Level-2-19990923
649     * @see AttrNSImpl
650     * @see ElementNSImpl
651     */
652    public String getPrefix()
653    {
654        return null;
655    }
656
657    /**
658     *  Introduced in DOM Level 2. <p>
659     *
660     *  The namespace prefix of this node, or null if it is unspecified. When
661     *  this node is of any type other than ELEMENT_NODE and ATTRIBUTE_NODE
662     *  this is always null and setting it has no effect.<p>
663     *
664     *  For nodes created with a DOM Level 1 method, such as createElement from
665     *  the Document interface, this is null.<p>
666     *
667     *  Note that setting this attribute changes the nodeName attribute, which
668     *  holds the qualified name, as well as the tagName and name attributes of
669     *  the Element and Attr interfaces, when applicable.<p>
670     *
671     * @throws INVALID_CHARACTER_ERR Raised if the specified
672     *  prefix contains an invalid character.
673     *
674     * @since WD-DOM-Level-2-19990923
675     * @see AttrNSImpl
676     * @see ElementNSImpl
677     */
678    public void setPrefix(String prefix)
679        throws DOMException
680    {
681        throw new DOMException(DOMException.NAMESPACE_ERR,
682              DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
683                 "NAMESPACE_ERR", null));
684    }
685
686    /**
687     * Introduced in DOM Level 2. <p>
688     *
689     * Returns the local part of the qualified name of this node.
690     * For nodes created with a DOM Level 1 method, such as createElement
691     * from the Document interface, and for nodes of any type other than
692     * ELEMENT_NODE and ATTRIBUTE_NODE this is the same as the nodeName
693     * attribute.
694     * @since WD-DOM-Level-2-19990923
695     * @see AttrNSImpl
696     * @see ElementNSImpl
697     */
698    public String             getLocalName()
699    {
700        return null;
701    }
702
703    //
704    // EventTarget support
705    //
706
707    public void addEventListener(String type, EventListener listener,
708                                 boolean useCapture) {
709        // simply forward to Document
710        ownerDocument().addEventListener(this, type, listener, useCapture);
711    }
712
713    public void removeEventListener(String type, EventListener listener,
714                                    boolean useCapture) {
715        // simply forward to Document
716        ownerDocument().removeEventListener(this, type, listener, useCapture);
717    }
718
719    public boolean dispatchEvent(Event event) {
720        // simply forward to Document
721        return ownerDocument().dispatchEvent(this, event);
722    }
723
724    //
725    // Public DOM Level 3 methods
726    //
727
728    /**
729     * The absolute base URI of this node or <code>null</code> if undefined.
730     * This value is computed according to . However, when the
731     * <code>Document</code> supports the feature "HTML" , the base URI is
732     * computed using first the value of the href attribute of the HTML BASE
733     * element if any, and the value of the <code>documentURI</code>
734     * attribute from the <code>Document</code> interface otherwise.
735     * <br> When the node is an <code>Element</code>, a <code>Document</code>
736     * or a a <code>ProcessingInstruction</code>, this attribute represents
737     * the properties [base URI] defined in . When the node is a
738     * <code>Notation</code>, an <code>Entity</code>, or an
739     * <code>EntityReference</code>, this attribute represents the
740     * properties [declaration base URI] in the . How will this be affected
741     * by resolution of relative namespace URIs issue?It's not.Should this
742     * only be on Document, Element, ProcessingInstruction, Entity, and
743     * Notation nodes, according to the infoset? If not, what is it equal to
744     * on other nodes? Null? An empty string? I think it should be the
745     * parent's.No.Should this be read-only and computed or and actual
746     * read-write attribute?Read-only and computed (F2F 19 Jun 2000 and
747     * teleconference 30 May 2001).If the base HTML element is not yet
748     * attached to a document, does the insert change the Document.baseURI?
749     * Yes. (F2F 26 Sep 2001)
750     * @since DOM Level 3
751     */
752    public String getBaseURI() {
753        return null;
754    }
755
756    /**
757     * Compares a node with this node with regard to their position in the
758     * tree and according to the document order. This order can be extended
759     * by module that define additional types of nodes.
760     * @param other The node to compare against this node.
761     * @return Returns how the given node is positioned relatively to this
762     *   node.
763     * @since DOM Level 3
764     * @deprecated
765     */
766    public short compareTreePosition(Node other) {
767        // Questions of clarification for this method - to be answered by the
768        // DOM WG.   Current assumptions listed - LM
769        //
770        // 1. How do ENTITY nodes compare?
771        //    Current assumption: TREE_POSITION_DISCONNECTED, as ENTITY nodes
772        //    aren't really 'in the tree'
773        //
774        // 2. How do NOTATION nodes compare?
775        //    Current assumption: TREE_POSITION_DISCONNECTED, as NOTATION nodes
776        //    aren't really 'in the tree'
777        //
778        // 3. Are TREE_POSITION_ANCESTOR and TREE_POSITION_DESCENDANT
779        //    only relevant for nodes that are "part of the document tree"?
780        //     <outer>
781        //         <inner  myattr="true"/>
782        //     </outer>
783        //    Is the element node "outer" considered an ancestor of "myattr"?
784        //    Current assumption: No.
785        //
786        // 4. How do children of ATTRIBUTE nodes compare (with eachother, or
787        //    with children of other attribute nodes with the same element)
788        //    Current assumption: Children of ATTRIBUTE nodes are treated as if
789        //    they they are the attribute node itself, unless the 2 nodes
790        //    are both children of the same attribute.
791        //
792        // 5. How does an ENTITY_REFERENCE node compare with it's children?
793        //    Given the DOM, it should precede its children as an ancestor.
794        //    Given "document order",  does it represent the same position?
795        //    Current assumption: An ENTITY_REFERENCE node is an ancestor of its
796        //    children.
797        //
798        // 6. How do children of a DocumentFragment compare?
799        //    Current assumption: If both nodes are part of the same document
800        //    fragment, there are compared as if they were part of a document.
801
802
803        // If the nodes are the same...
804        if (this==other)
805          return (TREE_POSITION_SAME_NODE | TREE_POSITION_EQUIVALENT);
806
807        // If either node is of type ENTITY or NOTATION, compare as disconnected
808        short thisType = this.getNodeType();
809        short otherType = other.getNodeType();
810
811        // If either node is of type ENTITY or NOTATION, compare as disconnected
812        if (thisType == Node.ENTITY_NODE ||
813            thisType == Node.NOTATION_NODE ||
814            otherType == Node.ENTITY_NODE ||
815            otherType == Node.NOTATION_NODE ) {
816          return TREE_POSITION_DISCONNECTED;
817        }
818
819        // Find the ancestor of each node, and the distance each node is from
820        // its ancestor.
821        // During this traversal, look for ancestor/descendent relationships
822        // between the 2 nodes in question.
823        // We do this now, so that we get this info correct for attribute nodes
824        // and their children.
825
826        Node node;
827        Node thisAncestor = this;
828        Node otherAncestor = other;
829        int thisDepth=0;
830        int otherDepth=0;
831        for (node=this; node != null; node = node.getParentNode()) {
832            thisDepth +=1;
833            if (node == other)
834              // The other node is an ancestor of this one.
835              return (TREE_POSITION_ANCESTOR | TREE_POSITION_PRECEDING);
836            thisAncestor = node;
837        }
838
839        for (node=other; node!=null; node=node.getParentNode()) {
840            otherDepth +=1;
841            if (node == this)
842              // The other node is a descendent of the reference node.
843              return (TREE_POSITION_DESCENDANT | TREE_POSITION_FOLLOWING);
844            otherAncestor = node;
845        }
846
847
848        Node thisNode = this;
849        Node otherNode = other;
850
851        int thisAncestorType = thisAncestor.getNodeType();
852        int otherAncestorType = otherAncestor.getNodeType();
853
854        // if the ancestor is an attribute, get owning element.
855        // we are now interested in the owner to determine position.
856
857        if (thisAncestorType == Node.ATTRIBUTE_NODE)  {
858           thisNode = ((AttrImpl)thisAncestor).getOwnerElement();
859        }
860        if (otherAncestorType == Node.ATTRIBUTE_NODE) {
861           otherNode = ((AttrImpl)otherAncestor).getOwnerElement();
862        }
863
864        // Before proceeding, we should check if both ancestor nodes turned
865        // out to be attributes for the same element
866        if (thisAncestorType == Node.ATTRIBUTE_NODE &&
867            otherAncestorType == Node.ATTRIBUTE_NODE &&
868            thisNode==otherNode)
869            return TREE_POSITION_EQUIVALENT;
870
871        // Now, find the ancestor of the owning element, if the original
872        // ancestor was an attribute
873
874        // Note:  the following 2 loops are quite close to the ones above.
875        // May want to common them up.  LM.
876        if (thisAncestorType == Node.ATTRIBUTE_NODE) {
877            thisDepth=0;
878            for (node=thisNode; node != null; node=node.getParentNode()) {
879                thisDepth +=1;
880                if (node == otherNode)
881                  // The other node is an ancestor of the owning element
882                  {
883                  return TREE_POSITION_PRECEDING;
884                  }
885                thisAncestor = node;
886            }
887        }
888
889        // Now, find the ancestor of the owning element, if the original
890        // ancestor was an attribute
891        if (otherAncestorType == Node.ATTRIBUTE_NODE) {
892            otherDepth=0;
893            for (node=otherNode; node != null; node=node.getParentNode()) {
894                otherDepth +=1;
895                if (node == thisNode)
896                  // The other node is a descendent of the reference
897                  // node's element
898                  return TREE_POSITION_FOLLOWING;
899                otherAncestor = node;
900            }
901        }
902
903        // thisAncestor and otherAncestor must be the same at this point,
904        // otherwise, we are not in the same tree or document fragment
905        if (thisAncestor != otherAncestor)
906          return TREE_POSITION_DISCONNECTED;
907
908
909        // Go up the parent chain of the deeper node, until we find a node
910        // with the same depth as the shallower node
911
912        if (thisDepth > otherDepth) {
913          for (int i=0; i<thisDepth - otherDepth; i++)
914            thisNode = thisNode.getParentNode();
915          // Check if the node we have reached is in fact "otherNode". This can
916          // happen in the case of attributes.  In this case, otherNode
917          // "precedes" this.
918          if (thisNode == otherNode)
919            return TREE_POSITION_PRECEDING;
920        }
921
922        else {
923          for (int i=0; i<otherDepth - thisDepth; i++)
924            otherNode = otherNode.getParentNode();
925          // Check if the node we have reached is in fact "thisNode".  This can
926          // happen in the case of attributes.  In this case, otherNode
927          // "follows" this.
928          if (otherNode == thisNode)
929            return TREE_POSITION_FOLLOWING;
930        }
931
932        // We now have nodes at the same depth in the tree.  Find a common
933        // ancestor.
934        Node thisNodeP, otherNodeP;
935        for (thisNodeP=thisNode.getParentNode(),
936                  otherNodeP=otherNode.getParentNode();
937             thisNodeP!=otherNodeP;) {
938             thisNode = thisNodeP;
939             otherNode = otherNodeP;
940             thisNodeP = thisNodeP.getParentNode();
941             otherNodeP = otherNodeP.getParentNode();
942        }
943
944        // At this point, thisNode and otherNode are direct children of
945        // the common ancestor.
946        // See whether thisNode or otherNode is the leftmost
947
948        for (Node current=thisNodeP.getFirstChild();
949                  current!=null;
950                  current=current.getNextSibling()) {
951               if (current==otherNode) {
952                 return TREE_POSITION_PRECEDING;
953               }
954               else if (current==thisNode) {
955                 return TREE_POSITION_FOLLOWING;
956               }
957        }
958        // REVISIT:  shouldn't get here.   Should probably throw an
959        // exception
960        return 0;
961
962    }
963    /**
964     * Compares a node with this node with regard to their position in the
965     * document.
966     * @param other The node to compare against this node.
967     * @return Returns how the given node is positioned relatively to this
968     *   node.
969     * @since DOM Level 3
970     */
971    public short compareDocumentPosition(Node other) throws DOMException {
972
973        // If the nodes are the same, no flags should be set
974        if (this==other)
975          return 0;
976
977        // check if other is from a different implementation
978        try {
979            NodeImpl node = (NodeImpl) other;
980        } catch (ClassCastException e) {
981            // other comes from a different implementation
982            String msg = DOMMessageFormatter.formatMessage(
983               DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
984            throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
985        }
986
987        Document thisOwnerDoc, otherOwnerDoc;
988        // get the respective Document owners.
989        if (this.getNodeType() == Node.DOCUMENT_NODE)
990          thisOwnerDoc = (Document)this;
991        else
992          thisOwnerDoc = this.getOwnerDocument();
993        if (other.getNodeType() == Node.DOCUMENT_NODE)
994          otherOwnerDoc = (Document)other;
995        else
996          otherOwnerDoc = other.getOwnerDocument();
997
998        // If from different documents, we know they are disconnected.
999        // and have an implementation dependent order
1000        if (thisOwnerDoc != otherOwnerDoc &&
1001            thisOwnerDoc !=null &&
1002            otherOwnerDoc !=null)
1003 {
1004          int otherDocNum = ((CoreDocumentImpl)otherOwnerDoc).getNodeNumber();
1005          int thisDocNum = ((CoreDocumentImpl)thisOwnerDoc).getNodeNumber();
1006          if (otherDocNum > thisDocNum)
1007            return DOCUMENT_POSITION_DISCONNECTED |
1008                   DOCUMENT_POSITION_FOLLOWING |
1009                   DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
1010          else
1011            return DOCUMENT_POSITION_DISCONNECTED |
1012                   DOCUMENT_POSITION_PRECEDING |
1013                   DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
1014
1015        }
1016
1017        // Find the ancestor of each node, and the distance each node is from
1018        // its ancestor.
1019        // During this traversal, look for ancestor/descendent relationships
1020        // between the 2 nodes in question.
1021        // We do this now, so that we get this info correct for attribute nodes
1022        // and their children.
1023
1024        Node node;
1025        Node thisAncestor = this;
1026        Node otherAncestor = other;
1027
1028        int thisDepth=0;
1029        int otherDepth=0;
1030        for (node=this; node != null; node = node.getParentNode()) {
1031            thisDepth +=1;
1032            if (node == other)
1033              // The other node is an ancestor of this one.
1034              return (DOCUMENT_POSITION_CONTAINS |
1035                      DOCUMENT_POSITION_PRECEDING);
1036            thisAncestor = node;
1037        }
1038
1039        for (node=other; node!=null; node=node.getParentNode()) {
1040            otherDepth +=1;
1041            if (node == this)
1042              // The other node is a descendent of the reference node.
1043              return (DOCUMENT_POSITION_IS_CONTAINED |
1044                      DOCUMENT_POSITION_FOLLOWING);
1045            otherAncestor = node;
1046        }
1047
1048
1049
1050        int thisAncestorType = thisAncestor.getNodeType();
1051        int otherAncestorType = otherAncestor.getNodeType();
1052        Node thisNode = this;
1053        Node otherNode = other;
1054
1055        // Special casing for ENTITY, NOTATION, DOCTYPE and ATTRIBUTES
1056        // LM:  should rewrite this.
1057        switch (thisAncestorType) {
1058          case Node.NOTATION_NODE:
1059          case Node.ENTITY_NODE: {
1060            DocumentType container = thisOwnerDoc.getDoctype();
1061            if (container == otherAncestor) return
1062                   (DOCUMENT_POSITION_CONTAINS | DOCUMENT_POSITION_PRECEDING);
1063            switch (otherAncestorType) {
1064              case Node.NOTATION_NODE:
1065              case Node.ENTITY_NODE:  {
1066                if (thisAncestorType != otherAncestorType)
1067                 // the nodes are of different types
1068                 return ((thisAncestorType>otherAncestorType) ?
1069                    DOCUMENT_POSITION_PRECEDING:DOCUMENT_POSITION_FOLLOWING);
1070                else {
1071                 // the nodes are of the same type.  Find order.
1072                 if (thisAncestorType == Node.NOTATION_NODE)
1073
1074                     if (((NamedNodeMapImpl)container.getNotations()).precedes(otherAncestor,thisAncestor))
1075                       return (DOCUMENT_POSITION_PRECEDING |
1076                               DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
1077                     else
1078                       return (DOCUMENT_POSITION_FOLLOWING |
1079                               DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
1080                 else
1081                     if (((NamedNodeMapImpl)container.getEntities()).precedes(otherAncestor,thisAncestor))
1082                       return (DOCUMENT_POSITION_PRECEDING |
1083                               DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
1084                     else
1085                       return (DOCUMENT_POSITION_FOLLOWING |
1086                               DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
1087                }
1088              }
1089            }
1090            thisNode = thisAncestor = thisOwnerDoc;
1091            break;
1092          }
1093          case Node.DOCUMENT_TYPE_NODE: {
1094            if (otherNode == thisOwnerDoc)
1095              return (DOCUMENT_POSITION_PRECEDING |
1096                      DOCUMENT_POSITION_CONTAINS);
1097            else if (thisOwnerDoc!=null && thisOwnerDoc==otherOwnerDoc)
1098              return (DOCUMENT_POSITION_FOLLOWING);
1099            break;
1100          }
1101          case Node.ATTRIBUTE_NODE: {
1102            thisNode = ((AttrImpl)thisAncestor).getOwnerElement();
1103            if (otherAncestorType==Node.ATTRIBUTE_NODE) {
1104              otherNode = ((AttrImpl)otherAncestor).getOwnerElement();
1105              if (otherNode == thisNode) {
1106                if (((NamedNodeMapImpl)thisNode.getAttributes()).precedes(other,this))
1107                  return (DOCUMENT_POSITION_PRECEDING |
1108                          DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
1109                else
1110                  return (DOCUMENT_POSITION_FOLLOWING |
1111                          DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
1112              }
1113            }
1114
1115            // Now, find the ancestor of the element
1116            thisDepth=0;
1117            for (node=thisNode; node != null; node=node.getParentNode()) {
1118                thisDepth +=1;
1119                if (node == otherNode)
1120                  {
1121                  // The other node is an ancestor of the owning element
1122                  return (DOCUMENT_POSITION_CONTAINS |
1123                          DOCUMENT_POSITION_PRECEDING);
1124                  }
1125                thisAncestor = node;
1126            }
1127          }
1128        }
1129        switch (otherAncestorType) {
1130          case Node.NOTATION_NODE:
1131          case Node.ENTITY_NODE: {
1132          DocumentType container = thisOwnerDoc.getDoctype();
1133            if (container == this) return (DOCUMENT_POSITION_IS_CONTAINED |
1134                                          DOCUMENT_POSITION_FOLLOWING);
1135            otherNode = otherAncestor = thisOwnerDoc;
1136            break;
1137          }
1138          case Node.DOCUMENT_TYPE_NODE: {
1139            if (thisNode == otherOwnerDoc)
1140              return (DOCUMENT_POSITION_FOLLOWING |
1141                      DOCUMENT_POSITION_IS_CONTAINED);
1142            else if (otherOwnerDoc!=null && thisOwnerDoc==otherOwnerDoc)
1143              return (DOCUMENT_POSITION_PRECEDING);
1144            break;
1145          }
1146          case Node.ATTRIBUTE_NODE: {
1147            otherDepth=0;
1148            otherNode = ((AttrImpl)otherAncestor).getOwnerElement();
1149            for (node=otherNode; node != null; node=node.getParentNode()) {
1150                otherDepth +=1;
1151                if (node == thisNode)
1152                  // The other node is a descendent of the reference
1153                  // node's element
1154                  return DOCUMENT_POSITION_FOLLOWING |
1155                         DOCUMENT_POSITION_IS_CONTAINED;
1156                otherAncestor = node;
1157            }
1158
1159          }
1160        }
1161
1162        // thisAncestor and otherAncestor must be the same at this point,
1163        // otherwise, the original nodes are disconnected
1164        if (thisAncestor != otherAncestor) {
1165          int thisAncestorNum, otherAncestorNum;
1166          thisAncestorNum = ((NodeImpl)thisAncestor).getNodeNumber();
1167          otherAncestorNum = ((NodeImpl)otherAncestor).getNodeNumber();
1168
1169          if (thisAncestorNum > otherAncestorNum)
1170            return DOCUMENT_POSITION_DISCONNECTED |
1171                   DOCUMENT_POSITION_FOLLOWING |
1172                   DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
1173          else
1174            return DOCUMENT_POSITION_DISCONNECTED |
1175                   DOCUMENT_POSITION_PRECEDING |
1176                   DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
1177        }
1178
1179
1180        // Go up the parent chain of the deeper node, until we find a node
1181        // with the same depth as the shallower node
1182
1183        if (thisDepth > otherDepth) {
1184          for (int i=0; i<thisDepth - otherDepth; i++)
1185            thisNode = thisNode.getParentNode();
1186          // Check if the node we have reached is in fact "otherNode". This can
1187          // happen in the case of attributes.  In this case, otherNode
1188          // "precedes" this.
1189          if (thisNode == otherNode)
1190{
1191            return DOCUMENT_POSITION_PRECEDING;
1192          }
1193        }
1194
1195        else {
1196          for (int i=0; i<otherDepth - thisDepth; i++)
1197            otherNode = otherNode.getParentNode();
1198          // Check if the node we have reached is in fact "thisNode".  This can
1199          // happen in the case of attributes.  In this case, otherNode
1200          // "follows" this.
1201          if (otherNode == thisNode)
1202            return DOCUMENT_POSITION_FOLLOWING;
1203        }
1204
1205        // We now have nodes at the same depth in the tree.  Find a common
1206        // ancestor.
1207        Node thisNodeP, otherNodeP;
1208        for (thisNodeP=thisNode.getParentNode(),
1209                  otherNodeP=otherNode.getParentNode();
1210             thisNodeP!=otherNodeP;) {
1211             thisNode = thisNodeP;
1212             otherNode = otherNodeP;
1213             thisNodeP = thisNodeP.getParentNode();
1214             otherNodeP = otherNodeP.getParentNode();
1215        }
1216
1217        // At this point, thisNode and otherNode are direct children of
1218        // the common ancestor.
1219        // See whether thisNode or otherNode is the leftmost
1220
1221        for (Node current=thisNodeP.getFirstChild();
1222                  current!=null;
1223                  current=current.getNextSibling()) {
1224               if (current==otherNode) {
1225                 return DOCUMENT_POSITION_PRECEDING;
1226               }
1227               else if (current==thisNode) {
1228                 return DOCUMENT_POSITION_FOLLOWING;
1229               }
1230        }
1231        // REVISIT:  shouldn't get here.   Should probably throw an
1232        // exception
1233        return 0;
1234
1235    }
1236
1237    /**
1238     * This attribute returns the text content of this node and its
1239     * descendants. When it is defined to be null, setting it has no effect.
1240     * When set, any possible children this node may have are removed and
1241     * replaced by a single <code>Text</code> node containing the string
1242     * this attribute is set to. On getting, no serialization is performed,
1243     * the returned string does not contain any markup. No whitespace
1244     * normalization is performed, the returned string does not contain the
1245     * element content whitespaces . Similarly, on setting, no parsing is
1246     * performed either, the input string is taken as pure textual content.
1247     * <br>The string returned is made of the text content of this node
1248     * depending on its type, as defined below:
1249     * <table border='1'>
1250     * <tr>
1251     * <th>Node type</th>
1252     * <th>Content</th>
1253     * </tr>
1254
1255    /**
1256     * This attribute returns the text content of this node and its
1257     * descendants. When it is defined to be null, setting it has no effect.
1258     * When set, any possible children this node may have are removed and
1259     * replaced by a single <code>Text</code> node containing the string
1260     * this attribute is set to. On getting, no serialization is performed,
1261     * the returned string does not contain any markup. No whitespace
1262     * normalization is performed, the returned string does not contain the
1263     * element content whitespaces . Similarly, on setting, no parsing is
1264     * performed either, the input string is taken as pure textual content.
1265     * <br>The string returned is made of the text content of this node
1266     * depending on its type, as defined below:
1267     * <table border='1'>
1268     * <tr>
1269     * <th>Node type</th>
1270     * <th>Content</th>
1271     * </tr>
1272     * <tr>
1273     * <td valign='top' rowspan='1' colspan='1'>
1274     * ELEMENT_NODE, ENTITY_NODE, ENTITY_REFERENCE_NODE,
1275     * DOCUMENT_FRAGMENT_NODE</td>
1276     * <td valign='top' rowspan='1' colspan='1'>concatenation of the <code>textContent</code>
1277     * attribute value of every child node, excluding COMMENT_NODE and
1278     * PROCESSING_INSTRUCTION_NODE nodes</td>
1279     * </tr>
1280     * <tr>
1281     * <td valign='top' rowspan='1' colspan='1'>ATTRIBUTE_NODE, TEXT_NODE,
1282     * CDATA_SECTION_NODE, COMMENT_NODE, PROCESSING_INSTRUCTION_NODE</td>
1283     * <td valign='top' rowspan='1' colspan='1'>
1284     * <code>nodeValue</code></td>
1285     * </tr>
1286     * <tr>
1287     * <td valign='top' rowspan='1' colspan='1'>DOCUMENT_NODE, DOCUMENT_TYPE_NODE, NOTATION_NODE</td>
1288     * <td valign='top' rowspan='1' colspan='1'>
1289     * null</td>
1290     * </tr>
1291     * </table>
1292     * @exception DOMException
1293     *   NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
1294     * @exception DOMException
1295     *   DOMSTRING_SIZE_ERR: Raised when it would return more characters than
1296     *   fit in a <code>DOMString</code> variable on the implementation
1297     *   platform.
1298     * @since DOM Level 3
1299     */
1300    public String getTextContent() throws DOMException {
1301        return getNodeValue();  // overriden in some subclasses
1302    }
1303
1304    // internal method taking a StringBuffer in parameter
1305    void getTextContent(StringBuffer buf) throws DOMException {
1306        String content = getNodeValue();
1307        if (content != null) {
1308            buf.append(content);
1309        }
1310    }
1311
1312    /**
1313     * This attribute returns the text content of this node and its
1314     * descendants. When it is defined to be null, setting it has no effect.
1315     * When set, any possible children this node may have are removed and
1316     * replaced by a single <code>Text</code> node containing the string
1317     * this attribute is set to. On getting, no serialization is performed,
1318     * the returned string does not contain any markup. No whitespace
1319     * normalization is performed, the returned string does not contain the
1320     * element content whitespaces . Similarly, on setting, no parsing is
1321     * performed either, the input string is taken as pure textual content.
1322     * <br>The string returned is made of the text content of this node
1323     * depending on its type, as defined below:
1324     * <table border='1'>
1325     * <tr>
1326     * <th>Node type</th>
1327     * <th>Content</th>
1328     * </tr>
1329     * <tr>
1330     * <td valign='top' rowspan='1' colspan='1'>
1331     * ELEMENT_NODE, ENTITY_NODE, ENTITY_REFERENCE_NODE,
1332     * DOCUMENT_FRAGMENT_NODE</td>
1333     * <td valign='top' rowspan='1' colspan='1'>concatenation of the <code>textContent</code>
1334     * attribute value of every child node, excluding COMMENT_NODE and
1335     * PROCESSING_INSTRUCTION_NODE nodes</td>
1336     * </tr>
1337     * <tr>
1338     * <td valign='top' rowspan='1' colspan='1'>ATTRIBUTE_NODE, TEXT_NODE,
1339     * CDATA_SECTION_NODE, COMMENT_NODE, PROCESSING_INSTRUCTION_NODE</td>
1340     * <td valign='top' rowspan='1' colspan='1'>
1341     * <code>nodeValue</code></td>
1342     * </tr>
1343     * <tr>
1344     * <td valign='top' rowspan='1' colspan='1'>DOCUMENT_NODE, DOCUMENT_TYPE_NODE, NOTATION_NODE</td>
1345     * <td valign='top' rowspan='1' colspan='1'>
1346     * null</td>
1347     * </tr>
1348     * </table>
1349     * @exception DOMException
1350     *   NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
1351     * @exception DOMException
1352     *   DOMSTRING_SIZE_ERR: Raised when it would return more characters than
1353     *   fit in a <code>DOMString</code> variable on the implementation
1354     *   platform.
1355     * @since DOM Level 3
1356     */
1357    public void setTextContent(String textContent)
1358        throws DOMException {
1359        setNodeValue(textContent);
1360    }
1361
1362    /**
1363     * Returns whether this node is the same node as the given one.
1364     * <br>This method provides a way to determine whether two
1365     * <code>Node</code> references returned by the implementation reference
1366     * the same object. When two <code>Node</code> references are references
1367     * to the same object, even if through a proxy, the references may be
1368     * used completely interchangably, such that all attributes have the
1369     * same values and calling the same DOM method on either reference
1370     * always has exactly the same effect.
1371     * @param other The node to test against.
1372     * @return Returns <code>true</code> if the nodes are the same,
1373     *   <code>false</code> otherwise.
1374     * @since DOM Level 3
1375     */
1376    public boolean isSameNode(Node other) {
1377        // we do not use any wrapper so the answer is obvious
1378        return this == other;
1379    }
1380
1381
1382
1383
1384    /**
1385     *  DOM Level 3: Experimental
1386     *  This method checks if the specified <code>namespaceURI</code> is the
1387     *  default namespace or not.
1388     *  @param namespaceURI The namespace URI to look for.
1389     *  @return  <code>true</code> if the specified <code>namespaceURI</code>
1390     *   is the default namespace, <code>false</code> otherwise.
1391     * @since DOM Level 3
1392     */
1393    public boolean isDefaultNamespace(String namespaceURI){
1394        // REVISIT: remove casts when DOM L3 becomes REC.
1395        short type = this.getNodeType();
1396        switch (type) {
1397        case Node.ELEMENT_NODE: {
1398            String namespace = this.getNamespaceURI();
1399            String prefix = this.getPrefix();
1400
1401            // REVISIT: is it possible that prefix is empty string?
1402            if (prefix == null || prefix.length() == 0) {
1403                if (namespaceURI == null) {
1404                    return (namespace == namespaceURI);
1405                }
1406                return namespaceURI.equals(namespace);
1407            }
1408            if (this.hasAttributes()) {
1409                ElementImpl elem = (ElementImpl)this;
1410                NodeImpl attr = (NodeImpl)elem.getAttributeNodeNS("http://www.w3.org/2000/xmlns/", "xmlns");
1411                if (attr != null) {
1412                    String value = attr.getNodeValue();
1413                    if (namespaceURI == null) {
1414                        return (namespace == value);
1415                    }
1416                    return namespaceURI.equals(value);
1417                }
1418            }
1419
1420            NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
1421            if (ancestor != null) {
1422                return ancestor.isDefaultNamespace(namespaceURI);
1423            }
1424            return false;
1425        }
1426        case Node.DOCUMENT_NODE:{
1427                return((NodeImpl)((Document)this).getDocumentElement()).isDefaultNamespace(namespaceURI);
1428            }
1429
1430        case Node.ENTITY_NODE :
1431        case Node.NOTATION_NODE:
1432        case Node.DOCUMENT_FRAGMENT_NODE:
1433        case Node.DOCUMENT_TYPE_NODE:
1434            // type is unknown
1435            return false;
1436        case Node.ATTRIBUTE_NODE:{
1437                if (this.ownerNode.getNodeType() == Node.ELEMENT_NODE) {
1438                    return ownerNode.isDefaultNamespace(namespaceURI);
1439
1440                }
1441                return false;
1442            }
1443        default:{
1444                NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
1445                if (ancestor != null) {
1446                    return ancestor.isDefaultNamespace(namespaceURI);
1447                }
1448                return false;
1449            }
1450
1451        }
1452
1453
1454    }
1455
1456
1457    /**
1458     *
1459     * DOM Level 3 - Experimental:
1460     * Look up the prefix associated to the given namespace URI, starting from this node.
1461     *
1462     * @param namespaceURI
1463     * @return the prefix for the namespace
1464     */
1465    public String lookupPrefix(String namespaceURI){
1466
1467        // REVISIT: When Namespaces 1.1 comes out this may not be true
1468        // Prefix can't be bound to null namespace
1469        if (namespaceURI == null) {
1470            return null;
1471        }
1472
1473        short type = this.getNodeType();
1474
1475        switch (type) {
1476        case Node.ELEMENT_NODE: {
1477
1478                String namespace = this.getNamespaceURI(); // to flip out children
1479                return lookupNamespacePrefix(namespaceURI, (ElementImpl)this);
1480            }
1481        case Node.DOCUMENT_NODE:{
1482                return((NodeImpl)((Document)this).getDocumentElement()).lookupPrefix(namespaceURI);
1483            }
1484
1485        case Node.ENTITY_NODE :
1486        case Node.NOTATION_NODE:
1487        case Node.DOCUMENT_FRAGMENT_NODE:
1488        case Node.DOCUMENT_TYPE_NODE:
1489            // type is unknown
1490            return null;
1491        case Node.ATTRIBUTE_NODE:{
1492                if (this.ownerNode.getNodeType() == Node.ELEMENT_NODE) {
1493                    return ownerNode.lookupPrefix(namespaceURI);
1494
1495                }
1496                return null;
1497            }
1498        default:{
1499                NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
1500                if (ancestor != null) {
1501                    return ancestor.lookupPrefix(namespaceURI);
1502                }
1503                return null;
1504            }
1505
1506        }
1507    }
1508    /**
1509     * DOM Level 3 - Experimental:
1510     * Look up the namespace URI associated to the given prefix, starting from this node.
1511     * Use lookupNamespaceURI(null) to lookup the default namespace
1512     *
1513     * @param namespaceURI
1514     * @return th URI for the namespace
1515     * @since DOM Level 3
1516     */
1517    public String lookupNamespaceURI(String specifiedPrefix) {
1518        short type = this.getNodeType();
1519        switch (type) {
1520        case Node.ELEMENT_NODE : {
1521
1522                String namespace = this.getNamespaceURI();
1523                String prefix = this.getPrefix();
1524                if (namespace !=null) {
1525                    // REVISIT: is it possible that prefix is empty string?
1526                    if (specifiedPrefix== null && prefix==specifiedPrefix) {
1527                        // looking for default namespace
1528                        return namespace;
1529                    } else if (prefix != null && prefix.equals(specifiedPrefix)) {
1530                        // non default namespace
1531                        return namespace;
1532                    }
1533                }
1534                if (this.hasAttributes()) {
1535                    NamedNodeMap map = this.getAttributes();
1536                    int length = map.getLength();
1537                    for (int i=0;i<length;i++) {
1538                        Node attr = map.item(i);
1539                        String attrPrefix = attr.getPrefix();
1540                        String value = attr.getNodeValue();
1541                        namespace = attr.getNamespaceURI();
1542                        if (namespace !=null && namespace.equals("http://www.w3.org/2000/xmlns/")) {
1543                            // at this point we are dealing with DOM Level 2 nodes only
1544                            if (specifiedPrefix == null &&
1545                                attr.getNodeName().equals("xmlns")) {
1546                                // default namespace
1547                                return value;
1548                            } else if (attrPrefix !=null &&
1549                                       attrPrefix.equals("xmlns") &&
1550                                       attr.getLocalName().equals(specifiedPrefix)) {
1551                                // non default namespace
1552                                return value;
1553                            }
1554                        }
1555                    }
1556                }
1557                NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
1558                if (ancestor != null) {
1559                    return ancestor.lookupNamespaceURI(specifiedPrefix);
1560                }
1561
1562                return null;
1563
1564
1565            }
1566        case Node.DOCUMENT_NODE : {
1567                return((NodeImpl)((Document)this).getDocumentElement()).lookupNamespaceURI(specifiedPrefix);
1568            }
1569        case Node.ENTITY_NODE :
1570        case Node.NOTATION_NODE:
1571        case Node.DOCUMENT_FRAGMENT_NODE:
1572        case Node.DOCUMENT_TYPE_NODE:
1573            // type is unknown
1574            return null;
1575        case Node.ATTRIBUTE_NODE:{
1576                if (this.ownerNode.getNodeType() == Node.ELEMENT_NODE) {
1577                    return ownerNode.lookupNamespaceURI(specifiedPrefix);
1578
1579                }
1580                return null;
1581            }
1582        default:{
1583                NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
1584                if (ancestor != null) {
1585                    return ancestor.lookupNamespaceURI(specifiedPrefix);
1586                }
1587                return null;
1588            }
1589
1590        }
1591    }
1592
1593
1594    Node getElementAncestor (Node currentNode){
1595        Node parent = currentNode.getParentNode();
1596        if (parent != null) {
1597            short type = parent.getNodeType();
1598            if (type == Node.ELEMENT_NODE) {
1599                return parent;
1600            }
1601            return getElementAncestor(parent);
1602        }
1603        return null;
1604    }
1605
1606    String lookupNamespacePrefix(String namespaceURI, ElementImpl el){
1607        String namespace = this.getNamespaceURI();
1608        // REVISIT: if no prefix is available is it null or empty string, or
1609        //          could be both?
1610        String prefix = this.getPrefix();
1611
1612        if (namespace!=null && namespace.equals(namespaceURI)) {
1613            if (prefix != null) {
1614                String foundNamespace =  el.lookupNamespaceURI(prefix);
1615                if (foundNamespace !=null && foundNamespace.equals(namespaceURI)) {
1616                    return prefix;
1617                }
1618
1619            }
1620        }
1621        if (this.hasAttributes()) {
1622            NamedNodeMap map = this.getAttributes();
1623            int length = map.getLength();
1624            for (int i=0;i<length;i++) {
1625                Node attr = map.item(i);
1626                String attrPrefix = attr.getPrefix();
1627                String value = attr.getNodeValue();
1628                namespace = attr.getNamespaceURI();
1629                if (namespace !=null && namespace.equals("http://www.w3.org/2000/xmlns/")) {
1630                    // DOM Level 2 nodes
1631                    if (((attr.getNodeName().equals("xmlns")) ||
1632                         (attrPrefix !=null && attrPrefix.equals("xmlns")) &&
1633                         value.equals(namespaceURI))) {
1634
1635                        String localname= attr.getLocalName();
1636                        String foundNamespace = el.lookupNamespaceURI(localname);
1637                        if (foundNamespace !=null && foundNamespace.equals(namespaceURI)) {
1638                            return localname;
1639                        }
1640                    }
1641
1642
1643                }
1644            }
1645        }
1646        NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
1647
1648        if (ancestor != null) {
1649            return ancestor.lookupNamespacePrefix(namespaceURI, el);
1650        }
1651        return null;
1652    }
1653
1654    /**
1655     * Tests whether two nodes are equal.
1656     * <br>This method tests for equality of nodes, not sameness (i.e.,
1657     * whether the two nodes are references to the same object) which can be
1658     * tested with <code>Node.isSameNode</code>. All nodes that are the same
1659     * will also be equal, though the reverse may not be true.
1660     * <br>Two nodes are equal if and only if the following conditions are
1661     * satisfied: The two nodes are of the same type.The following string
1662     * attributes are equal: <code>nodeName</code>, <code>localName</code>,
1663     * <code>namespaceURI</code>, <code>prefix</code>, <code>nodeValue</code>
1664     * , <code>baseURI</code>. This is: they are both <code>null</code>, or
1665     * they have the same length and are character for character identical.
1666     * The <code>attributes</code> <code>NamedNodeMaps</code> are equal.
1667     * This is: they are both <code>null</code>, or they have the same
1668     * length and for each node that exists in one map there is a node that
1669     * exists in the other map and is equal, although not necessarily at the
1670     * same index.The <code>childNodes</code> <code>NodeLists</code> are
1671     * equal. This is: they are both <code>null</code>, or they have the
1672     * same length and contain equal nodes at the same index. This is true
1673     * for <code>Attr</code> nodes as for any other type of node. Note that
1674     * normalization can affect equality; to avoid this, nodes should be
1675     * normalized before being compared.
1676     * <br>For two <code>DocumentType</code> nodes to be equal, the following
1677     * conditions must also be satisfied: The following string attributes
1678     * are equal: <code>publicId</code>, <code>systemId</code>,
1679     * <code>internalSubset</code>.The <code>entities</code>
1680     * <code>NamedNodeMaps</code> are equal.The <code>notations</code>
1681     * <code>NamedNodeMaps</code> are equal.
1682     * <br>On the other hand, the following do not affect equality: the
1683     * <code>ownerDocument</code> attribute, the <code>specified</code>
1684     * attribute for <code>Attr</code> nodes, the
1685     * <code>isWhitespaceInElementContent</code> attribute for
1686     * <code>Text</code> nodes, as well as any user data or event listeners
1687     * registered on the nodes.
1688     * @param arg The node to compare equality with.
1689     * @param deep If <code>true</code>, recursively compare the subtrees; if
1690     *   <code>false</code>, compare only the nodes themselves (and its
1691     *   attributes, if it is an <code>Element</code>).
1692     * @return If the nodes, and possibly subtrees are equal,
1693     *   <code>true</code> otherwise <code>false</code>.
1694     * @since DOM Level 3
1695     */
1696    public boolean isEqualNode(Node arg) {
1697        if (arg == this) {
1698            return true;
1699        }
1700        if (arg.getNodeType() != getNodeType()) {
1701            return false;
1702        }
1703        // in theory nodeName can't be null but better be careful
1704        // who knows what other implementations may be doing?...
1705        if (getNodeName() == null) {
1706            if (arg.getNodeName() != null) {
1707                return false;
1708            }
1709        }
1710        else if (!getNodeName().equals(arg.getNodeName())) {
1711            return false;
1712        }
1713
1714        if (getLocalName() == null) {
1715            if (arg.getLocalName() != null) {
1716                return false;
1717            }
1718        }
1719        else if (!getLocalName().equals(arg.getLocalName())) {
1720            return false;
1721        }
1722
1723        if (getNamespaceURI() == null) {
1724            if (arg.getNamespaceURI() != null) {
1725                return false;
1726            }
1727        }
1728        else if (!getNamespaceURI().equals(arg.getNamespaceURI())) {
1729            return false;
1730        }
1731
1732        if (getPrefix() == null) {
1733            if (arg.getPrefix() != null) {
1734                return false;
1735            }
1736        }
1737        else if (!getPrefix().equals(arg.getPrefix())) {
1738            return false;
1739        }
1740
1741        if (getNodeValue() == null) {
1742            if (arg.getNodeValue() != null) {
1743                return false;
1744            }
1745        }
1746        else if (!getNodeValue().equals(arg.getNodeValue())) {
1747            return false;
1748        }
1749
1750
1751        return true;
1752    }
1753
1754    /**
1755     * @since DOM Level 3
1756     */
1757    public Object getFeature(String feature, String version) {
1758        // we don't have any alternate node, either this node does the job
1759        // or we don't have anything that does
1760        return isSupported(feature, version) ? this : null;
1761    }
1762
1763    /**
1764     * Associate an object to a key on this node. The object can later be
1765     * retrieved from this node by calling <code>getUserData</code> with the
1766     * same key.
1767     * @param key The key to associate the object to.
1768     * @param data The object to associate to the given key, or
1769     *   <code>null</code> to remove any existing association to that key.
1770     * @param handler The handler to associate to that key, or
1771     *   <code>null</code>.
1772     * @return Returns the <code>DOMObject</code> previously associated to
1773     *   the given key on this node, or <code>null</code> if there was none.
1774     * @since DOM Level 3
1775     */
1776    public Object setUserData(String key,
1777                              Object data,
1778                              UserDataHandler handler) {
1779        return ownerDocument().setUserData(this, key, data, handler);
1780    }
1781
1782    /**
1783     * Retrieves the object associated to a key on a this node. The object
1784     * must first have been set to this node by calling
1785     * <code>setUserData</code> with the same key.
1786     * @param key The key the object is associated to.
1787     * @return Returns the <code>DOMObject</code> associated to the given key
1788     *   on this node, or <code>null</code> if there was none.
1789     * @since DOM Level 3
1790     */
1791    public Object getUserData(String key) {
1792        return ownerDocument().getUserData(this, key);
1793    }
1794
1795    protected Map<String, ParentNode.UserDataRecord> getUserDataRecord(){
1796        return ownerDocument().getUserDataRecord(this);
1797        }
1798
1799    //
1800    // Public methods
1801    //
1802
1803    /**
1804     * NON-DOM: PR-DOM-Level-1-19980818 mentions readonly nodes in conjunction
1805     * with Entities, but provides no API to support this.
1806     * <P>
1807     * Most DOM users should not touch this method. Its anticpated use
1808     * is during construction of EntityRefernces, where it will be used to
1809     * lock the contents replicated from Entity so they can't be casually
1810     * altered. It _could_ be published as a DOM extension, if desired.
1811     * <P>
1812     * Note: since we never have any children deep is meaningless here,
1813     * ParentNode overrides this behavior.
1814     * @see ParentNode
1815     *
1816     * @param readOnly True or false as desired.
1817     * @param deep If true, children are also toggled. Note that this will
1818     *  not change the state of an EntityReference or its children,
1819     *  which are always read-only.
1820     */
1821    public void setReadOnly(boolean readOnly, boolean deep) {
1822
1823        if (needsSyncData()) {
1824            synchronizeData();
1825        }
1826        isReadOnly(readOnly);
1827
1828    } // setReadOnly(boolean,boolean)
1829
1830    /**
1831     * NON-DOM: Returns true if this node is read-only. This is a
1832     * shallow check.
1833     */
1834    public boolean getReadOnly() {
1835
1836        if (needsSyncData()) {
1837            synchronizeData();
1838        }
1839        return isReadOnly();
1840
1841    } // getReadOnly():boolean
1842
1843    /**
1844     * NON-DOM: As an alternative to subclassing the DOM, this implementation
1845     * has been extended with the ability to attach an object to each node.
1846     * (If you need multiple objects, you can attach a collection such as a
1847     * List or Map, then attach your application information to that.)
1848     * <p><b>Important Note:</b> You are responsible for removing references
1849     * to your data on nodes that are no longer used. Failure to do so will
1850     * prevent the nodes, your data is attached to, to be garbage collected
1851     * until the whole document is.
1852     *
1853     * @param data the object to store or null to remove any existing reference
1854     */
1855    public void setUserData(Object data) {
1856        ownerDocument().setUserData(this, data);
1857    }
1858
1859    /**
1860     * NON-DOM:
1861     * Returns the user data associated to this node.
1862     */
1863    public Object getUserData() {
1864        return ownerDocument().getUserData(this);
1865    }
1866
1867    //
1868    // Protected methods
1869    //
1870
1871    /**
1872     * Denotes that this node has changed.
1873     */
1874    protected void changed() {
1875        // we do not actually store this information on every node, we only
1876        // have a global indicator on the Document. Doing otherwise cost us too
1877        // much for little gain.
1878        ownerDocument().changed();
1879    }
1880
1881    /**
1882     * Returns the number of changes to this node.
1883     */
1884    protected int changes() {
1885        // we do not actually store this information on every node, we only
1886        // have a global indicator on the Document. Doing otherwise cost us too
1887        // much for little gain.
1888        return ownerDocument().changes();
1889    }
1890
1891    /**
1892     * Override this method in subclass to hook in efficient
1893     * internal data structure.
1894     */
1895    protected void synchronizeData() {
1896        // By default just change the flag to avoid calling this method again
1897        needsSyncData(false);
1898    }
1899
1900    /**
1901     * For non-child nodes, the node which "points" to this node.
1902     * For example, the owning element for an attribute
1903     */
1904    protected Node getContainer() {
1905       return null;
1906    }
1907
1908
1909    /*
1910     * Flags setters and getters
1911     */
1912
1913    final boolean isReadOnly() {
1914        return (flags & READONLY) != 0;
1915    }
1916
1917    final void isReadOnly(boolean value) {
1918        flags = (short) (value ? flags | READONLY : flags & ~READONLY);
1919    }
1920
1921    final boolean needsSyncData() {
1922        return (flags & SYNCDATA) != 0;
1923    }
1924
1925    final void needsSyncData(boolean value) {
1926        flags = (short) (value ? flags | SYNCDATA : flags & ~SYNCDATA);
1927    }
1928
1929    final boolean needsSyncChildren() {
1930        return (flags & SYNCCHILDREN) != 0;
1931    }
1932
1933    public final void needsSyncChildren(boolean value) {
1934        flags = (short) (value ? flags | SYNCCHILDREN : flags & ~SYNCCHILDREN);
1935    }
1936
1937    final boolean isOwned() {
1938        return (flags & OWNED) != 0;
1939    }
1940
1941    final void isOwned(boolean value) {
1942        flags = (short) (value ? flags | OWNED : flags & ~OWNED);
1943    }
1944
1945    final boolean isFirstChild() {
1946        return (flags & FIRSTCHILD) != 0;
1947    }
1948
1949    final void isFirstChild(boolean value) {
1950        flags = (short) (value ? flags | FIRSTCHILD : flags & ~FIRSTCHILD);
1951    }
1952
1953    final boolean isSpecified() {
1954        return (flags & SPECIFIED) != 0;
1955    }
1956
1957    final void isSpecified(boolean value) {
1958        flags = (short) (value ? flags | SPECIFIED : flags & ~SPECIFIED);
1959    }
1960
1961    // inconsistent name to avoid clash with public method on TextImpl
1962    final boolean internalIsIgnorableWhitespace() {
1963        return (flags & IGNORABLEWS) != 0;
1964    }
1965
1966    final void isIgnorableWhitespace(boolean value) {
1967        flags = (short) (value ? flags | IGNORABLEWS : flags & ~IGNORABLEWS);
1968    }
1969
1970    final boolean hasStringValue() {
1971        return (flags & HASSTRING) != 0;
1972    }
1973
1974    final void hasStringValue(boolean value) {
1975        flags = (short) (value ? flags | HASSTRING : flags & ~HASSTRING);
1976    }
1977
1978    final boolean isNormalized() {
1979        return (flags & NORMALIZED) != 0;
1980    }
1981
1982    final void isNormalized(boolean value) {
1983        // See if flag should propagate to parent.
1984        if (!value && isNormalized() && ownerNode != null) {
1985            ownerNode.isNormalized(false);
1986        }
1987        flags = (short) (value ?  flags | NORMALIZED : flags & ~NORMALIZED);
1988    }
1989
1990    final boolean isIdAttribute() {
1991        return (flags & ID) != 0;
1992    }
1993
1994    final void isIdAttribute(boolean value) {
1995        flags = (short) (value ? flags | ID : flags & ~ID);
1996    }
1997
1998    //
1999    // Object methods
2000    //
2001
2002    /** NON-DOM method for debugging convenience. */
2003    public String toString() {
2004        return "["+getNodeName()+": "+getNodeValue()+"]";
2005    }
2006
2007    //
2008    // Serialization methods
2009    //
2010
2011    /** Serialize object. */
2012    private void writeObject(ObjectOutputStream out) throws IOException {
2013
2014        // synchronize data
2015        if (needsSyncData()) {
2016            synchronizeData();
2017        }
2018        // write object
2019        out.defaultWriteObject();
2020
2021    } // writeObject(ObjectOutputStream)
2022
2023} // class NodeImpl
2024