1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Copyright 2002-2005 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;
  22 
  23 import java.lang.reflect.Array;
  24 import java.util.AbstractList;
  25 import java.util.Iterator;
  26 import java.util.ListIterator;
  27 import java.util.NoSuchElementException;
  28 import java.util.Vector;
  29 
  30 import com.sun.org.apache.xerces.internal.impl.Constants;
  31 import com.sun.org.apache.xerces.internal.impl.xs.util.StringListImpl;
  32 import com.sun.org.apache.xerces.internal.impl.xs.util.XSNamedMap4Types;
  33 import com.sun.org.apache.xerces.internal.impl.xs.util.XSNamedMapImpl;
  34 import com.sun.org.apache.xerces.internal.impl.xs.util.XSObjectListImpl;
  35 import com.sun.org.apache.xerces.internal.util.SymbolHash;
  36 import com.sun.org.apache.xerces.internal.util.XMLSymbols;
  37 import com.sun.org.apache.xerces.internal.xs.StringList;
  38 import com.sun.org.apache.xerces.internal.xs.XSAttributeDeclaration;
  39 import com.sun.org.apache.xerces.internal.xs.XSAttributeGroupDefinition;
  40 import com.sun.org.apache.xerces.internal.xs.XSConstants;
  41 import com.sun.org.apache.xerces.internal.xs.XSElementDeclaration;
  42 import com.sun.org.apache.xerces.internal.xs.XSModel;
  43 import com.sun.org.apache.xerces.internal.xs.XSModelGroupDefinition;
  44 import com.sun.org.apache.xerces.internal.xs.XSNamedMap;
  45 import com.sun.org.apache.xerces.internal.xs.XSNamespaceItem;
  46 import com.sun.org.apache.xerces.internal.xs.XSNamespaceItemList;
  47 import com.sun.org.apache.xerces.internal.xs.XSNotationDeclaration;
  48 import com.sun.org.apache.xerces.internal.xs.XSObject;
  49 import com.sun.org.apache.xerces.internal.xs.XSObjectList;
  50 import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
  51 
  52 /**
  53  * Implements XSModel:  a read-only interface that represents an XML Schema,
  54  * which could be components from different namespaces.
  55  *
  56  * @xerces.internal
  57  *
  58  * @author Sandy Gao, IBM
  59  *
  60  * @version $Id: XSModelImpl.java,v 1.7 2010-11-01 04:39:55 joehw Exp $
  61  */
  62 public final class XSModelImpl extends AbstractList implements XSModel, XSNamespaceItemList {
  63 
  64     // the max index / the max value of XSObject type
  65     private static final short MAX_COMP_IDX = XSTypeDefinition.SIMPLE_TYPE;
  66     private static final boolean[] GLOBAL_COMP = {false,    // null
  67                                                   true,     // attribute
  68                                                   true,     // element
  69                                                   true,     // type
  70                                                   false,    // attribute use
  71                                                   true,     // attribute group
  72                                                   true,     // group
  73                                                   false,    // model group
  74                                                   false,    // particle
  75                                                   false,    // wildcard
  76                                                   false,    // idc
  77                                                   true,     // notation
  78                                                   false,    // annotation
  79                                                   false,    // facet
  80                                                   false,    // multi value facet
  81                                                   true,     // complex type
  82                                                   true      // simple type
  83                                                  };
  84 
  85     // number of grammars/namespaces stored here
  86     private final int fGrammarCount;
  87     // all target namespaces
  88     private final String[] fNamespaces;
  89     // all schema grammar objects (for each namespace)
  90     private final SchemaGrammar[] fGrammarList;
  91     // a map from namespace to schema grammar
  92     private final SymbolHash fGrammarMap;
  93     // a map from element declaration to its substitution group
  94     private final SymbolHash fSubGroupMap;
  95 
  96     // store a certain kind of components from all namespaces
  97     private final XSNamedMap[] fGlobalComponents;
  98     // store a certain kind of components from one namespace
  99     private final XSNamedMap[][] fNSComponents;
 100 
 101     // a string list of all the target namespaces.
 102     private final StringList fNamespacesList;
 103     // store all annotations
 104     private XSObjectList fAnnotations = null;
 105 
 106     // whether there is any IDC in this XSModel
 107     private final boolean fHasIDC;
 108 
 109    /**
 110     * Construct an XSModelImpl, by storing some grammars and grammars imported
 111     * by them to this object.
 112     *
 113     * @param grammars   the array of schema grammars
 114     */
 115     public XSModelImpl(SchemaGrammar[] grammars) {
 116         this(grammars, Constants.SCHEMA_VERSION_1_0);
 117     }
 118 
 119     public XSModelImpl(SchemaGrammar[] grammars, short s4sVersion) {
 120         // copy namespaces/grammars from the array to our arrays
 121         int len = grammars.length;
 122         final int initialSize = Math.max(len+1, 5);
 123         String[] namespaces = new String[initialSize];
 124         SchemaGrammar[] grammarList = new SchemaGrammar[initialSize];
 125         boolean hasS4S = false;
 126         for (int i = 0; i < len; i++) {
 127             final SchemaGrammar sg = grammars[i];
 128             final String tns = sg.getTargetNamespace();
 129             namespaces[i] = tns;
 130             grammarList[i] = sg;
 131             if (tns == SchemaSymbols.URI_SCHEMAFORSCHEMA) {
 132                 hasS4S = true;
 133             }
 134         }
 135         // If a schema for the schema namespace isn't included, include it here.
 136         if (!hasS4S) {
 137             namespaces[len] = SchemaSymbols.URI_SCHEMAFORSCHEMA;
 138             grammarList[len++] = SchemaGrammar.getS4SGrammar(s4sVersion);
 139         }
 140 
 141         SchemaGrammar sg1, sg2;
 142         Vector gs;
 143         int i, j, k;
 144         // and recursively get all imported grammars, add them to our arrays
 145         for (i = 0; i < len; i++) {
 146             // get the grammar
 147             sg1 = grammarList[i];
 148             gs = sg1.getImportedGrammars();
 149             // for each imported grammar
 150             for (j = gs == null ? -1 : gs.size() - 1; j >= 0; j--) {
 151                 sg2 = (SchemaGrammar)gs.elementAt(j);
 152                 // check whether this grammar is already in the list
 153                 for (k = 0; k < len; k++) {
 154                     if (sg2 == grammarList[k]) {
 155                         break;
 156                     }
 157                 }
 158                 // if it's not, add it to the list
 159                 if (k == len) {
 160                     // ensure the capacity of the arrays
 161                     if (len == grammarList.length) {
 162                         String[] newSA = new String[len*2];
 163                         System.arraycopy(namespaces, 0, newSA, 0, len);
 164                         namespaces = newSA;
 165                         SchemaGrammar[] newGA = new SchemaGrammar[len*2];
 166                         System.arraycopy(grammarList, 0, newGA, 0, len);
 167                         grammarList = newGA;
 168                     }
 169                     namespaces[len] = sg2.getTargetNamespace();
 170                     grammarList[len] = sg2;
 171                     len++;
 172                 }
 173             }
 174         }
 175 
 176         fNamespaces = namespaces;
 177         fGrammarList = grammarList;
 178 
 179         boolean hasIDC = false;
 180         // establish the mapping from namespace to grammars
 181         fGrammarMap = new SymbolHash(len*2);
 182         for (i = 0; i < len; i++) {
 183             fGrammarMap.put(null2EmptyString(fNamespaces[i]), fGrammarList[i]);
 184             // update the idc field
 185             if (fGrammarList[i].hasIDConstraints()) {
 186                 hasIDC = true;
 187             }
 188         }
 189 
 190         fHasIDC = hasIDC;
 191         fGrammarCount = len;
 192         fGlobalComponents = new XSNamedMap[MAX_COMP_IDX+1];
 193         fNSComponents = new XSNamedMap[len][MAX_COMP_IDX+1];
 194         fNamespacesList = new StringListImpl(fNamespaces, fGrammarCount);
 195 
 196         // build substitution groups
 197         fSubGroupMap = buildSubGroups();
 198     }
 199 
 200     private SymbolHash buildSubGroups_Org() {
 201         SubstitutionGroupHandler sgHandler = new SubstitutionGroupHandler(null);
 202         for (int i = 0 ; i < fGrammarCount; i++) {
 203             sgHandler.addSubstitutionGroup(fGrammarList[i].getSubstitutionGroups());
 204         }
 205 
 206         final XSNamedMap elements = getComponents(XSConstants.ELEMENT_DECLARATION);
 207         final int len = elements.getLength();
 208         final SymbolHash subGroupMap = new SymbolHash(len*2);
 209         XSElementDecl head;
 210         XSElementDeclaration[] subGroup;
 211         for (int i = 0; i < len; i++) {
 212             head = (XSElementDecl)elements.item(i);
 213             subGroup = sgHandler.getSubstitutionGroup(head);
 214             subGroupMap.put(head, subGroup.length > 0 ?
 215                     new XSObjectListImpl(subGroup, subGroup.length) : XSObjectListImpl.EMPTY_LIST);
 216         }
 217         return subGroupMap;
 218     }
 219 
 220     private SymbolHash buildSubGroups() {
 221         SubstitutionGroupHandler sgHandler = new SubstitutionGroupHandler(null);
 222         for (int i = 0 ; i < fGrammarCount; i++) {
 223             sgHandler.addSubstitutionGroup(fGrammarList[i].getSubstitutionGroups());
 224         }
 225 
 226         final XSObjectListImpl elements = getGlobalElements();
 227         final int len = elements.getLength();
 228         final SymbolHash subGroupMap = new SymbolHash(len*2);
 229         XSElementDecl head;
 230         XSElementDeclaration[] subGroup;
 231         for (int i = 0; i < len; i++) {
 232             head = (XSElementDecl)elements.item(i);
 233             subGroup = sgHandler.getSubstitutionGroup(head);
 234             subGroupMap.put(head, subGroup.length > 0 ?
 235                     new XSObjectListImpl(subGroup, subGroup.length) : XSObjectListImpl.EMPTY_LIST);
 236         }
 237         return subGroupMap;
 238     }
 239 
 240     private XSObjectListImpl getGlobalElements() {
 241         final SymbolHash[] tables = new SymbolHash[fGrammarCount];
 242         int length = 0;
 243 
 244         for (int i = 0; i < fGrammarCount; i++) {
 245             tables[i] = fGrammarList[i].fAllGlobalElemDecls;
 246             length += tables[i].getLength();
 247         }
 248 
 249         if (length == 0) {
 250             return XSObjectListImpl.EMPTY_LIST;
 251         }
 252 
 253         final XSObject[] components = new XSObject[length];
 254 
 255         int start = 0;
 256         for (int i = 0; i < fGrammarCount; i++) {
 257             tables[i].getValues(components, start);
 258             start += tables[i].getLength();
 259         }
 260 
 261         return new XSObjectListImpl(components, length);
 262     }
 263 
 264     /**
 265      * Convenience method. Returns a list of all namespaces that belong to
 266      * this schema.
 267      * @return A list of all namespaces that belong to this schema or
 268      *   <code>null</code> if all components don't have a targetNamespace.
 269      */
 270     public StringList getNamespaces() {
 271         return fNamespacesList;
 272     }
 273 
 274     /**
 275      * A set of namespace schema information information items (of type
 276      * <code>XSNamespaceItem</code>), one for each namespace name which
 277      * appears as the target namespace of any schema component in the schema
 278      * used for that assessment, and one for absent if any schema component
 279      * in the schema had no target namespace. For more information see
 280      * schema information.
 281      */
 282     public XSNamespaceItemList getNamespaceItems() {
 283         return this;
 284     }
 285 
 286     /**
 287      * Returns a list of top-level components, i.e. element declarations,
 288      * attribute declarations, etc.
 289      * @param objectType The type of the declaration, i.e.
 290      *   <code>ELEMENT_DECLARATION</code>. Note that
 291      *   <code>XSTypeDefinition.SIMPLE_TYPE</code> and
 292      *   <code>XSTypeDefinition.COMPLEX_TYPE</code> can also be used as the
 293      *   <code>objectType</code> to retrieve only complex types or simple
 294      *   types, instead of all types.
 295      * @return  A list of top-level definitions of the specified type in
 296      *   <code>objectType</code> or an empty <code>XSNamedMap</code> if no
 297      *   such definitions exist.
 298      */
 299     public synchronized XSNamedMap getComponents(short objectType) {
 300         if (objectType <= 0 || objectType > MAX_COMP_IDX ||
 301             !GLOBAL_COMP[objectType]) {
 302             return XSNamedMapImpl.EMPTY_MAP;
 303         }
 304 
 305         SymbolHash[] tables = new SymbolHash[fGrammarCount];
 306         // get all hashtables from all namespaces for this type of components
 307         if (fGlobalComponents[objectType] == null) {
 308             for (int i = 0; i < fGrammarCount; i++) {
 309                 switch (objectType) {
 310                 case XSConstants.TYPE_DEFINITION:
 311                 case XSTypeDefinition.COMPLEX_TYPE:
 312                 case XSTypeDefinition.SIMPLE_TYPE:
 313                     tables[i] = fGrammarList[i].fGlobalTypeDecls;
 314                     break;
 315                 case XSConstants.ATTRIBUTE_DECLARATION:
 316                     tables[i] = fGrammarList[i].fGlobalAttrDecls;
 317                     break;
 318                 case XSConstants.ELEMENT_DECLARATION:
 319                     tables[i] = fGrammarList[i].fGlobalElemDecls;
 320                     break;
 321                 case XSConstants.ATTRIBUTE_GROUP:
 322                     tables[i] = fGrammarList[i].fGlobalAttrGrpDecls;
 323                     break;
 324                 case XSConstants.MODEL_GROUP_DEFINITION:
 325                     tables[i] = fGrammarList[i].fGlobalGroupDecls;
 326                     break;
 327                 case XSConstants.NOTATION_DECLARATION:
 328                     tables[i] = fGrammarList[i].fGlobalNotationDecls;
 329                     break;
 330                 }
 331             }
 332             // for complex/simple types, create a special implementation,
 333             // which take specific types out of the hash table
 334             if (objectType == XSTypeDefinition.COMPLEX_TYPE ||
 335                 objectType == XSTypeDefinition.SIMPLE_TYPE) {
 336                 fGlobalComponents[objectType] = new XSNamedMap4Types(fNamespaces, tables, fGrammarCount, objectType);
 337             }
 338             else {
 339                 fGlobalComponents[objectType] = new XSNamedMapImpl(fNamespaces, tables, fGrammarCount);
 340             }
 341         }
 342 
 343         return fGlobalComponents[objectType];
 344     }
 345 
 346     /**
 347      * Convenience method. Returns a list of top-level component declarations
 348      * that are defined within the specified namespace, i.e. element
 349      * declarations, attribute declarations, etc.
 350      * @param objectType The type of the declaration, i.e.
 351      *   <code>ELEMENT_DECLARATION</code>.
 352      * @param namespace The namespace to which the declaration belongs or
 353      *   <code>null</code> (for components with no target namespace).
 354      * @return  A list of top-level definitions of the specified type in
 355      *   <code>objectType</code> and defined in the specified
 356      *   <code>namespace</code> or an empty <code>XSNamedMap</code>.
 357      */
 358     public synchronized XSNamedMap getComponentsByNamespace(short objectType,
 359                                                             String namespace) {
 360         if (objectType <= 0 || objectType > MAX_COMP_IDX ||
 361             !GLOBAL_COMP[objectType]) {
 362             return XSNamedMapImpl.EMPTY_MAP;
 363         }
 364 
 365         // try to find the grammar
 366         int i = 0;
 367         if (namespace != null) {
 368             for (; i < fGrammarCount; ++i) {
 369                 if (namespace.equals(fNamespaces[i])) {
 370                     break;
 371                 }
 372             }
 373         }
 374         else {
 375             for (; i < fGrammarCount; ++i) {
 376                 if (fNamespaces[i] == null) {
 377                     break;
 378                 }
 379             }
 380         }
 381         if (i == fGrammarCount) {
 382             return XSNamedMapImpl.EMPTY_MAP;
 383         }
 384 
 385         // get the hashtable for this type of components
 386         if (fNSComponents[i][objectType] == null) {
 387             SymbolHash table = null;
 388             switch (objectType) {
 389             case XSConstants.TYPE_DEFINITION:
 390             case XSTypeDefinition.COMPLEX_TYPE:
 391             case XSTypeDefinition.SIMPLE_TYPE:
 392                 table = fGrammarList[i].fGlobalTypeDecls;
 393                 break;
 394             case XSConstants.ATTRIBUTE_DECLARATION:
 395                 table = fGrammarList[i].fGlobalAttrDecls;
 396                 break;
 397             case XSConstants.ELEMENT_DECLARATION:
 398                 table = fGrammarList[i].fGlobalElemDecls;
 399                 break;
 400             case XSConstants.ATTRIBUTE_GROUP:
 401                 table = fGrammarList[i].fGlobalAttrGrpDecls;
 402                 break;
 403             case XSConstants.MODEL_GROUP_DEFINITION:
 404                 table = fGrammarList[i].fGlobalGroupDecls;
 405                 break;
 406             case XSConstants.NOTATION_DECLARATION:
 407                 table = fGrammarList[i].fGlobalNotationDecls;
 408                 break;
 409             }
 410 
 411             // for complex/simple types, create a special implementation,
 412             // which take specific types out of the hash table
 413             if (objectType == XSTypeDefinition.COMPLEX_TYPE ||
 414                 objectType == XSTypeDefinition.SIMPLE_TYPE) {
 415                 fNSComponents[i][objectType] = new XSNamedMap4Types(namespace, table, objectType);
 416             }
 417             else {
 418                 fNSComponents[i][objectType] = new XSNamedMapImpl(namespace, table);
 419             }
 420         }
 421 
 422         return fNSComponents[i][objectType];
 423     }
 424 
 425     /**
 426      * Convenience method. Returns a top-level simple or complex type
 427      * definition.
 428      * @param name The name of the definition.
 429      * @param namespace The namespace of the definition, otherwise null.
 430      * @return An <code>XSTypeDefinition</code> or null if such definition
 431      *   does not exist.
 432      */
 433     public XSTypeDefinition getTypeDefinition(String name,
 434                                               String namespace) {
 435         SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
 436         if (sg == null) {
 437             return null;
 438         }
 439         return (XSTypeDefinition)sg.fGlobalTypeDecls.get(name);
 440     }
 441 
 442     /**
 443      * Convenience method. Returns a top-level simple or complex type
 444      * definition.
 445      * @param name The name of the definition.
 446      * @param namespace The namespace of the definition, otherwise null.
 447      * @param loc The schema location where the component was defined
 448      * @return An <code>XSTypeDefinition</code> or null if such definition
 449      *   does not exist.
 450      */
 451     public XSTypeDefinition getTypeDefinition(String name,
 452                                               String namespace,
 453                                               String loc) {
 454         SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
 455         if (sg == null) {
 456             return null;
 457         }
 458         return sg.getGlobalTypeDecl(name, loc);
 459     }
 460 
 461     /**
 462      * Convenience method. Returns a top-level attribute declaration.
 463      * @param name The name of the declaration.
 464      * @param namespace The namespace of the definition, otherwise null.
 465      * @return A top-level attribute declaration or null if such declaration
 466      *   does not exist.
 467      */
 468     public XSAttributeDeclaration getAttributeDeclaration(String name,
 469                                                    String namespace) {
 470         SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
 471         if (sg == null) {
 472             return null;
 473         }
 474         return (XSAttributeDeclaration)sg.fGlobalAttrDecls.get(name);
 475     }
 476 
 477     /**
 478      * Convenience method. Returns a top-level attribute declaration.
 479      * @param name The name of the declaration.
 480      * @param namespace The namespace of the definition, otherwise null.
 481      * @param loc The schema location where the component was defined
 482      * @return A top-level attribute declaration or null if such declaration
 483      *   does not exist.
 484      */
 485     public XSAttributeDeclaration getAttributeDeclaration(String name,
 486                                                    String namespace,
 487                                                    String loc) {
 488         SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
 489         if (sg == null) {
 490             return null;
 491         }
 492         return sg.getGlobalAttributeDecl(name, loc);
 493     }
 494 
 495     /**
 496      * Convenience method. Returns a top-level element declaration.
 497      * @param name The name of the declaration.
 498      * @param namespace The namespace of the definition, otherwise null.
 499      * @return A top-level element declaration or null if such declaration
 500      *   does not exist.
 501      */
 502     public XSElementDeclaration getElementDeclaration(String name,
 503                                                String namespace) {
 504         SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
 505         if (sg == null) {
 506             return null;
 507         }
 508         return (XSElementDeclaration)sg.fGlobalElemDecls.get(name);
 509     }
 510 
 511     /**
 512      * Convenience method. Returns a top-level element declaration.
 513      * @param name The name of the declaration.
 514      * @param namespace The namespace of the definition, otherwise null.
 515      * @param loc The schema location where the component was defined
 516      * @return A top-level element declaration or null if such declaration
 517      *   does not exist.
 518      */
 519     public XSElementDeclaration getElementDeclaration(String name,
 520                                                String namespace,
 521                                                String loc) {
 522         SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
 523         if (sg == null) {
 524             return null;
 525         }
 526         return sg.getGlobalElementDecl(name, loc);
 527     }
 528 
 529     /**
 530      * Convenience method. Returns a top-level attribute group definition.
 531      * @param name The name of the definition.
 532      * @param namespace The namespace of the definition, otherwise null.
 533      * @return A top-level attribute group definition or null if such
 534      *   definition does not exist.
 535      */
 536     public XSAttributeGroupDefinition getAttributeGroup(String name,
 537                                                         String namespace) {
 538         SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
 539         if (sg == null) {
 540             return null;
 541         }
 542         return (XSAttributeGroupDefinition)sg.fGlobalAttrGrpDecls.get(name);
 543     }
 544 
 545     /**
 546      * Convenience method. Returns a top-level attribute group definition.
 547      * @param name The name of the definition.
 548      * @param namespace The namespace of the definition, otherwise null.
 549      * @param loc The schema location where the component was defined
 550      * @return A top-level attribute group definition or null if such
 551      *   definition does not exist.
 552      */
 553     public XSAttributeGroupDefinition getAttributeGroup(String name,
 554                                                         String namespace,
 555                                                         String loc) {
 556         SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
 557         if (sg == null) {
 558             return null;
 559         }
 560         return sg.getGlobalAttributeGroupDecl(name, loc);
 561     }
 562 
 563     /**
 564      * Convenience method. Returns a top-level model group definition.
 565      *
 566      * @param name      The name of the definition.
 567      * @param namespace The namespace of the definition, otherwise null.
 568      * @return A top-level model group definition definition or null if such
 569      *         definition does not exist.
 570      */
 571     public XSModelGroupDefinition getModelGroupDefinition(String name,
 572                                                           String namespace) {
 573         SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
 574         if (sg == null) {
 575             return null;
 576         }
 577         return (XSModelGroupDefinition)sg.fGlobalGroupDecls.get(name);
 578     }
 579 
 580     /**
 581      * Convenience method. Returns a top-level model group definition.
 582      *
 583      * @param name      The name of the definition.
 584      * @param namespace The namespace of the definition, otherwise null.
 585      * @param loc The schema location where the component was defined
 586      * @return A top-level model group definition definition or null if such
 587      *         definition does not exist.
 588      */
 589     public XSModelGroupDefinition getModelGroupDefinition(String name,
 590                                                           String namespace,
 591                                                           String loc) {
 592         SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
 593         if (sg == null) {
 594             return null;
 595         }
 596         return sg.getGlobalGroupDecl(name, loc);
 597     }
 598 
 599 
 600     /**
 601      * @see org.apache.xerces.xs.XSModel#getNotationDeclaration(String, String)
 602      */
 603     public XSNotationDeclaration getNotationDeclaration(String name,
 604                                                  String namespace) {
 605         SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
 606         if (sg == null) {
 607             return null;
 608         }
 609         return (XSNotationDeclaration)sg.fGlobalNotationDecls.get(name);
 610     }
 611 
 612     public XSNotationDeclaration getNotationDeclaration(String name,
 613                                                  String namespace,
 614                                                  String loc) {
 615         SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
 616         if (sg == null) {
 617             return null;
 618         }
 619         return sg.getGlobalNotationDecl(name, loc);
 620     }
 621 
 622     /**
 623      *  [annotations]: a set of annotations if it exists, otherwise an empty
 624      * <code>XSObjectList</code>.
 625      */
 626     public synchronized XSObjectList getAnnotations() {
 627         if (fAnnotations != null) {
 628             return fAnnotations;
 629         }
 630 
 631         // do this in two passes to avoid inaccurate array size
 632         int totalAnnotations = 0;
 633         for (int i = 0; i < fGrammarCount; i++) {
 634             totalAnnotations += fGrammarList[i].fNumAnnotations;
 635         }
 636         if (totalAnnotations == 0) {
 637             fAnnotations = XSObjectListImpl.EMPTY_LIST;
 638             return fAnnotations;
 639         }
 640         XSAnnotationImpl [] annotations = new XSAnnotationImpl [totalAnnotations];
 641         int currPos = 0;
 642         for (int i = 0; i < fGrammarCount; i++) {
 643             SchemaGrammar currGrammar = fGrammarList[i];
 644             if (currGrammar.fNumAnnotations > 0) {
 645                 System.arraycopy(currGrammar.fAnnotations, 0, annotations, currPos, currGrammar.fNumAnnotations);
 646                 currPos += currGrammar.fNumAnnotations;
 647             }
 648         }
 649         fAnnotations = new XSObjectListImpl(annotations, annotations.length);
 650         return fAnnotations;
 651     }
 652 
 653     private static final String null2EmptyString(String str) {
 654         return str == null ? XMLSymbols.EMPTY_STRING : str;
 655     }
 656 
 657     /**
 658      * REVISIT: to expose identity constraints from XSModel.
 659      * For now, we only expose whether there are any IDCs.
 660      * We also need to add these methods to the public
 661      * XSModel interface.
 662      */
 663     public boolean hasIDConstraints() {
 664         return fHasIDC;
 665     }
 666 
 667     /**
 668      * Convenience method. Returns a list containing the members of the
 669      * substitution group for the given <code>XSElementDeclaration</code>
 670      * or an empty <code>XSObjectList</code> if the substitution group
 671      * contains no members.
 672      * @param head The substitution group head.
 673      * @return A list containing the members of the substitution group
 674      *  for the given <code>XSElementDeclaration</code> or an empty
 675      *  <code>XSObjectList</code> if the substitution group contains
 676      *  no members.
 677      */
 678     public XSObjectList getSubstitutionGroup(XSElementDeclaration head) {
 679         return (XSObjectList)fSubGroupMap.get(head);
 680     }
 681 
 682     //
 683     // XSNamespaceItemList methods
 684     //
 685 
 686     /**
 687      * The number of <code>XSNamespaceItem</code>s in the list. The range of
 688      * valid child object indices is 0 to <code>length-1</code> inclusive.
 689      */
 690     public int getLength() {
 691         return fGrammarCount;
 692     }
 693 
 694     /**
 695      * Returns the <code>index</code>th item in the collection or
 696      * <code>null</code> if <code>index</code> is greater than or equal to
 697      * the number of objects in the list. The index starts at 0.
 698      * @param index  index into the collection.
 699      * @return  The <code>XSNamespaceItem</code> at the <code>index</code>th
 700      *   position in the <code>XSNamespaceItemList</code>, or
 701      *   <code>null</code> if the index specified is not valid.
 702      */
 703     public XSNamespaceItem item(int index) {
 704         if (index < 0 || index >= fGrammarCount) {
 705             return null;
 706         }
 707         return fGrammarList[index];
 708     }
 709 
 710     //
 711     // java.util.List methods
 712     //
 713 
 714     public Object get(int index) {
 715         if (index >= 0 && index < fGrammarCount) {
 716             return fGrammarList[index];
 717         }
 718         throw new IndexOutOfBoundsException("Index: " + index);
 719     }
 720 
 721     public int size() {
 722         return getLength();
 723     }
 724 
 725     public Iterator iterator() {
 726         return listIterator0(0);
 727     }
 728 
 729     public ListIterator listIterator() {
 730         return listIterator0(0);
 731     }
 732 
 733     public ListIterator listIterator(int index) {
 734         if (index >= 0 && index < fGrammarCount) {
 735             return listIterator0(index);
 736         }
 737         throw new IndexOutOfBoundsException("Index: " + index);
 738     }
 739 
 740     private ListIterator listIterator0(int index) {
 741         return new XSNamespaceItemListIterator(index);
 742     }
 743 
 744     public Object[] toArray() {
 745         Object[] a = new Object[fGrammarCount];
 746         toArray0(a);
 747         return a;
 748     }
 749 
 750     public Object[] toArray(Object[] a) {
 751         if (a.length < fGrammarCount) {
 752             Class arrayClass = a.getClass();
 753             Class componentType = arrayClass.getComponentType();
 754             a = (Object[]) Array.newInstance(componentType, fGrammarCount);
 755         }
 756         toArray0(a);
 757         if (a.length > fGrammarCount) {
 758             a[fGrammarCount] = null;
 759         }
 760         return a;
 761     }
 762 
 763     private void toArray0(Object[] a) {
 764         if (fGrammarCount > 0) {
 765             System.arraycopy(fGrammarList, 0, a, 0, fGrammarCount);
 766         }
 767     }
 768 
 769     private final class XSNamespaceItemListIterator implements ListIterator {
 770         private int index;
 771         public XSNamespaceItemListIterator(int index) {
 772             this.index = index;
 773         }
 774         public boolean hasNext() {
 775             return (index < fGrammarCount);
 776         }
 777         public Object next() {
 778             if (index < fGrammarCount) {
 779                 return fGrammarList[index++];
 780             }
 781             throw new NoSuchElementException();
 782         }
 783         public boolean hasPrevious() {
 784             return (index > 0);
 785         }
 786         public Object previous() {
 787             if (index > 0) {
 788                 return fGrammarList[--index];
 789             }
 790             throw new NoSuchElementException();
 791         }
 792         public int nextIndex() {
 793             return index;
 794         }
 795         public int previousIndex() {
 796             return index - 1;
 797         }
 798         public void remove() {
 799             throw new UnsupportedOperationException();
 800         }
 801         public void set(Object o) {
 802             throw new UnsupportedOperationException();
 803         }
 804         public void add(Object o) {
 805             throw new UnsupportedOperationException();
 806         }
 807     }
 808 
 809 } // class XSModelImpl