KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > xpath > datamodel > xerces > dom > NodeImpl


1 /*
2 * The Apache Software License, Version 1.1
3 *
4 *
5 * Copyright (c) 1999 The Apache Software Foundation. All rights
6 * reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution,
21 * if any, must include the following acknowledgment:
22 * "This product includes software developed by the
23 * Apache Software Foundation (http://www.apache.org/)."
24 * Alternately, this acknowledgment may appear in the software itself,
25 * if and wherever such third-party acknowledgments normally appear.
26 *
27 * 4. The names "Xerces" and "Apache Software Foundation" must
28 * not be used to endorse or promote products derived from this
29 * software without prior written permission. For written
30 * permission, please contact apache@apache.org.
31 *
32 * 5. Products derived from this software may not be called "Apache",
33 * nor may "Apache" appear in their name, without prior written
34 * permission of the Apache Software Foundation.
35 *
36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
48 * ====================================================================
49 *
50 * This software consists of voluntary contributions made by many
51 * individuals on behalf of the Apache Software Foundation and was
52 * originally based on software copyright (c) 1999, International
53 * Business Machines, Inc., http://www.apache.org. For more
54 * information on the Apache Software Foundation, please see
55 * <http://www.apache.org/>.
56 */

57
58 package org.xquark.xpath.datamodel.xerces.dom;
59
60 import java.io.IOException JavaDoc;
61 import java.io.ObjectOutputStream JavaDoc;
62 import java.io.Serializable JavaDoc;
63 import java.util.Vector JavaDoc;
64
65 //import org.apache.xpath.XPathException;
66
import org.w3c.dom.*;
67 import org.w3c.dom.events.*;
68 import org.xml.sax.SAXException JavaDoc;
69 import org.xquark.xpath.datamodel.xerces.dom.events.EventImpl;
70 import org.xquark.xpath.datamodel.xerces.dom.events.MutationEventImpl;
71
72 /**
73  * Node provides the basic structure of a DOM tree. It is never used
74  * directly, but instead is subclassed to add type and data
75  * information, and additional methods, appropriate to each node of
76  * the tree. Only its subclasses should be instantiated -- and those,
77  * with the exception of Document itself, only through a specific
78  * Document's factory methods.
79  * <P>
80  * The Node interface provides shared behaviors such as siblings and
81  * children, both for consistancy and so that the most common tree
82  * operations may be performed without constantly having to downcast
83  * to specific node types. When there is no obvious mapping for one of
84  * these queries, it will respond with null.
85  * Note that the default behavior is that children are forbidden. To
86  * permit them, the subclass ParentNode overrides several methods.
87  * <P>
88  * NodeImpl also implements NodeList, so it can return itself in
89  * response to the getChildNodes() query. This eliminiates the need
90  * for a separate ChildNodeList object. Note that this is an
91  * IMPLEMENTATION DETAIL; applications should _never_ assume that
92  * this identity exists.
93  * <P>
94  * All nodes in a single document must originate
95  * in that document. (Note that this is much tighter than "must be
96  * same implementation") Nodes are all aware of their ownerDocument,
97  * and attempts to mismatch will throw WRONG_DOCUMENT_ERR.
98  * <P>
99  * However, to save memory not all nodes always have a direct reference
100  * to their ownerDocument. When a node is owned by another node it relies
101  * on its owner to store its ownerDocument. Parent nodes always store it
102  * though, so there is never more than one level of indirection.
103  * And when a node doesn't have an owner, ownerNode refers to its
104  * ownerDocument.
105  *
106  * @author Arnaud Le Hors, IBM
107  * @author Joe Kesselman, IBM
108  * @version
109  * @since PR-DOM-Level-1-19980818.
110  */

111 public abstract class NodeImpl implements Node, NodeList, EventTarget, Cloneable JavaDoc, Serializable JavaDoc {
112
113     //
114
// Constants
115
//
116

117     /** Serialization version. */
118     static final long serialVersionUID = -6316591992167219696L;
119
120     // public
121

122     /** Element definition node type. */
123     public static final short ELEMENT_DEFINITION_NODE = -1;
124
125     //
126
// Data
127
//
128

129     // links
130

131     protected NodeImpl ownerNode; // typically the parent but not always!
132

133     // data
134

135     protected short flags;
136
137     protected final static short READONLY = 0x1 << 0;
138     protected final static short SYNCDATA = 0x1 << 1;
139     protected final static short SYNCCHILDREN = 0x1 << 2;
140     protected final static short OWNED = 0x1 << 3;
141     protected final static short FIRSTCHILD = 0x1 << 4;
142     protected final static short SPECIFIED = 0x1 << 5;
143     protected final static short IGNORABLEWS = 0x1 << 6;
144     protected final static short SETVALUE = 0x1 << 7;
145     protected final static short HASSTRING = 0x1 << 8;
146     protected final static short UNNORMALIZED = 0x1 << 9;
147
148     //
149
// Constructors
150
//
151

152     /**
153      * No public constructor; only subclasses of Node should be
154      * instantiated, and those normally via a Document's factory methods
155      * <p>
156      * Every Node knows what Document it belongs to.
157      */

158     protected NodeImpl(DocumentImpl ownerDocument) {
159         // as long as we do not have any owner, ownerNode is our ownerDocument
160
ownerNode = ownerDocument;
161     } // <init>(DocumentImpl)
162

163     /** Constructor for serialization. */
164     public NodeImpl() {
165     }
166
167     //
168
// Node methods
169
//
170

171     /**
172      * A short integer indicating what type of node this is. The named
173      * constants for this value are defined in the org.w3c.dom.Node interface.
174      */

175     public abstract short getNodeType();
176
177     /**
178      * the name of this node.
179      */

180     public abstract String JavaDoc getNodeName();
181
182     /**
183      * Returns the node value.
184      */

185     public String JavaDoc getNodeValue() {
186         return null; // overridden in some subclasses
187
}
188
189     /**
190      * Sets the node value.
191      * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR)
192      */

193     public void setNodeValue(String JavaDoc x) throws DOMException {
194         // Default behavior is to do nothing, overridden in some subclasses
195
}
196
197     /**
198      * Adds a child node to the end of the list of children for this node.
199      * Convenience shorthand for insertBefore(newChild,null).
200      * @see #insertBefore(Node, Node)
201      * <P>
202      * By default we do not accept any children, ParentNode overrides this.
203      * @see ParentNode
204      *
205      * @returns newChild, in its new state (relocated, or emptied in the
206      * case of DocumentNode.)
207      *
208      * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a
209      * type that shouldn't be a child of this node.
210      *
211      * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a
212      * different owner document than we do.
213      *
214      * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
215      * read-only.
216      */

217     public Node appendChild(Node newChild) throws DOMException {
218         return insertBefore(newChild, null);
219     }
220
221     /**
222      * Returns a duplicate of a given node. You can consider this a
223      * generic "copy constructor" for nodes. The newly returned object should
224      * be completely independent of the source object's subtree, so changes
225      * in one after the clone has been made will not affect the other.
226      * <P>
227      * Note: since we never have any children deep is meaningless here,
228      * ParentNode overrides this behavior.
229      * @see ParentNode
230      *
231      * <p>
232      * Example: Cloning a Text node will copy both the node and the text it
233      * contains.
234      * <p>
235      * Example: Cloning something that has children -- Element or Attr, for
236      * example -- will _not_ clone those children unless a "deep clone"
237      * has been requested. A shallow clone of an Attr node will yield an
238      * empty Attr of the same name.
239      * <p>
240      * NOTE: Clones will always be read/write, even if the node being cloned
241      * is read-only, to permit applications using only the DOM API to obtain
242      * editable copies of locked portions of the tree.
243      */

244     public Node cloneNode(boolean deep) {
245
246         if (needsSyncData()) {
247             synchronizeData();
248         }
249
250         NodeImpl newnode;
251         try {
252             newnode = (NodeImpl) clone();
253         } catch (CloneNotSupportedException JavaDoc e) {
254             // Revisit : don't fail silently - but don't want to tie to parser guts
255
// System.out.println("UNEXPECTED "+e);
256
return null;
257         }
258
259         // Need to break the association w/ original kids
260
newnode.ownerNode = ownerDocument();
261         newnode.isOwned(false);
262
263         // REVISIT: What to do when readOnly? -Ac
264
newnode.isReadOnly(false);
265
266         return newnode;
267
268     } // cloneNode(boolean):Node
269

270     /**
271      * Find the Document that this Node belongs to (the document in
272      * whose context the Node was created). The Node may or may not
273      * currently be part of that Document's actual contents.
274      */

275     public Document getOwnerDocument() {
276         // if we have an owner simply forward the request
277
// otherwise ownerNode is our ownerDocument
278
if (isOwned()) {
279             return ownerNode.ownerDocument();
280         } else {
281             return (Document) ownerNode;
282         }
283     }
284
285     /**
286      * same as above but returns internal type and this one is not overridden
287      * by DocumentImpl to return null
288      */

289     DocumentImpl ownerDocument() {
290         // if we have an owner simply forward the request
291
// otherwise ownerNode is our ownerDocument
292
if (isOwned()) {
293             return ownerNode.ownerDocument();
294         } else {
295             return (DocumentImpl) ownerNode;
296         }
297     }
298
299     /**
300      * NON-DOM
301      * set the ownerDocument of this node
302      */

303     void setOwnerDocument(DocumentImpl doc) {
304         if (needsSyncData()) {
305             synchronizeData();
306         }
307         // if we have an owner we rely on it to have it right
308
// otherwise ownerNode is our ownerDocument
309
if (!isOwned()) {
310             ownerNode = doc;
311         }
312     }
313
314     /**
315      * Obtain the DOM-tree parent of this node, or null if it is not
316      * currently active in the DOM tree (perhaps because it has just been
317      * created or removed). Note that Document, DocumentFragment, and
318      * Attribute will never have parents.
319      */

320     public Node getParentNode() {
321         return null; // overriden by ChildNode
322
}
323
324     /*
325      * same as above but returns internal type
326      */

327     NodeImpl parentNode() {
328         return null;
329     }
330
331     /** The next child of this node's parent, or null if none */
332     public Node getNextSibling() {
333         return null; // default behavior, overriden in ChildNode
334
}
335
336     /** The previous child of this node's parent, or null if none */
337     public Node getPreviousSibling() {
338         return null; // default behavior, overriden in ChildNode
339
}
340
341     ChildNode previousSibling() {
342         return null; // default behavior, overriden in ChildNode
343
}
344
345     /**
346      * Return the collection of attributes associated with this node,
347      * or null if none. At this writing, Element is the only type of node
348      * which will ever have attributes.
349      *
350      * @see ElementImpl
351      */

352     public NamedNodeMap getAttributes() {
353         return null; // overridden in ElementImpl
354
}
355
356     /**
357      * Returns whether this node (if it is an element) has any attributes.
358      * @return <code>true</code> if this node has any attributes,
359      * <code>false</code> otherwise.
360      * @since DOM Level 2
361      * @see ElementImpl
362      */

363     public boolean hasAttributes() {
364         return false; // overridden in ElementImpl
365
}
366
367     /**
368      * Test whether this node has any children. Convenience shorthand
369      * for (Node.getFirstChild()!=null)
370      * <P>
371      * By default we do not have any children, ParentNode overrides this.
372      * @see ParentNode
373      */

374     public boolean hasChildNodes() {
375         return false;
376     }
377
378     /**
379      * Obtain a NodeList enumerating all children of this node. If there
380      * are none, an (initially) empty NodeList is returned.
381      * <p>
382      * NodeLists are "live"; as children are added/removed the NodeList
383      * will immediately reflect those changes. Also, the NodeList refers
384      * to the actual nodes, so changes to those nodes made via the DOM tree
385      * will be reflected in the NodeList and vice versa.
386      * <p>
387      * In this implementation, Nodes implement the NodeList interface and
388      * provide their own getChildNodes() support. Other DOMs may solve this
389      * differently.
390      */

391     public NodeList getChildNodes() {
392         return this;
393     }
394
395     /** The first child of this Node, or null if none.
396      * <P>
397      * By default we do not have any children, ParentNode overrides this.
398      * @see ParentNode
399      */

400     public Node getFirstChild() {
401         return null;
402     }
403
404     /** The first child of this Node, or null if none.
405      * <P>
406      * By default we do not have any children, ParentNode overrides this.
407      * @see ParentNode
408      */

409     public Node getLastChild() {
410         return null;
411     }
412
413     /**
414      * Move one or more node(s) to our list of children. Note that this
415      * implicitly removes them from their previous parent.
416      * <P>
417      * By default we do not accept any children, ParentNode overrides this.
418      * @see ParentNode
419      *
420      * @param newChild The Node to be moved to our subtree. As a
421      * convenience feature, inserting a DocumentNode will instead insert
422      * all its children.
423      *
424      * @param refChild Current child which newChild should be placed
425      * immediately before. If refChild is null, the insertion occurs
426      * after all existing Nodes, like appendChild().
427      *
428      * @returns newChild, in its new state (relocated, or emptied in the
429      * case of DocumentNode.)
430      *
431      * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a
432      * type that shouldn't be a child of this node, or if newChild is an
433      * ancestor of this node.
434      *
435      * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a
436      * different owner document than we do.
437      *
438      * @throws DOMException(NOT_FOUND_ERR) if refChild is not a child of
439      * this node.
440      *
441      * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
442      * read-only.
443      */

444     public Node insertBefore(Node newChild, Node refChild) throws DOMException {
445         throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, "DOM006 Hierarchy request error");
446     }
447
448     /**
449      * Remove a child from this Node. The removed child's subtree
450      * remains intact so it may be re-inserted elsewhere.
451      * <P>
452      * By default we do not have any children, ParentNode overrides this.
453      * @see ParentNode
454      *
455      * @return oldChild, in its new state (removed).
456      *
457      * @throws DOMException(NOT_FOUND_ERR) if oldChild is not a child of
458      * this node.
459      *
460      * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
461      * read-only.
462      */

463     public Node removeChild(Node oldChild) throws DOMException {
464         throw new DOMException(DOMException.NOT_FOUND_ERR, "DOM008 Not found");
465     }
466
467     /**
468      * Make newChild occupy the location that oldChild used to
469      * have. Note that newChild will first be removed from its previous
470      * parent, if any. Equivalent to inserting newChild before oldChild,
471      * then removing oldChild.
472      * <P>
473      * By default we do not have any children, ParentNode overrides this.
474      * @see ParentNode
475      *
476      * @returns oldChild, in its new state (removed).
477      *
478      * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a
479      * type that shouldn't be a child of this node, or if newChild is
480      * one of our ancestors.
481      *
482      * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a
483      * different owner document than we do.
484      *
485      * @throws DOMException(NOT_FOUND_ERR) if oldChild is not a child of
486      * this node.
487      *
488      * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
489      * read-only.
490      */

491     public Node replaceChild(Node newChild, Node oldChild) throws DOMException {
492         throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, "DOM006 Hierarchy request error");
493     }
494
495     //
496
// NodeList methods
497
//
498

499     /**
500      * NodeList method: Count the immediate children of this node
501      * <P>
502      * By default we do not have any children, ParentNode overrides this.
503      * @see ParentNode
504      *
505      * @return int
506      */

507     public int getLength() {
508         return 0;
509     }
510
511     /**
512      * NodeList method: Return the Nth immediate child of this node, or
513      * null if the index is out of bounds.
514      * <P>
515      * By default we do not have any children, ParentNode overrides this.
516      * @see ParentNode
517      *
518      * @return org.w3c.dom.Node
519      * @param Index int
520      */

521     public Node item(int index) {
522         return null;
523     }
524
525     //
526
// DOM2: methods, getters, setters
527
//
528

529     /**
530      * Puts all <code>Text</code> nodes in the full depth of the sub-tree
531      * underneath this <code>Node</code>, including attribute nodes, into a
532      * "normal" form where only markup (e.g., tags, comments, processing
533      * instructions, CDATA sections, and entity references) separates
534      * <code>Text</code> nodes, i.e., there are no adjacent <code>Text</code>
535      * nodes. This can be used to ensure that the DOM view of a document is
536      * the same as if it were saved and re-loaded, and is useful when
537      * operations (such as XPointer lookups) that depend on a particular
538      * document tree structure are to be used.In cases where the document
539      * contains <code>CDATASections</code>, the normalize operation alone may
540      * not be sufficient, since XPointers do not differentiate between
541      * <code>Text</code> nodes and <code>CDATASection</code> nodes.
542      * <p>
543      * Note that this implementation simply calls normalize() on this Node's
544      * children. It is up to implementors or Node to override normalize()
545      * to take action.
546      */

547     public void normalize() {
548         /* by default we do not have any children,
549            ParentNode overrides this behavior */

550     }
551
552     /**
553      * Introduced in DOM Level 2. <p>
554      * Tests whether the DOM implementation implements a specific feature and that
555      * feature is supported by this node.
556      * @param feature The package name of the feature to test. This is the
557      * same name as what can be passed to the method
558      * hasFeature on DOMImplementation.
559      * @param version This is the version number of the package name to
560      * test. In Level 2, version 1, this is the string "2.0". If
561      * the version is not specified, supporting any version of
562      * the feature will cause the method to return true.
563      * @return boolean Returns true if this node defines a subtree within which the
564      * specified feature is supported, false otherwise.
565      * @since WD-DOM-Level-2-19990923
566      */

567     public boolean isSupported(String JavaDoc feature, String JavaDoc version) {
568         return ownerDocument().getImplementation().hasFeature(feature, version);
569     }
570
571     /**
572      * Introduced in DOM Level 2. <p>
573      *
574      * The namespace URI of this node, or null if it is unspecified. When this node
575      * is of any type other than ELEMENT_NODE and ATTRIBUTE_NODE, this is always
576      * null and setting it has no effect. <p>
577      *
578      * This is not a computed value that is the result of a namespace lookup based on
579      * an examination of the namespace declarations in scope. It is merely the
580      * namespace URI given at creation time.<p>
581      *
582      * For nodes created with a DOM Level 1 method, such as createElement
583      * from the Document interface, this is null.
584      * @since WD-DOM-Level-2-19990923
585      * @see AttrNSImpl
586      * @see ElementNSImpl
587      */

588     public String JavaDoc getNamespaceURI() {
589         return null;
590     }
591
592     /**
593      * Introduced in DOM Level 2. <p>
594      *
595      * The namespace prefix of this node, or null if it is unspecified. When this
596      * node is of any type other than ELEMENT_NODE and ATTRIBUTE_NODE this is
597      * always null and setting it has no effect.<p>
598      *
599      * For nodes created with a DOM Level 1 method, such as createElement
600      * from the Document interface, this is null. <p>
601      *
602      * @since WD-DOM-Level-2-19990923
603      * @see AttrNSImpl
604      * @see ElementNSImpl
605      */

606     public String JavaDoc getPrefix() {
607         return null;
608     }
609
610     /**
611      * Introduced in DOM Level 2. <p>
612      *
613      * The namespace prefix of this node, or null if it is unspecified. When this
614      * node is of any type other than ELEMENT_NODE and ATTRIBUTE_NODE this is
615      * always null and setting it has no effect.<p>
616      *
617      * For nodes created with a DOM Level 1 method, such as createElement
618      * from the Document interface, this is null.<p>
619      *
620      * Note that setting this attribute changes the nodeName attribute, which holds the
621      * qualified name, as well as the tagName and name attributes of the Element
622      * and Attr interfaces, when applicable.<p>
623      *
624      * @throws INVALID_CHARACTER_ERR Raised if the specified
625      * prefix contains an invalid character.
626      *
627      * @since WD-DOM-Level-2-19990923
628      * @see AttrNSImpl
629      * @see ElementNSImpl
630      */

631     public void setPrefix(String JavaDoc prefix) throws DOMException {
632         throw new DOMException(DOMException.NAMESPACE_ERR, "DOM003 Namespace error");
633     }
634
635     /**
636      * Introduced in DOM Level 2. <p>
637      *
638      * Returns the local part of the qualified name of this node.
639      * For nodes created with a DOM Level 1 method, such as createElement
640      * from the Document interface, and for nodes of any type other than
641      * ELEMENT_NODE and ATTRIBUTE_NODE this is the same as the nodeName
642      * attribute.
643      * @since WD-DOM-Level-2-19990923
644      * @see AttrNSImpl
645      * @see ElementNSImpl
646      */

647     public String JavaDoc getLocalName() {
648         return null;
649     }
650
651     //
652
// EventTarget support (public and internal)
653
//
654
// Constants
655
//
656
/** Compile-time flag. If false, disables our code for
657         the DOM Level 2 Events module, perhaps allowing it
658         to be optimized out to save bytecodes.
659     */

660     protected final static boolean MUTATIONEVENTS = true;
661
662     /** The MUTATION_ values are parameters to the NON-DOM
663         internalInsertBefore() and internalRemoveChild() operations,
664         allowing us to control which MutationEvents are generated.
665      */

666     protected final static int MUTATION_NONE = 0x00;
667     protected final static int MUTATION_LOCAL = 0x01;
668     protected final static int MUTATION_AGGREGATE = 0x02;
669     protected final static int MUTATION_ALL = 0xffff;
670
671     /* NON-DOM INTERNAL: Class LEntry is just a struct used to represent
672      * event listeners registered with this node. Copies of this object
673      * are hung from the nodeListeners Vector.
674      * <p>
675      * I considered using two vectors -- one for capture,
676      * one for bubble -- but decided that since the list of listeners
677      * is probably short in most cases, it might not be worth spending
678      * the space. ***** REVISIT WHEN WE HAVE MORE EXPERIENCE.
679      */

680     class LEntry {
681         String JavaDoc type;
682         EventListener listener;
683         boolean useCapture;
684
685         /** NON-DOM INTERNAL: Constructor for Listener list Entry
686          * @param type Event name (NOT event group!) to listen for.
687          * @param listener Who gets called when event is dispatched
688          * @param useCaptue True iff listener is registered on
689          * capturing phase rather than at-target or bubbling
690          */

691         LEntry(String JavaDoc type, EventListener listener, boolean useCapture) {
692             this.type = type;
693             this.listener = listener;
694             this.useCapture = useCapture;
695         }
696     }; // LEntry
697

698     /** Introduced in DOM Level 2. <p>
699      * Register an event listener with this Node. A listener may be independently
700      * registered as both Capturing and Bubbling, but may only be
701      * registered once per role; redundant registrations are ignored.
702      * @param type Event name (NOT event group!) to listen for.
703      * @param listener Who gets called when event is dispatched
704      * @param useCapture True iff listener is registered on
705      * capturing phase rather than at-target or bubbling
706      */

707     public void addEventListener(String JavaDoc type, EventListener listener, boolean useCapture) {
708         // We can't dispatch to blank type-name, and of course we need
709
// a listener to dispatch to
710
if (type == null || type.equals("") || listener == null)
711             return;
712
713         // Each listener may be registered only once per type per phase.
714
// Simplest way to code that is to zap the previous entry, if any.
715
removeEventListener(type, listener, useCapture);
716
717         Vector JavaDoc nodeListeners = ownerDocument().getEventListeners(this);
718         if (nodeListeners == null) {
719             nodeListeners = new Vector JavaDoc();
720             ownerDocument().setEventListeners(this, nodeListeners);
721         }
722         nodeListeners.addElement(new LEntry(type, listener, useCapture));
723
724         // Record active listener
725
LCount lc = LCount.lookup(type);
726         if (useCapture)
727             ++lc.captures;
728         else
729             ++lc.bubbles;
730
731     } // addEventListener(String,EventListener,boolean) :void
732

733     /** Introduced in DOM Level 2. <p>
734      * Deregister an event listener previously registered with this Node.
735      * A listener must be independently removed from the
736      * Capturing and Bubbling roles. Redundant removals (of
737      * listeners not currently registered for this role) are ignored.
738      * @param type Event name (NOT event group!) to listen for.
739      * @param listener Who gets called when event is dispatched
740      * @param useCapture True iff listener is registered on
741      * capturing phase rather than at-target or bubbling
742      */

743     public void removeEventListener(String JavaDoc type, EventListener listener, boolean useCapture) {
744         // If this couldn't be a valid listener registration, ignore request
745
Vector JavaDoc nodeListeners = ownerDocument().getEventListeners(this);
746         if (nodeListeners == null || type == null || type.equals("") || listener == null)
747             return;
748
749         // Note that addListener has previously ensured that
750
// each listener may be registered only once per type per phase.
751
for (int i = nodeListeners.size() - 1; i >= 0; --i) // count-down is OK for deletions!
752
{
753             LEntry le = (LEntry) (nodeListeners.elementAt(i));
754             if (le.useCapture == useCapture && le.listener == listener && le.type.equals(type)) {
755                 nodeListeners.removeElementAt(i);
756                 // Storage management: Discard empty listener lists
757
if (nodeListeners.size() == 0)
758                     ownerDocument().setEventListeners(this, null);
759
760                 // Remove active listener
761
LCount lc = LCount.lookup(type);
762                 if (useCapture)
763                     --lc.captures;
764                 else
765                     --lc.bubbles;
766
767                 break; // Found it; no need to loop farther.
768
}
769         }
770     } // removeEventListener(String,EventListener,boolean) :void
771

772     /** COMMENTED OUT **
773             Now that event listeners are stored on the document with the node
774             as the key, nodes can't be finalized if they have any event
775             listener. This finalize method becomes useless... This is a place
776             where we could definitely use weak references!! If we did, then
777             this finalize method could be put back in (which is why I don't
778             remove if completely). - ALH
779          ** NON-DOM INTERNAL:
780         A finalizer has added to NodeImpl in order to correct the event-usage
781         counts of any remaining listeners before discarding the Node.
782         This isn't absolutely required, and finalizers are of dubious
783         reliability and have odd effects on some implementations of GC.
784         But given the expense of event generation and distribution it
785         seems a worthwhile safety net.
786         ***** RECONSIDER at some future point.
787     
788     protected void finalize() throws Throwable
789     {
790         super.finalize();
791         if(nodeListeners!=null)
792             for(int i=nodeListeners.size()-1;i>=0;--i) // count-down is OK for deletions!
793             {
794                 LEntry le=(LEntry)(nodeListeners.elementAt(i));
795                 LCount lc=LCount.lookup(le.type);
796                 if(le.useCapture)
797                     --lc.captures;
798                 else
799                     --lc.bubbles;
800             }
801     }
802        */

803
804     /**
805      * Introduced in DOM Level 2. <p>
806      * Distribution engine for DOM Level 2 Events.
807      * <p>
808      * Event propagation runs as follows:
809      * <ol>
810      * <li>Event is dispatched to a particular target node, which invokes
811      * this code. Note that the event's stopPropagation flag is
812      * cleared when dispatch begins; thereafter, if it has
813      * been set before processing of a node commences, we instead
814      * immediately advance to the DEFAULT phase.
815      * <li>The node's ancestors are established as destinations for events.
816      * For capture and bubble purposes, node ancestry is determined at
817      * the time dispatch starts. If an event handler alters the document
818      * tree, that does not change which nodes will be informed of the event.
819      * <li>CAPTURING_PHASE: Ancestors are scanned, root to target, for
820      * Capturing listeners. If found, they are invoked (see below).
821      * <li>AT_TARGET:
822      * Event is dispatched to NON-CAPTURING listeners on the
823      * target node. Note that capturing listeners on this node are _not_
824      * invoked.
825      * <li>BUBBLING_PHASE: Ancestors are scanned, target to root, for
826      * non-capturing listeners.
827      * <li>Default processing: Some DOMs have default behaviors bound to specific
828      * nodes. If this DOM does, and if the event's preventDefault flag has
829      * not been set, we now return to the target node and process its
830      * default handler for this event, if any.
831      * </ol>
832      * <p>
833      * Note that (de)registration of handlers during
834      * processing of an event does not take effect during
835      * this phase of this event; they will not be called until
836      * the next time this node is visited by dispatchEvent.
837      * <p>
838      * If an event handler itself causes events to be dispatched, they are
839      * processed synchronously, before processing resumes
840      * on the event which triggered them. Please be aware that this may
841      * result in events arriving at listeners "out of order" relative
842      * to the actual sequence of requests.
843      * <p>
844      * Note that our implementation resets the event's stop/prevent flags
845      * when dispatch begins.
846      * I believe the DOM's intent is that event objects be redispatchable,
847      * though it isn't stated in those terms.
848      * @param event the event object to be dispatched to
849      * registered EventListeners
850      * @return true if the event's <code>preventDefault()</code>
851      * method was invoked by an EventListener; otherwise false.
852     */

853     public boolean dispatchEvent(Event event) {
854         if (event == null)
855             return false;
856
857         // Can't use anyone else's implementation, since there's no public
858
// API for setting the event's processing-state fields.
859
EventImpl evt = (EventImpl) event;
860
861         // VALIDATE -- must have been initialized at least once, must have
862
// a non-null non-blank name.
863
if (!evt.initialized || evt.type == null || evt.type.equals(""))
864             throw new EventException(EventException.UNSPECIFIED_EVENT_TYPE_ERR, "DOM010 Unspecified event type");
865
866         // If nobody is listening for this event, discard immediately
867
LCount lc = LCount.lookup(evt.getType());
868         if (lc.captures + lc.bubbles + lc.defaults == 0)
869             return evt.preventDefault;
870
871         // INITIALIZE THE EVENT'S DISPATCH STATUS
872
// (Note that Event objects are reusable in our implementation;
873
// that doesn't seem to be explicitly guaranteed in the DOM, but
874
// I believe it is the intent.)
875
evt.target = this;
876         evt.stopPropagation = false;
877         evt.preventDefault = false;
878
879         // Capture pre-event parentage chain, not including target;
880
// use pre-event-dispatch ancestors even if event handlers mutate
881
// document and change the target's context.
882
// Note that this is parents ONLY; events do not
883
// cross the Attr/Element "blood/brain barrier".
884
// DOMAttrModified. which looks like an exception,
885
// is issued to the Element rather than the Attr
886
// and causes a _second_ DOMSubtreeModified in the Element's
887
// tree.
888
Vector JavaDoc pv = new Vector JavaDoc(10, 10);
889         Node p = this, n = p.getParentNode();
890         while (n != null) {
891             pv.addElement(n);
892             p = n;
893             n = n.getParentNode();
894         }
895
896         //CAPTURING_PHASE:
897
if (lc.captures > 0) {
898             evt.eventPhase = Event.CAPTURING_PHASE;
899             //Ancestors are scanned, root to target, for
900
//Capturing listeners.
901
for (int j = pv.size() - 1; j >= 0; --j) {
902                 if (evt.stopPropagation)
903                     break; // Someone set the flag. Phase ends.
904

905                 // Handle all capturing listeners on this node
906
NodeImpl nn = (NodeImpl) pv.elementAt(j);
907                 evt.currentTarget = nn;
908                 Vector JavaDoc nodeListeners = ownerDocument().getEventListeners(nn);
909                 if (nodeListeners != null) {
910                     Vector JavaDoc nl = (Vector JavaDoc) (nodeListeners.clone());
911                     for (int i = nl.size() - 1; i >= 0; --i) // count-down more efficient
912
{
913                         LEntry le = (LEntry) (nl.elementAt(i));
914                         if (le.useCapture && le.type.equals(evt.type))
915                             le.listener.handleEvent(evt);
916                     }
917                 }
918             }
919         }
920
921         //Both AT_TARGET and BUBBLE use non-capturing listeners.
922
if (lc.bubbles > 0) {
923             //AT_TARGET PHASE: Event is dispatched to NON-CAPTURING listeners
924
//on the target node. Note that capturing listeners on the target node
925
//are _not_ invoked, even during the capture phase.
926
evt.eventPhase = Event.AT_TARGET;
927             evt.currentTarget = this;
928             Vector JavaDoc nodeListeners = ownerDocument().getEventListeners(this);
929             if (!evt.stopPropagation && nodeListeners != null) {
930                 Vector JavaDoc nl = (Vector JavaDoc) nodeListeners.clone();
931                 for (int i = nl.size() - 1; i >= 0; --i) // count-down is more efficient
932
{
933                     LEntry le = (LEntry) nl.elementAt(i);
934                     if (le != null && !le.useCapture && le.type.equals(evt.type))
935                         le.listener.handleEvent(evt);
936                 }
937             }
938             //BUBBLING_PHASE: Ancestors are scanned, target to root, for
939
//non-capturing listeners. If the event's preventBubbling flag has
940
//been set before processing of a node commences, we instead
941
//immediately advance to the default phase.
942
//Note that not all events bubble.
943
if (evt.bubbles) {
944                 evt.eventPhase = Event.BUBBLING_PHASE;
945                 for (int j = 0; j < pv.size(); ++j) {
946                     if (evt.stopPropagation)
947                         break; // Someone set the flag. Phase ends.
948

949                     // Handle all bubbling listeners on this node
950
NodeImpl nn = (NodeImpl) pv.elementAt(j);
951                     evt.currentTarget = nn;
952                     nodeListeners = ownerDocument().getEventListeners(nn);
953                     if (nodeListeners != null) {
954                         Vector JavaDoc nl = (Vector JavaDoc) (nodeListeners.clone());
955                         for (int i = nl.size() - 1; i >= 0; --i) // count-down more efficient
956
{
957                             LEntry le = (LEntry) (nl.elementAt(i));
958                             if (!le.useCapture && le.type.equals(evt.type))
959                                 le.listener.handleEvent(evt);
960                         }
961                     }
962                 }
963             }
964         }
965
966         //DEFAULT PHASE: Some DOMs have default behaviors bound to specific
967
//nodes. If this DOM does, and if the event's preventDefault flag has
968
//not been set, we now return to the target node and process its
969
//default handler for this event, if any.
970
// No specific phase value defined, since this is DOM-internal
971
if (lc.defaults > 0 && (!evt.cancelable || !evt.preventDefault)) {
972             // evt.eventPhase=Event.DEFAULT_PHASE;
973
// evt.currentTarget=this;
974
// DO_DEFAULT_OPERATION
975
}
976
977         return evt.preventDefault;
978     } // dispatchEvent(Event) :boolean
979

980     /** NON-DOM INTERNAL: DOMNodeInsertedIntoDocument and ...RemovedFrom...
981      * are dispatched to an entire subtree. This is the distribution code
982      * therefor. They DO NOT bubble, thanks be, but may be captured.
983      * <p>
984      * ***** At the moment I'm being sloppy and using the normal
985      * capture dispatcher on every node. This could be optimized hugely
986      * by writing a capture engine that tracks our position in the tree to
987      * update the capture chain without repeated chases up to root.
988      * @param n node which was directly inserted or removed
989      * @param e event to be sent to that node and its subtree
990      */

991     void dispatchEventToSubtree(Node n, Event e) {
992         if (MUTATIONEVENTS && ownerDocument().mutationEvents) {
993             Vector JavaDoc nodeListeners = ownerDocument().getEventListeners(this);
994             if (nodeListeners == null || n == null)
995                 return;
996
997             // ***** Recursive implementation. This is excessively expensive,
998
// and should be replaced in conjunction with optimization
999
// mentioned above.
1000
((NodeImpl) n).dispatchEvent(e);
1001            if (n.getNodeType() == Node.ELEMENT_NODE) {
1002                NamedNodeMap a = n.getAttributes();
1003                for (int i = a.getLength() - 1; i >= 0; --i)
1004                    dispatchEventToSubtree(a.item(i), e);
1005            }
1006            dispatchEventToSubtree(n.getFirstChild(), e);
1007            dispatchEventToSubtree(n.getNextSibling(), e);
1008        }
1009    } // dispatchEventToSubtree(Node,Event) :void
1010

1011    /** NON-DOM INTERNAL: Return object for getEnclosingAttr. Carries
1012     * (two values, the Attr node affected (if any) and its previous
1013     * string value. Simple struct, no methods.
1014     */

1015    class EnclosingAttr {
1016        AttrImpl node;
1017        String JavaDoc oldvalue;
1018    } //EnclosingAttr
1019

1020    /** NON-DOM INTERNAL: Pre-mutation context check, in
1021     * preparation for later generating DOMAttrModified events.
1022     * Determines whether this node is within an Attr
1023     * @return either a description of that Attr, or Null
1024     * if none such.
1025     */

1026    EnclosingAttr getEnclosingAttr() {
1027        if (MUTATIONEVENTS && ownerDocument().mutationEvents) {
1028            NodeImpl eventAncestor = this;
1029            while (true) {
1030                if (eventAncestor == null)
1031                    return null;
1032                int type = eventAncestor.getNodeType();
1033                if (type == Node.ATTRIBUTE_NODE) {
1034                    EnclosingAttr retval = new EnclosingAttr();
1035                    retval.node = (AttrImpl) eventAncestor;
1036                    retval.oldvalue = retval.node.getNodeValue();
1037                    return retval;
1038                } else if (type == Node.ENTITY_REFERENCE_NODE)
1039                    eventAncestor = eventAncestor.parentNode();
1040                else
1041                    return null;
1042                // Any other parent means we're not in an Attr
1043
}
1044        }
1045        return null; // Safety net, should never be reached
1046
} // getEnclosingAttr() :EnclosingAttr
1047

1048    /** NON-DOM INTERNAL: Convenience wrapper for calling
1049     * dispatchAggregateEvents when the context was established
1050     * by <code>getEnclosingAttr</code>.
1051     * @param ea description of Attr affected by current operation
1052     */

1053    void dispatchAggregateEvents(EnclosingAttr ea) {
1054        if (ea != null)
1055            dispatchAggregateEvents(ea.node, ea.oldvalue, MutationEvent.MODIFICATION);
1056        else
1057            dispatchAggregateEvents(null, null, (short) 0);
1058
1059    } // dispatchAggregateEvents(EnclosingAttr) :void
1060

1061    /** NON-DOM INTERNAL: Generate the "aggregated" post-mutation events
1062     * DOMAttrModified and DOMSubtreeModified.
1063     * Both of these should be issued only once for each user-requested
1064     * mutation operation, even if that involves multiple changes to
1065     * the DOM.
1066     * For example, if a DOM operation makes multiple changes to a single
1067     * Attr before returning, it would be nice to generate only one
1068     * DOMAttrModified, and multiple changes over larger scope but within
1069     * a recognizable single subtree might want to generate only one
1070     * DOMSubtreeModified, sent to their lowest common ancestor.
1071     * <p>
1072     * To manage this, use the "internal" versions of insert and remove
1073     * with MUTATION_LOCAL, then make an explicit call to this routine
1074     * at the higher level. Some examples now exist in our code.
1075     *
1076     * @param enclosingAttr The Attr node (if any) whose value has
1077     * been changed as a result of the DOM operation. Null if none such.
1078     * @param oldValue The String value previously held by the
1079     * enclosingAttr. Ignored if none such.
1080         * @param change Type of modification to the attr. See
1081         * MutationEvent.attrChange
1082     */

1083    void dispatchAggregateEvents(AttrImpl enclosingAttr, String JavaDoc oldvalue, short change) {
1084        if (MUTATIONEVENTS && ownerDocument().mutationEvents) {
1085            // We have to send DOMAttrModified.
1086
NodeImpl owner = null;
1087            if (enclosingAttr != null) {
1088                LCount lc = LCount.lookup(MutationEventImpl.DOM_ATTR_MODIFIED);
1089                owner = ((NodeImpl) (enclosingAttr.getOwnerElement()));
1090                if (lc.captures + lc.bubbles + lc.defaults > 0) {
1091                    if (owner != null) {
1092                        MutationEventImpl me = new MutationEventImpl();
1093                        me.initMutationEvent(MutationEventImpl.DOM_ATTR_MODIFIED, true, false, enclosingAttr, oldvalue, enclosingAttr.getNodeValue(), enclosingAttr.getNodeName(), change);
1094                        owner.dispatchEvent(me);
1095                    }
1096                }
1097            }
1098
1099            // DOMSubtreeModified gets sent to the lowest common root of a
1100
// set of changes.
1101
// "This event is dispatched after all other events caused by the
1102
// mutation have been fired."
1103
LCount lc = LCount.lookup(MutationEventImpl.DOM_SUBTREE_MODIFIED);
1104            if (lc.captures + lc.bubbles + lc.defaults > 0) {
1105                MutationEvent me = new MutationEventImpl();
1106                me.initMutationEvent(MutationEventImpl.DOM_SUBTREE_MODIFIED, true, false, null, null, null, null, (short) 0);
1107
1108                // If we're within an Attr, DStM gets sent to the Attr
1109
// and to its owningElement. Otherwise we dispatch it
1110
// locally.
1111
if (enclosingAttr != null) {
1112                    enclosingAttr.dispatchEvent(me);
1113                    if (owner != null)
1114                        owner.dispatchEvent(me);
1115                } else
1116                    dispatchEvent(me);
1117            }
1118        }
1119    } //dispatchAggregateEvents(AttrImpl,String) :void
1120

1121    //
1122
// Public methods
1123
//
1124

1125    /**
1126     * NON-DOM: PR-DOM-Level-1-19980818 mentions readonly nodes in conjunction
1127     * with Entities, but provides no API to support this.
1128     * <P>
1129     * Most DOM users should not touch this method. Its anticpated use
1130     * is during construction of EntityRefernces, where it will be used to
1131     * lock the contents replicated from Entity so they can't be casually
1132     * altered. It _could_ be published as a DOM extension, if desired.
1133     * <P>
1134     * Note: since we never have any children deep is meaningless here,
1135     * ParentNode overrides this behavior.
1136     * @see ParentNode
1137     *
1138     * @param readOnly True or false as desired.
1139     * @param deep If true, children are also toggled. Note that this will
1140     * not change the state of an EntityReference or its children,
1141     * which are always read-only.
1142     */

1143    public void setReadOnly(boolean readOnly, boolean deep) {
1144
1145        if (needsSyncData()) {
1146            synchronizeData();
1147        }
1148        isReadOnly(readOnly);
1149
1150    } // setReadOnly(boolean,boolean)
1151

1152    /**
1153     * NON-DOM: Returns true if this node is read-only. This is a
1154     * shallow check.
1155     */

1156    public boolean getReadOnly() {
1157
1158        if (needsSyncData()) {
1159            synchronizeData();
1160        }
1161        return isReadOnly();
1162
1163    } // getReadOnly():boolean
1164

1165    /**
1166     * NON-DOM: As an alternative to subclassing the DOM, this implementation
1167     * has been extended with the ability to attach an object to each node.
1168     * (If you need multiple objects, you can attach a collection such as a
1169     * vector or hashtable, then attach your application information to that.)
1170     * <p><b>Important Note:</b> You are responsible for removing references
1171     * to your data on nodes that are no longer used. Failure to do so will
1172     * prevent the nodes, your data is attached to, to be garbage collected
1173     * until the whole document is.
1174     *
1175     * @param data the object to store or null to remove any existing reference
1176     */

1177    public void setUserData(Object JavaDoc data) {
1178        ownerDocument().setUserData(this, data);
1179    }
1180
1181    /**
1182     * NON-DOM:
1183     * Returns the user data associated to this node.
1184     */

1185    public Object JavaDoc getUserData() {
1186        return ownerDocument().getUserData(this);
1187    }
1188
1189    //
1190
// Protected methods
1191
//
1192

1193    /**
1194     * Denotes that this node has changed.
1195     */

1196    protected void changed() {
1197        // we do not actually store this information on every node, we only
1198
// have a global indicator on the Document. Doing otherwise cost us too
1199
// much for little gain.
1200
ownerDocument().changed();
1201    }
1202
1203    /**
1204     * Returns the number of changes to this node.
1205     */

1206    protected int changes() {
1207        // we do not actually store this information on every node, we only
1208
// have a global indicator on the Document. Doing otherwise cost us too
1209
// much for little gain.
1210
return ownerDocument().changes();
1211    }
1212
1213    /**
1214     * Override this method in subclass to hook in efficient
1215     * internal data structure.
1216     */

1217    protected void synchronizeData() {
1218        // By default just change the flag to avoid calling this method again
1219
needsSyncData(false);
1220    }
1221
1222    /*
1223     * Flags setters and getters
1224     */

1225
1226    final boolean isReadOnly() {
1227        return (flags & READONLY) != 0;
1228    }
1229
1230    final void isReadOnly(boolean value) {
1231        flags = (short) (value ? flags | READONLY : flags & ~READONLY);
1232    }
1233
1234    final boolean needsSyncData() {
1235        return (flags & SYNCDATA) != 0;
1236    }
1237
1238    final void needsSyncData(boolean value) {
1239        flags = (short) (value ? flags | SYNCDATA : flags & ~SYNCDATA);
1240    }
1241
1242    final boolean needsSyncChildren() {
1243        return (flags & SYNCCHILDREN) != 0;
1244    }
1245
1246    final void needsSyncChildren(boolean value) {
1247        flags = (short) (value ? flags | SYNCCHILDREN : flags & ~SYNCCHILDREN);
1248    }
1249
1250    final boolean isOwned() {
1251        return (flags & OWNED) != 0;
1252    }
1253
1254    final void isOwned(boolean value) {
1255        flags = (short) (value ? flags | OWNED : flags & ~OWNED);
1256    }
1257
1258    final boolean isFirstChild() {
1259        return (flags & FIRSTCHILD) != 0;
1260    }
1261
1262    final void isFirstChild(boolean value) {
1263        flags = (short) (value ? flags | FIRSTCHILD : flags & ~FIRSTCHILD);
1264    }
1265
1266    final boolean isSpecified() {
1267        return (flags & SPECIFIED) != 0;
1268    }
1269
1270    final void isSpecified(boolean value) {
1271        flags = (short) (value ? flags | SPECIFIED : flags & ~SPECIFIED);
1272    }
1273
1274    // inconsistent name to avoid clash with public method on TextImpl
1275
final boolean internalIsIgnorableWhitespace() {
1276        return (flags & IGNORABLEWS) != 0;
1277    }
1278
1279    final void isIgnorableWhitespace(boolean value) {
1280        flags = (short) (value ? flags | IGNORABLEWS : flags & ~IGNORABLEWS);
1281    }
1282
1283    final boolean setValueCalled() {
1284        return (flags & SETVALUE) != 0;
1285    }
1286
1287    final void setValueCalled(boolean value) {
1288        flags = (short) (value ? flags | SETVALUE : flags & ~SETVALUE);
1289    }
1290
1291    final boolean hasStringValue() {
1292        return (flags & HASSTRING) != 0;
1293    }
1294
1295    final void hasStringValue(boolean value) {
1296        flags = (short) (value ? flags | HASSTRING : flags & ~HASSTRING);
1297    }
1298
1299    final boolean isNormalized() {
1300        return (flags & UNNORMALIZED) == 0;
1301    }
1302
1303    final void isNormalized(boolean value) {
1304        // See if flag should propagate to parent.
1305
if (!value && isNormalized() && ownerNode != null) {
1306            ownerNode.isNormalized(false);
1307        }
1308        flags = (short) (value ? flags & ~UNNORMALIZED : flags | UNNORMALIZED);
1309    }
1310
1311    //
1312
// Object methods
1313
//
1314

1315    /** NON-DOM method for debugging convenience. */
1316    public String JavaDoc toString() {
1317        return "[" + getNodeName() + ": " + getNodeValue() + "]";
1318    }
1319
1320    //
1321
// Serialization methods
1322
//
1323

1324    /** Serialize object. */
1325    private void writeObject(ObjectOutputStream JavaDoc out) throws IOException JavaDoc {
1326
1327        // synchronize data
1328
if (needsSyncData()) {
1329            synchronizeData();
1330        }
1331        // write object
1332
out.defaultWriteObject();
1333
1334    } // writeObject(ObjectOutputStream)
1335

1336} // class NodeImpl
1337
Popular Tags