KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 2000-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.util.Vector JavaDoc;
61
62 import org.w3c.dom.DOMException JavaDoc;
63 import org.w3c.dom.Node JavaDoc;
64
65
66 /**
67  * AttributeMap inherits from NamedNodeMapImpl and extends it to deal with the
68  * specifics of storing attributes. These are:
69  * <ul>
70  * <li>managing ownership of attribute nodes
71  * <li>managing default attributes
72  * <li>firing mutation events
73  * </ul>
74  * <p>
75  * This class doesn't directly support mutation events, however, it notifies
76  * the document when mutations are performed so that the document class do so.
77  *
78  * @version $Id: AttributeMap.java,v 1.28 2004/02/16 23:09:35 mrglavas Exp $
79  */

80 public class AttributeMap extends NamedNodeMapImpl {
81     
82     /** Serialization version. */
83     static final long serialVersionUID = 8872606282138665383L;
84
85     //
86
// Constructors
87
//
88

89     /** Constructs a named node map. */
90     protected AttributeMap(ElementImpl ownerNode, NamedNodeMapImpl defaults) {
91         super(ownerNode);
92         if (defaults != null) {
93             // initialize map with the defaults
94
cloneContent(defaults);
95             if (nodes != null) {
96                 hasDefaults(true);
97             }
98         }
99     }
100
101     /**
102      * Adds an attribute using its nodeName attribute.
103      * @see org.w3c.dom.NamedNodeMap#setNamedItem
104      * @return If the new Node replaces an existing node the replaced Node is
105      * returned, otherwise null is returned.
106      * @param arg
107      * An Attr node to store in this map.
108      * @exception org.w3c.dom.DOMException The exception description.
109      */

110     public Node JavaDoc setNamedItem(Node JavaDoc arg)
111         throws DOMException JavaDoc {
112
113         if (isReadOnly()) {
114             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
115             throw new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
116         }
117         if(arg.getOwnerDocument() != ownerNode.ownerDocument()) {
118             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
119             throw new DOMException JavaDoc(DOMException.WRONG_DOCUMENT_ERR, msg);
120         }
121         if (arg.getNodeType() != Node.ATTRIBUTE_NODE) {
122             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null);
123             throw new DOMException JavaDoc(DOMException.HIERARCHY_REQUEST_ERR, msg);
124         }
125
126         AttrImpl argn = (AttrImpl)arg;
127
128         if (argn.isOwned()){
129             if (argn.getOwnerElement() != ownerNode) {
130                    String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INUSE_ATTRIBUTE_ERR", null);
131                    throw new DOMException JavaDoc(DOMException.INUSE_ATTRIBUTE_ERR, msg);
132             }
133             // replacing an Attribute with itself does nothing
134
return arg;
135         }
136
137         // set owner
138
argn.ownerNode = ownerNode;
139         argn.isOwned(true);
140
141     int i = findNamePoint(arg.getNodeName(),0);
142         AttrImpl previous = null;
143         if (i >= 0) {
144             previous = (AttrImpl) nodes.elementAt(i);
145             nodes.setElementAt(arg,i);
146             previous.ownerNode = ownerNode.ownerDocument();
147             previous.isOwned(false);
148             // make sure it won't be mistaken with defaults in case it's reused
149
previous.isSpecified(true);
150         } else {
151             i = -1 - i; // Insert point (may be end of list)
152
if (null == nodes) {
153                 nodes = new Vector JavaDoc(5, 10);
154             }
155             nodes.insertElementAt(arg, i);
156         }
157
158         // notify document
159
ownerNode.ownerDocument().setAttrNode(argn, previous);
160
161         // If the new attribute is not normalized,
162
// the owning element is inherently not normalized.
163
if (!argn.isNormalized()) {
164             ownerNode.isNormalized(false);
165         }
166         return previous;
167
168     } // setNamedItem(Node):Node
169

170     /**
171      * Adds an attribute using its namespaceURI and localName.
172      * @see org.w3c.dom.NamedNodeMap#setNamedItem
173      * @return If the new Node replaces an existing node the replaced Node is
174      * returned, otherwise null is returned.
175      * @param arg A node to store in a named node map.
176      */

177     public Node JavaDoc setNamedItemNS(Node JavaDoc arg)
178         throws DOMException JavaDoc {
179
180         if (isReadOnly()) {
181             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
182             throw new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
183         }
184     
185         if(arg.getOwnerDocument() != ownerNode.ownerDocument()) {
186             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
187             throw new DOMException JavaDoc(DOMException.WRONG_DOCUMENT_ERR, msg);
188         }
189
190         if (arg.getNodeType() != Node.ATTRIBUTE_NODE) {
191             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null);
192             throw new DOMException JavaDoc(DOMException.HIERARCHY_REQUEST_ERR, msg);
193         }
194         AttrImpl argn = (AttrImpl)arg;
195
196         if (argn.isOwned()){
197             if (argn.getOwnerElement() != ownerNode) {
198                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INUSE_ATTRIBUTE_ERR", null);
199                 throw new DOMException JavaDoc(DOMException.INUSE_ATTRIBUTE_ERR, msg);
200             }
201             // replacing an Attribute with itself does nothing
202
return arg;
203         }
204
205         // set owner
206
argn.ownerNode = ownerNode;
207         argn.isOwned(true);
208
209         int i = findNamePoint(argn.getNamespaceURI(), argn.getLocalName());
210         AttrImpl previous = null;
211         if (i >= 0) {
212             previous = (AttrImpl) nodes.elementAt(i);
213             nodes.setElementAt(arg,i);
214             previous.ownerNode = ownerNode.ownerDocument();
215             previous.isOwned(false);
216             // make sure it won't be mistaken with defaults in case it's reused
217
previous.isSpecified(true);
218         } else {
219             // If we can't find by namespaceURI, localName, then we find by
220
// nodeName so we know where to insert.
221
i = findNamePoint(arg.getNodeName(),0);
222             if (i >=0) {
223                 previous = (AttrImpl) nodes.elementAt(i);
224                 nodes.insertElementAt(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         }
233         // changed(true);
234

235         // notify document
236
ownerNode.ownerDocument().setAttrNode(argn, previous);
237
238         // If the new attribute is not normalized,
239
// the owning element is inherently not normalized.
240
if (!argn.isNormalized()) {
241             ownerNode.isNormalized(false);
242         }
243         return previous;
244
245     } // setNamedItemNS(Node):Node
246

247     /**
248      * Removes an attribute specified by name.
249      * @param name
250      * The name of a node to remove. If the
251      * removed attribute is known to have a default value, an
252      * attribute immediately appears containing the default value
253      * as well as the corresponding namespace URI, local name,
254      * and prefix when applicable.
255      * @return The node removed from the map if a node with such a name exists.
256      * @throws NOT_FOUND_ERR: Raised if there is no node named
257      * name in the map.
258      */

259     /***/
260     public Node JavaDoc removeNamedItem(String JavaDoc name)
261         throws DOMException JavaDoc {
262         return internalRemoveNamedItem(name, true);
263     }
264
265     /**
266      * Same as removeNamedItem except that it simply returns null if the
267      * specified name is not found.
268      */

269     Node JavaDoc safeRemoveNamedItem(String JavaDoc name) {
270         return internalRemoveNamedItem(name, false);
271     }
272
273
274     /**
275      * NON-DOM: Remove the node object
276      *
277      * NOTE: Specifically removes THIS NODE -- not the node with this
278      * name, nor the node with these contents. If node does not belong to
279      * this named node map, we throw a DOMException.
280      *
281      * @param item The node to remove
282      * @param addDefault true -- magically add default attribute
283      * @return Removed node
284      * @exception DOMException
285      */

286     protected Node JavaDoc removeItem(Node JavaDoc item, boolean addDefault)
287         throws DOMException JavaDoc {
288
289         int index = -1;
290         if (nodes != null) {
291             for (int i = 0; i < nodes.size(); i++) {
292                 if (nodes.elementAt(i) == item) {
293                     index = i;
294                     break;
295                 }
296             }
297         }
298         if (index < 0) {
299             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
300             throw new DOMException JavaDoc(DOMException.NOT_FOUND_ERR, msg);
301         }
302         
303         return remove((AttrImpl)item, index, addDefault);
304     }
305
306     /**
307      * Internal removeNamedItem method allowing to specify whether an exception
308      * must be thrown if the specified name is not found.
309      */

310     final protected Node JavaDoc internalRemoveNamedItem(String JavaDoc name, boolean raiseEx){
311         if (isReadOnly()) {
312                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
313                 throw new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
314         }
315         int i = findNamePoint(name,0);
316         if (i < 0) {
317             if (raiseEx) {
318                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
319                 throw new DOMException JavaDoc(DOMException.NOT_FOUND_ERR, msg);
320             } else {
321                 return null;
322             }
323         }
324
325         return remove((AttrImpl)nodes.elementAt(i), i, true);
326
327     } // internalRemoveNamedItem(String,boolean):Node
328

329     private final Node JavaDoc remove(AttrImpl attr, int index,
330                               boolean addDefault) {
331
332         CoreDocumentImpl ownerDocument = ownerNode.ownerDocument();
333         String JavaDoc name = attr.getNodeName();
334         if (attr.isIdAttribute()) {
335             ownerDocument.removeIdentifier(attr.getValue());
336         }
337
338         if (hasDefaults() && addDefault) {
339             // If there's a default, add it instead
340
NamedNodeMapImpl defaults =
341                 ((ElementImpl) ownerNode).getDefaultAttributes();
342
343             Node JavaDoc d;
344             if (defaults != null &&
345                 (d = defaults.getNamedItem(name)) != null &&
346                 findNamePoint(name, index+1) < 0) {
347                     NodeImpl clone = (NodeImpl)d.cloneNode(true);
348                     if (d.getLocalName() !=null){
349                             // we must rely on the name to find a default attribute
350
// ("test:attr"), but while copying it from the DOCTYPE
351
// we should not loose namespace URI that was assigned
352
// to the attribute in the instance document.
353
((AttrNSImpl)clone).namespaceURI = attr.getNamespaceURI();
354                     }
355                     clone.ownerNode = ownerNode;
356                     clone.isOwned(true);
357                     clone.isSpecified(false);
358                 
359                     nodes.setElementAt(clone, index);
360                     if (attr.isIdAttribute()) {
361                         ownerDocument.putIdentifier(clone.getNodeValue(),
362                                                 (ElementImpl)ownerNode);
363                     }
364             } else {
365                 nodes.removeElementAt(index);
366             }
367         } else {
368             nodes.removeElementAt(index);
369         }
370
371         // changed(true);
372

373         // remove reference to owner
374
attr.ownerNode = ownerDocument;
375         attr.isOwned(false);
376
377         // make sure it won't be mistaken with defaults in case it's
378
// reused
379
attr.isSpecified(true);
380         attr.isIdAttribute(false);
381
382         // notify document
383
ownerDocument.removedAttrNode(attr, ownerNode, name);
384
385         return attr;
386     }
387     
388     /**
389      * Introduced in DOM Level 2. <p>
390      * Removes an attribute specified by local name and namespace URI.
391      * @param namespaceURI
392      * The namespace URI of the node to remove.
393      * When it is null or an empty string, this
394      * method behaves like removeNamedItem.
395      * @param The local name of the node to remove. If the
396      * removed attribute is known to have a default
397      * value, an attribute immediately appears
398      * containing the default value.
399      * @return Node The node removed from the map if a node with such
400      * a local name and namespace URI exists.
401      * @throws NOT_FOUND_ERR: Raised if there is no node named
402      * name in the map.
403      */

404     public Node JavaDoc removeNamedItemNS(String JavaDoc namespaceURI, String JavaDoc name)
405         throws DOMException JavaDoc {
406         return internalRemoveNamedItemNS(namespaceURI, name, true);
407     }
408
409     /**
410      * Same as removeNamedItem except that it simply returns null if the
411      * specified local name and namespace URI is not found.
412      */

413     Node JavaDoc safeRemoveNamedItemNS(String JavaDoc namespaceURI, String JavaDoc name) {
414         return internalRemoveNamedItemNS(namespaceURI, name, false);
415     }
416
417     /**
418      * Internal removeNamedItemNS method allowing to specify whether an
419      * exception must be thrown if the specified local name and namespace URI
420      * is not found.
421      */

422     final protected Node JavaDoc internalRemoveNamedItemNS(String JavaDoc namespaceURI,
423                                                    String JavaDoc name,
424                                                    boolean raiseEx) {
425         if (isReadOnly()) {
426             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
427             throw new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
428         }
429         int i = findNamePoint(namespaceURI, name);
430         if (i < 0) {
431             if (raiseEx) {
432                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
433                 throw new DOMException JavaDoc(DOMException.NOT_FOUND_ERR, msg);
434             } else {
435                 return null;
436             }
437         }
438
439         AttrImpl n = (AttrImpl)nodes.elementAt(i);
440         CoreDocumentImpl ownerDocument = ownerNode.ownerDocument();
441
442         if (n.isIdAttribute()) {
443                 ownerDocument.removeIdentifier(n.getValue());
444         }
445         // If there's a default, add it instead
446
String JavaDoc nodeName = n.getNodeName();
447         if (hasDefaults()) {
448             NamedNodeMapImpl defaults = ((ElementImpl) ownerNode).getDefaultAttributes();
449             Node JavaDoc d;
450             if (defaults != null
451                 && (d = defaults.getNamedItem(nodeName)) != null)
452                 {
453                     int j = findNamePoint(nodeName,0);
454                     if (j>=0 && findNamePoint(nodeName, j+1) < 0) {
455                         NodeImpl clone = (NodeImpl)d.cloneNode(true);
456                         clone.ownerNode = ownerNode;
457                         if (d.getLocalName() != null) {
458                             // we must rely on the name to find a default attribute
459
// ("test:attr"), but while copying it from the DOCTYPE
460
// we should not loose namespace URI that was assigned
461
// to the attribute in the instance document.
462
((AttrNSImpl)clone).namespaceURI = namespaceURI;
463                         }
464                         clone.isOwned(true);
465                         clone.isSpecified(false);
466                         nodes.setElementAt(clone, i);
467                         if (clone.isIdAttribute()) {
468                                 ownerDocument.putIdentifier(clone.getNodeValue(),
469                                                             (ElementImpl)ownerNode);
470                         }
471                     } else {
472                         nodes.removeElementAt(i);
473                     }
474                 } else {
475                     nodes.removeElementAt(i);
476                 }
477         } else {
478             nodes.removeElementAt(i);
479         }
480
481         // changed(true);
482

483         // remove reference to owner
484
n.ownerNode = ownerDocument;
485         n.isOwned(false);
486         // make sure it won't be mistaken with defaults in case it's
487
// reused
488
n.isSpecified(true);
489         // update id table if needed
490
n.isIdAttribute(false);
491
492         // notify document
493
ownerDocument.removedAttrNode(n, ownerNode, name);
494
495         return n;
496
497     } // internalRemoveNamedItemNS(String,String,boolean):Node
498

499     //
500
// Public methods
501
//
502

503     /**
504      * Cloning a NamedNodeMap is a DEEP OPERATION; it always clones
505      * all the nodes contained in the map.
506      */

507      
508     public NamedNodeMapImpl cloneMap(NodeImpl ownerNode) {
509         AttributeMap newmap =
510             new AttributeMap((ElementImpl) ownerNode, null);
511         newmap.hasDefaults(hasDefaults());
512         newmap.cloneContent(this);
513         return newmap;
514     } // cloneMap():AttributeMap
515

516     /**
517      * Override parent's method to set the ownerNode correctly
518      */

519     protected void cloneContent(NamedNodeMapImpl srcmap) {
520         Vector JavaDoc srcnodes = srcmap.nodes;
521         if (srcnodes != null) {
522             int size = srcnodes.size();
523             if (size != 0) {
524                 if (nodes == null) {
525                     nodes = new Vector JavaDoc(size);
526                 }
527                 nodes.setSize(size);
528                 for (int i = 0; i < size; ++i) {
529                     NodeImpl n = (NodeImpl) srcnodes.elementAt(i);
530                     NodeImpl clone = (NodeImpl) n.cloneNode(true);
531                     clone.isSpecified(n.isSpecified());
532                     nodes.setElementAt(clone, i);
533                     clone.ownerNode = ownerNode;
534                     clone.isOwned(true);
535                 }
536             }
537         }
538     } // cloneContent():AttributeMap
539

540
541     /**
542      * Move specified attributes from the given map to this one
543      */

544     void moveSpecifiedAttributes(AttributeMap srcmap) {
545         int nsize = (srcmap.nodes != null) ? srcmap.nodes.size() : 0;
546         for (int i = nsize - 1; i >= 0; i--) {
547             AttrImpl attr = (AttrImpl) srcmap.nodes.elementAt(i);
548             if (attr.isSpecified()) {
549                 srcmap.remove(attr, i, false);
550                 if (attr.getLocalName() != null) {
551                     setNamedItem(attr);
552                 }
553                 else {
554                     setNamedItemNS(attr);
555                 }
556             }
557         }
558     } // moveSpecifiedAttributes(AttributeMap):void
559

560
561     /**
562      * Get this AttributeMap in sync with the given "defaults" map.
563      * @param defaults The default attributes map to sync with.
564      */

565     protected void reconcileDefaults(NamedNodeMapImpl defaults) {
566
567         // remove any existing default
568
int nsize = (nodes != null) ? nodes.size() : 0;
569         for (int i = nsize - 1; i >= 0; i--) {
570             AttrImpl attr = (AttrImpl) nodes.elementAt(i);
571             if (!attr.isSpecified()) {
572                 remove(attr, i, false);
573             }
574         }
575         // add the new defaults
576
if (defaults == null) {
577             return;
578         }
579         if (nodes == null || nodes.size() == 0) {
580             cloneContent(defaults);
581         }
582         else {
583             int dsize = defaults.nodes.size();
584             for (int n = 0; n < dsize; n++) {
585                 AttrImpl d = (AttrImpl) defaults.nodes.elementAt(n);
586                 int i = findNamePoint(d.getNodeName(), 0);
587                 if (i < 0) {
588                     i = -1 - i;
589                     NodeImpl clone = (NodeImpl) d.cloneNode(true);
590                     clone.ownerNode = ownerNode;
591                     clone.isOwned(true);
592                     clone.isSpecified(false);
593                     nodes.insertElementAt(clone, i);
594                 }
595             }
596         }
597
598     } // reconcileDefaults()
599

600 } // class AttributeMap
601
Popular Tags