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;
23
24import com.sun.org.apache.xerces.internal.impl.Constants;
25import com.sun.org.apache.xerces.internal.impl.xs.util.StringListImpl;
26import com.sun.org.apache.xerces.internal.impl.xs.util.XSNamedMap4Types;
27import com.sun.org.apache.xerces.internal.impl.xs.util.XSNamedMapImpl;
28import com.sun.org.apache.xerces.internal.impl.xs.util.XSObjectListImpl;
29import com.sun.org.apache.xerces.internal.util.SymbolHash;
30import com.sun.org.apache.xerces.internal.util.XMLSymbols;
31import com.sun.org.apache.xerces.internal.xs.StringList;
32import com.sun.org.apache.xerces.internal.xs.XSAttributeDeclaration;
33import com.sun.org.apache.xerces.internal.xs.XSAttributeGroupDefinition;
34import com.sun.org.apache.xerces.internal.xs.XSConstants;
35import com.sun.org.apache.xerces.internal.xs.XSElementDeclaration;
36import com.sun.org.apache.xerces.internal.xs.XSIDCDefinition;
37import com.sun.org.apache.xerces.internal.xs.XSModel;
38import com.sun.org.apache.xerces.internal.xs.XSModelGroupDefinition;
39import com.sun.org.apache.xerces.internal.xs.XSNamedMap;
40import com.sun.org.apache.xerces.internal.xs.XSNamespaceItem;
41import com.sun.org.apache.xerces.internal.xs.XSNamespaceItemList;
42import com.sun.org.apache.xerces.internal.xs.XSNotationDeclaration;
43import com.sun.org.apache.xerces.internal.xs.XSObject;
44import com.sun.org.apache.xerces.internal.xs.XSObjectList;
45import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
46import java.lang.reflect.Array;
47import java.util.AbstractList;
48import java.util.Iterator;
49import java.util.ListIterator;
50import java.util.NoSuchElementException;
51import java.util.Vector;
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 */
62public 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                                                  true,    // 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                case XSConstants.IDENTITY_CONSTRAINT:
331                    tables[i] = fGrammarList[i].fGlobalIDConstraintDecls;
332                    break;
333                }
334            }
335            // for complex/simple types, create a special implementation,
336            // which take specific types out of the hash table
337            if (objectType == XSTypeDefinition.COMPLEX_TYPE ||
338                objectType == XSTypeDefinition.SIMPLE_TYPE) {
339                fGlobalComponents[objectType] = new XSNamedMap4Types(fNamespaces, tables, fGrammarCount, objectType);
340            }
341            else {
342                fGlobalComponents[objectType] = new XSNamedMapImpl(fNamespaces, tables, fGrammarCount);
343            }
344        }
345
346        return fGlobalComponents[objectType];
347    }
348
349    /**
350     * Convenience method. Returns a list of top-level component declarations
351     * that are defined within the specified namespace, i.e. element
352     * declarations, attribute declarations, etc.
353     * @param objectType The type of the declaration, i.e.
354     *   <code>ELEMENT_DECLARATION</code>.
355     * @param namespace The namespace to which the declaration belongs or
356     *   <code>null</code> (for components with no target namespace).
357     * @return  A list of top-level definitions of the specified type in
358     *   <code>objectType</code> and defined in the specified
359     *   <code>namespace</code> or an empty <code>XSNamedMap</code>.
360     */
361    public synchronized XSNamedMap getComponentsByNamespace(short objectType,
362                                                            String namespace) {
363        if (objectType <= 0 || objectType > MAX_COMP_IDX ||
364            !GLOBAL_COMP[objectType]) {
365            return XSNamedMapImpl.EMPTY_MAP;
366        }
367
368        // try to find the grammar
369        int i = 0;
370        if (namespace != null) {
371            for (; i < fGrammarCount; ++i) {
372                if (namespace.equals(fNamespaces[i])) {
373                    break;
374                }
375            }
376        }
377        else {
378            for (; i < fGrammarCount; ++i) {
379                if (fNamespaces[i] == null) {
380                    break;
381                }
382            }
383        }
384        if (i == fGrammarCount) {
385            return XSNamedMapImpl.EMPTY_MAP;
386        }
387
388        // get the hashtable for this type of components
389        if (fNSComponents[i][objectType] == null) {
390            SymbolHash table = null;
391            switch (objectType) {
392            case XSConstants.TYPE_DEFINITION:
393            case XSTypeDefinition.COMPLEX_TYPE:
394            case XSTypeDefinition.SIMPLE_TYPE:
395                table = fGrammarList[i].fGlobalTypeDecls;
396                break;
397            case XSConstants.ATTRIBUTE_DECLARATION:
398                table = fGrammarList[i].fGlobalAttrDecls;
399                break;
400            case XSConstants.ELEMENT_DECLARATION:
401                table = fGrammarList[i].fGlobalElemDecls;
402                break;
403            case XSConstants.ATTRIBUTE_GROUP:
404                table = fGrammarList[i].fGlobalAttrGrpDecls;
405                break;
406            case XSConstants.MODEL_GROUP_DEFINITION:
407                table = fGrammarList[i].fGlobalGroupDecls;
408                break;
409            case XSConstants.NOTATION_DECLARATION:
410                table = fGrammarList[i].fGlobalNotationDecls;
411                break;
412            case XSConstants.IDENTITY_CONSTRAINT:
413                table = fGrammarList[i].fGlobalIDConstraintDecls;
414                break;
415            }
416
417            // for complex/simple types, create a special implementation,
418            // which take specific types out of the hash table
419            if (objectType == XSTypeDefinition.COMPLEX_TYPE ||
420                objectType == XSTypeDefinition.SIMPLE_TYPE) {
421                fNSComponents[i][objectType] = new XSNamedMap4Types(namespace, table, objectType);
422            }
423            else {
424                fNSComponents[i][objectType] = new XSNamedMapImpl(namespace, table);
425            }
426        }
427
428        return fNSComponents[i][objectType];
429    }
430
431    /**
432     * Convenience method. Returns a top-level simple or complex type
433     * definition.
434     * @param name The name of the definition.
435     * @param namespace The namespace of the definition, otherwise null.
436     * @return An <code>XSTypeDefinition</code> or null if such definition
437     *   does not exist.
438     */
439    public XSTypeDefinition getTypeDefinition(String name,
440                                              String namespace) {
441        SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
442        if (sg == null) {
443            return null;
444        }
445        return (XSTypeDefinition)sg.fGlobalTypeDecls.get(name);
446    }
447
448    /**
449     * Convenience method. Returns a top-level simple or complex type
450     * definition.
451     * @param name The name of the definition.
452     * @param namespace The namespace of the definition, otherwise null.
453     * @param loc The schema location where the component was defined
454     * @return An <code>XSTypeDefinition</code> or null if such definition
455     *   does not exist.
456     */
457    public XSTypeDefinition getTypeDefinition(String name,
458                                              String namespace,
459                                              String loc) {
460        SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
461        if (sg == null) {
462            return null;
463        }
464        return sg.getGlobalTypeDecl(name, loc);
465    }
466
467    /**
468     * Convenience method. Returns a top-level attribute declaration.
469     * @param name The name of the declaration.
470     * @param namespace The namespace of the definition, otherwise null.
471     * @return A top-level attribute declaration or null if such declaration
472     *   does not exist.
473     */
474    public XSAttributeDeclaration getAttributeDeclaration(String name,
475                                                   String namespace) {
476        SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
477        if (sg == null) {
478            return null;
479        }
480        return (XSAttributeDeclaration)sg.fGlobalAttrDecls.get(name);
481    }
482
483    /**
484     * Convenience method. Returns a top-level attribute declaration.
485     * @param name The name of the declaration.
486     * @param namespace The namespace of the definition, otherwise null.
487     * @param loc The schema location where the component was defined
488     * @return A top-level attribute declaration or null if such declaration
489     *   does not exist.
490     */
491    public XSAttributeDeclaration getAttributeDeclaration(String name,
492                                                   String namespace,
493                                                   String loc) {
494        SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
495        if (sg == null) {
496            return null;
497        }
498        return sg.getGlobalAttributeDecl(name, loc);
499    }
500
501    /**
502     * Convenience method. Returns a top-level element declaration.
503     * @param name The name of the declaration.
504     * @param namespace The namespace of the definition, otherwise null.
505     * @return A top-level element declaration or null if such declaration
506     *   does not exist.
507     */
508    public XSElementDeclaration getElementDeclaration(String name,
509                                               String namespace) {
510        SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
511        if (sg == null) {
512            return null;
513        }
514        return (XSElementDeclaration)sg.fGlobalElemDecls.get(name);
515    }
516
517    /**
518     * Convenience method. Returns a top-level element declaration.
519     * @param name The name of the declaration.
520     * @param namespace The namespace of the definition, otherwise null.
521     * @param loc The schema location where the component was defined
522     * @return A top-level element declaration or null if such declaration
523     *   does not exist.
524     */
525    public XSElementDeclaration getElementDeclaration(String name,
526                                               String namespace,
527                                               String loc) {
528        SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
529        if (sg == null) {
530            return null;
531        }
532        return sg.getGlobalElementDecl(name, loc);
533    }
534
535    /**
536     * Convenience method. Returns a top-level attribute group definition.
537     * @param name The name of the definition.
538     * @param namespace The namespace of the definition, otherwise null.
539     * @return A top-level attribute group definition or null if such
540     *   definition does not exist.
541     */
542    public XSAttributeGroupDefinition getAttributeGroup(String name,
543                                                        String namespace) {
544        SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
545        if (sg == null) {
546            return null;
547        }
548        return (XSAttributeGroupDefinition)sg.fGlobalAttrGrpDecls.get(name);
549    }
550
551    /**
552     * Convenience method. Returns a top-level attribute group definition.
553     * @param name The name of the definition.
554     * @param namespace The namespace of the definition, otherwise null.
555     * @param loc The schema location where the component was defined
556     * @return A top-level attribute group definition or null if such
557     *   definition does not exist.
558     */
559    public XSAttributeGroupDefinition getAttributeGroup(String name,
560                                                        String namespace,
561                                                        String loc) {
562        SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
563        if (sg == null) {
564            return null;
565        }
566        return sg.getGlobalAttributeGroupDecl(name, loc);
567    }
568
569    /**
570     * Convenience method. Returns a top-level model group definition.
571     *
572     * @param name      The name of the definition.
573     * @param namespace The namespace of the definition, otherwise null.
574     * @return A top-level model group definition definition or null if such
575     *         definition does not exist.
576     */
577    public XSModelGroupDefinition getModelGroupDefinition(String name,
578                                                          String namespace) {
579        SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
580        if (sg == null) {
581            return null;
582        }
583        return (XSModelGroupDefinition)sg.fGlobalGroupDecls.get(name);
584    }
585
586    /**
587     * Convenience method. Returns a top-level model group definition.
588     *
589     * @param name      The name of the definition.
590     * @param namespace The namespace of the definition, otherwise null.
591     * @param loc The schema location where the component was defined
592     * @return A top-level model group definition definition or null if such
593     *         definition does not exist.
594     */
595    public XSModelGroupDefinition getModelGroupDefinition(String name,
596                                                          String namespace,
597                                                          String loc) {
598        SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
599        if (sg == null) {
600            return null;
601        }
602        return sg.getGlobalGroupDecl(name, loc);
603    }
604
605    /**
606     * Convenience method. Returns a top-level model group definition.
607     *
608     * @param name      The name of the definition.
609     * @param namespace The namespace of the definition, otherwise null.
610     * @return A top-level model group definition definition or null if such
611     *         definition does not exist.
612     */
613    public XSIDCDefinition getIDCDefinition(String name, String namespace) {
614        SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
615        if (sg == null) {
616            return null;
617        }
618        return (XSIDCDefinition)sg.fGlobalIDConstraintDecls.get(name);
619    }
620
621    /**
622     * Convenience method. Returns a top-level model group definition.
623     *
624     * @param name      The name of the definition.
625     * @param namespace The namespace of the definition, otherwise null.
626     * @param loc The schema location where the component was defined
627     * @return A top-level model group definition definition or null if such
628     *         definition does not exist.
629     */
630    public XSIDCDefinition getIDCDefinition(String name, String namespace,
631                                                          String loc) {
632        SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
633        if (sg == null) {
634            return null;
635        }
636        return sg.getIDConstraintDecl(name, loc);
637    }
638
639
640    /**
641     * @see org.apache.xerces.xs.XSModel#getNotationDeclaration(String, String)
642     */
643    public XSNotationDeclaration getNotationDeclaration(String name,
644                                                 String namespace) {
645        SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
646        if (sg == null) {
647            return null;
648        }
649        return (XSNotationDeclaration)sg.fGlobalNotationDecls.get(name);
650    }
651
652    public XSNotationDeclaration getNotationDeclaration(String name,
653                                                 String namespace,
654                                                 String loc) {
655        SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace));
656        if (sg == null) {
657            return null;
658        }
659        return sg.getGlobalNotationDecl(name, loc);
660    }
661
662    /**
663     *  [annotations]: a set of annotations if it exists, otherwise an empty
664     * <code>XSObjectList</code>.
665     */
666    public synchronized XSObjectList getAnnotations() {
667        if (fAnnotations != null) {
668            return fAnnotations;
669        }
670
671        // do this in two passes to avoid inaccurate array size
672        int totalAnnotations = 0;
673        for (int i = 0; i < fGrammarCount; i++) {
674            totalAnnotations += fGrammarList[i].fNumAnnotations;
675        }
676        if (totalAnnotations == 0) {
677            fAnnotations = XSObjectListImpl.EMPTY_LIST;
678            return fAnnotations;
679        }
680        XSAnnotationImpl [] annotations = new XSAnnotationImpl [totalAnnotations];
681        int currPos = 0;
682        for (int i = 0; i < fGrammarCount; i++) {
683            SchemaGrammar currGrammar = fGrammarList[i];
684            if (currGrammar.fNumAnnotations > 0) {
685                System.arraycopy(currGrammar.fAnnotations, 0, annotations, currPos, currGrammar.fNumAnnotations);
686                currPos += currGrammar.fNumAnnotations;
687            }
688        }
689        fAnnotations = new XSObjectListImpl(annotations, annotations.length);
690        return fAnnotations;
691    }
692
693    private static final String null2EmptyString(String str) {
694        return str == null ? XMLSymbols.EMPTY_STRING : str;
695    }
696
697    /**
698     * REVISIT: to expose identity constraints from XSModel.
699     * For now, we only expose whether there are any IDCs.
700     * We also need to add these methods to the public
701     * XSModel interface.
702     */
703    public boolean hasIDConstraints() {
704        return fHasIDC;
705    }
706
707    /**
708     * Convenience method. Returns a list containing the members of the
709     * substitution group for the given <code>XSElementDeclaration</code>
710     * or an empty <code>XSObjectList</code> if the substitution group
711     * contains no members.
712     * @param head The substitution group head.
713     * @return A list containing the members of the substitution group
714     *  for the given <code>XSElementDeclaration</code> or an empty
715     *  <code>XSObjectList</code> if the substitution group contains
716     *  no members.
717     */
718    public XSObjectList getSubstitutionGroup(XSElementDeclaration head) {
719        return (XSObjectList)fSubGroupMap.get(head);
720    }
721
722    //
723    // XSNamespaceItemList methods
724    //
725
726    /**
727     * The number of <code>XSNamespaceItem</code>s in the list. The range of
728     * valid child object indices is 0 to <code>length-1</code> inclusive.
729     */
730    public int getLength() {
731        return fGrammarCount;
732    }
733
734    /**
735     * Returns the <code>index</code>th item in the collection or
736     * <code>null</code> if <code>index</code> is greater than or equal to
737     * the number of objects in the list. The index starts at 0.
738     * @param index  index into the collection.
739     * @return  The <code>XSNamespaceItem</code> at the <code>index</code>th
740     *   position in the <code>XSNamespaceItemList</code>, or
741     *   <code>null</code> if the index specified is not valid.
742     */
743    public XSNamespaceItem item(int index) {
744        if (index < 0 || index >= fGrammarCount) {
745            return null;
746        }
747        return fGrammarList[index];
748    }
749
750    //
751    // java.util.List methods
752    //
753
754    public Object get(int index) {
755        if (index >= 0 && index < fGrammarCount) {
756            return fGrammarList[index];
757        }
758        throw new IndexOutOfBoundsException("Index: " + index);
759    }
760
761    public int size() {
762        return getLength();
763    }
764
765    public Iterator iterator() {
766        return listIterator0(0);
767    }
768
769    public ListIterator listIterator() {
770        return listIterator0(0);
771    }
772
773    public ListIterator listIterator(int index) {
774        if (index >= 0 && index < fGrammarCount) {
775            return listIterator0(index);
776        }
777        throw new IndexOutOfBoundsException("Index: " + index);
778    }
779
780    private ListIterator listIterator0(int index) {
781        return new XSNamespaceItemListIterator(index);
782    }
783
784    public Object[] toArray() {
785        Object[] a = new Object[fGrammarCount];
786        toArray0(a);
787        return a;
788    }
789
790    public Object[] toArray(Object[] a) {
791        if (a.length < fGrammarCount) {
792            Class arrayClass = a.getClass();
793            Class componentType = arrayClass.getComponentType();
794            a = (Object[]) Array.newInstance(componentType, fGrammarCount);
795        }
796        toArray0(a);
797        if (a.length > fGrammarCount) {
798            a[fGrammarCount] = null;
799        }
800        return a;
801    }
802
803    private void toArray0(Object[] a) {
804        if (fGrammarCount > 0) {
805            System.arraycopy(fGrammarList, 0, a, 0, fGrammarCount);
806        }
807    }
808
809    private final class XSNamespaceItemListIterator implements ListIterator {
810        private int index;
811        public XSNamespaceItemListIterator(int index) {
812            this.index = index;
813        }
814        public boolean hasNext() {
815            return (index < fGrammarCount);
816        }
817        public Object next() {
818            if (index < fGrammarCount) {
819                return fGrammarList[index++];
820            }
821            throw new NoSuchElementException();
822        }
823        public boolean hasPrevious() {
824            return (index > 0);
825        }
826        public Object previous() {
827            if (index > 0) {
828                return fGrammarList[--index];
829            }
830            throw new NoSuchElementException();
831        }
832        public int nextIndex() {
833            return index;
834        }
835        public int previousIndex() {
836            return index - 1;
837        }
838        public void remove() {
839            throw new UnsupportedOperationException();
840        }
841        public void set(Object o) {
842            throw new UnsupportedOperationException();
843        }
844        public void add(Object o) {
845            throw new UnsupportedOperationException();
846        }
847    }
848
849} // class XSModelImpl
850