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 */ 45 public class XSNamedMapImpl extends AbstractMap implements XSNamedMap { 46 47 /** 48 * An immutable empty map. 49 */ 50 public static final XSNamedMapImpl EMPTY_MAP = new XSNamedMapImpl(new XSObject[0], 0); 51 52 // components of these namespaces are stored in this map 53 final String[] fNamespaces; 54 // number of namespaces 55 final int fNSNum; 56 // each entry contains components in one namespace 57 final SymbolHash[] fMaps; 58 // store all components from all namespace. 59 // used when this map is accessed as a list. 60 XSObject[] fArray = null; 61 // store the number of components. 62 // used when this map is accessed as a list. 63 int fLength = -1; 64 // Set of Map.Entry<QName,XSObject> for the java.util.Map methods 65 private Set fEntrySet = null; 66 67 /** 68 * Construct an XSNamedMap implementation for one namespace 69 * 70 * @param namespace the namespace to which the components belong 71 * @param map the map from local names to components 72 */ 73 public XSNamedMapImpl(String namespace, SymbolHash map) { 74 fNamespaces = new String[] {namespace}; 75 fMaps = new SymbolHash[] {map}; 76 fNSNum = 1; 77 } 78 79 /** 80 * Construct an XSNamedMap implementation for a list of namespaces 81 * 82 * @param namespaces the namespaces to which the components belong 83 * @param maps the maps from local names to components 84 * @param num the number of namespaces 85 */ 86 public XSNamedMapImpl(String[] namespaces, SymbolHash[] maps, int num) { 87 fNamespaces = namespaces; 88 fMaps = maps; 89 fNSNum = num; 90 } 91 92 /** 93 * Construct an XSNamedMap implementation one namespace from an array 94 * 95 * @param array containing all components 96 * @param length number of components 97 */ 98 public XSNamedMapImpl(XSObject[] array, int length) { 99 if (length == 0) { 100 fNamespaces = null; 101 fMaps = null; 102 fNSNum = 0; 103 fArray = array; 104 fLength = 0; 105 return; 106 } 107 // because all components are from the same target namesapce, 108 // get the namespace from the first one. 109 fNamespaces = new String[]{array[0].getNamespace()}; 110 fMaps = null; 111 fNSNum = 1; 112 // copy elements to the Vector 113 fArray = array; 114 fLength = length; 115 } 116 117 /** 118 * The number of <code>XSObjects</code> in the <code>XSObjectList</code>. 119 * The range of valid child object indices is 0 to <code>length-1</code> 120 * inclusive. 121 */ 122 public synchronized int getLength() { 123 if (fLength == -1) { 124 fLength = 0; 125 for (int i = 0; i < fNSNum; i++) { 126 fLength += fMaps[i].getLength(); 127 } 128 } 129 return fLength; 130 } 131 132 /** 133 * Retrieves an <code>XSObject</code> specified by local name and 134 * namespace URI. 135 * <br>Per XML Namespaces, applications must use the value <code>null</code> as the 136 * <code>namespace</code> parameter for methods if they wish to specify 137 * no namespace. 138 * @param namespace The namespace URI of the <code>XSObject</code> to 139 * retrieve, or <code>null</code> if the <code>XSObject</code> has no 140 * namespace. 141 * @param localName The local name of the <code>XSObject</code> to 142 * retrieve. 143 * @return A <code>XSObject</code> (of any type) with the specified local 144 * name and namespace URI, or <code>null</code> if they do not 145 * identify any object in this map. 146 */ 147 public XSObject itemByName(String namespace, String localName) { 148 for (int i = 0; i < fNSNum; i++) { 149 if (isEqual(namespace, fNamespaces[i])) { 150 // when this map is created from SymbolHash's 151 // get the component from SymbolHash 152 if (fMaps != null) { 153 return (XSObject)fMaps[i].get(localName); 154 } 155 // Otherwise (it's created from an array) 156 // go through the array to find a matching name 157 XSObject ret; 158 for (int j = 0; j < fLength; j++) { 159 ret = fArray[j]; 160 if (ret.getName().equals(localName)) { 161 return ret; 162 } 163 } 164 return null; 165 } 166 } 167 return null; 168 } 169 170 /** 171 * Returns the <code>index</code>th item in the collection or 172 * <code>null</code> if <code>index</code> is greater than or equal to 173 * the number of objects in the list. The index starts at 0. 174 * @param index index into the collection. 175 * @return The <code>XSObject</code> at the <code>index</code>th 176 * position in the <code>XSObjectList</code>, or <code>null</code> if 177 * the index specified is not valid. 178 */ 179 public synchronized XSObject item(int index) { 180 if (fArray == null) { 181 // calculate the total number of elements 182 getLength(); 183 fArray = new XSObject[fLength]; 184 int pos = 0; 185 // get components from all SymbolHashes 186 for (int i = 0; i < fNSNum; i++) { 187 pos += fMaps[i].getValues(fArray, pos); 188 } 189 } 190 if (index < 0 || index >= fLength) { 191 return null; 192 } 193 return fArray[index]; 194 } 195 196 static boolean isEqual(String one, String two) { 197 return (one != null) ? one.equals(two) : (two == null); 198 } 199 200 /* 201 * java.util.Map methods 202 */ 203 204 public boolean containsKey(Object key) { 205 return (get(key) != null); 206 } 207 208 public Object get(Object key) { 209 if (key instanceof QName) { 210 final QName name = (QName) key; 211 String namespaceURI = name.getNamespaceURI(); 212 if (XMLConstants.NULL_NS_URI.equals(namespaceURI)) { 213 namespaceURI = null; 214 } 215 String localPart = name.getLocalPart(); 216 return itemByName(namespaceURI, localPart); 217 } 218 return null; 219 } 220 221 public int size() { 222 return getLength(); 223 } 224 225 public synchronized Set entrySet() { 226 // Defer creation of the entry set until it is actually needed. 227 if (fEntrySet == null) { 228 final int length = getLength(); 229 final XSNamedMapEntry[] entries = new XSNamedMapEntry[length]; 230 for (int i = 0; i < length; ++i) { 231 XSObject xso = item(i); 232 entries[i] = new XSNamedMapEntry(new QName(xso.getNamespace(), xso.getName()), xso); 233 } 234 // Create a view of this immutable map. 235 fEntrySet = new AbstractSet() { 236 public Iterator iterator() { 237 return new Iterator() { 238 private int index = 0; 239 public boolean hasNext() { 240 return (index < length); 241 } 242 public Object next() { 243 if (index < length) { 244 return entries[index++]; 245 } 246 throw new NoSuchElementException(); 247 } 248 public void remove() { 249 throw new UnsupportedOperationException(); 250 } 251 }; 252 } 253 public int size() { 254 return length; 255 } 256 }; 257 } 258 return fEntrySet; 259 } 260 261 /** An entry in the XSNamedMap. **/ 262 private static final class XSNamedMapEntry implements Map.Entry { 263 private final QName key; 264 private final XSObject value; 265 public XSNamedMapEntry(QName key, XSObject value) { 266 this.key = key; 267 this.value = value; 268 } 269 public Object getKey() { 270 return key; 271 } 272 public Object getValue() { 273 return value; 274 } 275 public Object setValue(Object value) { 276 throw new UnsupportedOperationException(); 277 } 278 public boolean equals(Object o) { 279 if (o instanceof Map.Entry) { 280 Map.Entry e = (Map.Entry) o; 281 Object otherKey = e.getKey(); 282 Object otherValue = e.getValue(); 283 return (key == null ? otherKey == null : key.equals(otherKey)) && 284 (value == null ? otherValue == null : value.equals(otherValue)); 285 } 286 return false; 287 } 288 public int hashCode() { 289 return (key == null ? 0 : key.hashCode()) 290 ^ (value == null ? 0 : value.hashCode()); 291 } 292 public String toString() { 293 StringBuffer buffer = new StringBuffer(); 294 buffer.append(String.valueOf(key)); 295 buffer.append('='); 296 buffer.append(String.valueOf(value)); 297 return buffer.toString(); 298 } 299 } 300 301 } // class XSNamedMapImpl