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