KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xerces > internal > dom > NamedNodeMapImpl


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

57
58 package com.sun.org.apache.xerces.internal.dom;
59
60 import java.io.Serializable JavaDoc;
61 import java.util.Vector JavaDoc;
62
63 import org.w3c.dom.DOMException JavaDoc;
64 import org.w3c.dom.NamedNodeMap JavaDoc;
65 import org.w3c.dom.Node JavaDoc;
66
67 /**
68  * NamedNodeMaps represent collections of Nodes that can be accessed
69  * by name. Entity and Notation nodes are stored in NamedNodeMaps
70  * attached to the DocumentType. Attributes are placed in a NamedNodeMap
71  * attached to the elem they're related too. However, because attributes
72  * require more work, such as firing mutation events, they are stored in
73  * a subclass of NamedNodeMapImpl.
74  * <P>
75  * Only one Node may be stored per name; attempting to
76  * store another will replace the previous value.
77  * <P>
78  * NOTE: The "primary" storage key is taken from the NodeName attribute of the
79  * node. The "secondary" storage key is the namespaceURI and localName, when
80  * accessed by DOM level 2 nodes. All nodes, even DOM Level 2 nodes are stored
81  * in a single Vector sorted by the primary "nodename" key.
82  * <P>
83  * NOTE: item()'s integer index does _not_ imply that the named nodes
84  * must be stored in an array; that's only an access method. Note too
85  * that these indices are "live"; if someone changes the map's
86  * contents, the indices associated with nodes may change.
87  * <P>
88  *
89  * @version $Id: NamedNodeMapImpl.java,v 1.35 2003/01/23 23:23:25 lmartin Exp $
90  * @since PR-DOM-Level-1-19980818.
91  */

92 public class NamedNodeMapImpl
93     implements NamedNodeMap JavaDoc, Serializable JavaDoc {
94
95     //
96
// Constants
97
//
98

99     /** Serialization version. */
100     static final long serialVersionUID = -7039242451046758020L;
101
102     //
103
// Data
104
//
105

106     protected short flags;
107
108     protected final static short READONLY = 0x1<<0;
109     protected final static short CHANGED = 0x1<<1;
110     protected final static short HASDEFAULTS = 0x1<<2;
111
112     /** Nodes. */
113     protected Vector JavaDoc nodes;
114
115     protected NodeImpl ownerNode; // the node this map belongs to
116

117     //
118
// Constructors
119
//
120

121     /** Constructs a named node map. */
122     protected NamedNodeMapImpl(NodeImpl ownerNode) {
123         this.ownerNode = ownerNode;
124     }
125
126     //
127
// NamedNodeMap methods
128
//
129

130     /**
131      * Report how many nodes are currently stored in this NamedNodeMap.
132      * Caveat: This is a count rather than an index, so the
133      * highest-numbered node at any time can be accessed via
134      * item(getLength()-1).
135      */

136     public int getLength() {
137         return (nodes != null) ? nodes.size() : 0;
138     }
139
140     /**
141      * Retrieve an item from the map by 0-based index.
142      *
143      * @param index Which item to retrieve. Note that indices are just an
144      * enumeration of the current contents; they aren't guaranteed to be
145      * stable, nor do they imply any promises about the order of the
146      * NamedNodeMap's contents. In other words, DO NOT assume either that
147      * index(i) will always refer to the same entry, or that there is any
148      * stable ordering of entries... and be prepared for double-reporting
149      * or skips as insertion and deletion occur.
150      *
151      * @return the node which currenly has the specified index, or null if index
152      * is greater than or equal to getLength().
153      */

154     public Node JavaDoc item(int index) {
155         return (nodes != null && index < nodes.size()) ?
156                     (Node JavaDoc)(nodes.elementAt(index)) : null;
157     }
158
159     /**
160      * Retrieve a node by name.
161      *
162      * @param name Name of a node to look up.
163      * @return the Node (of unspecified sub-class) stored with that name, or
164      * null if no value has been assigned to that name.
165      */

166     public Node JavaDoc getNamedItem(String JavaDoc name) {
167
168         int i = findNamePoint(name,0);
169         return (i < 0) ? null : (Node JavaDoc)(nodes.elementAt(i));
170
171     } // getNamedItem(String):Node
172

173     /**
174      * Introduced in DOM Level 2. <p>
175      * Retrieves a node specified by local name and namespace URI.
176      *
177      * @param namespaceURI The namespace URI of the node to retrieve.
178      * When it is null or an empty string, this
179      * method behaves like getNamedItem.
180      * @param localName The local name of the node to retrieve.
181      * @return Node A Node (of any type) with the specified name, or null if the specified
182      * name did not identify any node in the map.
183      */

184     public Node JavaDoc getNamedItemNS(String JavaDoc namespaceURI, String JavaDoc localName) {
185
186         int i = findNamePoint(namespaceURI, localName);
187         return (i < 0) ? null : (Node JavaDoc)(nodes.elementAt(i));
188
189     } // getNamedItemNS(String,String):Node
190

191     /**
192      * Adds a node using its nodeName attribute.
193      * As the nodeName attribute is used to derive the name which the node must be
194      * stored under, multiple nodes of certain types (those that have a "special" string
195      * value) cannot be stored as the names would clash. This is seen as preferable to
196      * allowing nodes to be aliased.
197      * @see org.w3c.dom.NamedNodeMap#setNamedItem
198      * @return If the new Node replaces an existing node the replaced Node is returned,
199      * otherwise null is returned.
200      * @param arg
201      * A node to store in a named node map. The node will later be
202      * accessible using the value of the namespaceURI and localName
203      * attribute of the node. If a node with those namespace URI and
204      * local name is already present in the map, it is replaced by the new
205      * one.
206      * @exception org.w3c.dom.DOMException The exception description.
207      */

208     public Node JavaDoc setNamedItem(Node JavaDoc arg)
209         throws DOMException JavaDoc {
210
211         if (isReadOnly()) {
212             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
213             throw new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
214         }
215         if (arg.getOwnerDocument() != ownerNode.ownerDocument()) {
216             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
217             throw new DOMException JavaDoc(DOMException.WRONG_DOCUMENT_ERR, msg);
218         }
219
220     int i = findNamePoint(arg.getNodeName(),0);
221         NodeImpl previous = null;
222         if (i >= 0) {
223             previous = (NodeImpl) nodes.elementAt(i);
224             nodes.setElementAt(arg,i);
225         } else {
226             i = -1 - i; // Insert point (may be end of list)
227
if (null == nodes) {
228                 nodes = new Vector JavaDoc(5, 10);
229             }
230             nodes.insertElementAt(arg, i);
231         }
232         return previous;
233
234     } // setNamedItem(Node):Node
235

236     /**
237      * Adds a node using its namespaceURI and localName.
238      * @see org.w3c.dom.NamedNodeMap#setNamedItem
239      * @return If the new Node replaces an existing node the replaced Node is returned,
240      * otherwise null is returned.
241      * @param arg A node to store in a named node map. The node will later be
242      * accessible using the value of the namespaceURI and localName
243      * attribute of the node. If a node with those namespace URI and
244      * local name is already present in the map, it is replaced by the new
245      * one.
246      */

247     public Node JavaDoc setNamedItemNS(Node JavaDoc arg)
248         throws DOMException JavaDoc {
249
250         if (isReadOnly()) {
251             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
252             throw new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
253         }
254     
255         if(arg.getOwnerDocument() != ownerNode.ownerDocument()) {
256             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
257             throw new DOMException JavaDoc(DOMException.WRONG_DOCUMENT_ERR, msg);
258         }
259
260         int i = findNamePoint(arg.getNamespaceURI(), arg.getLocalName());
261         NodeImpl previous = null;
262         if (i >= 0) {
263             previous = (NodeImpl) nodes.elementAt(i);
264             nodes.setElementAt(arg,i);
265         } else {
266             // If we can't find by namespaceURI, localName, then we find by
267
// nodeName so we know where to insert.
268
i = findNamePoint(arg.getNodeName(),0);
269             if (i >=0) {
270                 previous = (NodeImpl) nodes.elementAt(i);
271                 nodes.insertElementAt(arg,i);
272             } else {
273                 i = -1 - i; // Insert point (may be end of list)
274
if (null == nodes) {
275                     nodes = new Vector JavaDoc(5, 10);
276                 }
277                 nodes.insertElementAt(arg, i);
278             }
279         }
280         return previous;
281
282     } // setNamedItem(Node):Node
283

284     /**
285      * Removes a node specified by name.
286      * @param name The name of a node to remove.
287      * @return The node removed from the map if a node with such a name exists.
288      */

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

312     /**
313      * Introduced in DOM Level 2. <p>
314      * Removes a node specified by local name and namespace URI.
315      * @param namespaceURI
316      * The namespace URI of the node to remove.
317      * When it is null or an empty string, this
318      * method behaves like removeNamedItem.
319      * @param The local name of the node to remove.
320      * @return Node The node removed from the map if a node with such
321      * a local name and namespace URI exists.
322      * @throws NOT_FOUND_ERR: Raised if there is no node named
323      * name in the map.
324
325      */

326      public Node JavaDoc removeNamedItemNS(String JavaDoc namespaceURI, String JavaDoc name)
327         throws DOMException JavaDoc {
328
329         if (isReadOnly()) {
330             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
331             throw
332                 new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR,
333                 msg);
334         }
335         int i = findNamePoint(namespaceURI, name);
336         if (i < 0) {
337             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
338             throw new DOMException JavaDoc(DOMException.NOT_FOUND_ERR, msg);
339         }
340
341         NodeImpl n = (NodeImpl)nodes.elementAt(i);
342         nodes.removeElementAt(i);
343
344         return n;
345
346     } // removeNamedItem(String):Node
347

348     //
349
// Public methods
350
//
351

352     /**
353      * Cloning a NamedNodeMap is a DEEP OPERATION; it always clones
354      * all the nodes contained in the map.
355      */

356      
357     public NamedNodeMapImpl cloneMap(NodeImpl ownerNode) {
358         NamedNodeMapImpl newmap = new NamedNodeMapImpl(ownerNode);
359         newmap.cloneContent(this);
360         return newmap;
361     }
362
363     protected void cloneContent(NamedNodeMapImpl srcmap) {
364         Vector JavaDoc srcnodes = srcmap.nodes;
365         if (srcnodes != null) {
366             int size = srcnodes.size();
367             if (size != 0) {
368                 if (nodes == null) {
369                     nodes = new Vector JavaDoc(size);
370                 }
371                 nodes.setSize(size);
372                 for (int i = 0; i < size; ++i) {
373                     NodeImpl n = (NodeImpl) srcmap.nodes.elementAt(i);
374                     NodeImpl clone = (NodeImpl) n.cloneNode(true);
375                     clone.isSpecified(n.isSpecified());
376                     nodes.setElementAt(clone, i);
377                 }
378             }
379         }
380     } // cloneMap():NamedNodeMapImpl
381

382     //
383
// Package methods
384
//
385

386     /**
387      * Internal subroutine to allow read-only Nodes to make their contained
388      * NamedNodeMaps readonly too. I expect that in fact the shallow
389      * version of this operation will never be
390      *
391      * @param readOnly boolean true to make read-only, false to permit editing.
392      * @param deep boolean true to pass this request along to the contained
393      * nodes, false to only toggle the NamedNodeMap itself. I expect that
394      * the shallow version of this operation will never be used, but I want
395      * to design it in now, while I'm thinking about it.
396      */

397     void setReadOnly(boolean readOnly, boolean deep) {
398         isReadOnly(readOnly);
399         if (deep && nodes != null) {
400             for (int i = nodes.size() - 1; i >= 0; i--) {
401                 ((NodeImpl) nodes.elementAt(i)).setReadOnly(readOnly,deep);
402             }
403         }
404     } // setReadOnly(boolean,boolean)
405

406     /**
407      * Internal subroutine returns this NodeNameMap's (shallow) readOnly value.
408      *
409      */

410     boolean getReadOnly() {
411         return isReadOnly();
412     } // getReadOnly()
413

414
415     //
416
// Protected methods
417
//
418

419     /**
420      * NON-DOM
421      * set the ownerDocument of this node, and the attributes it contains
422      */

423     void setOwnerDocument(CoreDocumentImpl doc) {
424         if (nodes != null) {
425             for (int i = 0; i < nodes.size(); i++) {
426                 ((NodeImpl)item(i)).setOwnerDocument(doc);
427             }
428         }
429     }
430
431     final boolean isReadOnly() {
432         return (flags & READONLY) != 0;
433     }
434
435     final void isReadOnly(boolean value) {
436         flags = (short) (value ? flags | READONLY : flags & ~READONLY);
437     }
438
439     final boolean changed() {
440         return (flags & CHANGED) != 0;
441     }
442
443     final void changed(boolean value) {
444         flags = (short) (value ? flags | CHANGED : flags & ~CHANGED);
445     }
446
447     final boolean hasDefaults() {
448         return (flags & HASDEFAULTS) != 0;
449     }
450
451     final void hasDefaults(boolean value) {
452         flags = (short) (value ? flags | HASDEFAULTS : flags & ~HASDEFAULTS);
453     }
454
455     //
456
// Private methods
457
//
458

459     /**
460      * Subroutine: Locate the named item, or the point at which said item
461      * should be added.
462      *
463      * @param name Name of a node to look up.
464      *
465      * @return If positive or zero, the index of the found item.
466      * If negative, index of the appropriate point at which to insert
467      * the item, encoded as -1-index and hence reconvertable by subtracting
468      * it from -1. (Encoding because I don't want to recompare the strings
469      * but don't want to burn bytes on a datatype to hold a flagged value.)
470      */

471     protected int findNamePoint(String JavaDoc name, int start) {
472
473         // Binary search
474
int i = 0;
475         if (nodes != null) {
476             int first = start;
477             int last = nodes.size() - 1;
478
479             while (first <= last) {
480                 i = (first + last) / 2;
481                 int test = name.compareTo(((Node JavaDoc)(nodes.elementAt(i))).getNodeName());
482                 if (test == 0) {
483                     return i; // Name found
484
}
485                 else if (test < 0) {
486                     last = i - 1;
487                 }
488                 else {
489                     first = i + 1;
490                 }
491             }
492
493             if (first > i) {
494                 i = first;
495             }
496         }
497
498         return -1 - i; // not-found has to be encoded.
499

500     } // findNamePoint(String):int
501

502     
503     /** This findNamePoint is for DOM Level 2 Namespaces.
504      */

505     protected int findNamePoint(String JavaDoc namespaceURI, String JavaDoc name) {
506         
507         if (nodes == null) return -1;
508         if (name == null) return -1;
509         
510         // This is a linear search through the same nodes Vector.
511
// The Vector is sorted on the DOM Level 1 nodename.
512
// The DOM Level 2 NS keys are namespaceURI and Localname,
513
// so we must linear search thru it.
514
// In addition, to get this to work with nodes without any namespace
515
// (namespaceURI and localNames are both null) we then use the nodeName
516
// as a seconday key.
517
for (int i = 0; i < nodes.size(); i++) {
518             NodeImpl a = (NodeImpl)nodes.elementAt(i);
519             String JavaDoc aNamespaceURI = a.getNamespaceURI();
520             String JavaDoc aLocalName = a.getLocalName();
521             if (namespaceURI == null) {
522               if (aNamespaceURI == null
523                   &&
524                   (name.equals(aLocalName)
525                    ||
526                    (aLocalName == null && name.equals(a.getNodeName()))))
527                 return i;
528             } else {
529               if (namespaceURI.equals(aNamespaceURI)
530                   &&
531                   name.equals(aLocalName))
532                 return i;
533             }
534         }
535         return -1;
536     }
537
538     // compare 2 nodes in the map. If a precedes b, return true, otherwise
539
// return false
540
protected boolean precedes(Node JavaDoc a, Node JavaDoc b) {
541
542        if (nodes != null) {
543           for (int i = 0; i < nodes.size(); i++) {
544               Node JavaDoc n = (Node JavaDoc)nodes.elementAt(i);
545               if (n==a) return true;
546               if (n==b) return false;
547           }
548        }
549
550        return false;
551     }
552
553
554     /**
555       * NON-DOM: Remove attribute at specified index
556       */

557     protected void removeItem(int index) {
558        if (nodes != null && index < nodes.size()){
559            nodes.removeElementAt(index);
560        }
561     }
562
563
564     protected Object JavaDoc getItem (int index){
565         if (nodes !=null) {
566             return nodes.elementAt(index);
567         }
568         return null;
569     }
570
571     protected int addItem (Node JavaDoc arg) {
572         int i = findNamePoint(arg.getNamespaceURI(), arg.getLocalName());
573         NodeImpl previous = null;
574         if (i >= 0) {
575             previous = (NodeImpl) nodes.elementAt(i);
576             nodes.setElementAt(arg,i);
577         } else {
578             // If we can't find by namespaceURI, localName, then we find by
579
// nodeName so we know where to insert.
580
i = findNamePoint(arg.getNodeName(),0);
581             if (i >=0) {
582                 previous = (NodeImpl) nodes.elementAt(i);
583                 nodes.insertElementAt(arg,i);
584             } else {
585                 i = -1 - i; // Insert point (may be end of list)
586
if (null == nodes) {
587                     nodes = new Vector JavaDoc(5, 10);
588                 }
589                 nodes.insertElementAt(arg, i);
590             }
591         }
592         return i;
593     }
594
595     /**
596      * NON-DOM: copy content of this map into the specified vector
597      *
598      * @param list Vector to copy information into.
599      * @return A copy of this node named map
600      */

601     protected Vector JavaDoc cloneMap(Vector JavaDoc list){
602         if (list == null) {
603             list = new Vector JavaDoc(5, 10);
604         }
605         list.setSize(0);
606         if (nodes != null) {
607             for (int i=0; i<nodes.size(); i++) {
608                 list.insertElementAt(nodes.elementAt(i), i);
609             }
610         }
611         
612         return list;
613     }
614     
615      protected int getNamedItemIndex(String JavaDoc namespaceURI, String JavaDoc localName) {
616         return findNamePoint(namespaceURI, localName);
617      }
618
619     /**
620       * NON-DOM remove all elements from this map
621       */

622     public void removeAll (){
623         if (nodes != null) {
624             nodes.removeAllElements();
625         }
626     }
627     
628
629 } // class NamedNodeMapImpl
630
Popular Tags