View Javadoc

1   /*
2    * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
3    *
4    * This software is open source.
5    * See the bottom of this file for the licence.
6    */
7   
8   package org.dom4j.util;
9   
10  import java.util.ArrayList;
11  import java.util.HashMap;
12  import java.util.Iterator;
13  import java.util.List;
14  import java.util.Map;
15  
16  import org.dom4j.Attribute;
17  import org.dom4j.Element;
18  import org.dom4j.Node;
19  import org.dom4j.QName;
20  import org.dom4j.tree.BackedList;
21  import org.dom4j.tree.DefaultElement;
22  
23  /***
24   * <p>
25   * <code>IndexedElement</code> is an implementation of {@link Element}which
26   * maintains an index of the attributes and elements it contains to optimise
27   * lookups via name.
28   * </p>
29   * 
30   * @author <a href="mailto:james.strachan@metastuff.com">James Strachan </a>
31   * @version $Revision: 1.10 $
32   */
33  public class IndexedElement extends DefaultElement {
34      /*** Lazily constructed index for elements */
35      private Map elementIndex;
36  
37      /*** Lazily constructed index for attributes */
38      private Map attributeIndex;
39  
40      public IndexedElement(String name) {
41          super(name);
42      }
43  
44      public IndexedElement(QName qname) {
45          super(qname);
46      }
47  
48      public IndexedElement(QName qname, int attributeCount) {
49          super(qname, attributeCount);
50      }
51  
52      public Attribute attribute(String name) {
53          return (Attribute) attributeIndex().get(name);
54      }
55  
56      public Attribute attribute(QName qName) {
57          return (Attribute) attributeIndex().get(qName);
58      }
59  
60      public Element element(String name) {
61          return asElement(elementIndex().get(name));
62      }
63  
64      public Element element(QName qName) {
65          return asElement(elementIndex().get(qName));
66      }
67  
68      public List elements(String name) {
69          return asElementList(elementIndex().get(name));
70      }
71  
72      public List elements(QName qName) {
73          return asElementList(elementIndex().get(qName));
74      }
75  
76      // Implementation methods
77      // -------------------------------------------------------------------------
78      protected Element asElement(Object object) {
79          if (object instanceof Element) {
80              return (Element) object;
81          } else if (object != null) {
82              List list = (List) object;
83  
84              if (list.size() >= 1) {
85                  return (Element) list.get(0);
86              }
87          }
88  
89          return null;
90      }
91  
92      protected List asElementList(Object object) {
93          if (object instanceof Element) {
94              return createSingleResultList(object);
95          } else if (object != null) {
96              List list = (List) object;
97              BackedList answer = createResultList();
98  
99              for (int i = 0, size = list.size(); i < size; i++) {
100                 answer.addLocal(list.get(i));
101             }
102 
103             return answer;
104         }
105 
106         return createEmptyList();
107     }
108 
109     /***
110      * DOCUMENT ME!
111      * 
112      * @param object
113      *            DOCUMENT ME!
114      * 
115      * @return DOCUMENT ME!
116      * 
117      * @deprecated WILL BE REMOVED IN dom4j-1.6 !!
118      */
119     protected Iterator asElementIterator(Object object) {
120         return asElementList(object).iterator();
121     }
122 
123     // #### could we override the add(Element) remove(Element methods?
124     protected void addNode(Node node) {
125         super.addNode(node);
126 
127         if ((elementIndex != null) && node instanceof Element) {
128             addToElementIndex((Element) node);
129         } else if ((attributeIndex != null) && node instanceof Attribute) {
130             addToAttributeIndex((Attribute) node);
131         }
132     }
133 
134     protected boolean removeNode(Node node) {
135         if (super.removeNode(node)) {
136             if ((elementIndex != null) && node instanceof Element) {
137                 removeFromElementIndex((Element) node);
138             } else if ((attributeIndex != null) && node instanceof Attribute) {
139                 removeFromAttributeIndex((Attribute) node);
140             }
141 
142             return true;
143         }
144 
145         return false;
146     }
147 
148     protected Map attributeIndex() {
149         if (attributeIndex == null) {
150             attributeIndex = createAttributeIndex();
151 
152             for (Iterator iter = attributeIterator(); iter.hasNext();) {
153                 addToAttributeIndex((Attribute) iter.next());
154             }
155         }
156 
157         return attributeIndex;
158     }
159 
160     protected Map elementIndex() {
161         if (elementIndex == null) {
162             elementIndex = createElementIndex();
163 
164             for (Iterator iter = elementIterator(); iter.hasNext();) {
165                 addToElementIndex((Element) iter.next());
166             }
167         }
168 
169         return elementIndex;
170     }
171 
172     /***
173      * A Factory Method to create the index for attributes
174      * 
175      * @return DOCUMENT ME!
176      */
177     protected Map createAttributeIndex() {
178         Map answer = createIndex();
179 
180         return answer;
181     }
182 
183     /***
184      * A Factory Method to create the index for elements
185      * 
186      * @return DOCUMENT ME!
187      */
188     protected Map createElementIndex() {
189         Map answer = createIndex();
190 
191         return answer;
192     }
193 
194     protected void addToElementIndex(Element element) {
195         QName qName = element.getQName();
196         String name = qName.getName();
197         addToElementIndex(qName, element);
198         addToElementIndex(name, element);
199     }
200 
201     protected void addToElementIndex(Object key, Element value) {
202         Object oldValue = elementIndex.get(key);
203 
204         if (oldValue == null) {
205             elementIndex.put(key, value);
206         } else {
207             if (oldValue instanceof List) {
208                 List list = (List) oldValue;
209                 list.add(value);
210             } else {
211                 List list = createList();
212                 list.add(oldValue);
213                 list.add(value);
214                 elementIndex.put(key, list);
215             }
216         }
217     }
218 
219     protected void removeFromElementIndex(Element element) {
220         QName qName = element.getQName();
221         String name = qName.getName();
222         removeFromElementIndex(qName, element);
223         removeFromElementIndex(name, element);
224     }
225 
226     protected void removeFromElementIndex(Object key, Element value) {
227         Object oldValue = elementIndex.get(key);
228 
229         if (oldValue instanceof List) {
230             List list = (List) oldValue;
231             list.remove(value);
232         } else {
233             elementIndex.remove(key);
234         }
235     }
236 
237     protected void addToAttributeIndex(Attribute attribute) {
238         QName qName = attribute.getQName();
239         String name = qName.getName();
240         addToAttributeIndex(qName, attribute);
241         addToAttributeIndex(name, attribute);
242     }
243 
244     protected void addToAttributeIndex(Object key, Attribute value) {
245         Object oldValue = attributeIndex.get(key);
246 
247         if (oldValue != null) {
248             attributeIndex.put(key, value);
249         }
250     }
251 
252     protected void removeFromAttributeIndex(Attribute attribute) {
253         QName qName = attribute.getQName();
254         String name = qName.getName();
255         removeFromAttributeIndex(qName, attribute);
256         removeFromAttributeIndex(name, attribute);
257     }
258 
259     protected void removeFromAttributeIndex(Object key, Attribute value) {
260         Object oldValue = attributeIndex.get(key);
261 
262         if ((oldValue != null) && oldValue.equals(value)) {
263             attributeIndex.remove(key);
264         }
265     }
266 
267     /***
268      * Factory method to return a new map implementation for indices
269      * 
270      * @return DOCUMENT ME!
271      */
272     protected Map createIndex() {
273         return new HashMap();
274     }
275 
276     /***
277      * Factory method to return a list implementation for indices
278      * 
279      * @return DOCUMENT ME!
280      */
281     protected List createList() {
282         return new ArrayList();
283     }
284 }
285 
286 /*
287  * Redistribution and use of this software and associated documentation
288  * ("Software"), with or without modification, are permitted provided that the
289  * following conditions are met:
290  * 
291  * 1. Redistributions of source code must retain copyright statements and
292  * notices. Redistributions must also contain a copy of this document.
293  * 
294  * 2. Redistributions in binary form must reproduce the above copyright notice,
295  * this list of conditions and the following disclaimer in the documentation
296  * and/or other materials provided with the distribution.
297  * 
298  * 3. The name "DOM4J" must not be used to endorse or promote products derived
299  * from this Software without prior written permission of MetaStuff, Ltd. For
300  * written permission, please contact dom4j-info@metastuff.com.
301  * 
302  * 4. Products derived from this Software may not be called "DOM4J" nor may
303  * "DOM4J" appear in their names without prior written permission of MetaStuff,
304  * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
305  * 
306  * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
307  * 
308  * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
309  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
310  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
311  * ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
312  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
313  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
314  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
315  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
316  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
317  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
318  * POSSIBILITY OF SUCH DAMAGE.
319  * 
320  * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
321  */