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 22package com.sun.org.apache.xerces.internal.impl.xs.util; 23 24import java.util.AbstractMap; 25import java.util.AbstractSet; 26import java.util.Iterator; 27import java.util.Map; 28import java.util.NoSuchElementException; 29import java.util.Set; 30 31import javax.xml.XMLConstants; 32import javax.xml.namespace.QName; 33 34import com.sun.org.apache.xerces.internal.util.SymbolHash; 35import com.sun.org.apache.xerces.internal.xs.XSNamedMap; 36import 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 */ 46public 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 303