001: /*
002: * The Apache Software License, Version 1.1
003: *
004: *
005: * Copyright (c) 1999-2001 The Apache Software Foundation. All rights
006: * reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * 1. Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * 2. Redistributions in binary form must reproduce the above copyright
016: * notice, this list of conditions and the following disclaimer in
017: * the documentation and/or other materials provided with the
018: * distribution.
019: *
020: * 3. The end-user documentation included with the redistribution,
021: * if any, must include the following acknowledgment:
022: * "This product includes software developed by the
023: * Apache Software Foundation (http://www.apache.org/)."
024: * Alternately, this acknowledgment may appear in the software itself,
025: * if and wherever such third-party acknowledgments normally appear.
026: *
027: * 4. The names "Xerces" and "Apache Software Foundation" must
028: * not be used to endorse or promote products derived from this
029: * software without prior written permission. For written
030: * permission, please contact apache@apache.org.
031: *
032: * 5. Products derived from this software may not be called "Apache",
033: * nor may "Apache" appear in their name, without prior written
034: * permission of the Apache Software Foundation.
035: *
036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
040: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: * SUCH DAMAGE.
048: * ====================================================================
049: *
050: * This software consists of voluntary contributions made by many
051: * individuals on behalf of the Apache Software Foundation and was
052: * originally based on software copyright (c) 1999, International
053: * Business Machines, Inc., http://www.apache.org. For more
054: * information on the Apache Software Foundation, please see
055: * <http://www.apache.org/>.
056: */
057:
058: package org.apache.xerces.dom;
059:
060: import java.io.IOException;
061: import java.io.ObjectOutputStream;
062: import java.io.Serializable;
063: import java.util.Vector;
064:
065: import org.w3c.dom.DOMException;
066: import org.w3c.dom.Document;
067: import org.w3c.dom.NamedNodeMap;
068: import org.w3c.dom.Node;
069: import org.w3c.dom.NodeList;
070: import org.w3c.dom.events.Event;
071: import org.w3c.dom.events.EventListener;
072: import org.w3c.dom.events.EventTarget;
073:
074: /**
075: * NodeImpl provides the basic structure of a DOM tree. It is never used
076: * directly, but instead is subclassed to add type and data
077: * information, and additional methods, appropriate to each node of
078: * the tree. Only its subclasses should be instantiated -- and those,
079: * with the exception of Document itself, only through a specific
080: * Document's factory methods.
081: * <P>
082: * The Node interface provides shared behaviors such as siblings and
083: * children, both for consistancy and so that the most common tree
084: * operations may be performed without constantly having to downcast
085: * to specific node types. When there is no obvious mapping for one of
086: * these queries, it will respond with null.
087: * Note that the default behavior is that children are forbidden. To
088: * permit them, the subclass ParentNode overrides several methods.
089: * <P>
090: * NodeImpl also implements NodeList, so it can return itself in
091: * response to the getChildNodes() query. This eliminiates the need
092: * for a separate ChildNodeList object. Note that this is an
093: * IMPLEMENTATION DETAIL; applications should _never_ assume that
094: * this identity exists.
095: * <P>
096: * All nodes in a single document must originate
097: * in that document. (Note that this is much tighter than "must be
098: * same implementation") Nodes are all aware of their ownerDocument,
099: * and attempts to mismatch will throw WRONG_DOCUMENT_ERR.
100: * <P>
101: * However, to save memory not all nodes always have a direct reference
102: * to their ownerDocument. When a node is owned by another node it relies
103: * on its owner to store its ownerDocument. Parent nodes always store it
104: * though, so there is never more than one level of indirection.
105: * And when a node doesn't have an owner, ownerNode refers to its
106: * ownerDocument.
107: * <p>
108: * This class doesn't directly support mutation events, however, it still
109: * implements the EventTarget interface and forward all related calls to the
110: * document so that the document class do so.
111: *
112: * @author Arnaud Le Hors, IBM
113: * @author Joe Kesselman, IBM
114: * @version
115: * @since PR-DOM-Level-1-19980818.
116: */
117: public abstract class NodeImpl implements Node, NodeList, EventTarget,
118: Cloneable, Serializable {
119:
120: //
121: // Constants
122: //
123:
124: /** Serialization version. */
125: static final long serialVersionUID = -6316591992167219696L;
126:
127: // public
128:
129: /** Element definition node type. */
130: public static final short ELEMENT_DEFINITION_NODE = -1;
131:
132: //
133: // Data
134: //
135:
136: // links
137:
138: protected NodeImpl ownerNode; // typically the parent but not always!
139:
140: // data
141:
142: protected short flags;
143:
144: protected final static short READONLY = 0x1 << 0;
145: protected final static short SYNCDATA = 0x1 << 1;
146: protected final static short SYNCCHILDREN = 0x1 << 2;
147: protected final static short OWNED = 0x1 << 3;
148: protected final static short FIRSTCHILD = 0x1 << 4;
149: protected final static short SPECIFIED = 0x1 << 5;
150: protected final static short IGNORABLEWS = 0x1 << 6;
151: protected final static short HASSTRING = 0x1 << 7;
152: protected final static short UNNORMALIZED = 0x1 << 8;
153:
154: //
155: // Constructors
156: //
157:
158: /**
159: * No public constructor; only subclasses of Node should be
160: * instantiated, and those normally via a Document's factory methods
161: * <p>
162: * Every Node knows what Document it belongs to.
163: */
164: protected NodeImpl(CoreDocumentImpl ownerDocument) {
165: // as long as we do not have any owner, ownerNode is our ownerDocument
166: ownerNode = ownerDocument;
167: } // <init>(CoreDocumentImpl)
168:
169: /** Constructor for serialization. */
170: public NodeImpl() {
171: }
172:
173: //
174: // Node methods
175: //
176:
177: /**
178: * A short integer indicating what type of node this is. The named
179: * constants for this value are defined in the org.w3c.dom.Node interface.
180: */
181: public abstract short getNodeType();
182:
183: /**
184: * the name of this node.
185: */
186: public abstract String getNodeName();
187:
188: /**
189: * Returns the node value.
190: */
191: public String getNodeValue() {
192: return null; // overridden in some subclasses
193: }
194:
195: /**
196: * Sets the node value.
197: * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR)
198: */
199: public void setNodeValue(String x) throws DOMException {
200: // Default behavior is to do nothing, overridden in some subclasses
201: }
202:
203: /**
204: * Adds a child node to the end of the list of children for this node.
205: * Convenience shorthand for insertBefore(newChild,null).
206: * @see #insertBefore(Node, Node)
207: * <P>
208: * By default we do not accept any children, ParentNode overrides this.
209: * @see ParentNode
210: *
211: * @returns newChild, in its new state (relocated, or emptied in the
212: * case of DocumentNode.)
213: *
214: * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a
215: * type that shouldn't be a child of this node.
216: *
217: * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a
218: * different owner document than we do.
219: *
220: * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
221: * read-only.
222: */
223: public Node appendChild(Node newChild) throws DOMException {
224: return insertBefore(newChild, null);
225: }
226:
227: /**
228: * Returns a duplicate of a given node. You can consider this a
229: * generic "copy constructor" for nodes. The newly returned object should
230: * be completely independent of the source object's subtree, so changes
231: * in one after the clone has been made will not affect the other.
232: * <P>
233: * Note: since we never have any children deep is meaningless here,
234: * ParentNode overrides this behavior.
235: * @see ParentNode
236: *
237: * <p>
238: * Example: Cloning a Text node will copy both the node and the text it
239: * contains.
240: * <p>
241: * Example: Cloning something that has children -- Element or Attr, for
242: * example -- will _not_ clone those children unless a "deep clone"
243: * has been requested. A shallow clone of an Attr node will yield an
244: * empty Attr of the same name.
245: * <p>
246: * NOTE: Clones will always be read/write, even if the node being cloned
247: * is read-only, to permit applications using only the DOM API to obtain
248: * editable copies of locked portions of the tree.
249: */
250: public Node cloneNode(boolean deep) {
251:
252: if (needsSyncData()) {
253: synchronizeData();
254: }
255:
256: NodeImpl newnode;
257: try {
258: newnode = (NodeImpl) clone();
259: } catch (CloneNotSupportedException e) {
260: // Revisit : don't fail silently - but don't want to tie to parser guts
261: // System.out.println("UNEXPECTED "+e);
262: return null;
263: }
264:
265: // Need to break the association w/ original kids
266: newnode.ownerNode = ownerDocument();
267: newnode.isOwned(false);
268:
269: // REVISIT: What to do when readOnly? -Ac
270: newnode.isReadOnly(false);
271:
272: return newnode;
273:
274: } // cloneNode(boolean):Node
275:
276: /**
277: * Find the Document that this Node belongs to (the document in
278: * whose context the Node was created). The Node may or may not
279: * currently be part of that Document's actual contents.
280: */
281: public Document getOwnerDocument() {
282: // if we have an owner simply forward the request
283: // otherwise ownerNode is our ownerDocument
284: if (isOwned()) {
285: return ownerNode.ownerDocument();
286: } else {
287: return (Document) ownerNode;
288: }
289: }
290:
291: /**
292: * same as above but returns internal type and this one is not overridden
293: * by CoreDocumentImpl to return null
294: */
295: CoreDocumentImpl ownerDocument() {
296: // if we have an owner simply forward the request
297: // otherwise ownerNode is our ownerDocument
298: if (isOwned()) {
299: return ownerNode.ownerDocument();
300: } else {
301: return (CoreDocumentImpl) ownerNode;
302: }
303: }
304:
305: /**
306: * NON-DOM
307: * set the ownerDocument of this node
308: */
309: void setOwnerDocument(CoreDocumentImpl doc) {
310: if (needsSyncData()) {
311: synchronizeData();
312: }
313: // if we have an owner we rely on it to have it right
314: // otherwise ownerNode is our ownerDocument
315: if (!isOwned()) {
316: ownerNode = doc;
317: }
318: }
319:
320: /**
321: * Obtain the DOM-tree parent of this node, or null if it is not
322: * currently active in the DOM tree (perhaps because it has just been
323: * created or removed). Note that Document, DocumentFragment, and
324: * Attribute will never have parents.
325: */
326: public Node getParentNode() {
327: return null; // overriden by ChildNode
328: }
329:
330: /*
331: * same as above but returns internal type
332: */
333: NodeImpl parentNode() {
334: return null;
335: }
336:
337: /** The next child of this node's parent, or null if none */
338: public Node getNextSibling() {
339: return null; // default behavior, overriden in ChildNode
340: }
341:
342: /** The previous child of this node's parent, or null if none */
343: public Node getPreviousSibling() {
344: return null; // default behavior, overriden in ChildNode
345: }
346:
347: ChildNode previousSibling() {
348: return null; // default behavior, overriden in ChildNode
349: }
350:
351: /**
352: * Return the collection of attributes associated with this node,
353: * or null if none. At this writing, Element is the only type of node
354: * which will ever have attributes.
355: *
356: * @see ElementImpl
357: */
358: public NamedNodeMap getAttributes() {
359: return null; // overridden in ElementImpl
360: }
361:
362: /**
363: * Returns whether this node (if it is an element) has any attributes.
364: * @return <code>true</code> if this node has any attributes,
365: * <code>false</code> otherwise.
366: * @since DOM Level 2
367: * @see ElementImpl
368: */
369: public boolean hasAttributes() {
370: return false; // overridden in ElementImpl
371: }
372:
373: /**
374: * Test whether this node has any children. Convenience shorthand
375: * for (Node.getFirstChild()!=null)
376: * <P>
377: * By default we do not have any children, ParentNode overrides this.
378: * @see ParentNode
379: */
380: public boolean hasChildNodes() {
381: return false;
382: }
383:
384: /**
385: * Obtain a NodeList enumerating all children of this node. If there
386: * are none, an (initially) empty NodeList is returned.
387: * <p>
388: * NodeLists are "live"; as children are added/removed the NodeList
389: * will immediately reflect those changes. Also, the NodeList refers
390: * to the actual nodes, so changes to those nodes made via the DOM tree
391: * will be reflected in the NodeList and vice versa.
392: * <p>
393: * In this implementation, Nodes implement the NodeList interface and
394: * provide their own getChildNodes() support. Other DOMs may solve this
395: * differently.
396: */
397: public NodeList getChildNodes() {
398: return this ;
399: }
400:
401: /** The first child of this Node, or null if none.
402: * <P>
403: * By default we do not have any children, ParentNode overrides this.
404: * @see ParentNode
405: */
406: public Node getFirstChild() {
407: return null;
408: }
409:
410: /** The first child of this Node, or null if none.
411: * <P>
412: * By default we do not have any children, ParentNode overrides this.
413: * @see ParentNode
414: */
415: public Node getLastChild() {
416: return null;
417: }
418:
419: /**
420: * Move one or more node(s) to our list of children. Note that this
421: * implicitly removes them from their previous parent.
422: * <P>
423: * By default we do not accept any children, ParentNode overrides this.
424: * @see ParentNode
425: *
426: * @param newChild The Node to be moved to our subtree. As a
427: * convenience feature, inserting a DocumentNode will instead insert
428: * all its children.
429: *
430: * @param refChild Current child which newChild should be placed
431: * immediately before. If refChild is null, the insertion occurs
432: * after all existing Nodes, like appendChild().
433: *
434: * @returns newChild, in its new state (relocated, or emptied in the
435: * case of DocumentNode.)
436: *
437: * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a
438: * type that shouldn't be a child of this node, or if newChild is an
439: * ancestor of this node.
440: *
441: * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a
442: * different owner document than we do.
443: *
444: * @throws DOMException(NOT_FOUND_ERR) if refChild is not a child of
445: * this node.
446: *
447: * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
448: * read-only.
449: */
450: public Node insertBefore(Node newChild, Node refChild)
451: throws DOMException {
452: throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
453: "DOM006 Hierarchy request error");
454: }
455:
456: /**
457: * Remove a child from this Node. The removed child's subtree
458: * remains intact so it may be re-inserted elsewhere.
459: * <P>
460: * By default we do not have any children, ParentNode overrides this.
461: * @see ParentNode
462: *
463: * @return oldChild, in its new state (removed).
464: *
465: * @throws DOMException(NOT_FOUND_ERR) if oldChild is not a child of
466: * this node.
467: *
468: * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
469: * read-only.
470: */
471: public Node removeChild(Node oldChild) throws DOMException {
472: throw new DOMException(DOMException.NOT_FOUND_ERR,
473: "DOM008 Not found");
474: }
475:
476: /**
477: * Make newChild occupy the location that oldChild used to
478: * have. Note that newChild will first be removed from its previous
479: * parent, if any. Equivalent to inserting newChild before oldChild,
480: * then removing oldChild.
481: * <P>
482: * By default we do not have any children, ParentNode overrides this.
483: * @see ParentNode
484: *
485: * @returns oldChild, in its new state (removed).
486: *
487: * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a
488: * type that shouldn't be a child of this node, or if newChild is
489: * one of our ancestors.
490: *
491: * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a
492: * different owner document than we do.
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 replaceChild(Node newChild, Node oldChild)
501: throws DOMException {
502: throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
503: "DOM006 Hierarchy request error");
504: }
505:
506: //
507: // NodeList methods
508: //
509:
510: /**
511: * NodeList method: Count the immediate children of this node
512: * <P>
513: * By default we do not have any children, ParentNode overrides this.
514: * @see ParentNode
515: *
516: * @return int
517: */
518: public int getLength() {
519: return 0;
520: }
521:
522: /**
523: * NodeList method: Return the Nth immediate child of this node, or
524: * null if the index is out of bounds.
525: * <P>
526: * By default we do not have any children, ParentNode overrides this.
527: * @see ParentNode
528: *
529: * @return org.w3c.dom.Node
530: * @param Index int
531: */
532: public Node item(int index) {
533: return null;
534: }
535:
536: //
537: // DOM2: methods, getters, setters
538: //
539:
540: /**
541: * Puts all <code>Text</code> nodes in the full depth of the sub-tree
542: * underneath this <code>Node</code>, including attribute nodes, into a
543: * "normal" form where only markup (e.g., tags, comments, processing
544: * instructions, CDATA sections, and entity references) separates
545: * <code>Text</code> nodes, i.e., there are no adjacent <code>Text</code>
546: * nodes. This can be used to ensure that the DOM view of a document is
547: * the same as if it were saved and re-loaded, and is useful when
548: * operations (such as XPointer lookups) that depend on a particular
549: * document tree structure are to be used.In cases where the document
550: * contains <code>CDATASections</code>, the normalize operation alone may
551: * not be sufficient, since XPointers do not differentiate between
552: * <code>Text</code> nodes and <code>CDATASection</code> nodes.
553: * <p>
554: * Note that this implementation simply calls normalize() on this Node's
555: * children. It is up to implementors or Node to override normalize()
556: * to take action.
557: */
558: public void normalize() {
559: /* by default we do not have any children,
560: ParentNode overrides this behavior */
561: }
562:
563: /**
564: * Introduced in DOM Level 2. <p>
565: * Tests whether the DOM implementation implements a specific feature and
566: * that feature is supported by this node.
567: * @param feature The package name of the feature to test. This is the same
568: * name as what can be passed to the method hasFeature on
569: * DOMImplementation.
570: * @param version This is the version number of the package name to
571: * test. In Level 2, version 1, this is the string "2.0". If the version is
572: * not specified, supporting any version of the feature will cause the
573: * method to return true.
574: * @return boolean Returns true if this node defines a subtree within which
575: * the specified feature is supported, false otherwise.
576: * @since WD-DOM-Level-2-19990923
577: */
578: public boolean isSupported(String feature, String version) {
579: return ownerDocument().getImplementation().hasFeature(feature,
580: version);
581: }
582:
583: /**
584: * Introduced in DOM Level 2. <p>
585: *
586: * The namespace URI of this node, or null if it is unspecified. When this
587: * node is of any type other than ELEMENT_NODE and ATTRIBUTE_NODE, this is
588: * always null and setting it has no effect. <p>
589: *
590: * This is not a computed value that is the result of a namespace lookup
591: * based on an examination of the namespace declarations in scope. It is
592: * merely the namespace URI given at creation time.<p>
593: *
594: * For nodes created with a DOM Level 1 method, such as createElement
595: * from the Document interface, this is null.
596: * @since WD-DOM-Level-2-19990923
597: * @see AttrNSImpl
598: * @see ElementNSImpl
599: */
600: public String getNamespaceURI() {
601: return null;
602: }
603:
604: /**
605: * Introduced in DOM Level 2. <p>
606: *
607: * The namespace prefix of this node, or null if it is unspecified. When
608: * this node is of any type other than ELEMENT_NODE and ATTRIBUTE_NODE this
609: * is always null and setting it has no effect.<p>
610: *
611: * For nodes created with a DOM Level 1 method, such as createElement
612: * from the Document interface, this is null. <p>
613: *
614: * @since WD-DOM-Level-2-19990923
615: * @see AttrNSImpl
616: * @see ElementNSImpl
617: */
618: public String getPrefix() {
619: return null;
620: }
621:
622: /**
623: * Introduced in DOM Level 2. <p>
624: *
625: * The namespace prefix of this node, or null if it is unspecified. When
626: * this node is of any type other than ELEMENT_NODE and ATTRIBUTE_NODE
627: * this is always null and setting it has no effect.<p>
628: *
629: * For nodes created with a DOM Level 1 method, such as createElement from
630: * the Document interface, this is null.<p>
631: *
632: * Note that setting this attribute changes the nodeName attribute, which
633: * holds the qualified name, as well as the tagName and name attributes of
634: * the Element and Attr interfaces, when applicable.<p>
635: *
636: * @throws INVALID_CHARACTER_ERR Raised if the specified
637: * prefix contains an invalid character.
638: *
639: * @since WD-DOM-Level-2-19990923
640: * @see AttrNSImpl
641: * @see ElementNSImpl
642: */
643: public void setPrefix(String prefix) throws DOMException {
644: throw new DOMException(DOMException.NAMESPACE_ERR,
645: "DOM003 Namespace error");
646: }
647:
648: /**
649: * Introduced in DOM Level 2. <p>
650: *
651: * Returns the local part of the qualified name of this node.
652: * For nodes created with a DOM Level 1 method, such as createElement
653: * from the Document interface, and for nodes of any type other than
654: * ELEMENT_NODE and ATTRIBUTE_NODE this is the same as the nodeName
655: * attribute.
656: * @since WD-DOM-Level-2-19990923
657: * @see AttrNSImpl
658: * @see ElementNSImpl
659: */
660: public String getLocalName() {
661: return null;
662: }
663:
664: //
665: // EventTarget support
666: //
667:
668: public void addEventListener(String type, EventListener listener,
669: boolean useCapture) {
670: // simply forward to Document
671: ownerDocument().addEventListener(this , type, listener,
672: useCapture);
673: }
674:
675: public void removeEventListener(String type,
676: EventListener listener, boolean useCapture) {
677: // simply forward to Document
678: ownerDocument().removeEventListener(this , type, listener,
679: useCapture);
680: }
681:
682: public boolean dispatchEvent(Event event) {
683: // simply forward to Document
684: return ownerDocument().dispatchEvent(this , event);
685: }
686:
687: //
688: // Public methods
689: //
690:
691: /**
692: * NON-DOM: PR-DOM-Level-1-19980818 mentions readonly nodes in conjunction
693: * with Entities, but provides no API to support this.
694: * <P>
695: * Most DOM users should not touch this method. Its anticpated use
696: * is during construction of EntityRefernces, where it will be used to
697: * lock the contents replicated from Entity so they can't be casually
698: * altered. It _could_ be published as a DOM extension, if desired.
699: * <P>
700: * Note: since we never have any children deep is meaningless here,
701: * ParentNode overrides this behavior.
702: * @see ParentNode
703: *
704: * @param readOnly True or false as desired.
705: * @param deep If true, children are also toggled. Note that this will
706: * not change the state of an EntityReference or its children,
707: * which are always read-only.
708: */
709: public void setReadOnly(boolean readOnly, boolean deep) {
710:
711: if (needsSyncData()) {
712: synchronizeData();
713: }
714: isReadOnly(readOnly);
715:
716: } // setReadOnly(boolean,boolean)
717:
718: /**
719: * NON-DOM: Returns true if this node is read-only. This is a
720: * shallow check.
721: */
722: public boolean getReadOnly() {
723:
724: if (needsSyncData()) {
725: synchronizeData();
726: }
727: return isReadOnly();
728:
729: } // getReadOnly():boolean
730:
731: /**
732: * NON-DOM: As an alternative to subclassing the DOM, this implementation
733: * has been extended with the ability to attach an object to each node.
734: * (If you need multiple objects, you can attach a collection such as a
735: * vector or hashtable, then attach your application information to that.)
736: * <p><b>Important Note:</b> You are responsible for removing references
737: * to your data on nodes that are no longer used. Failure to do so will
738: * prevent the nodes, your data is attached to, to be garbage collected
739: * until the whole document is.
740: *
741: * @param data the object to store or null to remove any existing reference
742: */
743: public void setUserData(Object data) {
744: ownerDocument().setUserData(this , data);
745: }
746:
747: /**
748: * NON-DOM:
749: * Returns the user data associated to this node.
750: */
751: public Object getUserData() {
752: return ownerDocument().getUserData(this );
753: }
754:
755: //
756: // Protected methods
757: //
758:
759: /**
760: * Denotes that this node has changed.
761: */
762: protected void changed() {
763: // we do not actually store this information on every node, we only
764: // have a global indicator on the Document. Doing otherwise cost us too
765: // much for little gain.
766: ownerDocument().changed();
767: }
768:
769: /**
770: * Returns the number of changes to this node.
771: */
772: protected int changes() {
773: // we do not actually store this information on every node, we only
774: // have a global indicator on the Document. Doing otherwise cost us too
775: // much for little gain.
776: return ownerDocument().changes();
777: }
778:
779: /**
780: * Override this method in subclass to hook in efficient
781: * internal data structure.
782: */
783: protected void synchronizeData() {
784: // By default just change the flag to avoid calling this method again
785: needsSyncData(false);
786: }
787:
788: /*
789: * Flags setters and getters
790: */
791:
792: final boolean isReadOnly() {
793: return (flags & READONLY) != 0;
794: }
795:
796: final void isReadOnly(boolean value) {
797: flags = (short) (value ? flags | READONLY : flags & ~READONLY);
798: }
799:
800: final boolean needsSyncData() {
801: return (flags & SYNCDATA) != 0;
802: }
803:
804: final void needsSyncData(boolean value) {
805: flags = (short) (value ? flags | SYNCDATA : flags & ~SYNCDATA);
806: }
807:
808: final boolean needsSyncChildren() {
809: return (flags & SYNCCHILDREN) != 0;
810: }
811:
812: final void needsSyncChildren(boolean value) {
813: flags = (short) (value ? flags | SYNCCHILDREN : flags
814: & ~SYNCCHILDREN);
815: }
816:
817: final boolean isOwned() {
818: return (flags & OWNED) != 0;
819: }
820:
821: final void isOwned(boolean value) {
822: flags = (short) (value ? flags | OWNED : flags & ~OWNED);
823: }
824:
825: final boolean isFirstChild() {
826: return (flags & FIRSTCHILD) != 0;
827: }
828:
829: final void isFirstChild(boolean value) {
830: flags = (short) (value ? flags | FIRSTCHILD : flags
831: & ~FIRSTCHILD);
832: }
833:
834: final boolean isSpecified() {
835: return (flags & SPECIFIED) != 0;
836: }
837:
838: final void isSpecified(boolean value) {
839: flags = (short) (value ? flags | SPECIFIED : flags & ~SPECIFIED);
840: }
841:
842: // inconsistent name to avoid clash with public method on TextImpl
843: final boolean internalIsIgnorableWhitespace() {
844: return (flags & IGNORABLEWS) != 0;
845: }
846:
847: final void isIgnorableWhitespace(boolean value) {
848: flags = (short) (value ? flags | IGNORABLEWS : flags
849: & ~IGNORABLEWS);
850: }
851:
852: final boolean hasStringValue() {
853: return (flags & HASSTRING) != 0;
854: }
855:
856: final void hasStringValue(boolean value) {
857: flags = (short) (value ? flags | HASSTRING : flags & ~HASSTRING);
858: }
859:
860: final boolean isNormalized() {
861: return (flags & UNNORMALIZED) == 0;
862: }
863:
864: final void isNormalized(boolean value) {
865: // See if flag should propagate to parent.
866: if (!value && isNormalized() && ownerNode != null) {
867: ownerNode.isNormalized(false);
868: }
869: flags = (short) (value ? flags & ~UNNORMALIZED : flags
870: | UNNORMALIZED);
871: }
872:
873: //
874: // Object methods
875: //
876:
877: /** NON-DOM method for debugging convenience. */
878: public String toString() {
879: return "[" + getNodeName() + ": " + getNodeValue() + "]";
880: }
881:
882: //
883: // Serialization methods
884: //
885:
886: /** Serialize object. */
887: private void writeObject(ObjectOutputStream out) throws IOException {
888:
889: // synchronize data
890: if (needsSyncData()) {
891: synchronizeData();
892: }
893: // write object
894: out.defaultWriteObject();
895:
896: } // writeObject(ObjectOutputStream)
897:
898: } // class NodeImpl
|