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