KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ozoneDB > xml > dom > NodeImpl


1 /**
2  * Changes for Persistent DOM running with ozone are
3  * Copyright 1999 by SMB GmbH. All rights reserved.
4  */

5
6 package org.ozoneDB.xml.dom;
7
8 import java.io.*;
9 import org.ozoneDB.*;
10 import org.ozoneDB.xml.dom.iterator.*;
11 import org.w3c.dom.*;
12
13
14 public abstract class NodeImpl extends OzoneObject implements NodeProxy, Externalizable {
15
16     final static long serialVersionUID = 1;
17
18     // public Object invoke (String methodName, String sig, Object[] args)
19
// throws Exception {
20
// if (methodName.equals ("getNodeName")
21
// return
22
// }
23

24
25     public boolean supports( java.lang.String JavaDoc feature, java.lang.String JavaDoc version ) {
26         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
27                 "Node.supports(): ozone's persistent DOM doesn't support DOM level 2 yet." );
28     }
29
30
31     public void normalize() {
32         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
33                 "Node.normalize(): ozone's persistent DOM doesn't support DOM level 2 yet." );
34     }
35
36
37     public java.lang.String JavaDoc getNamespaceURI() {
38         // FIXME:
39
// throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
40
// "Node.getNamespaceURI(): ozone's persistent DOM doesn't support DOM level 2 yet." );
41
return null;
42     }
43
44
45     public java.lang.String JavaDoc getPrefix() {
46         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
47                 "Node.getPrefix(): ozone's persistent DOM doesn't support DOM level 2 yet." );
48     }
49
50
51     public void setPrefix( java.lang.String JavaDoc prefix ) throws DOMException {
52         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
53                 "Node.setPrefix(): ozone's persistent DOM doesn't support DOM level 2 yet." );
54     }
55
56
57     public java.lang.String JavaDoc getLocalName() {
58         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
59                 "Node.getLocalName(): ozone's persistent DOM doesn't support DOM level 2 yet." );
60     }
61
62
63     /**
64      * Abstract method must be implemented by each node class.
65      *
66      * @see org.w3c.dom.Node#getNodeType
67      */

68     public abstract short getNodeType();
69
70
71     /**
72      * Returns the name of the node, set from the constructor. Some derived classes
73      * do not have the notion of a name, and will return the same name each time.
74      * They should do so by setting the default name (e.g. <TT>"#comment"</TT>)
75      * in the constructor. This value is never null.
76      *
77      * @see org.w3c.dom.Node#getNodeName
78      */

79     public final String JavaDoc getNodeName() {
80         return _nodeName;
81     }
82
83
84     /**
85      */

86     public final void setNodeName( String JavaDoc nodeName ) {
87         _nodeName = nodeName;
88     }
89
90
91     /**
92      * Returns the value of the node. Depending on the node type, this value
93      * is either the node value (e.g. the text in {@link org.w3c.dom.Text}),
94      * or always null is node has no notion of a value (e.g. {@link
95      * org.w3c.dom.Element}). For complete list of which node types will return
96      * what, see {@link #setNodeValue}.
97      *
98      * @return Value of node, null if node has no value
99      */

100     public final String JavaDoc getNodeValue() {
101         return _nodeValue;
102     }
103
104
105     /**
106      * Changes the value of the node. Not all node types support the notion of
107      * a value. If the value is not supported by a particular node type, it will
108      * throw an exception when calling this method. The following table specifies
109      * which node types support values:
110      * <PRE>
111      * Element Not supported
112      * Attr Value supported
113      * Text Value supported
114      * CDATASection Value supported
115      * EntityReference Not supported
116      * Entity Not supported
117      * ProcessingInstruction Value supported
118      * Comment Value supported
119      * Document Not supported
120      * DocumentType Not supported
121      * DocumentFragment Not supported
122      * Notation Not supported
123      * </PRE>
124      * For most node types, if the value is set to null, {@link #getNodeValue}
125      * will return an empty string instead.
126      *
127      * @param value New value of node
128      * @throws org.w3c.dom.DOMException <TT>NO_MODIFICATION_ALLOWED_ERR</TT>
129      * Node is read-only and cannot be modified
130      * @throws org.w3c.dom.DOMException <TT>NO_DATA_ALLOWED_ERR</TT>
131      * This node does not support a value
132      */

133     public void setNodeValue( String JavaDoc value ) {
134         if (isReadOnly()) {
135             throw new DOMExceptionImpl( DOMException.NO_MODIFICATION_ALLOWED_ERR );
136         }
137         _nodeValue = value == null ? "" : value;
138     }
139
140
141     /**
142      * Returns the parent node of this node. Node may not necessarily have a
143      * parent node. If node has been created but not added to any other node,
144      * it will be parentless. The {@link org.w3c.dom.Document} node is always
145      * parentless.
146      *
147      * @return Parent node of this node
148      */

149     public Node getParentNode() {
150         return _parent;
151     }
152
153
154     /**
155      */

156     public void setParentNode( Node newParent ) {
157         _parent = (NodeProxy)newParent;
158     }
159
160
161     /**
162      * Called to notify all the iterators created from this node that a
163      * child of this node has been removed. Iterators that point at this
164      * child might choose to select another child to point to. This method
165      * is called before the child is removed.
166      * <P>
167      * The removed node is a direct child of this node. Affected iterators
168      * are those that point at the document tree directly below this node,
169      * or the tree below one of its parents. Other iterators are not affected
170      * by the change. This method also performs a notification on all the
171      * parents of this node.
172      *
173      * @param removedChild The child node being removed
174      */

175     protected void notifyIterators( Node removedChild ) {
176     /*
177 FIXME
178         NodeProxy node;
179         int i;
180
181         node = this;
182         while ( node != null ) {
183             if ( node._iterators != null )
184                 for ( i = node._iterators.length ; i -- > 0 ; )
185                     ( (NodeIteratorListener) node._iterators[ i ] ).removeNode( removedChild );
186             node = (NodeProxy) node.getParentNode();
187             }
188      */

189     }
190
191
192     /**
193      * Returns a {@link org.w3c.dom.NodeList} object that can be used to traverse
194      * this node's children. The node list is live, so every change to this node
195      * is reflected in it.
196      * <P>
197      * If children are not supported by the derived class, an exception is thrown.
198      *
199      * @return {@link org.w3c.dom.NodeList} on this node
200      * @throws org.w3c.dom.DOMException HIERARCHY_REQUEST_ERR Childern not supported
201      * by this node type
202      * @see org.w3c.dom.NodeList
203      * @see NodeListImpl
204      */

205     public NodeList getChildNodes() {
206         // Throw exception if children not supported by derived class.
207
if (!supportsChildern()) {
208             throw new DOMExceptionImpl( DOMException.HIERARCHY_REQUEST_ERR,
209                     "No childern supported by this node type." );
210         }
211         return new org.ozoneDB.xml.dom.NodeListImpl( this );
212     }
213
214
215     /**
216      * Returns the first child of the node. If node has no children, returns null.
217      *
218      * @return First child or null
219      */

220     public final Node getFirstChild() {
221         return _firstChild;
222     }
223
224
225     /**
226      * Returns the last child of the node. If node has no children, returns null.
227      *
228      * @return Last child or null
229      */

230     public final Node getLastChild() {
231         return _lastChild;
232     }
233
234
235     /**
236      * Returns the previous sibling of this node. If node has no previous siblings,
237      * returns null.
238      *
239      * @return Previous sibling or null
240      */

241     public Node getPreviousSibling() {
242         return _prevNode;
243     }
244
245
246     /**
247      */

248     public void setPreviousSibling( Node prevNode ) {
249         _prevNode = (NodeProxy)prevNode;
250     }
251
252
253     /**
254      * Returns the next sibling of this node. If node has no next siblings,
255      * returns null.
256      *
257      * @return Next sibling or null
258      */

259     public Node getNextSibling() {
260         return _nextNode;
261     }
262
263
264     /**
265      */

266     public void setNextSibling( Node nextNode ) {
267         _nextNode = (NodeProxy)nextNode;
268     }
269
270
271     /**
272      * Return attributes of node. Returns null unless node is of type {@link
273      * org.w3c.dom.Element}, in which case the returned {@link
274      * org.w3c.dom.NamedNodeMap} will provide access to all the element's
275      * attributes.
276      *
277      * @return Attributes of node or null
278      */

279     public NamedNodeMap getAttributes() {
280         return null;
281     }
282
283
284     public boolean hasAttributes() {
285         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
286                 "ozone's persistent DOM doesn't support DOM level 2 yet." );
287     }
288
289
290
291
292     public final Document getOwnerDocument() {
293         if (_ownerDocument != this) {
294             return _ownerDocument;
295         } else {
296             return null;
297         }
298     }
299
300
301     /**
302      * Return true if there are any childern to this node. Less intensive than
303      * calling {#link getChildNodes}.
304      *
305      * @return True if node has any children
306      */

307     public final boolean hasChildNodes() {
308         return _firstChild != null;
309     }
310
311
312     /**
313      * Insert <TT>newChild</TT> as the last child of this parent.
314      * <P>
315      * If <TT>newChild</TT> is null, <TT>newChild</TT> does not belong to this DOM,
316      * or childern are not supported by this node type, an exception is thrown.
317      * <P>
318      * <TT>newChild</TT> is removed from its original parent before adding to this
319      * parent. If <TT>newChild</TT> is a {@link org.w3c.dom.DocumentFragment}, all
320      * its children are inserted one by one into this parent.
321      *
322      * @param newChild The new child to add
323      * @return The newly inserted child
324      * @throws org.w3c.dom.DOMException <TT>NO_MODIFICATION_ALLOWED_ERR</TT>
325      * Node is read-only and cannot be modified
326      * @throws org.w3c.dom.DOMException <TT>HIERARCHY_REQUEST_ERR</TT>
327      * Children are not supported by this node type, or <TT>newChild</TT> is not
328      * a compatible type for this node
329      * @see #castNewChild
330      * @see #castOldChild
331      */

332     public synchronized final Node appendChild( Node newChild ) {
333         // Node arguments must be casted to NodeEx in order to operate on them.
334
NodeProxy newChildX;
335
336         // Make sure the node is not read-only.
337
// Throw exception if children not supported by derived class.
338
if (isReadOnly()) {
339             throw new DOMExceptionImpl( DOMException.NO_MODIFICATION_ALLOWED_ERR );
340         }
341         if (!supportsChildern()) {
342             throw new DOMExceptionImpl( DOMException.HIERARCHY_REQUEST_ERR,
343                     "No childern supported by this node type." );
344         }
345
346         // Cast newChild to NodeImpl and make sure it can be inserted to this node.
347
newChildX = (NodeProxy)castNewChild( newChild );
348
349         // We're going to mess with this child node, so make sure no other thread
350
// is touching it
351
synchronized (newChild) {
352             // If the newChild is already a child or some node, remove it first
353
// before becoming child of this node. Make sure that parent is not
354
// read-only.
355
if (newChildX.getParentNode() != null) {
356                 if (((NodeProxy)newChildX.getParentNode()).isReadOnly()) {
357                     throw new DOMExceptionImpl( DOMException.NO_MODIFICATION_ALLOWED_ERR );
358                 }
359                 newChildX.getParentNode().removeChild( newChildX );
360             }
361
362             // Special case: newChild is a DocumentFragment and instead of adding
363
// itself, all of its childs are added one by one.
364
if (newChildX instanceof DocumentFragment) {
365                 NodeProxy nextChild;
366
367                 newChildX = (NodeProxy)newChildX.getFirstChild();
368                 while (newChildX != null) {
369                     nextChild = (NodeProxy)newChildX.getNextSibling();
370                     appendChild( newChildX );
371                     newChildX = nextChild;
372                 }
373                 return newChild;
374             }
375
376             // Node becomes child of this parent and part of this document.
377
// Note that this code comes after the test for a DocumentFragment.
378
// A fragment does not become part of this node, only its children.
379
// The fragment becomes parent-less and child-less.
380
// newChildX._parent = this;
381
newChildX.setParentNode( this );
382             if (_ownerDocument != null) {
383                 newChildX.setOwnerDocument( _ownerDocument );
384             }
385
386             // If the list has no end (it is empty) then newChild is added as the
387
// only child in it.
388
if (_lastChild == null) {
389                 _lastChild = newChildX;
390                 _firstChild = newChildX;
391                 newChildX.setPreviousSibling( null );
392                 newChildX.setNextSibling( null );
393             } else {
394                 // newChild becomes the new end of the list, adjusting the previous
395
// last child.
396
_lastChild.setNextSibling( newChildX );
397                 newChildX.setPreviousSibling( _lastChild );
398                 newChildX.setNextSibling( null );
399                 _lastChild = newChildX;
400             }
401             // Keep this count accurate at all times.
402
++_childsCount;
403         }
404         return newChild;
405     }
406
407
408     /**
409      * Remove <TT>oldChild</TT> from this parent. If <TT>oldChild</TT> is not
410      * a direct child of this parent, or childern are not supported by this node
411      * type, an exception is thrown.
412      *
413      * @param oldChild The child to remove
414      * @return The removed child
415      * @throws org.w3c.dom.DOMException <TT>NO_MODIFICATION_ALLOWED_ERR</TT>
416      * Node is read-only and cannot be modified
417      * @throws org.w3c.dom.DOMException <TT>HIERARCHY_REQUEST_ERR</TT>
418      * Children are not supported by this node type
419      * @throws org.w3c.dom.DOMException <TT>NOT_FOUND_ERR</TT>
420      * <TT>oldChild</TT> is not a direct child of this node
421      * @see #castOldChild
422      */

423     public synchronized final Node removeChild( Node oldChild ) throws DOMException {
424         NodeProxy oldChildX;
425
426         // Make sure the node is not read-only.
427
// Throw exception if children not supported by derived class.
428
if (isReadOnly()) {
429             throw new DOMExceptionImpl( DOMException.NO_MODIFICATION_ALLOWED_ERR );
430         }
431         if (!supportsChildern()) {
432             throw new DOMExceptionImpl( DOMException.HIERARCHY_REQUEST_ERR,
433                     "No childern supported by this node type." );
434         }
435
436         // Cast refChild to NodeImpl, making sure it is a child of this node.
437
oldChildX = (NodeProxy)castOldChild( oldChild );
438
439         // We're going to mess with this child node, so make sure no other thread
440
// is touching it
441
synchronized (oldChild) {
442             // Need to tell all the iterators that might be observing the
443
// child node that the child node is removed from the current
444
// tree. The iterators will reflect the changed by selecting
445
// a different child to point to. Interesting iterators are
446
// those the observer the tree underneath this node and all its
447
// parents.
448
notifyIterators( oldChild );
449
450             // Child becomes orphan. It is no longer first or last child of this
451
// node. Removed from linked list.
452
oldChildX.setParentNode( null );
453
454             if (_firstChild != null && _firstChild.equals( oldChildX )) {
455                 _firstChild = (NodeProxy)oldChildX.getNextSibling();
456             }
457
458             if (_lastChild != null && _lastChild.equals( oldChildX )) {
459                 _lastChild = (NodeProxy)oldChildX.getPreviousSibling();
460             }
461
462             if (oldChildX.getPreviousSibling() != null) {
463                 ((NodeProxy)oldChildX.getPreviousSibling()).setNextSibling( oldChildX.getNextSibling() );
464             }
465
466             if (oldChildX.getNextSibling() != null) {
467                 ((NodeProxy)oldChildX.getNextSibling()).setPreviousSibling( oldChildX.getPreviousSibling() );
468             }
469
470             oldChildX.setPreviousSibling( null );
471             oldChildX.setNextSibling( null );
472
473             // Keep this count accurate at all times.
474
--_childsCount;
475
476         }
477         return oldChild;
478     }
479
480
481     /**
482      * Replace <TT>oldChild</TT> with <TT>newChild</TT>, adding the new child and
483      * removing the old one.
484      * <P>
485      * If <TT>newChild</TT> does not belong to this DOM, <TT>oldChild</TT> is not
486      * a direct child of this parent, or childern are not supported by this node
487      * type, an exception is thrown.
488      * <P>
489      * <TT>newChild</TT> is removed from its original parent before adding to this
490      * parent. If <TT>newChild</TT> is a {@link org.w3c.dom.DocumentFragment}, all
491      * its children are inserted one by one into this parent.
492      *
493      * @param newChild The new child to add
494      * @param oldChild The old child to take away
495      * @return The old child
496      * @throws org.w3c.dom.DOMException <TT>NO_MODIFICATION_ALLOWED_ERR</TT>
497      * Node is read-only and cannot be modified
498      * @throws org.w3c.dom.DOMException <TT>HIERARCHY_REQUEST_ERR</TT>
499      * Children are not supported by this node type, or <TT>newChild</TT> is not
500      * a compatible type for this node
501      * @throws org.w3c.dom.DOMException <TT>NOT_FOUND_ERR</TT>
502      * <TT>oldChild</TT> is not a direct child of this node
503      * @see #castNewChild
504      * @see #castOldChild
505      */

506     public synchronized final Node replaceChild( Node newChild, Node oldChild ) throws DOMException {
507         // Node arguments must be casted to NodeEx in order to operate on them.
508
NodeProxy newChildX;
509         NodeProxy oldChildX;
510
511         // Make sure the node is not read-only.
512
// Throw exception if children not supported by derived class.
513
if (isReadOnly()) {
514             throw new DOMExceptionImpl( DOMException.NO_MODIFICATION_ALLOWED_ERR );
515         }
516         if (!supportsChildern()) {
517             throw new DOMExceptionImpl( DOMException.HIERARCHY_REQUEST_ERR,
518                     "No childern supported by this node type." );
519         }
520
521         // Cast newChild to NodeImpl and make sure it can be inserted to this node.
522
// Cast oldChild to NodeImpl, making sure it is a child of this node.
523
if (newChild != null) {
524             newChildX = (NodeProxy)castNewChild( newChild );
525         }
526         oldChildX = (NodeProxy)castOldChild( oldChild );
527
528         // We're going to mess with this child node, so make sure no other thread
529
// is touching it
530
synchronized (oldChild) {
531             if (newChild != null) {
532                 // .. or this
533
synchronized (newChild) {
534                     // Lazy implementation adds newChild before oldChild and then takes
535
// oldChild away. Might be a touch slowed, but is way more reliable.
536
insertBefore( newChild, oldChild );
537                     removeChild( oldChild );
538                 }
539             } else {
540                 // The case of just removing the old child, when the new one
541
// is null.
542
removeChild( oldChild );
543             }
544         }
545         return oldChild;
546     }
547
548
549     /**
550      * Insert <TT>newChild</TT> in this parent, before the existing child
551      * <TT>refChild</TT>. If <TT>refChild</TT> is null, insert <TT>newChild</TT>
552      * as the last child of this parent, akin to calling {@link #appendChild}.
553      * <P>
554      * If <TT>newChild</TT> is null, <TT>newChild</TT> does not belong to this DOM,
555      * <TT>refChild</TT> is not a direct child of this node, or childern are not
556      * supported by this node type, an exception is thrown.
557      * <P>
558      * <TT>newChild</TT> is removed from its original parent before adding to this
559      * parent. If <TT>newChild</TT> is a {@link org.w3c.dom.DocumentFragment}, all
560      * its children are inserted one by one into this parent.
561      *
562      * @param newChild The new child to add
563      * @param refChild Insert new child before this child, or insert at the end
564      * if this child is null
565      * @return The newly inserted child
566      * @throws org.w3c.dom.DOMException <TT>NO_MODIFICATION_ALLOWED_ERR</TT>
567      * Node is read-only and cannot be modified
568      * @throws org.w3c.dom.DOMException <TT>HIERARCHY_REQUEST_ERR</TT>
569      * Children are not supported by this node type, or <TT>newChild</TT> is not
570      * a compatible type for this node
571      * @throws org.w3c.dom.DOMException <TT>NOT_FOUND_ERR</TT>
572      * <TT>oldChild</TT> is not null and not a direct child of this node
573      * @see #castNewChild
574      * @see #castOldChild
575      */

576     public synchronized final Node insertBefore( Node newChild, Node refChild ) throws DOMException {
577         // Node arguments must be casted to NodeEx in order to operate on them.
578
NodeProxy newChildX;
579         NodeProxy refChildX;
580
581         // Make sure the node is not read-only.
582
// Throw exception if children not supported by derived class.
583
if (isReadOnly()) {
584             throw new DOMExceptionImpl( DOMException.NO_MODIFICATION_ALLOWED_ERR );
585         }
586         if (!supportsChildern()) {
587             throw new DOMExceptionImpl( DOMException.HIERARCHY_REQUEST_ERR,
588                     "No childern supported by this node type." );
589         }
590
591         // If refChild is null, act as if appendChild was called.
592
if (refChild == null) {
593             return appendChild( newChild );
594         }
595
596         // Cast newChild to NodeImpl and make sure it can be inserted to this node.
597
// Cast refChild to NodeImpl, making sure it is a child of this node.
598
newChildX = (NodeProxy)castNewChild( newChild );
599         refChildX = (NodeProxy)castOldChild( refChild );
600
601         // We're going to mess with this child node, so make sure no other thread
602
// is touching it
603
synchronized (newChild) {
604             // .. or this
605
synchronized (refChild) {
606                 // If the newChild is already a child or some node, remove it first
607
// before becoming child of this node. Make sure that parent is not
608
// read-only.
609
if (newChildX.getParentNode() != null) {
610                     if (((NodeProxy)newChildX.getParentNode()).isReadOnly()) {
611                         throw new DOMExceptionImpl( DOMException.NO_MODIFICATION_ALLOWED_ERR );
612                     }
613                     newChildX.getParentNode().removeChild( newChildX );
614                 }
615
616                 // Special case: newChild is a DocumentFragment and instead of
617
// inserting itself, all of its childs are inserted one by one.
618
if (newChildX instanceof DocumentFragment) {
619                     NodeProxy nextChild;
620
621                     newChildX = (NodeProxy)newChildX.getFirstChild();
622                     while (newChildX != null) {
623                         nextChild = (NodeProxy)newChildX.getNextSibling();
624                         insertBefore( newChildX, refChild );
625                         newChildX = nextChild;
626                     }
627                     return newChild;
628                 }
629
630                 // Node becomes child of this parent and part of this document.
631
// Note that this code comes after the test for a DocumentFragment.
632
// A fragment does not become part of this node, only its children.
633
// The fragment becomes parent-less and child-less.
634
newChildX.setParentNode( this );
635                 newChildX.setOwnerDocument( _ownerDocument );
636
637                 // If refChild is the first child, newChild becomes the first
638
// child on the list.
639
if (_firstChild.equals( refChildX )) {
640                     _firstChild = newChildX;
641                 }
642                 // refChild is not the first child, so adjust the previous child
643
// to point at newChild instead.
644
if (refChildX.getPreviousSibling() != null) {
645                     newChildX.setPreviousSibling( refChildX.getPreviousSibling() );
646                     ((NodeProxy)refChildX.getPreviousSibling()).setNextSibling( newChildX );
647                 }
648                 // Adjust the refChild to point at this child and vice versa.
649
refChildX.setPreviousSibling( newChildX );
650                 newChildX.setNextSibling( refChildX );
651                 // Keep this count accurate at all times.
652
++_childsCount;
653             }
654         }
655         return newChild;
656     }
657
658
659     /**
660      * Checks whether <TT>newChild</TT> can be added to this node as a child, and
661      * if so, performs a necessary cast. <TT>newChild</TT> cannot be null and must
662      * belong to this DOM. It is impossible to transfer nodes between different
663      * DOM implementations.
664      * <P>
665      * The following rules govern the allowed <TT>newChild</TT> types:
666      * <UL>
667      * <LI>Parent is an {@link org.w3c.dom.Attr}, <TT>newChild</TT> must be either
668      * a {@link org.w3c.dom.Text} or an {@link org.w3c.dom.EntityReference}
669      * <LI>Parent is a {@link org.w3c.dom.DocumentType}, <TT>newChild</TT> must be
670      * either an {@link org.w3c.dom.Entity} or a {@link org.w3c.dom.Notation}.
671      * <LI>Parnet is any other node type, <TT>newChild</TT> must be an {@link
672      * org.w3c.dom.Element}, a {@link org.w3c.dom.CharacterData} derived type,
673      * a {@link org.w3c.dom.DocumentFragment}, an {@link
674      * org.w3c.dom.EntityReference} or a {@link org.w3c.dom.ProcessingInstruction}.
675      * </UL>
676      * Any deviation will throw an exception.
677      *
678      * @param newChild New child node
679      * @return <TT>newChild</TT> cast to type {@link NodeImpl}
680      * @throws org.w3c.dom.DOMException <TT>HIERARCHY_REQUEST_ERR</TT>
681      * <TT>newChild</TT> is null, does not belong to this DOM, or its node type
682      * is not supported for this parent
683      */

684     protected Node castNewChild( Node newChild ) throws DOMException {
685         if (newChild == null) {
686             throw new DOMExceptionImpl( DOMException.HIERARCHY_REQUEST_ERR, "Child reference is null." );
687         }
688
689         // newChild must be Element, CDATASection, Text, Comment (all three
690
// derived from CharacterData), DocumentFragment, EntityReference,
691
// or ProcessingInstruction.
692
if (!(newChild instanceof Node)) {
693             throw new DOMExceptionImpl( DOMException.HIERARCHY_REQUEST_ERR,
694                     "Child is not a compatible type for this node." );
695         }
696         if (!(newChild instanceof Element || newChild instanceof CharacterData || newChild instanceof DocumentFragment
697                 || newChild instanceof EntityReference || newChild instanceof ProcessingInstruction)) {
698             throw new DOMExceptionImpl( DOMException.HIERARCHY_REQUEST_ERR,
699                     "Child is not a compatible type for this node." );
700         }
701         return newChild;
702     }
703
704
705     /**
706      * Checks whether <TT>oldChild</TT> is a direct child of this node, and if so,
707      * performs a necessary cast. <TT>oldChild</TT> cannot be null.
708      *
709      * @param oldChild Old child node
710      * @return <T>oldChild</TT> cast to type {@link NodeImpl}
711      * @throws org.w3c.dom.DOMException <TT>NOT_FOUND_ERR</TT>
712      * <TT>oldChild</TT> is null, or not a direct child of this node
713      */

714     protected final Node castOldChild( Node oldChild ) throws DOMException {
715         if (oldChild == null || !(oldChild instanceof NodeProxy)
716                 || !((OzoneProxy)oldChild.getParentNode()).remoteID().equals( container().id() )) {
717             throw new DOMExceptionImpl( DOMException.NOT_FOUND_ERR, "Not a direct child of this node." );
718         }
719         return oldChild;
720     }
721
722
723     /**
724      * This clone method is called after a new node has been constructed to copy
725      * the contents of this node into the new one. It clones in contents but not
726      * in context, and guarantees that the cloned node will pass the equality
727      * test (see {@link #equals}).
728      * <P>
729      * <TT>into</TT> must be a valid node of the exact same class as this one.
730      * <TT>deep</TT> is true if deep cloning (includes all children nodes) is to
731      * be performed. If <TT>deep</TT> is false, the clone might not pass the
732      * equality test.
733      * <P>
734      * Derived classes override and call this method to add per-class variable
735      * copying. This method is called by {@link #cloneNode} and the default
736      * {@link java.lang.Object#clone} method.
737      * <P>
738      * Contents cloning duplicates the node's name and value, and its children.
739      * It does not duplicate it's context, that is, the node's parent or sibling.
740      * Initially a clone node has no parents or siblings. However, the node does
741      * belong to the same document, since all nodes must belong to some document.
742      * The cloned node is never read-only.
743      *
744      * @param into A node into which to duplicate this one
745      * @param deep True if deep cloning is required
746      */

747     public synchronized void cloneInto( NodeProxy into, boolean deep ) {
748         NodeProxy child;
749
750         // falko: this expression cannot be true in ozone so I commented this
751
// out
752
// Make sure no function messed up with the class types.
753
// if (this.getClass() != into.getClass()) {
754
// throw new IllegalArgumentException( "Argument 'into' not same type as this node." );
755
// }
756

757         // Duplicate node name and value.
758
into.setNodeName( _nodeName );
759         String JavaDoc nodeValue = getNodeValue();
760         if (nodeValue != null) {
761             into.setNodeValue( nodeValue );
762         }
763         into.setOwnerDocument( _ownerDocument );
764         if (deep) {
765             child = (NodeProxy)getFirstChild();
766             while (child != null) {
767                 into.appendChild( child.cloneNode( true ) );
768                 child = (NodeProxy)child.getNextSibling();
769             }
770         }
771     }
772
773
774     public synchronized void setOwnerDocument( Document owner ) {
775         Node node;
776
777         if (owner == null) {
778             _ownerDocument = null;
779         } else {
780             if (!(owner instanceof DocumentProxy)) {
781                 throw new IllegalArgumentException JavaDoc( "Argument 'owner' not of compatible DOM class." );
782             }
783             _ownerDocument = (DocumentProxy)owner;
784         }
785         node = getFirstChild();
786         while (node != null) {
787             ((NodeProxy)node).setOwnerDocument( owner );
788             node = node.getNextSibling();
789         }
790     }
791
792
793     /**
794      * Renders this node read only, preventing it's contents from being modified.
795      * Attempts to modify the node's contents will throw an exception. The node's
796      * children are also made read-only.
797      */

798     public synchronized final void setReadOnly() {
799         NodeProxy child;
800
801         _readOnly = true;
802         // Make all children read-only as well: this allows us to lock a branch
803
// but, for example, move it to a different tree.
804
child = (NodeProxy)getFirstChild();
805         while (child != null) {
806             child.setReadOnly();
807             child = (NodeProxy)child.getNextSibling();
808         }
809     }
810
811
812     /**
813      * Returns true if node is read-only and cannot be modified, or if node
814      * belongs to a read-only document.
815      *
816      * @return True if node is read-only and cannot be modified
817      * @see #setReadOnly
818      */

819     public final boolean isReadOnly() {
820         return _readOnly;
821     }
822
823
824     /**
825      * Returns true if this node supports children. Other methods query this to
826      * determine whether to properly support childern, return null or throw an
827      * exception in response. The default method returns false.
828      *
829      * @return True if childern supported by this node type
830      */

831     boolean supportsChildern() {
832         return false;
833     }
834
835
836     /**
837      * Returns the <TT>index</TT>-th child of this node. This method is used
838      * exclusively by {@link NodeListImpl}.
839      *
840      * @param index Index of child to retrieve
841      * @return The child node or null
842      * @see NodeListImpl#item(int)
843      */

844     public synchronized final Node getChild( int index ) {
845         NodeProxy node;
846
847         if (index < 0 || index > _childsCount) {
848             return null;
849         }
850         node = (NodeProxy)getFirstChild();
851         while (node != null && index > 0) {
852             node = (NodeProxy)node.getNextSibling();
853             --index;
854         }
855         return node;
856     }
857
858
859     /**
860      * Returns the number of children in this node. This method is used
861      * exclusively by {@link NodeListImpl}.
862      *
863      * @return Number of childern in this node
864      * @see NodeListImpl#getLength
865      */

866     public final int getChildCount() {
867         return _childsCount;
868     }
869
870
871     /**
872      * Hidden constructor creates a new node. Only one constructor is supported,
873      * although cloning is also supported. Owner document must be supplied except
874      * for {@link DocumentImpl} in which case the document itself becomes its
875      * owner. Name must be supplied, either dynamic or static (e.g. "#document#").
876      * <P>
877      * If <TT>checkName</TT> is true, the supplied named is assumed to be a valid
878      * XML name token, one that can contain any Unicode letter and digit, must
879      * start with a letter, and may also contain hyphen, underscore, digit or colon.
880      *
881      * @param owner Document owner of this node, or null
882      * @param name Name of node
883      * @param value Initial value of node or null
884      * @param checkName True if name is an XML name token
885      * @throws org.w3c.dom.DOMException <TT>INVALID_CHARACTER_ERR</TT>
886      * Node name cannot contain whitespaces or non-printable characters
887      */

888     protected NodeImpl( DocumentImpl owner, String JavaDoc name, String JavaDoc value, boolean checkName ) throws DOMException{
889         init( owner, name, value, checkName );
890     }
891
892
893     protected NodeImpl() {
894     }
895
896
897     public final void init( DocumentProxy owner, String JavaDoc name, String JavaDoc value, boolean checkName ) throws DOMException {
898         char ch;
899         int i;
900
901         if (name == null) {
902             throw new NullPointerException JavaDoc( "Argument 'name' is null." );
903         }
904
905         _nodeName = name;
906         _ownerDocument = owner;
907         // Check the node name one character at a time to assure that no
908
// illegal characters are used. Node name must conform to Name token
909
// as defined in XML spec, including use of all Unicode letters and
910
// digits.
911
if (checkName && name.length() > 0) {
912             ch = name.charAt( 0 );
913             if (!Character.isLetter( ch ) && ch != '_' && ch != ':') {
914                 throw new DOMExceptionImpl( DOMException.INVALID_CHARACTER_ERR );
915             }
916             for (i = 1; i < name.length(); ++i) {
917                 ch = name.charAt( 1 );
918                 if (!Character.isLetterOrDigit( ch ) && ch != '_' && ch != ':' && ch != '-' && ch != '.') {
919                     throw new DOMExceptionImpl( DOMException.INVALID_CHARACTER_ERR );
920                 }
921             }
922         }
923         if (value != null) {
924             setNodeValue( value );
925         }
926     }
927
928     /**
929      * Element declaration node. Not part of the DOM, identifies an element
930      * declaration node appearing in the DTD.
931      */

932     public final static short ELEMENT_DECL_NODE = 13;
933
934
935     /**
936      * Attributes list declaration node. Not part of the DOM, identifies an
937      * attributes list declaration node appearing in the DTD..
938      */

939     public final static short ATTLIST_DECL_NODE = 14;
940
941
942     /**
943      * Parameter entity declaration node. Not part of the DOM, identifies an
944      * internal or external parameter entity declaration node appearing in the
945      * DTD (see {@link ParamEntity}).
946      */

947     public final static short PARAM_ENTITY_NODE = 15;
948
949
950     /**
951      * This node ia part of a double-linked list that belongs to its parent.
952      * This reference identifies the next child in the list. Class access
953      * required by derived classes.
954      */

955     NodeProxy _nextNode;
956
957     /**
958      * This node ia part of a double-linked list that belongs to its parent.
959      * This reference identifies the previous child in the list. Class access
960      * required by derived classes.
961      */

962     NodeProxy _prevNode;
963
964     /**
965      * The parent of this node or null if the node has no parent. Class access
966      * required by derived classes.
967      */

968     NodeProxy _parent;
969
970     /**
971      * The document owner of this node, or the document itself. If the node belongs
972      * to any document, this will point to that document. For a document this will
973      * point at the document itself ({@link #getOwnerDocument} will return null,
974      * though). Class access required by derived classes.
975      */

976     DocumentProxy _ownerDocument;
977
978     /**
979      * The name of this node. All nodes have names, some are dynamic (e.g. the
980      * tag name of an element), others are static (e.g. "#document").
981      */

982     private String JavaDoc _nodeName;
983
984     /**
985      * The value of this node. Not all nodes support values and this might be
986      * null for some nodes.
987      */

988     private String JavaDoc _nodeValue;
989
990     /**
991      * The children of this node are arranged in a doubly linked lists.
992      * This reference identifies the first child in the list.
993      */

994     private NodeProxy _firstChild;
995
996     /**
997      * The children of this node are arranged in a doubly linked lists.
998      * This reference identifies the last child in the list.
999      */

1000    private NodeProxy _lastChild;
1001
1002    /**
1003     * Counts how many children nodes belong to this parent. Used to speed up
1004     * some checks.
1005     */

1006    private int _childsCount;
1007
1008    /**
1009     * True if this node is read-only and its contents cannot be modified.
1010     */

1011    private boolean _readOnly;
1012
1013    /**
1014     * Holdes a list of iterators that are observing this node of its
1015     * childern.
1016     */

1017    private NodeIteratorListener[] _iterators;
1018
1019
1020    /**
1021     */

1022    public void writeExternal( ObjectOutput out ) throws IOException {
1023        out.writeObject( _nextNode );
1024        out.writeObject( _prevNode );
1025        out.writeObject( _parent );
1026        out.writeObject( _ownerDocument );
1027
1028        //out.writeObject (_nodeName);
1029
if (_nodeName != null) {
1030            out.writeByte( 1 );
1031            out.writeUTF( _nodeName );
1032        } else {
1033            out.writeByte( -1 );
1034        }
1035
1036        // out.writeObject (_nodeValue);
1037
if (_nodeValue != null) {
1038            out.writeByte( 1 );
1039            out.writeUTF( _nodeValue );
1040        } else {
1041            out.writeByte( -1 );
1042        }
1043
1044        out.writeObject( _firstChild );
1045        out.writeObject( _lastChild );
1046        out.writeInt( _childsCount );
1047        out.writeBoolean( _readOnly );
1048
1049        if (_iterators != null) {
1050            int len = _iterators.length;
1051            out.writeInt( len );
1052            for (int i = 0; i < len; i++) {
1053                out.writeObject( _iterators[i] );
1054            }
1055        } else {
1056            out.writeInt( -1 );
1057        }
1058    }
1059
1060
1061    /**
1062     */

1063    public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException JavaDoc {
1064        _nextNode = (NodeProxy)in.readObject();
1065        _prevNode = (NodeProxy)in.readObject();
1066        _parent = (NodeProxy)in.readObject();
1067        _ownerDocument = (DocumentProxy)in.readObject();
1068
1069        int n = in.readByte();
1070        if (n > 0) {
1071            _nodeName = in.readUTF();
1072        } else {
1073            _nodeName = null;
1074        }
1075
1076        //_nodeValue = (String)in.readObject();
1077
n = in.readByte();
1078        if (n > 0) {
1079            _nodeValue = in.readUTF();
1080        } else {
1081            _nodeValue = null;
1082        }
1083
1084        _firstChild = (NodeProxy)in.readObject();
1085        _lastChild = (NodeProxy)in.readObject();
1086        _childsCount = in.readInt();
1087        _readOnly = in.readBoolean();
1088
1089        int len = in.readInt();
1090        if (len > -1) {
1091            _iterators = new NodeIteratorListener[len];
1092            for (int i = 0; i < len; i++) {
1093                _iterators[i] = (NodeIteratorListener)in.readObject();
1094            }
1095        } else {
1096            _iterators = null;
1097        }
1098    }
1099
1100    public boolean isSupported(String JavaDoc s, String JavaDoc s1) {
1101        throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
1102                "Node.getLocalName(): ozone's persistent DOM doesn't support DOM level 2 yet." );
1103    }
1104}
1105
Popular Tags