KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > xpath > datamodel > xerces > dom > AttributeMap


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 2000 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 org.xquark.xpath.datamodel.xerces.dom;
59
60 import java.util.Vector JavaDoc;
61
62 import org.w3c.dom.DOMException JavaDoc;
63 import org.w3c.dom.Node JavaDoc;
64 import org.w3c.dom.events.MutationEvent JavaDoc;
65 import org.xquark.xpath.datamodel.xerces.dom.events.MutationEventImpl;
66
67 /**
68  * AttributeMap inherits from NamedNodeMapImpl and extends it to deal with the
69  * specifics of storing attributes. These are:
70  * <ul>
71  * <li>managing ownership of attribute nodes
72  * <li>managing default attributes
73  * <li>firing mutation events
74  * </ul>
75  *
76  */

77 public class AttributeMap extends NamedNodeMapImpl {
78
79     final static boolean DEBUG = false;
80
81     //
82
// Constructors
83
//
84

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

106     public Node JavaDoc setNamedItem(Node JavaDoc arg)
107         throws DOMException JavaDoc {
108
109         if (isReadOnly()) {
110             throw
111                 new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR,
112                                      "DOM001 Modification not allowed");
113         }
114         if(arg.getOwnerDocument() != ownerNode.ownerDocument()) {
115             throw new DOMException JavaDoc(DOMException.WRONG_DOCUMENT_ERR,
116                                        "DOM005 Wrong document");
117         }
118         if (arg.getNodeType() != Node.ATTRIBUTE_NODE) {
119             throw new DOMException JavaDoc(DOMException.HIERARCHY_REQUEST_ERR,
120                                    "DOM006 Hierarchy request error");
121         }
122
123         NodeImpl argn = (NodeImpl)arg;
124
125         if (argn.isOwned()) {
126             throw new DOMException JavaDoc(DOMException.INUSE_ATTRIBUTE_ERR,
127                                        "DOM009 Attribute already in use");
128         }
129
130         // set owner
131
argn.ownerNode = ownerNode;
132         argn.isOwned(true);
133
134     int i = findNamePoint(arg.getNodeName(),0);
135         NodeImpl previous = null;
136         if (i >= 0) {
137             previous = (NodeImpl) nodes.elementAt(i);
138             nodes.setElementAt(arg,i);
139             previous.ownerNode = ownerNode.ownerDocument();
140             previous.isOwned(false);
141             // make sure it won't be mistaken with defaults in case it's reused
142
previous.isSpecified(true);
143         } else {
144             i = -1 - i; // Insert point (may be end of list)
145
if (null == nodes) {
146                 nodes = new Vector JavaDoc(5, 10);
147             }
148             nodes.insertElementAt(arg, i);
149         }
150
151         if (NodeImpl.MUTATIONEVENTS &&
152             ownerNode.ownerDocument().mutationEvents) {
153             // MUTATION POST-EVENTS:
154
ownerNode.dispatchAggregateEvents(
155                 (AttrImpl)arg,
156                 previous==null ? null : previous.getNodeValue(),
157                 previous==null ?
158                            MutationEvent.ADDITION : MutationEvent.MODIFICATION
159                 );
160         }
161
162         // If the new attribute is not normalized,
163
// the owning element is inherently not normalized.
164
if (!argn.isNormalized()) {
165             ownerNode.isNormalized(false);
166         }
167         return previous;
168
169     } // setNamedItem(Node):Node
170

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

178     public Node JavaDoc setNamedItemNS(Node JavaDoc arg)
179         throws DOMException JavaDoc {
180
181         if (isReadOnly()) {
182             throw
183                 new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR,
184                                      "DOM001 Modification not allowed");
185         }
186     
187         if(arg.getOwnerDocument() != ownerNode.ownerDocument()) {
188             throw new DOMException JavaDoc(DOMException.WRONG_DOCUMENT_ERR,
189                                        "DOM005 Wrong document");
190         }
191
192         if (arg.getNodeType() != Node.ATTRIBUTE_NODE) {
193             throw new DOMException JavaDoc(DOMException.HIERARCHY_REQUEST_ERR,
194                                    "DOM006 Hierarchy request error");
195         }
196         NodeImpl argn = (NodeImpl)arg;
197         if (argn.isOwned()) {
198             throw new DOMException JavaDoc(DOMException.INUSE_ATTRIBUTE_ERR,
199                                        "DOM009 Attribute already in use");
200         }
201
202         // set owner
203
argn.ownerNode = ownerNode;
204         argn.isOwned(true);
205
206         int i = findNamePoint(argn.getNamespaceURI(), argn.getLocalName());
207         NodeImpl previous = null;
208         if (i >= 0) {
209             previous = (NodeImpl) nodes.elementAt(i);
210             nodes.setElementAt(arg,i);
211             previous.ownerNode = ownerNode.ownerDocument();
212             previous.isOwned(false);
213             // make sure it won't be mistaken with defaults in case it's reused
214
previous.isSpecified(true);
215         } else {
216             // If we can't find by namespaceURI, localName, then we find by
217
// nodeName so we know where to insert.
218
i = findNamePoint(arg.getNodeName(),0);
219             if (i >=0) {
220                 previous = (NodeImpl) nodes.elementAt(i);
221                 nodes.insertElementAt(arg,i);
222             } else {
223                 i = -1 - i; // Insert point (may be end of list)
224
if (null == nodes) {
225                     nodes = new Vector JavaDoc(5, 10);
226                 }
227                 nodes.insertElementAt(arg, i);
228             }
229         }
230         // changed(true);
231

232         // Only NamedNodeMaps containing attributes (those which are
233
// bound to an element) need report MutationEvents
234
if (NodeImpl.MUTATIONEVENTS
235             && ownerNode.ownerDocument().mutationEvents)
236         {
237             // MUTATION POST-EVENTS:
238
ownerNode.dispatchAggregateEvents(
239                 (AttrImpl)arg,
240                 previous==null ? null : previous.getNodeValue(),
241                 previous==null ?
242                            MutationEvent.ADDITION : MutationEvent.MODIFICATION
243                 );
244         }
245
246         // If the new attribute is not normalized,
247
// the owning element is inherently not normalized.
248
if (!argn.isNormalized()) {
249             ownerNode.isNormalized(false);
250         }
251         return previous;
252
253     } // setNamedItemNS(Node):Node
254

255     /**
256      * Removes an attribute specified by name.
257      * @param name
258      * The name of a node to remove. If the
259      * removed attribute is known to have a default value, an
260      * attribute immediately appears containing the default value
261      * as well as the corresponding namespace URI, local name,
262      * and prefix when applicable.
263      * @return The node removed from the map if a node with such a name exists.
264      * @throws NOT_FOUND_ERR: Raised if there is no node named
265      * name in the map.
266      */

267     /***/
268     public Node JavaDoc removeNamedItem(String JavaDoc name)
269         throws DOMException JavaDoc {
270         return internalRemoveNamedItem(name, true);
271     }
272
273     /**
274      * Same as removeNamedItem except that it simply returns null if the
275      * specified name is not found.
276      */

277     Node JavaDoc safeRemoveNamedItem(String JavaDoc name) {
278         return internalRemoveNamedItem(name, false);
279     }
280
281     /**
282      * Internal removeNamedItem method allowing to specify whether an exception
283      * must be thrown if the specified name is not found.
284      */

285     final protected Node JavaDoc internalRemoveNamedItem(String JavaDoc name, boolean raiseEx){
286         if (isReadOnly()) {
287             throw
288                 new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR,
289                                      "DOM001 Modification not allowed");
290         }
291         int i = findNamePoint(name,0);
292         if (i < 0) {
293             if (raiseEx) {
294                 throw new DOMException JavaDoc(DOMException.NOT_FOUND_ERR,
295                                            "DOM008 Not found");
296             } else {
297                 return null;
298             }
299         }
300
301         LCount lc=null;
302         String JavaDoc oldvalue="";
303         AttrImpl enclosingAttribute=null;
304         if (NodeImpl.MUTATIONEVENTS
305             && ownerNode.ownerDocument().mutationEvents)
306         {
307             // MUTATION PREPROCESSING AND PRE-EVENTS:
308
lc=LCount.lookup(MutationEventImpl.DOM_ATTR_MODIFIED);
309             if(lc.captures+lc.bubbles+lc.defaults>0)
310             {
311                enclosingAttribute=(AttrImpl)(nodes.elementAt(i));
312                oldvalue=enclosingAttribute.getNodeValue();
313             }
314         } // End mutation preprocessing
315

316         NodeImpl n = (NodeImpl)nodes.elementAt(i);
317         // If there's a default, add it instead
318
if (hasDefaults()) {
319             NamedNodeMapImpl defaults =
320                 ((ElementImpl) ownerNode).getDefaultAttributes();
321             Node JavaDoc d;
322             if (defaults != null && (d = defaults.getNamedItem(name)) != null
323                 && findNamePoint(name, i+1) < 0) {
324             
325                 NodeImpl clone = (NodeImpl)d.cloneNode(true);
326                 clone.ownerNode = ownerNode;
327                 clone.isOwned(true);
328                 clone.isSpecified(false);
329                 nodes.setElementAt(clone, i);
330             } else {
331                 nodes.removeElementAt(i);
332             }
333         } else {
334             nodes.removeElementAt(i);
335         }
336
337         // changed(true);
338

339         // remove owning element
340
n.ownerNode = ownerNode.ownerDocument();
341         n.isOwned(false);
342         // make sure it won't be mistaken with defaults in case it's reused
343
n.isSpecified(true);
344
345         // We can't use the standard dispatchAggregate, since it assumes
346
// that the Attr is still attached to an owner. This code is
347
// similar but dispatches to the previous owner, "element".
348
if(NodeImpl.MUTATIONEVENTS && ownerNode.ownerDocument().mutationEvents)
349         {
350             // If we have to send DOMAttrModified (determined earlier),
351
// do so.
352
if(lc.captures+lc.bubbles+lc.defaults>0) {
353                 MutationEventImpl me= new MutationEventImpl();
354                 me.initMutationEvent(MutationEventImpl.DOM_ATTR_MODIFIED,
355                                      true, false,
356                                      null, n.getNodeValue(),
357                      null, name, MutationEvent.REMOVAL);
358                 ownerNode.dispatchEvent(me);
359             }
360
361             // We can hand off to process DOMSubtreeModified, though.
362
// Note that only the Element needs to be informed; the
363
// Attr's subtree has not been changed by this operation.
364
ownerNode.dispatchAggregateEvents(null,null,(short)0);
365         }
366
367         return n;
368
369     } // removeNamedItem(String):Node
370

371     /**
372      * Introduced in DOM Level 2. <p>
373      * Removes an attribute specified by local name and namespace URI.
374      * @param namespaceURI
375      * The namespace URI of the node to remove.
376      * When it is null or an empty string, this
377      * method behaves like removeNamedItem.
378      * @param The local name of the node to remove. If the
379      * removed attribute is known to have a default
380      * value, an attribute immediately appears
381      * containing the default value.
382      * @return Node The node removed from the map if a node with such
383      * a local name and namespace URI exists.
384      * @throws NOT_FOUND_ERR: Raised if there is no node named
385      * name in the map.
386      */

387     public Node JavaDoc removeNamedItemNS(String JavaDoc namespaceURI, String JavaDoc name)
388         throws DOMException JavaDoc {
389         return internalRemoveNamedItemNS(namespaceURI, name, true);
390     }
391
392     /**
393      * Same as removeNamedItem except that it simply returns null if the
394      * specified local name and namespace URI is not found.
395      */

396     Node JavaDoc safeRemoveNamedItemNS(String JavaDoc namespaceURI, String JavaDoc name) {
397         return internalRemoveNamedItemNS(namespaceURI, name, false);
398     }
399
400     /**
401      * Internal removeNamedItemNS method allowing to specify whether an
402      * exception must be thrown if the specified local name and namespace URI
403      * is not found.
404      */

405     final protected Node JavaDoc internalRemoveNamedItemNS(String JavaDoc namespaceURI,
406                                                    String JavaDoc name,
407                                                    boolean raiseEx) {
408         if (isReadOnly()) {
409             throw
410                 new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR,
411                                      "DOM001 Modification not allowed");
412         }
413         int i = findNamePoint(namespaceURI, name);
414         if (i < 0) {
415             if (raiseEx) {
416                 throw new DOMException JavaDoc(DOMException.NOT_FOUND_ERR,
417                                            "DOM008 Not found");
418             } else {
419                 return null;
420             }
421         }
422
423         LCount lc=null;
424         String JavaDoc oldvalue="";
425         AttrImpl enclosingAttribute=null;
426         if (NodeImpl.MUTATIONEVENTS
427             && ownerNode.ownerDocument().mutationEvents)
428         {
429             // MUTATION PREPROCESSING AND PRE-EVENTS:
430
lc=LCount.lookup(MutationEventImpl.DOM_ATTR_MODIFIED);
431             if(lc.captures+lc.bubbles+lc.defaults>0)
432             {
433                enclosingAttribute=(AttrImpl)(nodes.elementAt(i));
434                oldvalue=enclosingAttribute.getNodeValue();
435             }
436         } // End mutation preprocessing
437

438         NodeImpl n = (NodeImpl)nodes.elementAt(i);
439         // If there's a default, add it instead
440
String JavaDoc nodeName = n.getNodeName();
441         if (hasDefaults()) {
442             NamedNodeMapImpl defaults =
443                 ((ElementImpl) ownerNode).getDefaultAttributes();
444             Node JavaDoc d;
445             if (defaults != null
446                 && (d = defaults.getNamedItem(nodeName)) != null)
447                 {
448                     int j = findNamePoint(nodeName,0);
449                     if (j>=0 && findNamePoint(nodeName, j+1) < 0) {
450                         NodeImpl clone = (NodeImpl)d.cloneNode(true);
451                         clone.ownerNode = ownerNode;
452                         clone.isOwned(true);
453                         clone.isSpecified(false);
454                         nodes.setElementAt(clone, i);
455                     } else {
456                         nodes.removeElementAt(i);
457                     }
458                 } else {
459                     nodes.removeElementAt(i);
460                 }
461         } else {
462             nodes.removeElementAt(i);
463         }
464
465         // changed(true);
466

467         // Need to remove references to an Attr's owner before the
468
// MutationEvents fire.
469
n.ownerNode = ownerNode.ownerDocument();
470         n.isOwned(false);
471         // make sure it won't be mistaken with defaults in case it's reused
472
n.isSpecified(true);
473
474         // We can't use the standard dispatchAggregate, since it assumes
475
// that the Attr is still attached to an owner. This code is
476
// similar but dispatches to the previous owner, "element".
477
if(NodeImpl.MUTATIONEVENTS && ownerNode.ownerDocument().mutationEvents)
478         {
479             // If we have to send DOMAttrModified (determined earlier),
480
// do so.
481
if(lc.captures+lc.bubbles+lc.defaults>0) {
482                 MutationEventImpl me= new MutationEventImpl();
483                 me.initMutationEvent(MutationEventImpl.DOM_ATTR_MODIFIED,
484                                      true, false, null, n.getNodeValue(),
485                      null, name, MutationEvent.REMOVAL);
486                 ownerNode.dispatchEvent(me);
487             }
488
489             // We can hand off to process DOMSubtreeModified, though.
490
// Note that only the Element needs to be informed; the
491
// Attr's subtree has not been changed by this operation.
492
ownerNode.dispatchAggregateEvents(null,null,(short)0);
493         }
494         return n;
495
496     } // removeNamedItem(String):Node
497

498     //
499
// Public methods
500
//
501

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

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

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

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

537
538     /**
539      * Get this AttributeMap in sync with the given "defaults" map.
540      * @param defaults The default attributes map to sync with.
541      */

542     protected void reconcileDefaults(NamedNodeMapImpl defaults) {
543         
544         // remove any existing default
545
int nsize = (nodes != null) ? nodes.size() : 0;
546         for (int i = nsize - 1; i >= 0; i--) {
547             AttrImpl attr = (AttrImpl) nodes.elementAt(i);
548             if (!attr.isSpecified()) {
549                 // remove owning element
550
attr.ownerNode = ownerNode.ownerDocument();
551                 attr.isOwned(false);
552                 // make sure it won't be mistaken in case it's reused
553
attr.isSpecified(true);
554                 nodes.removeElementAt(i);
555             }
556         }
557         // add the new defaults
558
if (defaults == null) {
559             return;
560         }
561         if (nodes == null || nodes.size() == 0) {
562             cloneContent(defaults);
563         }
564         else {
565             int dsize = defaults.nodes.size();
566             for (int n = 0; n < dsize; n++) {
567                 AttrImpl d = (AttrImpl) defaults.nodes.elementAt(n);
568                 int i = findNamePoint(d.getNodeName(), 0);
569                 if (i < 0) {
570                     NodeImpl clone = (NodeImpl) d.cloneNode(true);
571                     clone.ownerNode = ownerNode;
572                     clone.isOwned(true);
573                     clone.isSpecified(false);
574                     nodes.setElementAt(clone, i);
575                 }
576             }
577         }
578
579     } // reconcileDefaults()
580

581 } // class AttributeMap
582
Popular Tags