View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 2002,2004 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * You may obtain a copy of the License at
11   *
12   *      http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package com.sun.org.apache.xerces.internal.impl.xs.util;
22  
23  import java.util.AbstractMap;
24  import java.util.AbstractSet;
25  import java.util.Iterator;
26  import java.util.Map;
27  import java.util.NoSuchElementException;
28  import java.util.Set;
29  
30  import javax.xml.XMLConstants;
31  import javax.xml.namespace.QName;
32  
33  import com.sun.org.apache.xerces.internal.util.SymbolHash;
34  import com.sun.org.apache.xerces.internal.xs.XSNamedMap;
35  import com.sun.org.apache.xerces.internal.xs.XSObject;
36  
37  /**
38   * Containts the map between qnames and XSObject's.
39   *
40   * @xerces.internal
41   *
42   * @author Sandy Gao, IBM
43   *
44   * @version $Id: XSNamedMapImpl.java,v 1.7 2010-11-01 04:40:06 joehw Exp $
45   */
46  public class XSNamedMapImpl extends AbstractMap implements XSNamedMap {
47  
48      /**
49       * An immutable empty map.
50       */
51      public static final XSNamedMapImpl EMPTY_MAP = new XSNamedMapImpl(new XSObject[0], 0);
52  
53      // components of these namespaces are stored in this map
54      final String[] fNamespaces;
55      // number of namespaces
56      final int fNSNum;
57      // each entry contains components in one namespace
58      final SymbolHash[] fMaps;
59      // store all components from all namespace.
60      // used when this map is accessed as a list.
61      XSObject[] fArray = null;
62      // store the number of components.
63      // used when this map is accessed as a list.
64      int fLength = -1;
65      // Set of Map.Entry<QName,XSObject> for the java.util.Map methods
66      private Set fEntrySet = null;
67  
68      /**
69       * Construct an XSNamedMap implementation for one namespace
70       *
71       * @param namespace the namespace to which the components belong
72       * @param map       the map from local names to components
73       */
74      public XSNamedMapImpl(String namespace, SymbolHash map) {
75          fNamespaces = new String[] {namespace};
76          fMaps = new SymbolHash[] {map};
77          fNSNum = 1;
78      }
79  
80      /**
81       * Construct an XSNamedMap implementation for a list of namespaces
82       *
83       * @param namespaces the namespaces to which the components belong
84       * @param maps       the maps from local names to components
85       * @param num        the number of namespaces
86       */
87      public XSNamedMapImpl(String[] namespaces, SymbolHash[] maps, int num) {
88          fNamespaces = namespaces;
89          fMaps = maps;
90          fNSNum = num;
91      }
92  
93      /**
94       * Construct an XSNamedMap implementation one namespace from an array
95       *
96       * @param array     containing all components
97       * @param length    number of components
98       */
99      public XSNamedMapImpl(XSObject[] array, int length) {
100         if (length == 0) {
101             fNamespaces = null;
102             fMaps = null;
103             fNSNum = 0;
104             fArray = array;
105             fLength = 0;
106             return;
107         }
108         // because all components are from the same target namesapce,
109         // get the namespace from the first one.
110         fNamespaces = new String[]{array[0].getNamespace()};
111         fMaps = null;
112         fNSNum = 1;
113         // copy elements to the Vector
114         fArray = array;
115         fLength = length;
116     }
117 
118     /**
119      * The number of <code>XSObjects</code> in the <code>XSObjectList</code>.
120      * The range of valid child object indices is 0 to <code>length-1</code>
121      * inclusive.
122      */
123     public synchronized int getLength() {
124         if (fLength == -1) {
125             fLength = 0;
126             for (int i = 0; i < fNSNum; i++) {
127                 fLength += fMaps[i].getLength();
128             }
129         }
130         return fLength;
131     }
132 
133     /**
134      * Retrieves an <code>XSObject</code> specified by local name and
135      * namespace URI.
136      * <br>Per XML Namespaces, applications must use the value <code>null</code> as the
137      * <code>namespace</code> parameter for methods if they wish to specify
138      * no namespace.
139      * @param namespace The namespace URI of the <code>XSObject</code> to
140      *   retrieve, or <code>null</code> if the <code>XSObject</code> has no
141      *   namespace.
142      * @param localName The local name of the <code>XSObject</code> to
143      *   retrieve.
144      * @return A <code>XSObject</code> (of any type) with the specified local
145      *   name and namespace URI, or <code>null</code> if they do not
146      *   identify any object in this map.
147      */
148     public XSObject itemByName(String namespace, String localName) {
149         for (int i = 0; i < fNSNum; i++) {
150             if (isEqual(namespace, fNamespaces[i])) {
151                 // when this map is created from SymbolHash's
152                 // get the component from SymbolHash
153                 if (fMaps != null) {
154                     return (XSObject)fMaps[i].get(localName);
155                 }
156                 // Otherwise (it's created from an array)
157                 // go through the array to find a matching name
158                 XSObject ret;
159                 for (int j = 0; j < fLength; j++) {
160                     ret = fArray[j];
161                     if (ret.getName().equals(localName)) {
162                         return ret;
163                     }
164                 }
165                 return null;
166             }
167         }
168         return null;
169     }
170 
171     /**
172      * Returns the <code>index</code>th item in the collection or
173      * <code>null</code> if <code>index</code> is greater than or equal to
174      * the number of objects in the list. The index starts at 0.
175      * @param index  index into the collection.
176      * @return  The <code>XSObject</code> at the <code>index</code>th
177      *   position in the <code>XSObjectList</code>, or <code>null</code> if
178      *   the index specified is not valid.
179      */
180     public synchronized XSObject item(int index) {
181         if (fArray == null) {
182             // calculate the total number of elements
183             getLength();
184             fArray = new XSObject[fLength];
185             int pos = 0;
186             // get components from all SymbolHashes
187             for (int i = 0; i < fNSNum; i++) {
188                 pos += fMaps[i].getValues(fArray, pos);
189             }
190         }
191         if (index < 0 || index >= fLength) {
192             return null;
193         }
194         return fArray[index];
195     }
196 
197     static boolean isEqual(String one, String two) {
198         return (one != null) ? one.equals(two) : (two == null);
199     }
200 
201     /*
202      * java.util.Map methods
203      */
204 
205     public boolean containsKey(Object key) {
206         return (get(key) != null);
207     }
208 
209     public Object get(Object key) {
210         if (key instanceof QName) {
211             final QName name = (QName) key;
212             String namespaceURI = name.getNamespaceURI();
213             if (XMLConstants.NULL_NS_URI.equals(namespaceURI)) {
214                 namespaceURI = null;
215             }
216             String localPart = name.getLocalPart();
217             return itemByName(namespaceURI, localPart);
218         }
219         return null;
220     }
221 
222     public int size() {
223         return getLength();
224     }
225 
226     public synchronized Set entrySet() {
227         // Defer creation of the entry set until it is actually needed.
228         if (fEntrySet == null) {
229             final int length = getLength();
230             final XSNamedMapEntry[] entries = new XSNamedMapEntry[length];
231             for (int i = 0; i < length; ++i) {
232                 XSObject xso = item(i);
233                 entries[i] = new XSNamedMapEntry(new QName(xso.getNamespace(), xso.getName()), xso);
234             }
235             // Create a view of this immutable map.
236             fEntrySet = new AbstractSet() {
237                 public Iterator iterator() {
238                     return new Iterator() {
239                         private int index = 0;
240                         public boolean hasNext() {
241                             return (index < length);
242                         }
243                         public Object next() {
244                             if (index < length) {
245                                 return entries[index++];
246                             }
247                             throw new NoSuchElementException();
248                         }
249                         public void remove() {
250                             throw new UnsupportedOperationException();
251                         }
252                     };
253                 }
254                 public int size() {
255                     return length;
256                 }
257             };
258         }
259         return fEntrySet;
260     }
261 
262     /** An entry in the XSNamedMap. **/
263     private static final class XSNamedMapEntry implements Map.Entry {
264         private final QName key;
265         private final XSObject value;
266         public XSNamedMapEntry(QName key, XSObject value) {
267             this.key = key;
268             this.value = value;
269         }
270         public Object getKey() {
271             return key;
272         }
273         public Object getValue() {
274             return value;
275         }
276         public Object setValue(Object value) {
277             throw new UnsupportedOperationException();
278         }
279         public boolean equals(Object o) {
280             if (o instanceof Map.Entry) {
281                 Map.Entry e = (Map.Entry) o;
282                 Object otherKey = e.getKey();
283                 Object otherValue = e.getValue();
284                 return (key == null ? otherKey == null : key.equals(otherKey)) &&
285                     (value == null ? otherValue == null : value.equals(otherValue));
286             }
287             return false;
288         }
289         public int hashCode() {
290             return (key == null ? 0 : key.hashCode())
291                 ^ (value == null ? 0 : value.hashCode());
292         }
293         public String toString() {
294             StringBuffer buffer = new StringBuffer();
295             buffer.append(String.valueOf(key));
296             buffer.append('=');
297             buffer.append(String.valueOf(value));
298             return buffer.toString();
299         }
300     }
301 
302 } // class XSNamedMapImpl