KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xerces > dom > NamedNodeMapImpl


1 /*
2  * Copyright 1999-2002,2004,2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.xerces.dom;
18
19 import java.io.Serializable JavaDoc;
20 import java.util.Vector JavaDoc;
21
22 import org.w3c.dom.DOMException JavaDoc;
23 import org.w3c.dom.NamedNodeMap JavaDoc;
24 import org.w3c.dom.Node JavaDoc;
25
26 /**
27  * NamedNodeMaps represent collections of Nodes that can be accessed
28  * by name. Entity and Notation nodes are stored in NamedNodeMaps
29  * attached to the DocumentType. Attributes are placed in a NamedNodeMap
30  * attached to the elem they're related too. However, because attributes
31  * require more work, such as firing mutation events, they are stored in
32  * a subclass of NamedNodeMapImpl.
33  * <P>
34  * Only one Node may be stored per name; attempting to
35  * store another will replace the previous value.
36  * <P>
37  * NOTE: The "primary" storage key is taken from the NodeName attribute of the
38  * node. The "secondary" storage key is the namespaceURI and localName, when
39  * accessed by DOM level 2 nodes. All nodes, even DOM Level 2 nodes are stored
40  * in a single Vector sorted by the primary "nodename" key.
41  * <P>
42  * NOTE: item()'s integer index does _not_ imply that the named nodes
43  * must be stored in an array; that's only an access method. Note too
44  * that these indices are "live"; if someone changes the map's
45  * contents, the indices associated with nodes may change.
46  * <P>
47  *
48  * @xerces.internal
49  *
50  * @version $Id: NamedNodeMapImpl.java,v 1.40 2005/03/07 23:28:40 mrglavas Exp $
51  * @since PR-DOM-Level-1-19980818.
52  */

53 public class NamedNodeMapImpl
54     implements NamedNodeMap JavaDoc, Serializable JavaDoc {
55
56     //
57
// Constants
58
//
59

60     /** Serialization version. */
61     static final long serialVersionUID = -7039242451046758020L;
62
63     //
64
// Data
65
//
66

67     protected short flags;
68
69     protected final static short READONLY = 0x1<<0;
70     protected final static short CHANGED = 0x1<<1;
71     protected final static short HASDEFAULTS = 0x1<<2;
72
73     /** Nodes. */
74     protected Vector JavaDoc nodes;
75
76     protected NodeImpl ownerNode; // the node this map belongs to
77

78     //
79
// Constructors
80
//
81

82     /** Constructs a named node map. */
83     protected NamedNodeMapImpl(NodeImpl ownerNode) {
84         this.ownerNode = ownerNode;
85     }
86
87     //
88
// NamedNodeMap methods
89
//
90

91     /**
92      * Report how many nodes are currently stored in this NamedNodeMap.
93      * Caveat: This is a count rather than an index, so the
94      * highest-numbered node at any time can be accessed via
95      * item(getLength()-1).
96      */

97     public int getLength() {
98         return (nodes != null) ? nodes.size() : 0;
99     }
100
101     /**
102      * Retrieve an item from the map by 0-based index.
103      *
104      * @param index Which item to retrieve. Note that indices are just an
105      * enumeration of the current contents; they aren't guaranteed to be
106      * stable, nor do they imply any promises about the order of the
107      * NamedNodeMap's contents. In other words, DO NOT assume either that
108      * index(i) will always refer to the same entry, or that there is any
109      * stable ordering of entries... and be prepared for double-reporting
110      * or skips as insertion and deletion occur.
111      *
112      * @return the node which currenly has the specified index, or null if index
113      * is greater than or equal to getLength().
114      */

115     public Node JavaDoc item(int index) {
116         return (nodes != null && index < nodes.size()) ?
117                     (Node JavaDoc)(nodes.elementAt(index)) : null;
118     }
119
120     /**
121      * Retrieve a node by name.
122      *
123      * @param name Name of a node to look up.
124      * @return the Node (of unspecified sub-class) stored with that name, or
125      * null if no value has been assigned to that name.
126      */

127     public Node JavaDoc getNamedItem(String JavaDoc name) {
128
129         int i = findNamePoint(name,0);
130         return (i < 0) ? null : (Node JavaDoc)(nodes.elementAt(i));
131
132     } // getNamedItem(String):Node
133

134     /**
135      * Introduced in DOM Level 2. <p>
136      * Retrieves a node specified by local name and namespace URI.
137      *
138      * @param namespaceURI The namespace URI of the node to retrieve.
139      * When it is null or an empty string, this
140      * method behaves like getNamedItem.
141      * @param localName The local name of the node to retrieve.
142      * @return Node A Node (of any type) with the specified name, or null if the specified
143      * name did not identify any node in the map.
144      */

145     public Node JavaDoc getNamedItemNS(String JavaDoc namespaceURI, String JavaDoc localName) {
146
147         int i = findNamePoint(namespaceURI, localName);
148         return (i < 0) ? null : (Node JavaDoc)(nodes.elementAt(i));
149
150     } // getNamedItemNS(String,String):Node
151

152     /**
153      * Adds a node using its nodeName attribute.
154      * As the nodeName attribute is used to derive the name which the node must be
155      * stored under, multiple nodes of certain types (those that have a "special" string
156      * value) cannot be stored as the names would clash. This is seen as preferable to
157      * allowing nodes to be aliased.
158      * @see org.w3c.dom.NamedNodeMap#setNamedItem
159      * @return If the new Node replaces an existing node the replaced Node is returned,
160      * otherwise null is returned.
161      * @param arg
162      * A node to store in a named node map. The node will later be
163      * accessible using the value of the namespaceURI and localName
164      * attribute of the node. If a node with those namespace URI and
165      * local name is already present in the map, it is replaced by the new
166      * one.
167      * @exception org.w3c.dom.DOMException The exception description.
168      */

169     public Node JavaDoc setNamedItem(Node JavaDoc arg)
170     throws DOMException JavaDoc {
171         
172         CoreDocumentImpl ownerDocument = ownerNode.ownerDocument();
173         if (ownerDocument.errorChecking) {
174             if (isReadOnly()) {
175                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
176                 throw new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
177             }
178             if (arg.getOwnerDocument() != ownerDocument) {
179                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
180                 throw new DOMException JavaDoc(DOMException.WRONG_DOCUMENT_ERR, msg);
181             }
182         }
183         
184         int i = findNamePoint(arg.getNodeName(),0);
185         NodeImpl previous = null;
186         if (i >= 0) {
187             previous = (NodeImpl) nodes.elementAt(i);
188             nodes.setElementAt(arg,i);
189         } else {
190             i = -1 - i; // Insert point (may be end of list)
191
if (null == nodes) {
192                 nodes = new Vector JavaDoc(5, 10);
193             }
194             nodes.insertElementAt(arg, i);
195         }
196         return previous;
197         
198     } // setNamedItem(Node):Node
199

200     /**
201      * Adds a node using its namespaceURI and localName.
202      * @see org.w3c.dom.NamedNodeMap#setNamedItem
203      * @return If the new Node replaces an existing node the replaced Node is returned,
204      * otherwise null is returned.
205      * @param arg A node to store in a named node map. The node will later be
206      * accessible using the value of the namespaceURI and localName
207      * attribute of the node. If a node with those namespace URI and
208      * local name is already present in the map, it is replaced by the new
209      * one.
210      */

211     public Node JavaDoc setNamedItemNS(Node JavaDoc arg)
212     throws DOMException JavaDoc {
213         
214         CoreDocumentImpl ownerDocument = ownerNode.ownerDocument();
215         if (ownerDocument.errorChecking) {
216             if (isReadOnly()) {
217                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
218                 throw new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
219             }
220             
221             if(arg.getOwnerDocument() != ownerDocument) {
222                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
223                 throw new DOMException JavaDoc(DOMException.WRONG_DOCUMENT_ERR, msg);
224             }
225         }
226         
227         int i = findNamePoint(arg.getNamespaceURI(), arg.getLocalName());
228         NodeImpl previous = null;
229         if (i >= 0) {
230             previous = (NodeImpl) nodes.elementAt(i);
231             nodes.setElementAt(arg,i);
232         } else {
233             // If we can't find by namespaceURI, localName, then we find by
234
// nodeName so we know where to insert.
235
i = findNamePoint(arg.getNodeName(),0);
236             if (i >= 0) {
237                 previous = (NodeImpl) nodes.elementAt(i);
238                 nodes.insertElementAt(arg,i);
239             } else {
240                 i = -1 - i; // Insert point (may be end of list)
241
if (null == nodes) {
242                     nodes = new Vector JavaDoc(5, 10);
243                 }
244                 nodes.insertElementAt(arg, i);
245             }
246         }
247         return previous;
248         
249     } // setNamedItemNS(Node):Node
250

251     /**
252      * Removes a node specified by name.
253      * @param name The name of a node to remove.
254      * @return The node removed from the map if a node with such a name exists.
255      */

256     /***/
257     public Node JavaDoc removeNamedItem(String JavaDoc name)
258         throws DOMException JavaDoc {
259
260         if (isReadOnly()) {
261             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
262             throw
263                 new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR,
264                 msg);
265         }
266         int i = findNamePoint(name,0);
267         if (i < 0) {
268             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
269             throw new DOMException JavaDoc(DOMException.NOT_FOUND_ERR, msg);
270         }
271
272         NodeImpl n = (NodeImpl)nodes.elementAt(i);
273         nodes.removeElementAt(i);
274
275         return n;
276
277     } // removeNamedItem(String):Node
278

279     /**
280      * Introduced in DOM Level 2. <p>
281      * Removes a node specified by local name and namespace URI.
282      * @param namespaceURI
283      * The namespace URI of the node to remove.
284      * When it is null or an empty string, this
285      * method behaves like removeNamedItem.
286      * @param The local name of the node to remove.
287      * @return Node The node removed from the map if a node with such
288      * a local name and namespace URI exists.
289      * @throws NOT_FOUND_ERR: Raised if there is no node named
290      * name in the map.
291
292      */

293      public Node JavaDoc removeNamedItemNS(String JavaDoc namespaceURI, String JavaDoc name)
294         throws DOMException JavaDoc {
295
296         if (isReadOnly()) {
297             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
298             throw
299                 new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR,
300                 msg);
301         }
302         int i = findNamePoint(namespaceURI, name);
303         if (i < 0) {
304             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
305             throw new DOMException JavaDoc(DOMException.NOT_FOUND_ERR, msg);
306         }
307
308         NodeImpl n = (NodeImpl)nodes.elementAt(i);
309         nodes.removeElementAt(i);
310
311         return n;
312
313     } // removeNamedItem(String):Node
314

315     //
316
// Public methods
317
//
318

319     /**
320      * Cloning a NamedNodeMap is a DEEP OPERATION; it always clones
321      * all the nodes contained in the map.
322      */

323      
324     public NamedNodeMapImpl cloneMap(NodeImpl ownerNode) {
325         NamedNodeMapImpl newmap = new NamedNodeMapImpl(ownerNode);
326         newmap.cloneContent(this);
327         return newmap;
328     }
329
330     protected void cloneContent(NamedNodeMapImpl srcmap) {
331         Vector JavaDoc srcnodes = srcmap.nodes;
332         if (srcnodes != null) {
333             int size = srcnodes.size();
334             if (size != 0) {
335                 if (nodes == null) {
336                     nodes = new Vector JavaDoc(size);
337                 }
338                 nodes.setSize(size);
339                 for (int i = 0; i < size; ++i) {
340                     NodeImpl n = (NodeImpl) srcmap.nodes.elementAt(i);
341                     NodeImpl clone = (NodeImpl) n.cloneNode(true);
342                     clone.isSpecified(n.isSpecified());
343                     nodes.setElementAt(clone, i);
344                 }
345             }
346         }
347     } // cloneMap():NamedNodeMapImpl
348

349     //
350
// Package methods
351
//
352

353     /**
354      * Internal subroutine to allow read-only Nodes to make their contained
355      * NamedNodeMaps readonly too. I expect that in fact the shallow
356      * version of this operation will never be
357      *
358      * @param readOnly boolean true to make read-only, false to permit editing.
359      * @param deep boolean true to pass this request along to the contained
360      * nodes, false to only toggle the NamedNodeMap itself. I expect that
361      * the shallow version of this operation will never be used, but I want
362      * to design it in now, while I'm thinking about it.
363      */

364     void setReadOnly(boolean readOnly, boolean deep) {
365         isReadOnly(readOnly);
366         if (deep && nodes != null) {
367             for (int i = nodes.size() - 1; i >= 0; i--) {
368                 ((NodeImpl) nodes.elementAt(i)).setReadOnly(readOnly,deep);
369             }
370         }
371     } // setReadOnly(boolean,boolean)
372

373     /**
374      * Internal subroutine returns this NodeNameMap's (shallow) readOnly value.
375      *
376      */

377     boolean getReadOnly() {
378         return isReadOnly();
379     } // getReadOnly()
380

381
382     //
383
// Protected methods
384
//
385

386     /**
387      * NON-DOM
388      * set the ownerDocument of this node, and the attributes it contains
389      */

390     void setOwnerDocument(CoreDocumentImpl doc) {
391         if (nodes != null) {
392             for (int i = 0; i < nodes.size(); i++) {
393                 ((NodeImpl)item(i)).setOwnerDocument(doc);
394             }
395         }
396     }
397
398     final boolean isReadOnly() {
399         return (flags & READONLY) != 0;
400     }
401
402     final void isReadOnly(boolean value) {
403         flags = (short) (value ? flags | READONLY : flags & ~READONLY);
404     }
405
406     final boolean changed() {
407         return (flags & CHANGED) != 0;
408     }
409
410     final void changed(boolean value) {
411         flags = (short) (value ? flags | CHANGED : flags & ~CHANGED);
412     }
413
414     final boolean hasDefaults() {
415         return (flags & HASDEFAULTS) != 0;
416     }
417
418     final void hasDefaults(boolean value) {
419         flags = (short) (value ? flags | HASDEFAULTS : flags & ~HASDEFAULTS);
420     }
421
422     //
423
// Private methods
424
//
425

426     /**
427      * Subroutine: Locate the named item, or the point at which said item
428      * should be added.
429      *
430      * @param name Name of a node to look up.
431      *
432      * @return If positive or zero, the index of the found item.
433      * If negative, index of the appropriate point at which to insert
434      * the item, encoded as -1-index and hence reconvertable by subtracting
435      * it from -1. (Encoding because I don't want to recompare the strings
436      * but don't want to burn bytes on a datatype to hold a flagged value.)
437      */

438     protected int findNamePoint(String JavaDoc name, int start) {
439
440         // Binary search
441
int i = 0;
442         if (nodes != null) {
443             int first = start;
444             int last = nodes.size() - 1;
445
446             while (first <= last) {
447                 i = (first + last) / 2;
448                 int test = name.compareTo(((Node JavaDoc)(nodes.elementAt(i))).getNodeName());
449                 if (test == 0) {
450                     return i; // Name found
451
}
452                 else if (test < 0) {
453                     last = i - 1;
454                 }
455                 else {
456                     first = i + 1;
457                 }
458             }
459
460             if (first > i) {
461                 i = first;
462             }
463         }
464
465         return -1 - i; // not-found has to be encoded.
466

467     } // findNamePoint(String):int
468

469     
470     /** This findNamePoint is for DOM Level 2 Namespaces.
471      */

472     protected int findNamePoint(String JavaDoc namespaceURI, String JavaDoc name) {
473         
474         if (nodes == null) return -1;
475         if (name == null) return -1;
476         
477         // This is a linear search through the same nodes Vector.
478
// The Vector is sorted on the DOM Level 1 nodename.
479
// The DOM Level 2 NS keys are namespaceURI and Localname,
480
// so we must linear search thru it.
481
// In addition, to get this to work with nodes without any namespace
482
// (namespaceURI and localNames are both null) we then use the nodeName
483
// as a seconday key.
484
for (int i = 0; i < nodes.size(); i++) {
485             NodeImpl a = (NodeImpl)nodes.elementAt(i);
486             String JavaDoc aNamespaceURI = a.getNamespaceURI();
487             String JavaDoc aLocalName = a.getLocalName();
488             if (namespaceURI == null) {
489               if (aNamespaceURI == null
490                   &&
491                   (name.equals(aLocalName)
492                    ||
493                    (aLocalName == null && name.equals(a.getNodeName()))))
494                 return i;
495             } else {
496               if (namespaceURI.equals(aNamespaceURI)
497                   &&
498                   name.equals(aLocalName))
499                 return i;
500             }
501         }
502         return -1;
503     }
504
505     // compare 2 nodes in the map. If a precedes b, return true, otherwise
506
// return false
507
protected boolean precedes(Node JavaDoc a, Node JavaDoc b) {
508
509        if (nodes != null) {
510           for (int i = 0; i < nodes.size(); i++) {
511               Node JavaDoc n = (Node JavaDoc)nodes.elementAt(i);
512               if (n==a) return true;
513               if (n==b) return false;
514           }
515        }
516
517        return false;
518     }
519
520
521     /**
522       * NON-DOM: Remove attribute at specified index
523       */

524     protected void removeItem(int index) {
525        if (nodes != null && index < nodes.size()){
526            nodes.removeElementAt(index);
527        }
528     }
529
530
531     protected Object JavaDoc getItem (int index){
532         if (nodes !=null) {
533             return nodes.elementAt(index);
534         }
535         return null;
536     }
537
538     protected int addItem (Node JavaDoc arg) {
539         int i = findNamePoint(arg.getNamespaceURI(), arg.getLocalName());
540         if (i >= 0) {
541             nodes.setElementAt(arg,i);
542         }
543         else {
544             // If we can't find by namespaceURI, localName, then we find by
545
// nodeName so we know where to insert.
546
i = findNamePoint(arg.getNodeName(),0);
547             if (i >= 0) {
548                 nodes.insertElementAt(arg,i);
549             }
550             else {
551                 i = -1 - i; // Insert point (may be end of list)
552
if (null == nodes) {
553                     nodes = new Vector JavaDoc(5, 10);
554                 }
555                 nodes.insertElementAt(arg, i);
556             }
557         }
558         return i;
559     }
560
561     /**
562      * NON-DOM: copy content of this map into the specified vector
563      *
564      * @param list Vector to copy information into.
565      * @return A copy of this node named map
566      */

567     protected Vector JavaDoc cloneMap(Vector JavaDoc list){
568         if (list == null) {
569             list = new Vector JavaDoc(5, 10);
570         }
571         list.setSize(0);
572         if (nodes != null) {
573             for (int i=0; i<nodes.size(); i++) {
574                 list.insertElementAt(nodes.elementAt(i), i);
575             }
576         }
577         
578         return list;
579     }
580     
581      protected int getNamedItemIndex(String JavaDoc namespaceURI, String JavaDoc localName) {
582         return findNamePoint(namespaceURI, localName);
583      }
584
585     /**
586       * NON-DOM remove all elements from this map
587       */

588     public void removeAll (){
589         if (nodes != null) {
590             nodes.removeAllElements();
591         }
592     }
593     
594
595 } // class NamedNodeMapImpl
596
Popular Tags