~vcs-imports/xena/trunk

« back to all changes in this revision

Viewing changes to ext/src/xerces-2_9_1/src/org/apache/xerces/impl/xs/traversers/XSDHandler.java

  • Committer: matthewoliver
  • Date: 2009-12-10 03:18:07 UTC
  • Revision ID: vcs-imports@canonical.com-20091210031807-l086qguzdlljtkl9
Merged Xena Testing into Xena Stable for the Xena 5 release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
 
3
 * contributor license agreements.  See the NOTICE file distributed with
 
4
 * this work for additional information regarding copyright ownership.
 
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
 
6
 * (the "License"); you may not use this file except in compliance with
 
7
 * the License.  You may obtain a copy of the License at
 
8
 *
 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
 
10
 *
 
11
 * Unless required by applicable law or agreed to in writing, software
 
12
 * distributed under the License is distributed on an "AS IS" BASIS,
 
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
14
 * See the License for the specific language governing permissions and
 
15
 * limitations under the License.
 
16
 */
 
17
 
 
18
package org.apache.xerces.impl.xs.traversers;
 
19
 
 
20
import java.io.IOException;
 
21
import java.io.StringReader;
 
22
import java.util.ArrayList;
 
23
import java.util.Hashtable;
 
24
import java.util.Stack;
 
25
import java.util.Vector;
 
26
 
 
27
import org.apache.xerces.impl.Constants;
 
28
import org.apache.xerces.impl.XMLEntityManager;
 
29
import org.apache.xerces.impl.XMLErrorReporter;
 
30
import org.apache.xerces.impl.xs.SchemaGrammar;
 
31
import org.apache.xerces.impl.xs.SchemaNamespaceSupport;
 
32
import org.apache.xerces.impl.xs.SchemaSymbols;
 
33
import org.apache.xerces.impl.xs.XMLSchemaException;
 
34
import org.apache.xerces.impl.xs.XMLSchemaLoader;
 
35
import org.apache.xerces.impl.xs.XSComplexTypeDecl;
 
36
import org.apache.xerces.impl.xs.XSDDescription;
 
37
import org.apache.xerces.impl.xs.XSDeclarationPool;
 
38
import org.apache.xerces.impl.xs.XSElementDecl;
 
39
import org.apache.xerces.impl.xs.XSGrammarBucket;
 
40
import org.apache.xerces.impl.xs.XSGroupDecl;
 
41
import org.apache.xerces.impl.xs.XSMessageFormatter;
 
42
import org.apache.xerces.impl.xs.XSModelGroupImpl;
 
43
import org.apache.xerces.impl.xs.XSParticleDecl;
 
44
import org.apache.xerces.impl.xs.opti.ElementImpl;
 
45
import org.apache.xerces.impl.xs.opti.SchemaDOMParser;
 
46
import org.apache.xerces.impl.xs.opti.SchemaParsingConfig;
 
47
import org.apache.xerces.impl.xs.util.SimpleLocator;
 
48
 
 
49
import org.apache.xerces.util.DOMUtil;
 
50
import org.apache.xerces.parsers.SAXParser;
 
51
import org.apache.xerces.parsers.XML11Configuration;
 
52
import org.apache.xerces.util.DOMInputSource;
 
53
import org.apache.xerces.util.DefaultErrorHandler;
 
54
import org.apache.xerces.util.SAXInputSource;
 
55
import org.apache.xerces.util.SymbolTable;
 
56
import org.apache.xerces.util.XMLSymbols;
 
57
import org.apache.xerces.util.URI.MalformedURIException;
 
58
import org.apache.xerces.xni.QName;
 
59
import org.apache.xerces.xni.grammars.Grammar;
 
60
import org.apache.xerces.xni.grammars.XMLGrammarDescription;
 
61
import org.apache.xerces.xni.grammars.XMLGrammarPool;
 
62
import org.apache.xerces.xni.grammars.XMLSchemaDescription;
 
63
import org.apache.xerces.xni.parser.XMLComponentManager;
 
64
import org.apache.xerces.xni.parser.XMLConfigurationException;
 
65
import org.apache.xerces.xni.parser.XMLEntityResolver;
 
66
import org.apache.xerces.xni.parser.XMLErrorHandler;
 
67
import org.apache.xerces.xni.parser.XMLInputSource;
 
68
import org.apache.xerces.xs.XSObject;
 
69
import org.apache.xerces.xs.XSParticle;
 
70
import org.w3c.dom.Document;
 
71
import org.w3c.dom.Element;
 
72
import org.w3c.dom.Node;
 
73
import org.xml.sax.InputSource;
 
74
import org.xml.sax.SAXException;
 
75
import org.xml.sax.XMLReader;
 
76
import org.xml.sax.helpers.XMLReaderFactory;
 
77
 
 
78
 
 
79
/**
 
80
 * The purpose of this class is to co-ordinate the construction of a
 
81
 * grammar object corresponding to a schema.  To do this, it must be
 
82
 * prepared to parse several schema documents (for instance if the
 
83
 * schema document originally referred to contains <include> or
 
84
 * <redefined> information items).  If any of the schemas imports a
 
85
 * schema, other grammars may be constructed as a side-effect.
 
86
 *
 
87
 * @xerces.internal 
 
88
 *
 
89
 * @author Neil Graham, IBM
 
90
 * @author Pavani Mukthipudi, Sun Microsystems
 
91
 * 
 
92
 * @version $Id: XSDHandler.java,v 1.2 2009/12/10 03:18:40 matthewoliver Exp $
 
93
 */
 
94
public class XSDHandler {
 
95
    
 
96
    /** Feature identifier: validation. */
 
97
    protected static final String VALIDATION =
 
98
        Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
 
99
    
 
100
    /** feature identifier: XML Schema validation */
 
101
    protected static final String XMLSCHEMA_VALIDATION =
 
102
        Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE;
 
103
    
 
104
    /** Feature identifier:  allow java encodings */
 
105
    protected static final String ALLOW_JAVA_ENCODINGS =
 
106
        Constants.XERCES_FEATURE_PREFIX + Constants.ALLOW_JAVA_ENCODINGS_FEATURE;
 
107
    
 
108
    /** Feature identifier:  continue after fatal error */
 
109
    protected static final String CONTINUE_AFTER_FATAL_ERROR =
 
110
        Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE;
 
111
    
 
112
    /** Feature identifier:  allow java encodings */
 
113
    protected static final String STANDARD_URI_CONFORMANT_FEATURE =
 
114
        Constants.XERCES_FEATURE_PREFIX + Constants.STANDARD_URI_CONFORMANT_FEATURE;
 
115
    
 
116
    /** Feature: disallow doctype*/
 
117
    protected static final String DISALLOW_DOCTYPE =
 
118
        Constants.XERCES_FEATURE_PREFIX + Constants.DISALLOW_DOCTYPE_DECL_FEATURE;
 
119
    
 
120
    /** Feature: generate synthetic annotations */
 
121
    protected static final String GENERATE_SYNTHETIC_ANNOTATIONS = 
 
122
        Constants.XERCES_FEATURE_PREFIX + Constants.GENERATE_SYNTHETIC_ANNOTATIONS_FEATURE;
 
123
    
 
124
    /** Feature identifier: validate annotations. */
 
125
    protected static final String VALIDATE_ANNOTATIONS =
 
126
        Constants.XERCES_FEATURE_PREFIX + Constants.VALIDATE_ANNOTATIONS_FEATURE;
 
127
    
 
128
    /** Feature identifier: honour all schemaLocations */
 
129
    protected static final String HONOUR_ALL_SCHEMALOCATIONS = 
 
130
      Constants.XERCES_FEATURE_PREFIX + Constants.HONOUR_ALL_SCHEMALOCATIONS_FEATURE;
 
131
    
 
132
    /** Feature identifier: namespace prefixes. */
 
133
    private static final String NAMESPACE_PREFIXES =
 
134
        Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACE_PREFIXES_FEATURE;
 
135
    
 
136
    /** Feature identifier: string interning. */
 
137
    protected static final String STRING_INTERNING =
 
138
        Constants.SAX_FEATURE_PREFIX + Constants.STRING_INTERNING_FEATURE;
 
139
   
 
140
    /** Property identifier: error handler. */
 
141
    protected static final String ERROR_HANDLER =
 
142
        Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY;
 
143
    
 
144
    /** Property identifier: JAXP schema source. */
 
145
    protected static final String JAXP_SCHEMA_SOURCE =
 
146
        Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE;
 
147
    
 
148
    /** Property identifier: entity resolver. */
 
149
    public static final String ENTITY_RESOLVER =
 
150
        Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
 
151
    /** Property identifier: entity manager. */
 
152
    protected static final String ENTITY_MANAGER =
 
153
        Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;
 
154
    
 
155
    /** Property identifier: error reporter. */
 
156
    public static final String ERROR_REPORTER =
 
157
        Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
 
158
    
 
159
    /** Property identifier: grammar pool. */
 
160
    public static final String XMLGRAMMAR_POOL =
 
161
        Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;
 
162
    
 
163
    /** Property identifier: symbol table. */
 
164
    public static final String SYMBOL_TABLE =
 
165
        Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
 
166
    
 
167
    /** Property identifier: security manager. */
 
168
    protected static final String SECURITY_MANAGER =
 
169
        Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
 
170
    
 
171
    protected static final boolean DEBUG_NODE_POOL = false;
 
172
    
 
173
    // Data
 
174
    
 
175
    // different sorts of declarations; should make lookup and
 
176
    // traverser calling more efficient/less bulky.
 
177
    final static int ATTRIBUTE_TYPE          = 1;
 
178
    final static int ATTRIBUTEGROUP_TYPE     = 2;
 
179
    final static int ELEMENT_TYPE            = 3;
 
180
    final static int GROUP_TYPE              = 4;
 
181
    final static int IDENTITYCONSTRAINT_TYPE = 5;
 
182
    final static int NOTATION_TYPE           = 6;
 
183
    final static int TYPEDECL_TYPE           = 7;
 
184
    
 
185
    // this string gets appended to redefined names; it's purpose is to be
 
186
    // as unlikely as possible to cause collisions.
 
187
    public final static String REDEF_IDENTIFIER = "_fn3dktizrknc9pi";
 
188
    
 
189
    //
 
190
    //protected data that can be accessable by any traverser
 
191
    // stores <notation> decl
 
192
    protected Hashtable fNotationRegistry = new Hashtable();
 
193
    
 
194
    protected XSDeclarationPool fDeclPool = null;
 
195
    
 
196
    
 
197
    // These tables correspond to the symbol spaces defined in the
 
198
    // spec.
 
199
    // They are keyed with a QName (that is, String("URI,localpart) and
 
200
    // their values are nodes corresponding to the given name's decl.
 
201
    // By asking the node for its ownerDocument and looking in
 
202
    // XSDocumentInfoRegistry we can easily get the corresponding
 
203
    // XSDocumentInfo object.
 
204
    private Hashtable fUnparsedAttributeRegistry = new Hashtable();
 
205
    private Hashtable fUnparsedAttributeGroupRegistry = new Hashtable();
 
206
    private Hashtable fUnparsedElementRegistry = new Hashtable();
 
207
    private Hashtable fUnparsedGroupRegistry = new Hashtable();
 
208
    private Hashtable fUnparsedIdentityConstraintRegistry = new Hashtable();
 
209
    private Hashtable fUnparsedNotationRegistry = new Hashtable();
 
210
    private Hashtable fUnparsedTypeRegistry = new Hashtable();
 
211
    // Compensation for the above hashtables to locate XSDocumentInfo, 
 
212
    // Since we may take Schema Element directly, so can not get the
 
213
    // corresponding XSDocumentInfo object just using above hashtables.
 
214
    private Hashtable fUnparsedAttributeRegistrySub = new Hashtable();
 
215
    private Hashtable fUnparsedAttributeGroupRegistrySub = new Hashtable();
 
216
    private Hashtable fUnparsedElementRegistrySub = new Hashtable();
 
217
    private Hashtable fUnparsedGroupRegistrySub = new Hashtable();
 
218
    private Hashtable fUnparsedIdentityConstraintRegistrySub = new Hashtable();
 
219
    private Hashtable fUnparsedNotationRegistrySub = new Hashtable();
 
220
    private Hashtable fUnparsedTypeRegistrySub = new Hashtable();
 
221
    
 
222
    // this is keyed with a documentNode (or the schemaRoot nodes
 
223
    // contained in the XSDocumentInfo objects) and its value is the
 
224
    // XSDocumentInfo object corresponding to that document.
 
225
    // Basically, the function of this registry is to be a link
 
226
    // between the nodes we fetch from calls to the fUnparsed*
 
227
    // arrays and the XSDocumentInfos they live in.
 
228
    private Hashtable fXSDocumentInfoRegistry = new Hashtable();
 
229
    
 
230
    // this hashtable is keyed on by XSDocumentInfo objects.  Its values
 
231
    // are Vectors containing the XSDocumentInfo objects <include>d,
 
232
    // <import>ed or <redefine>d by the key XSDocumentInfo.
 
233
    private Hashtable fDependencyMap = new Hashtable();
 
234
    
 
235
    // this hashtable is keyed on by a target namespace.  Its values
 
236
    // are Vectors containing namespaces imported by schema documents
 
237
    // with the key target namespace.
 
238
    // if an imprted schema has absent namespace, the value "null" is stored.
 
239
    private Hashtable fImportMap = new Hashtable();
 
240
    // all namespaces that imports other namespaces
 
241
    // if the importing schema has absent namespace, empty string is stored.
 
242
    // (because the key of a hashtable can't be null.)
 
243
    private Vector fAllTNSs = new Vector();
 
244
    // stores instance document mappings between namespaces and schema hints
 
245
    private Hashtable fLocationPairs = null;
 
246
    private static final Hashtable EMPTY_TABLE = new Hashtable();
 
247
    
 
248
    // Records which nodes are hidden when the input is a DOMInputSource.
 
249
    Hashtable fHiddenNodes = null;
 
250
    
 
251
    // convenience methods
 
252
    private String null2EmptyString(String ns) {
 
253
        return ns == null ? XMLSymbols.EMPTY_STRING : ns;
 
254
    }
 
255
    private String emptyString2Null(String ns) {
 
256
        return ns == XMLSymbols.EMPTY_STRING ? null : ns;
 
257
    }
 
258
    // use Schema Element to lookup the SystemId.
 
259
    private String doc2SystemId(Element ele) {
 
260
        String documentURI = null;
 
261
        /**
 
262
         * REVISIT: Casting until DOM Level 3 interfaces are available. -- mrglavas
 
263
         */
 
264
        if(ele.getOwnerDocument() instanceof org.apache.xerces.impl.xs.opti.SchemaDOM){
 
265
            documentURI = ((org.apache.xerces.impl.xs.opti.SchemaDOM) ele.getOwnerDocument()).getDocumentURI();
 
266
        }
 
267
        return documentURI != null ? documentURI : (String) fDoc2SystemId.get(ele);
 
268
    }
 
269
    
 
270
    // This vector stores strings which are combinations of the
 
271
    // publicId and systemId of the inputSource corresponding to a
 
272
    // schema document.  This combination is used so that the user's
 
273
    // EntityResolver can provide a consistent way of identifying a
 
274
    // schema document that is included in multiple other schemas.
 
275
    private Hashtable fTraversed = new Hashtable();
 
276
    
 
277
    // this hashtable contains a mapping from Schema Element to its systemId
 
278
    // this is useful to resolve a uri relative to the referring document
 
279
    private Hashtable fDoc2SystemId = new Hashtable();
 
280
    
 
281
    // the primary XSDocumentInfo we were called to parse
 
282
    private XSDocumentInfo fRoot = null;
 
283
    
 
284
    // This hashtable's job is to act as a link between the Schema Element and its
 
285
    // XSDocumentInfo object.
 
286
    private Hashtable fDoc2XSDocumentMap = new Hashtable();
 
287
    
 
288
    // map between <redefine> elements and the XSDocumentInfo
 
289
    // objects that correspond to the documents being redefined.
 
290
    private Hashtable fRedefine2XSDMap = new Hashtable();
 
291
    
 
292
    // map between <redefine> elements and the namespace support
 
293
    private Hashtable fRedefine2NSSupport = new Hashtable();
 
294
    
 
295
    // these objects store a mapping between the names of redefining
 
296
    // groups/attributeGroups and the groups/AttributeGroups which
 
297
    // they redefine by restriction (implicitly).  It is up to the
 
298
    // Group and AttributeGroup traversers to check these restrictions for
 
299
    // validity.
 
300
    private Hashtable fRedefinedRestrictedAttributeGroupRegistry = new Hashtable();
 
301
    private Hashtable fRedefinedRestrictedGroupRegistry = new Hashtable();
 
302
    
 
303
    // a variable storing whether the last schema document
 
304
    // processed (by getSchema) was a duplicate.
 
305
    private boolean fLastSchemaWasDuplicate;
 
306
    
 
307
    // validate annotations feature
 
308
    private boolean fValidateAnnotations = false;
 
309
    
 
310
    //handle multiple import feature
 
311
    private boolean fHonourAllSchemaLocations = false;
 
312
 
 
313
    // the XMLErrorReporter
 
314
    private XMLErrorReporter fErrorReporter;
 
315
    private XMLEntityResolver fEntityResolver;
 
316
    
 
317
    // the XSAttributeChecker
 
318
    private XSAttributeChecker fAttributeChecker;
 
319
    
 
320
    // the symbol table
 
321
    private SymbolTable fSymbolTable;
 
322
    
 
323
    // the GrammarResolver
 
324
    private XSGrammarBucket fGrammarBucket;
 
325
    
 
326
    // the Grammar description
 
327
    private XSDDescription fSchemaGrammarDescription;
 
328
    
 
329
    // the Grammar Pool
 
330
    private XMLGrammarPool fGrammarPool;
 
331
    
 
332
    //************ Traversers **********
 
333
    XSDAttributeGroupTraverser fAttributeGroupTraverser;
 
334
    XSDAttributeTraverser fAttributeTraverser;
 
335
    XSDComplexTypeTraverser fComplexTypeTraverser;
 
336
    XSDElementTraverser fElementTraverser;
 
337
    XSDGroupTraverser fGroupTraverser;
 
338
    XSDKeyrefTraverser fKeyrefTraverser;
 
339
    XSDNotationTraverser fNotationTraverser;
 
340
    XSDSimpleTypeTraverser fSimpleTypeTraverser;
 
341
    XSDUniqueOrKeyTraverser fUniqueOrKeyTraverser;
 
342
    XSDWildcardTraverser fWildCardTraverser;
 
343
    
 
344
    SchemaDOMParser fSchemaParser;
 
345
    SchemaContentHandler fXSContentHandler;
 
346
    XML11Configuration fAnnotationValidator;
 
347
    XSAnnotationGrammarPool fGrammarBucketAdapter;
 
348
    
 
349
    // these data members are needed for the deferred traversal
 
350
    // of local elements.
 
351
    
 
352
    // the initial size of the array to store deferred local elements
 
353
    private static final int INIT_STACK_SIZE = 30;
 
354
    // the incremental size of the array to store deferred local elements
 
355
    private static final int INC_STACK_SIZE  = 10;
 
356
    // current position of the array (# of deferred local elements)
 
357
    private int fLocalElemStackPos = 0;
 
358
    
 
359
    private XSParticleDecl[] fParticle = new XSParticleDecl[INIT_STACK_SIZE];
 
360
    private Element[] fLocalElementDecl = new Element[INIT_STACK_SIZE];
 
361
    private XSDocumentInfo[] fLocalElementDecl_schema = new XSDocumentInfo[INIT_STACK_SIZE]; //JACK
 
362
    private int[] fAllContext = new int[INIT_STACK_SIZE];
 
363
    private XSObject[] fParent = new XSObject[INIT_STACK_SIZE];
 
364
    private String [][] fLocalElemNamespaceContext = new String [INIT_STACK_SIZE][1];
 
365
    
 
366
    // these data members are needed for the deferred traversal
 
367
    // of keyrefs.
 
368
    
 
369
    // the initial size of the array to store deferred keyrefs
 
370
    private static final int INIT_KEYREF_STACK = 2;
 
371
    // the incremental size of the array to store deferred keyrefs
 
372
    private static final int INC_KEYREF_STACK_AMOUNT = 2;
 
373
    // current position of the array (# of deferred keyrefs)
 
374
    private int fKeyrefStackPos = 0;
 
375
    
 
376
    private Element [] fKeyrefs = new Element[INIT_KEYREF_STACK];
 
377
    private XSDocumentInfo [] fKeyrefsMapXSDocumentInfo = new XSDocumentInfo[INIT_KEYREF_STACK];
 
378
    private XSElementDecl [] fKeyrefElems = new XSElementDecl [INIT_KEYREF_STACK];
 
379
    private String [][] fKeyrefNamespaceContext = new String[INIT_KEYREF_STACK][1];
 
380
    
 
381
    // Constructors
 
382
    public XSDHandler(){
 
383
        fHiddenNodes = new Hashtable();       
 
384
        fSchemaParser = new SchemaDOMParser(new SchemaParsingConfig());
 
385
    }
 
386
    
 
387
    // it should be possible to use the same XSDHandler to parse
 
388
    // multiple schema documents; this will allow one to be
 
389
    // constructed.
 
390
    public XSDHandler (XSGrammarBucket gBucket) {
 
391
        this();
 
392
        fGrammarBucket = gBucket;
 
393
        
 
394
        // Note: don't use SchemaConfiguration internally
 
395
        //       we will get stack overflaw because
 
396
        //       XMLSchemaValidator will be instantiating XSDHandler...
 
397
        fSchemaGrammarDescription = new XSDDescription();
 
398
    } // end constructor
 
399
       
 
400
    /**
 
401
     * This method initiates the parse of a schema.  It will likely be
 
402
     * called from the Validator and it will make the
 
403
     * resulting grammar available; it returns a reference to this object just
 
404
     * in case.  A reset(XMLComponentManager) must be called before this methods is called.
 
405
     * @param is
 
406
     * @param desc
 
407
     * @param locationPairs
 
408
     * @return the SchemaGrammar
 
409
     * @throws IOException
 
410
     */
 
411
    public SchemaGrammar parseSchema(XMLInputSource is, XSDDescription desc,
 
412
            Hashtable locationPairs)
 
413
    throws IOException {
 
414
        fLocationPairs = locationPairs;
 
415
        fSchemaParser.resetNodePool();   
 
416
        SchemaGrammar grammar = null;
 
417
        String schemaNamespace  = null;
 
418
        short referType = desc.getContextType();
 
419
        // if loading using JAXP schemaSource property, or using grammar caching loadGrammar
 
420
        // the desc.targetNamespace is always null.
 
421
        // Therefore we should not attempt to find out if
 
422
        // the schema is already in the bucket, since in the case we have
 
423
        // no namespace schema in the bucket, findGrammar will always return the
 
424
        // no namespace schema.
 
425
        if (referType != XSDDescription.CONTEXT_PREPARSE){
 
426
            // first try to find it in the bucket/pool, return if one is found
 
427
            if(fHonourAllSchemaLocations && referType == XSDDescription.CONTEXT_IMPORT && isExistingGrammar(desc)) {
 
428
                grammar = fGrammarBucket.getGrammar(desc.getTargetNamespace());
 
429
            }
 
430
            else {
 
431
                grammar = findGrammar(desc);
 
432
            }
 
433
            if (grammar != null)
 
434
                return grammar;
 
435
            schemaNamespace = desc.getTargetNamespace();
 
436
            // handle empty string URI as null
 
437
            if (schemaNamespace != null) {
 
438
                schemaNamespace = fSymbolTable.addSymbol(schemaNamespace);
 
439
            }
 
440
        }
 
441
        
 
442
        // before parsing a schema, need to clear registries associated with
 
443
        // parsing schemas
 
444
        prepareForParse();       
 
445
        
 
446
        Document schemaRootDoc = null;
 
447
        Element schemaRoot = null;
 
448
        // first phase:  construct trees.
 
449
        if (is instanceof DOMInputSource) {
 
450
            //clean up the field fHiddenNodes, used for DOMInputSource
 
451
            fHiddenNodes.clear();
 
452
            Node domNode = ((DOMInputSource)is).getNode();
 
453
            
 
454
            if (domNode instanceof Document) {
 
455
                schemaRootDoc = (Document)domNode;
 
456
                schemaRoot = DOMUtil.getRoot(schemaRootDoc);
 
457
            }
 
458
            else if (domNode instanceof Element) {
 
459
                schemaRoot = (Element)domNode;
 
460
            }
 
461
            else {
 
462
                return null;
 
463
            }
 
464
        } // DOMInputSource
 
465
        else if (is instanceof SAXInputSource) {
 
466
            XMLReader parser = ((SAXInputSource)is).getXMLReader();
 
467
            InputSource inputSource = ((SAXInputSource)is).getInputSource(); 
 
468
            boolean namespacePrefixes = false;
 
469
            if (parser != null) {
 
470
                try {
 
471
                    namespacePrefixes = parser.getFeature(NAMESPACE_PREFIXES);
 
472
                }
 
473
                catch (SAXException se) {}
 
474
            }
 
475
            else {
 
476
                try {
 
477
                    parser = XMLReaderFactory.createXMLReader();
 
478
                }
 
479
                // If something went wrong with the factory
 
480
                // just use our own SAX parser.
 
481
                catch (SAXException se) {
 
482
                    parser = new SAXParser();
 
483
                }
 
484
                try {
 
485
                    parser.setFeature(NAMESPACE_PREFIXES, true);
 
486
                    namespacePrefixes = true;
 
487
                }
 
488
                catch (SAXException se) {}
 
489
            }
 
490
            // If XML names and Namespace URIs are already internalized we
 
491
            // can avoid running them through the SymbolTable.
 
492
            boolean stringsInternalized = false;
 
493
            try {
 
494
                stringsInternalized = parser.getFeature(STRING_INTERNING);
 
495
            }
 
496
            catch (SAXException exc) {
 
497
                // The feature isn't recognized or getting it is not supported.
 
498
                // In either case, assume that strings are not internalized.
 
499
            }
 
500
            if (fXSContentHandler == null) {
 
501
                fXSContentHandler = new SchemaContentHandler();
 
502
            }
 
503
            fXSContentHandler.reset(fSchemaParser, fSymbolTable, 
 
504
                    namespacePrefixes, stringsInternalized);
 
505
            parser.setContentHandler(fXSContentHandler);
 
506
            parser.setErrorHandler(fErrorReporter.getSAXErrorHandler());
 
507
                try {
 
508
                parser.parse(inputSource);      
 
509
                }
 
510
                catch (SAXException se) {
 
511
                        return null;
 
512
                }
 
513
                schemaRootDoc = fXSContentHandler.getDocument();
 
514
            if (schemaRootDoc == null) {
 
515
                // something went wrong right off the hop
 
516
                return null;
 
517
            }
 
518
                schemaRoot = DOMUtil.getRoot(schemaRootDoc);          
 
519
        }            
 
520
        else {
 
521
                schemaRoot = getSchemaDocument(schemaNamespace, is,
 
522
                  referType == XSDDescription.CONTEXT_PREPARSE,
 
523
                  referType, null);
 
524
             
 
525
        }//is instanceof XMLInputSource
 
526
 
 
527
        if(schemaRoot == null){
 
528
            // something went wrong right off the hop
 
529
            return null;
 
530
        }      
 
531
        
 
532
        if ( referType == XSDDescription.CONTEXT_PREPARSE) {
 
533
                Element schemaElem = schemaRoot;
 
534
            schemaNamespace = DOMUtil.getAttrValue(schemaElem, SchemaSymbols.ATT_TARGETNAMESPACE);
 
535
            if(schemaNamespace != null && schemaNamespace.length() > 0) {
 
536
                // Since now we've discovered a namespace, we need to update xsd key
 
537
                // and store this schema in traversed schemas bucket
 
538
                schemaNamespace = fSymbolTable.addSymbol(schemaNamespace);
 
539
                desc.setTargetNamespace(schemaNamespace);
 
540
            }
 
541
            else {
 
542
                schemaNamespace = null;
 
543
            }
 
544
            grammar = findGrammar(desc);
 
545
            if (grammar != null)
 
546
                return grammar;
 
547
            String schemaId = XMLEntityManager.expandSystemId(is.getSystemId(), is.getBaseSystemId(), false);
 
548
            XSDKey key = new XSDKey(schemaId, referType, schemaNamespace);
 
549
            fTraversed.put(key, schemaRoot);
 
550
            if (schemaId != null) {
 
551
                fDoc2SystemId.put(schemaRoot, schemaId);
 
552
            }
 
553
        }
 
554
        
 
555
        // before constructing trees and traversing a schema, need to reset
 
556
        // all traversers and clear all registries
 
557
        prepareForTraverse();
 
558
        
 
559
        fRoot = constructTrees(schemaRoot, is.getSystemId(), desc);
 
560
        if (fRoot == null) {
 
561
            return null;
 
562
        }
 
563
        
 
564
        // second phase:  fill global registries.
 
565
        buildGlobalNameRegistries();
 
566
        
 
567
        // third phase:  call traversers
 
568
        ArrayList annotationInfo = fValidateAnnotations ? new ArrayList() : null;
 
569
        traverseSchemas(annotationInfo);
 
570
        
 
571
        // fourth phase: handle local element decls
 
572
        traverseLocalElements();
 
573
        
 
574
        // fifth phase:  handle Keyrefs
 
575
        resolveKeyRefs();
 
576
        
 
577
        // sixth phase:  validate attribute of non-schema namespaces
 
578
        // REVISIT: skip this for now. we really don't want to do it.
 
579
        //fAttributeChecker.checkNonSchemaAttributes(fGrammarBucket);
 
580
        
 
581
        // seventh phase:  store imported grammars
 
582
        // for all grammars with <import>s
 
583
        for (int i = fAllTNSs.size() - 1; i >= 0; i--) {
 
584
            // get its target namespace
 
585
            String tns = (String)fAllTNSs.elementAt(i);
 
586
            // get all namespaces it imports
 
587
            Vector ins = (Vector)fImportMap.get(tns);
 
588
            // get the grammar
 
589
            SchemaGrammar sg = fGrammarBucket.getGrammar(emptyString2Null(tns));
 
590
            if (sg == null)
 
591
                continue;
 
592
            SchemaGrammar isg;
 
593
            // for imported namespace
 
594
            int count = 0;
 
595
            for (int j = 0; j < ins.size(); j++) {
 
596
                // get imported grammar
 
597
                isg = fGrammarBucket.getGrammar((String)ins.elementAt(j));
 
598
                // reuse the same vector
 
599
                if (isg != null)
 
600
                    ins.setElementAt(isg, count++);
 
601
            }
 
602
            ins.setSize(count);
 
603
            // set the imported grammars
 
604
            sg.setImportedGrammars(ins);
 
605
        }
 
606
        
 
607
        /** validate annotations **/
 
608
        if (fValidateAnnotations && annotationInfo.size() > 0) {
 
609
            validateAnnotations(annotationInfo);
 
610
        }
 
611
 
 
612
        // and return.
 
613
        return fGrammarBucket.getGrammar(fRoot.fTargetNamespace);
 
614
    } // end parseSchema
 
615
    
 
616
    private void validateAnnotations(ArrayList annotationInfo) {
 
617
        if (fAnnotationValidator == null) {
 
618
            createAnnotationValidator();
 
619
        }
 
620
        final int size = annotationInfo.size();
 
621
        final XMLInputSource src = new XMLInputSource(null, null, null);
 
622
        fGrammarBucketAdapter.refreshGrammars(fGrammarBucket);
 
623
        for (int i = 0; i < size; i += 2) {
 
624
            src.setSystemId((String) annotationInfo.get(i));
 
625
            XSAnnotationInfo annotation = (XSAnnotationInfo) annotationInfo.get(i+1);
 
626
            while (annotation != null) {
 
627
                src.setCharacterStream(new StringReader(annotation.fAnnotation));
 
628
                try {
 
629
                    fAnnotationValidator.parse(src);
 
630
                }
 
631
                catch (IOException exc) {}
 
632
                annotation = annotation.next;
 
633
            }
 
634
        }
 
635
    }
 
636
    
 
637
    private void createAnnotationValidator() {
 
638
        fAnnotationValidator = new XML11Configuration();
 
639
        fGrammarBucketAdapter = new XSAnnotationGrammarPool();
 
640
        fAnnotationValidator.setFeature(VALIDATION, true);
 
641
        fAnnotationValidator.setFeature(XMLSCHEMA_VALIDATION, true);
 
642
        fAnnotationValidator.setProperty(XMLGRAMMAR_POOL, fGrammarBucketAdapter);
 
643
        /** Set error handler. **/
 
644
        XMLErrorHandler errorHandler = fErrorReporter.getErrorHandler();
 
645
        fAnnotationValidator.setProperty(ERROR_HANDLER, (errorHandler != null) ? errorHandler : new DefaultErrorHandler());
 
646
    }
 
647
 
 
648
    /**
 
649
     * Pull the grammar out of the bucket simply using
 
650
     * its TNS as a key
 
651
     */
 
652
    SchemaGrammar getGrammar(String tns) {
 
653
        return fGrammarBucket.getGrammar(tns);
 
654
    }
 
655
    
 
656
    /**
 
657
     * First try to find a grammar in the bucket, if failed, consult the
 
658
     * grammar pool. If a grammar is found in the pool, then add it (and all
 
659
     * imported ones) into the bucket.
 
660
     */
 
661
    protected SchemaGrammar findGrammar(XSDDescription desc) {
 
662
        SchemaGrammar sg = fGrammarBucket.getGrammar(desc.getTargetNamespace());
 
663
        if (sg == null) {
 
664
            if (fGrammarPool != null) {
 
665
                sg = (SchemaGrammar)fGrammarPool.retrieveGrammar(desc);
 
666
                if (sg != null) {
 
667
                    // put this grammar into the bucket, along with grammars
 
668
                    // imported by it (directly or indirectly)
 
669
                    if (!fGrammarBucket.putGrammar(sg, true)) {
 
670
                        // REVISIT: a conflict between new grammar(s) and grammars
 
671
                        // in the bucket. What to do? A warning? An exception?
 
672
                        reportSchemaWarning("GrammarConflict", null, null);
 
673
                        sg = null;
 
674
                    }
 
675
                }
 
676
            }
 
677
        }
 
678
        return sg;
 
679
    }
 
680
    
 
681
    // may wish to have setter methods for ErrorHandler,
 
682
    // EntityResolver...
 
683
    
 
684
    private static final String[][] NS_ERROR_CODES = {
 
685
            {"src-include.2.1", "src-include.2.1"},
 
686
            {"src-redefine.3.1", "src-redefine.3.1"},
 
687
            {"src-import.3.1", "src-import.3.2"},
 
688
            null,
 
689
            {"TargetNamespace.1", "TargetNamespace.2"},
 
690
            {"TargetNamespace.1", "TargetNamespace.2"},
 
691
            {"TargetNamespace.1", "TargetNamespace.2"},
 
692
            {"TargetNamespace.1", "TargetNamespace.2"}
 
693
    };
 
694
    
 
695
    private static final String[] ELE_ERROR_CODES = {
 
696
            "src-include.1", "src-redefine.2", "src-import.2", "schema_reference.4",
 
697
            "schema_reference.4", "schema_reference.4", "schema_reference.4", "schema_reference.4"
 
698
    };
 
699
    
 
700
    // This method does several things:
 
701
    // It constructs an instance of an XSDocumentInfo object using the
 
702
    // schemaRoot node.  Then, for each <include>,
 
703
    // <redefine>, and <import> children, it attempts to resolve the
 
704
    // requested schema document, initiates a DOM parse, and calls
 
705
    // itself recursively on that document's root.  It also records in
 
706
    // the DependencyMap object what XSDocumentInfo objects its XSDocumentInfo
 
707
    // depends on.
 
708
    // It also makes sure the targetNamespace of the schema it was
 
709
    // called to parse is correct.
 
710
    protected XSDocumentInfo constructTrees(Element schemaRoot, String locationHint, XSDDescription desc) {
 
711
        if (schemaRoot == null) return null;
 
712
        String callerTNS = desc.getTargetNamespace();
 
713
        short referType = desc.getContextType();
 
714
        
 
715
        XSDocumentInfo currSchemaInfo = null;
 
716
        try {
 
717
            // note that attributes are freed at end of traverseSchemas()
 
718
            currSchemaInfo = new XSDocumentInfo(schemaRoot, fAttributeChecker, fSymbolTable);
 
719
        } catch (XMLSchemaException se) {
 
720
            reportSchemaError(ELE_ERROR_CODES[referType],
 
721
                    new Object[]{locationHint},
 
722
                                          schemaRoot);
 
723
            return null;
 
724
        }
 
725
        // targetNamespace="" is not valid, issue a warning, and ignore it
 
726
        if (currSchemaInfo.fTargetNamespace != null &&
 
727
                currSchemaInfo.fTargetNamespace.length() == 0) {
 
728
            reportSchemaWarning("EmptyTargetNamespace",
 
729
                    new Object[]{locationHint},
 
730
                                        schemaRoot);
 
731
            currSchemaInfo.fTargetNamespace = null;
 
732
        }
 
733
        
 
734
        if (callerTNS != null) {
 
735
            // the second index to the NS_ERROR_CODES array
 
736
            // if the caller/expected NS is not absent, we use the first column
 
737
            int secondIdx = 0;
 
738
            // for include and redefine
 
739
            if (referType == XSDDescription.CONTEXT_INCLUDE ||
 
740
                    referType == XSDDescription.CONTEXT_REDEFINE) {
 
741
                // if the referred document has no targetNamespace,
 
742
                // it's a chameleon schema
 
743
                if (currSchemaInfo.fTargetNamespace == null) {
 
744
                    currSchemaInfo.fTargetNamespace = callerTNS;
 
745
                    currSchemaInfo.fIsChameleonSchema = true;
 
746
                }
 
747
                // if the referred document has a target namespace differing
 
748
                // from the caller, it's an error
 
749
                else if (callerTNS != currSchemaInfo.fTargetNamespace) {
 
750
                    reportSchemaError(NS_ERROR_CODES[referType][secondIdx],
 
751
                            new Object [] {callerTNS, currSchemaInfo.fTargetNamespace},
 
752
                                                        schemaRoot);
 
753
                    return null;
 
754
                }
 
755
            }
 
756
            // for instance and import, the two NS's must be the same
 
757
            else if (referType != XSDDescription.CONTEXT_PREPARSE && callerTNS != currSchemaInfo.fTargetNamespace) {
 
758
                reportSchemaError(NS_ERROR_CODES[referType][secondIdx],
 
759
                        new Object [] {callerTNS, currSchemaInfo.fTargetNamespace},
 
760
                                                schemaRoot);
 
761
                return null;
 
762
            }
 
763
        }
 
764
        // now there is no caller/expected NS, it's an error for the referred
 
765
        // document to have a target namespace, unless we are preparsing a schema
 
766
        else if (currSchemaInfo.fTargetNamespace != null) {
 
767
            // set the target namespace of the description
 
768
            if (referType == XSDDescription.CONTEXT_PREPARSE) {
 
769
                desc.setTargetNamespace(currSchemaInfo.fTargetNamespace);
 
770
                callerTNS = currSchemaInfo.fTargetNamespace;
 
771
            }
 
772
            else {
 
773
                // the second index to the NS_ERROR_CODES array
 
774
                // if the caller/expected NS is absent, we use the second column
 
775
                int secondIdx = 1;
 
776
                reportSchemaError(NS_ERROR_CODES[referType][secondIdx],
 
777
                        new Object [] {callerTNS, currSchemaInfo.fTargetNamespace},
 
778
                                                schemaRoot);
 
779
                return null;
 
780
            }
 
781
        }
 
782
        // the other cases (callerTNS == currSchemaInfo.fTargetNamespce == null)
 
783
        // are valid
 
784
        
 
785
        // a schema document can always access it's own target namespace
 
786
        currSchemaInfo.addAllowedNS(currSchemaInfo.fTargetNamespace);
 
787
        
 
788
        SchemaGrammar sg = null;
 
789
        
 
790
        if (referType == XSDDescription.CONTEXT_INCLUDE ||
 
791
                referType == XSDDescription.CONTEXT_REDEFINE) {
 
792
            sg = fGrammarBucket.getGrammar(currSchemaInfo.fTargetNamespace);
 
793
        }
 
794
        else if(fHonourAllSchemaLocations && referType == XSDDescription.CONTEXT_IMPORT) {
 
795
            sg = findGrammar(desc);
 
796
            if(sg == null) {
 
797
                sg = new SchemaGrammar(currSchemaInfo.fTargetNamespace, desc.makeClone(), fSymbolTable);
 
798
                fGrammarBucket.putGrammar(sg);
 
799
            }
 
800
        }
 
801
        else {
 
802
            sg = new SchemaGrammar(currSchemaInfo.fTargetNamespace, desc.makeClone(), fSymbolTable);
 
803
            fGrammarBucket.putGrammar(sg);
 
804
        }
 
805
        
 
806
        // store the document and its location
 
807
        // REVISIT: don't expose the DOM tree
 
808
        sg.addDocument(null, (String)fDoc2SystemId.get(currSchemaInfo.fSchemaElement));
 
809
        
 
810
        fDoc2XSDocumentMap.put(schemaRoot, currSchemaInfo);
 
811
        Vector dependencies = new Vector();
 
812
        Element rootNode = schemaRoot;
 
813
        
 
814
        Element newSchemaRoot = null;
 
815
        for (Element child = DOMUtil.getFirstChildElement(rootNode);
 
816
        child != null;
 
817
        child = DOMUtil.getNextSiblingElement(child)) {
 
818
            String schemaNamespace=null;
 
819
            String schemaHint=null;
 
820
            String localName = DOMUtil.getLocalName(child);
 
821
            
 
822
            short refType = -1;
 
823
            
 
824
            if (localName.equals(SchemaSymbols.ELT_ANNOTATION))
 
825
                continue;
 
826
            else if (localName.equals(SchemaSymbols.ELT_IMPORT)) {
 
827
                refType = XSDDescription.CONTEXT_IMPORT;
 
828
                // have to handle some validation here too!
 
829
                // call XSAttributeChecker to fill in attrs
 
830
                Object[] importAttrs = fAttributeChecker.checkAttributes(child, true, currSchemaInfo);
 
831
                schemaHint = (String)importAttrs[XSAttributeChecker.ATTIDX_SCHEMALOCATION];
 
832
                schemaNamespace = (String)importAttrs[XSAttributeChecker.ATTIDX_NAMESPACE];
 
833
                if (schemaNamespace != null)
 
834
                    schemaNamespace = fSymbolTable.addSymbol(schemaNamespace);
 
835
                // a document can't import another document with the same namespace
 
836
                if (schemaNamespace == currSchemaInfo.fTargetNamespace) {
 
837
                    reportSchemaError(schemaNamespace != null ? 
 
838
                            "src-import.1.1" : "src-import.1.2", new Object [] {schemaNamespace}, child);
 
839
                }
 
840
                
 
841
                // check contents and process optional annotations
 
842
                Element importChild = DOMUtil.getFirstChildElement(child);
 
843
                if(importChild != null ) {
 
844
                    String importComponentType = DOMUtil.getLocalName(importChild);
 
845
                    if (importComponentType.equals(SchemaSymbols.ELT_ANNOTATION)) {
 
846
                        // promoting annotations to parent component
 
847
                        sg.addAnnotation(
 
848
                                fElementTraverser.traverseAnnotationDecl(importChild, importAttrs, true, currSchemaInfo));
 
849
                    } else {
 
850
                        reportSchemaError("s4s-elt-must-match.1", new Object [] {localName, "annotation?", importComponentType}, child);
 
851
                    }
 
852
                    if(DOMUtil.getNextSiblingElement(importChild) != null) {
 
853
                        reportSchemaError("s4s-elt-must-match.1", new Object [] {localName, "annotation?", DOMUtil.getLocalName(DOMUtil.getNextSiblingElement(importChild))}, child);
 
854
                    }
 
855
                }
 
856
                else {
 
857
                    String text = DOMUtil.getSyntheticAnnotation(child);
 
858
                    if (text != null) {
 
859
                        sg.addAnnotation(fElementTraverser.traverseSyntheticAnnotation(child, text, importAttrs, true, currSchemaInfo));
 
860
                    }
 
861
                }
 
862
                fAttributeChecker.returnAttrArray(importAttrs, currSchemaInfo);
 
863
                
 
864
                // if this namespace has not been imported by this document,
 
865
                //  then import if multiple imports support is enabled.
 
866
                if(currSchemaInfo.isAllowedNS(schemaNamespace)) {
 
867
                    if(!fHonourAllSchemaLocations)
 
868
                        continue;
 
869
                }
 
870
                else  {
 
871
                    currSchemaInfo.addAllowedNS(schemaNamespace);
 
872
                }
 
873
                // also record the fact that one namespace imports another one
 
874
                // convert null to ""
 
875
                String tns = null2EmptyString(currSchemaInfo.fTargetNamespace);
 
876
                // get all namespaces imported by this one
 
877
                Vector ins = (Vector)fImportMap.get(tns);
 
878
                // if no namespace was imported, create new Vector
 
879
                if (ins == null) {
 
880
                    // record that this one imports other(s)
 
881
                    fAllTNSs.addElement(tns);
 
882
                    ins = new Vector();
 
883
                    fImportMap.put(tns, ins);
 
884
                    ins.addElement(schemaNamespace);
 
885
                }
 
886
                else if (!ins.contains(schemaNamespace)){
 
887
                    ins.addElement(schemaNamespace);
 
888
                }
 
889
                
 
890
                fSchemaGrammarDescription.reset();
 
891
                fSchemaGrammarDescription.setContextType(XSDDescription.CONTEXT_IMPORT);
 
892
                fSchemaGrammarDescription.setBaseSystemId(doc2SystemId(schemaRoot));
 
893
                fSchemaGrammarDescription.setLocationHints(new String[]{schemaHint});
 
894
                fSchemaGrammarDescription.setTargetNamespace(schemaNamespace);
 
895
                
 
896
                // if a grammar with the same namespace and location exists (or being
 
897
                // built), ignore this one (don't traverse it).
 
898
                if ((!fHonourAllSchemaLocations && findGrammar(fSchemaGrammarDescription) != null) || isExistingGrammar(fSchemaGrammarDescription))
 
899
                    continue;
 
900
                // If "findGrammar" returns a grammar, then this is not the
 
901
                // the first time we see a location for a given namespace.
 
902
                // Don't consult the location pair hashtable in this case,
 
903
                // otherwise the location will be ignored because it'll get
 
904
                // resolved to the same location as the first hint.
 
905
                newSchemaRoot = resolveSchema(fSchemaGrammarDescription, false, child,
 
906
                                              findGrammar(fSchemaGrammarDescription) == null);
 
907
            }
 
908
            else if ((localName.equals(SchemaSymbols.ELT_INCLUDE)) ||
 
909
                    (localName.equals(SchemaSymbols.ELT_REDEFINE))) {
 
910
                // validation for redefine/include will be the same here; just
 
911
                // make sure TNS is right (don't care about redef contents
 
912
                // yet).
 
913
                Object[] includeAttrs = fAttributeChecker.checkAttributes(child, true, currSchemaInfo);
 
914
                schemaHint = (String)includeAttrs[XSAttributeChecker.ATTIDX_SCHEMALOCATION];
 
915
                // store the namespace decls of the redefine element
 
916
                if (localName.equals(SchemaSymbols.ELT_REDEFINE)) {
 
917
                    fRedefine2NSSupport.put(child, new SchemaNamespaceSupport(currSchemaInfo.fNamespaceSupport));
 
918
                }
 
919
                
 
920
                // check annotations.  Must do this here to avoid having to
 
921
                // re-parse attributes later
 
922
                if(localName.equals(SchemaSymbols.ELT_INCLUDE)) {
 
923
                    Element includeChild = DOMUtil.getFirstChildElement(child);
 
924
                    if(includeChild != null ) {
 
925
                        String includeComponentType = DOMUtil.getLocalName(includeChild);
 
926
                        if (includeComponentType.equals(SchemaSymbols.ELT_ANNOTATION)) {
 
927
                            // promoting annotations to parent component
 
928
                            sg.addAnnotation(
 
929
                                    fElementTraverser.traverseAnnotationDecl(includeChild, includeAttrs, true, currSchemaInfo));
 
930
                        } else {
 
931
                            reportSchemaError("s4s-elt-must-match.1", new Object [] {localName, "annotation?", includeComponentType}, child);
 
932
                        }
 
933
                        if(DOMUtil.getNextSiblingElement(includeChild) != null) {
 
934
                            reportSchemaError("s4s-elt-must-match.1", new Object [] {localName, "annotation?", DOMUtil.getLocalName(DOMUtil.getNextSiblingElement(includeChild))}, child);
 
935
                        }
 
936
                    }
 
937
                    else {
 
938
                        String text = DOMUtil.getSyntheticAnnotation(child);
 
939
                        if (text != null) {
 
940
                            sg.addAnnotation(fElementTraverser.traverseSyntheticAnnotation(child, text, includeAttrs, true, currSchemaInfo));
 
941
                        }
 
942
                    }
 
943
                }
 
944
                else {
 
945
                    for (Element redefinedChild = DOMUtil.getFirstChildElement(child);
 
946
                    redefinedChild != null;
 
947
                    redefinedChild = DOMUtil.getNextSiblingElement(redefinedChild)) {
 
948
                        String redefinedComponentType = DOMUtil.getLocalName(redefinedChild);
 
949
                        if (redefinedComponentType.equals(SchemaSymbols.ELT_ANNOTATION)) {
 
950
                            // promoting annotations to parent component
 
951
                            sg.addAnnotation(
 
952
                                    fElementTraverser.traverseAnnotationDecl(redefinedChild, includeAttrs, true, currSchemaInfo));
 
953
                            DOMUtil.setHidden(redefinedChild, fHiddenNodes);
 
954
                        }
 
955
                        else {
 
956
                            String text = DOMUtil.getSyntheticAnnotation(child);
 
957
                            if (text != null) {
 
958
                                sg.addAnnotation(fElementTraverser.traverseSyntheticAnnotation(child, text, includeAttrs, true, currSchemaInfo));
 
959
                            }
 
960
                        }
 
961
                        // catch all other content errors later
 
962
                    }
 
963
                }
 
964
                fAttributeChecker.returnAttrArray(includeAttrs, currSchemaInfo);
 
965
                // schemaLocation is required on <include> and <redefine>
 
966
                if (schemaHint == null) {
 
967
                    reportSchemaError("s4s-att-must-appear", new Object [] {
 
968
                            "<include> or <redefine>", "schemaLocation"},
 
969
                            child);
 
970
                }
 
971
                // pass the systemId of the current document as the base systemId
 
972
                boolean mustResolve = false;
 
973
                refType = XSDDescription.CONTEXT_INCLUDE;
 
974
                if(localName.equals(SchemaSymbols.ELT_REDEFINE)) {
 
975
                    mustResolve = nonAnnotationContent(child);
 
976
                    refType = XSDDescription.CONTEXT_REDEFINE;
 
977
                }
 
978
                fSchemaGrammarDescription.reset();
 
979
                fSchemaGrammarDescription.setContextType(refType);
 
980
                fSchemaGrammarDescription.setBaseSystemId(doc2SystemId(schemaRoot));
 
981
                fSchemaGrammarDescription.setLocationHints(new String[]{schemaHint});
 
982
                fSchemaGrammarDescription.setTargetNamespace(callerTNS);
 
983
                newSchemaRoot = resolveSchema(fSchemaGrammarDescription, mustResolve, child, true);
 
984
                schemaNamespace = currSchemaInfo.fTargetNamespace;
 
985
            }
 
986
            else {
 
987
                // no more possibility of schema references in well-formed
 
988
                // schema...
 
989
                break;
 
990
            }
 
991
            
 
992
            // If the schema is duplicate, we needn't call constructTrees() again.
 
993
            // To handle mutual <include>s
 
994
            XSDocumentInfo newSchemaInfo = null;
 
995
            if (fLastSchemaWasDuplicate) {
 
996
                newSchemaInfo = newSchemaRoot == null ? null : (XSDocumentInfo)fDoc2XSDocumentMap.get(newSchemaRoot);
 
997
            }
 
998
            else {
 
999
                newSchemaInfo = constructTrees(newSchemaRoot, schemaHint, fSchemaGrammarDescription);
 
1000
            }
 
1001
            
 
1002
            if (localName.equals(SchemaSymbols.ELT_REDEFINE) &&
 
1003
                    newSchemaInfo != null) {
 
1004
                // must record which schema we're redefining so that we can
 
1005
                // rename the right things later!
 
1006
                fRedefine2XSDMap.put(child, newSchemaInfo);
 
1007
            }
 
1008
            if (newSchemaRoot != null) {
 
1009
                if (newSchemaInfo != null)
 
1010
                    dependencies.addElement(newSchemaInfo);
 
1011
                newSchemaRoot = null;
 
1012
            }
 
1013
        }
 
1014
        
 
1015
        fDependencyMap.put(currSchemaInfo, dependencies);
 
1016
        return currSchemaInfo;
 
1017
    } // end constructTrees
 
1018
    
 
1019
    private boolean isExistingGrammar(XSDDescription desc) {
 
1020
        SchemaGrammar sg = fGrammarBucket.getGrammar(desc.getTargetNamespace());
 
1021
        if(sg == null) {
 
1022
            return findGrammar(desc) != null;
 
1023
        }
 
1024
        else {
 
1025
            try {
 
1026
                return sg.getDocumentLocations().contains(XMLEntityManager.expandSystemId(desc.getLiteralSystemId(), desc.getBaseSystemId(), false));
 
1027
            } catch (MalformedURIException e) {
 
1028
                return false;
 
1029
            }
 
1030
        }
 
1031
    }
 
1032
    
 
1033
    // This method builds registries for all globally-referenceable
 
1034
    // names.  A registry will be built for each symbol space defined
 
1035
    // by the spec.  It is also this method's job to rename redefined
 
1036
    // components, and to record which components redefine others (so
 
1037
    // that implicit redefinitions of groups and attributeGroups can be handled).
 
1038
    protected void buildGlobalNameRegistries() {
 
1039
        
 
1040
 
 
1041
        // Starting with fRoot, we examine each child of the schema
 
1042
        // element.  Skipping all imports and includes, we record the names
 
1043
        // of all other global components (and children of <redefine>).  We
 
1044
        // also put <redefine> names in a registry that we look through in
 
1045
        // case something needs renaming.  Once we're done with a schema we
 
1046
        // set its Document node to hidden so that we don't try to traverse
 
1047
        // it again; then we look to its Dependency map entry.  We keep a
 
1048
        // stack of schemas that we haven't yet finished processing; this
 
1049
        // is a depth-first traversal.
 
1050
            
 
1051
        Stack schemasToProcess = new Stack();
 
1052
        schemasToProcess.push(fRoot);
 
1053
       
 
1054
        while (!schemasToProcess.empty()) {            
 
1055
            XSDocumentInfo currSchemaDoc =
 
1056
                (XSDocumentInfo)schemasToProcess.pop();
 
1057
            Element currDoc = currSchemaDoc.fSchemaElement; 
 
1058
            if(DOMUtil.isHidden(currDoc, fHiddenNodes)){
 
1059
                // must have processed this already!
 
1060
                continue;
 
1061
            }
 
1062
 
 
1063
            Element currRoot = currDoc;
 
1064
            // process this schema's global decls
 
1065
            boolean dependenciesCanOccur = true;
 
1066
            for (Element globalComp =
 
1067
                DOMUtil.getFirstChildElement(currRoot);
 
1068
            globalComp != null;
 
1069
            globalComp = DOMUtil.getNextSiblingElement(globalComp)) {
 
1070
                // this loop makes sure the <schema> element ordering is
 
1071
                // also valid.
 
1072
                if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_ANNOTATION)) {
 
1073
                    //skip it; traverse it later
 
1074
                    continue;
 
1075
                }
 
1076
                else if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_INCLUDE) ||
 
1077
                        DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_IMPORT)) {
 
1078
                    if (!dependenciesCanOccur) {
 
1079
                        reportSchemaError("s4s-elt-invalid-content.3", new Object [] {DOMUtil.getLocalName(globalComp)}, globalComp);
 
1080
                    }
 
1081
                    DOMUtil.setHidden(globalComp, fHiddenNodes);
 
1082
                }
 
1083
                else if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_REDEFINE)) {
 
1084
                    if (!dependenciesCanOccur) {
 
1085
                        reportSchemaError("s4s-elt-invalid-content.3", new Object [] {DOMUtil.getLocalName(globalComp)}, globalComp);
 
1086
                    }
 
1087
                    for (Element redefineComp = DOMUtil.getFirstChildElement(globalComp);
 
1088
                    redefineComp != null;
 
1089
                    redefineComp = DOMUtil.getNextSiblingElement(redefineComp)) {
 
1090
                        String lName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME);
 
1091
                        if (lName.length() == 0) // an error we'll catch later
 
1092
                            continue;
 
1093
                        String qName = currSchemaDoc.fTargetNamespace == null ?
 
1094
                                ","+lName:
 
1095
                                    currSchemaDoc.fTargetNamespace +","+lName;
 
1096
                        String componentType = DOMUtil.getLocalName(redefineComp);
 
1097
                        if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
 
1098
                            checkForDuplicateNames(qName, fUnparsedAttributeGroupRegistry, fUnparsedAttributeGroupRegistrySub, redefineComp, currSchemaDoc);
 
1099
                            // the check will have changed our name;
 
1100
                            String targetLName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME)+REDEF_IDENTIFIER;
 
1101
                            // and all we need to do is error-check+rename our kkids:
 
1102
                            renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_ATTRIBUTEGROUP,
 
1103
                                    lName, targetLName);
 
1104
                        }
 
1105
                        else if ((componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) ||
 
1106
                                (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE))) {
 
1107
                            checkForDuplicateNames(qName, fUnparsedTypeRegistry, fUnparsedTypeRegistrySub, redefineComp, currSchemaDoc);
 
1108
                            // the check will have changed our name;
 
1109
                            String targetLName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME) + REDEF_IDENTIFIER;
 
1110
                            // and all we need to do is error-check+rename our kkids:
 
1111
                            if (componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) {
 
1112
                                renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_COMPLEXTYPE,
 
1113
                                        lName, targetLName);
 
1114
                            }
 
1115
                            else { // must be simpleType
 
1116
                                renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_SIMPLETYPE,
 
1117
                                        lName, targetLName);
 
1118
                            }
 
1119
                        }
 
1120
                        else if (componentType.equals(SchemaSymbols.ELT_GROUP)) {
 
1121
                            checkForDuplicateNames(qName, fUnparsedGroupRegistry, fUnparsedGroupRegistrySub, redefineComp, currSchemaDoc);
 
1122
                            // the check will have changed our name;
 
1123
                            String targetLName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME)+REDEF_IDENTIFIER;
 
1124
                            // and all we need to do is error-check+rename our kids:
 
1125
                            renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_GROUP,
 
1126
                                    lName, targetLName);
 
1127
                        }
 
1128
                    } // end march through <redefine> children
 
1129
                    // and now set as traversed
 
1130
                    //DOMUtil.setHidden(globalComp);
 
1131
                }
 
1132
                else {
 
1133
                    dependenciesCanOccur = false;
 
1134
                    String lName = DOMUtil.getAttrValue(globalComp, SchemaSymbols.ATT_NAME);
 
1135
                    if (lName.length() == 0) // an error we'll catch later
 
1136
                        continue;
 
1137
                    String qName = currSchemaDoc.fTargetNamespace == null?
 
1138
                            ","+lName:
 
1139
                                currSchemaDoc.fTargetNamespace +","+lName;
 
1140
                    String componentType = DOMUtil.getLocalName(globalComp);
 
1141
                    if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTE)) {
 
1142
                        checkForDuplicateNames(qName, fUnparsedAttributeRegistry, fUnparsedAttributeRegistrySub, globalComp, currSchemaDoc);
 
1143
                    }
 
1144
                    else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
 
1145
                        checkForDuplicateNames(qName, fUnparsedAttributeGroupRegistry, fUnparsedAttributeGroupRegistrySub, globalComp, currSchemaDoc);
 
1146
                    }
 
1147
                    else if ((componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) ||
 
1148
                            (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE))) {
 
1149
                        checkForDuplicateNames(qName, fUnparsedTypeRegistry, fUnparsedTypeRegistrySub, globalComp, currSchemaDoc);
 
1150
                    }
 
1151
                    else if (componentType.equals(SchemaSymbols.ELT_ELEMENT)) {
 
1152
                        checkForDuplicateNames(qName, fUnparsedElementRegistry, fUnparsedElementRegistrySub, globalComp, currSchemaDoc);
 
1153
                    }
 
1154
                    else if (componentType.equals(SchemaSymbols.ELT_GROUP)) {
 
1155
                        checkForDuplicateNames(qName, fUnparsedGroupRegistry, fUnparsedGroupRegistrySub, globalComp, currSchemaDoc);
 
1156
                    }
 
1157
                    else if (componentType.equals(SchemaSymbols.ELT_NOTATION)) {
 
1158
                        checkForDuplicateNames(qName, fUnparsedNotationRegistry, fUnparsedNotationRegistrySub, globalComp, currSchemaDoc);
 
1159
                    }
 
1160
                }
 
1161
            } // end for
 
1162
            
 
1163
            // now we're done with this one!
 
1164
                DOMUtil.setHidden(currDoc, fHiddenNodes);
 
1165
            // now add the schemas this guy depends on
 
1166
            Vector currSchemaDepends = (Vector)fDependencyMap.get(currSchemaDoc);
 
1167
            for (int i = 0; i < currSchemaDepends.size(); i++) {
 
1168
                schemasToProcess.push(currSchemaDepends.elementAt(i));
 
1169
            }
 
1170
        } // while
 
1171
 
 
1172
    } // end buildGlobalNameRegistries
 
1173
    
 
1174
    // Beginning at the first schema processing was requested for
 
1175
    // (fRoot), this method
 
1176
    // examines each child (global schema information item) of each
 
1177
    // schema document (and of each <redefine> element)
 
1178
    // corresponding to an XSDocumentInfo object.  If the
 
1179
    // readOnly field on that node has not been set, it calls an
 
1180
    // appropriate traverser to traverse it.  Once all global decls in
 
1181
    // an XSDocumentInfo object have been traversed, it marks that object
 
1182
    // as traversed (or hidden) in order to avoid infinite loops.  It completes
 
1183
    // when it has visited all XSDocumentInfo objects in the
 
1184
    // DependencyMap and marked them as traversed.
 
1185
    protected void traverseSchemas(ArrayList annotationInfo) {
 
1186
        // the process here is very similar to that in
 
1187
        // buildGlobalRegistries, except we can't set our schemas as
 
1188
        // hidden for a second time; so make them all visible again
 
1189
        // first!
 
1190
        setSchemasVisible(fRoot);
 
1191
        Stack schemasToProcess = new Stack();
 
1192
        schemasToProcess.push(fRoot);
 
1193
        while (!schemasToProcess.empty()) {
 
1194
            XSDocumentInfo currSchemaDoc =
 
1195
                (XSDocumentInfo)schemasToProcess.pop();
 
1196
            Element currDoc = currSchemaDoc.fSchemaElement;
 
1197
       
 
1198
            SchemaGrammar currSG = fGrammarBucket.getGrammar(currSchemaDoc.fTargetNamespace);
 
1199
 
 
1200
            if(DOMUtil.isHidden(currDoc, fHiddenNodes)) {
 
1201
                // must have processed this already!
 
1202
                continue;
 
1203
            }
 
1204
            Element currRoot = currDoc;
 
1205
            boolean sawAnnotation = false;
 
1206
            // traverse this schema's global decls
 
1207
            for (Element globalComp =
 
1208
                DOMUtil.getFirstVisibleChildElement(currRoot, fHiddenNodes);
 
1209
            globalComp != null;
 
1210
            globalComp = DOMUtil.getNextVisibleSiblingElement(globalComp, fHiddenNodes)) {
 
1211
                DOMUtil.setHidden(globalComp, fHiddenNodes); 
 
1212
                String componentType = DOMUtil.getLocalName(globalComp);
 
1213
                // includes and imports will not show up here!
 
1214
                if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_REDEFINE)) {
 
1215
                    // use the namespace decls for the redefine, instead of for the parent <schema>
 
1216
                    currSchemaDoc.backupNSSupport((SchemaNamespaceSupport)fRedefine2NSSupport.get(globalComp));
 
1217
                    for (Element redefinedComp = DOMUtil.getFirstVisibleChildElement(globalComp, fHiddenNodes);
 
1218
                    redefinedComp != null;
 
1219
                    redefinedComp = DOMUtil.getNextVisibleSiblingElement(redefinedComp, fHiddenNodes)) {
 
1220
                        String redefinedComponentType = DOMUtil.getLocalName(redefinedComp);
 
1221
                        DOMUtil.setHidden(redefinedComp, fHiddenNodes);
 
1222
                        if (redefinedComponentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
 
1223
                            fAttributeGroupTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG);
 
1224
                        }
 
1225
                        else if (redefinedComponentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) {
 
1226
                            fComplexTypeTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG);
 
1227
                        }
 
1228
                        else if (redefinedComponentType.equals(SchemaSymbols.ELT_GROUP)) {
 
1229
                            fGroupTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG);
 
1230
                        }
 
1231
                        else if (redefinedComponentType.equals(SchemaSymbols.ELT_SIMPLETYPE)) {
 
1232
                            fSimpleTypeTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG);
 
1233
                        }
 
1234
                        // annotations will have been processed already; this is now
 
1235
                        // unnecessary
 
1236
                        //else if (redefinedComponentType.equals(SchemaSymbols.ELT_ANNOTATION)) {
 
1237
                        //    fElementTraverser.traverseAnnotationDecl(redefinedComp, null, true, currSchemaDoc);
 
1238
                        //}
 
1239
                        else {
 
1240
                            reportSchemaError("s4s-elt-must-match.1", new Object [] {DOMUtil.getLocalName(globalComp), "(annotation | (simpleType | complexType | group | attributeGroup))*", redefinedComponentType}, redefinedComp);
 
1241
                        }
 
1242
                    } // end march through <redefine> children
 
1243
                    currSchemaDoc.restoreNSSupport();
 
1244
                }
 
1245
                else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTE)) {
 
1246
                    fAttributeTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
 
1247
                }
 
1248
                else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
 
1249
                    fAttributeGroupTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
 
1250
                }
 
1251
                else if (componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) {
 
1252
                    fComplexTypeTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
 
1253
                }
 
1254
                else if (componentType.equals(SchemaSymbols.ELT_ELEMENT)) {
 
1255
                    fElementTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
 
1256
                }
 
1257
                else if (componentType.equals(SchemaSymbols.ELT_GROUP)) {
 
1258
                    fGroupTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
 
1259
                }
 
1260
                else if (componentType.equals(SchemaSymbols.ELT_NOTATION)) {
 
1261
                    fNotationTraverser.traverse(globalComp, currSchemaDoc, currSG);
 
1262
                }
 
1263
                else if (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE)) {
 
1264
                    fSimpleTypeTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
 
1265
                }
 
1266
                else if (componentType.equals(SchemaSymbols.ELT_ANNOTATION)) {
 
1267
                    currSG.addAnnotation(fElementTraverser.traverseAnnotationDecl(globalComp, currSchemaDoc.getSchemaAttrs(), true, currSchemaDoc));
 
1268
                    sawAnnotation = true;
 
1269
                }
 
1270
                else {
 
1271
                    reportSchemaError("s4s-elt-invalid-content.1", new Object [] {SchemaSymbols.ELT_SCHEMA, DOMUtil.getLocalName(globalComp)}, globalComp);
 
1272
                }
 
1273
            } // end for
 
1274
            
 
1275
            if (!sawAnnotation) {
 
1276
                String text = DOMUtil.getSyntheticAnnotation(currRoot);
 
1277
                if (text != null) {
 
1278
                    currSG.addAnnotation(fElementTraverser.traverseSyntheticAnnotation(currRoot, text, currSchemaDoc.getSchemaAttrs(), true, currSchemaDoc));
 
1279
                }
 
1280
            }
 
1281
            
 
1282
            /** Collect annotation information for validation. **/
 
1283
            if (annotationInfo != null) {
 
1284
                XSAnnotationInfo info = currSchemaDoc.getAnnotations();
 
1285
                /** Only add annotations to the list if there were any in this document. **/
 
1286
                if (info != null) {
 
1287
                    annotationInfo.add(doc2SystemId(currDoc));
 
1288
                    annotationInfo.add(info);
 
1289
                }
 
1290
            }
 
1291
            // now we're done with this one!
 
1292
            currSchemaDoc.returnSchemaAttrs();
 
1293
            DOMUtil.setHidden(currDoc, fHiddenNodes);
 
1294
 
 
1295
            // now add the schemas this guy depends on
 
1296
            Vector currSchemaDepends = (Vector)fDependencyMap.get(currSchemaDoc);
 
1297
            for (int i = 0; i < currSchemaDepends.size(); i++) {
 
1298
                schemasToProcess.push(currSchemaDepends.elementAt(i));
 
1299
            }
 
1300
        } // while
 
1301
    } // end traverseSchemas
 
1302
    
 
1303
    // store whether we have reported an error about that no grammar
 
1304
    // is found for the given namespace uri
 
1305
    private Vector fReportedTNS = null;
 
1306
    // check whether we need to report an error against the given uri.
 
1307
    // if we have reported an error, then we don't need to report again;
 
1308
    // otherwise we reported the error, and remember this fact.
 
1309
    private final boolean needReportTNSError(String uri) {
 
1310
        if (fReportedTNS == null)
 
1311
            fReportedTNS = new Vector();
 
1312
        else if (fReportedTNS.contains(uri))
 
1313
            return false;
 
1314
        fReportedTNS.addElement(uri);
 
1315
        return true;
 
1316
    }
 
1317
    
 
1318
    private static final String[] COMP_TYPE = {
 
1319
            null,               // index 0
 
1320
            "attribute declaration",
 
1321
            "attribute group",
 
1322
            "element declaration",
 
1323
            "group",
 
1324
            "identity constraint",
 
1325
            "notation",
 
1326
            "type definition",
 
1327
    };
 
1328
    
 
1329
    private static final String[] CIRCULAR_CODES = {
 
1330
            "Internal-Error",
 
1331
            "Internal-Error",
 
1332
            "src-attribute_group.3",
 
1333
            "e-props-correct.6",
 
1334
            "mg-props-correct.2",
 
1335
            "Internal-Error",
 
1336
            "Internal-Error",
 
1337
            "st-props-correct.2",       //or ct-props-correct.3
 
1338
    };
 
1339
    
 
1340
    // since it is forbidden for traversers to talk to each other
 
1341
    // directly (except wen a traverser encounters a local declaration),
 
1342
    // this provides a generic means for a traverser to call
 
1343
    // for the traversal of some declaration.  An XSDocumentInfo is
 
1344
    // required because the XSDocumentInfo that the traverser is traversing
 
1345
    // may bear no relation to the one the handler is operating on.
 
1346
    // This method will:
 
1347
    // 1.  See if a global definition matching declToTraverse exists;
 
1348
    // 2. if so, determine if there is a path from currSchema to the
 
1349
    // schema document where declToTraverse lives (i.e., do a lookup
 
1350
    // in DependencyMap);
 
1351
    // 3. depending on declType (which will be relevant to step 1 as
 
1352
    // well), call the appropriate traverser with the appropriate
 
1353
    // XSDocumentInfo object.
 
1354
    // This method returns whatever the traverser it called returned;
 
1355
    // this will be an Object of some kind
 
1356
    // that lives in the Grammar.
 
1357
    protected Object getGlobalDecl(XSDocumentInfo currSchema,
 
1358
            int declType,
 
1359
            QName declToTraverse,
 
1360
            Element elmNode) {
 
1361
        
 
1362
        if (DEBUG_NODE_POOL) {
 
1363
            System.out.println("TRAVERSE_GL: "+declToTraverse.toString());
 
1364
        }
 
1365
        // from the schema spec, all built-in types are present in all schemas,
 
1366
        // so if the requested component is a type, and could be found in the
 
1367
        // default schema grammar, we should return that type.
 
1368
        // otherwise (since we would support user-defined schema grammar) we'll
 
1369
        // use the normal way to get the decl
 
1370
        if (declToTraverse.uri != null &&
 
1371
                declToTraverse.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA) {
 
1372
            if (declType == TYPEDECL_TYPE) {
 
1373
                Object retObj = SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(declToTraverse.localpart);
 
1374
                if (retObj != null)
 
1375
                    return retObj;
 
1376
            }
 
1377
        }
 
1378
        
 
1379
        // now check whether this document can access the requsted namespace
 
1380
        if (!currSchema.isAllowedNS(declToTraverse.uri)) {
 
1381
            // cannot get to this schema from the one containing the requesting decl
 
1382
            if (currSchema.needReportTNSError(declToTraverse.uri)) {
 
1383
                String code = declToTraverse.uri == null ? "src-resolve.4.1" : "src-resolve.4.2";
 
1384
                reportSchemaError(code, new Object[]{fDoc2SystemId.get(currSchema.fSchemaElement), declToTraverse.uri, declToTraverse.rawname}, elmNode);
 
1385
            }
 
1386
            return null;
 
1387
        }
 
1388
        
 
1389
        // check whether there is grammar for the requested namespace
 
1390
        SchemaGrammar sGrammar = fGrammarBucket.getGrammar(declToTraverse.uri);
 
1391
        if (sGrammar == null) {
 
1392
            if (needReportTNSError(declToTraverse.uri))
 
1393
                reportSchemaError("src-resolve", new Object[]{declToTraverse.rawname, COMP_TYPE[declType]}, elmNode);
 
1394
            return null;
 
1395
        }
 
1396
        
 
1397
        // if there is such grammar, check whether the requested component is in the grammar
 
1398
        Object retObj = null;
 
1399
        switch (declType) {
 
1400
        case ATTRIBUTE_TYPE :
 
1401
            retObj = sGrammar.getGlobalAttributeDecl(declToTraverse.localpart);
 
1402
            break;
 
1403
        case ATTRIBUTEGROUP_TYPE :
 
1404
            retObj = sGrammar.getGlobalAttributeGroupDecl(declToTraverse.localpart);
 
1405
            break;
 
1406
        case ELEMENT_TYPE :
 
1407
            retObj = sGrammar.getGlobalElementDecl(declToTraverse.localpart);
 
1408
            break;
 
1409
        case GROUP_TYPE :
 
1410
            retObj = sGrammar.getGlobalGroupDecl(declToTraverse.localpart);
 
1411
            break;
 
1412
        case IDENTITYCONSTRAINT_TYPE :
 
1413
            retObj = sGrammar.getIDConstraintDecl(declToTraverse.localpart);
 
1414
            break;
 
1415
        case NOTATION_TYPE :
 
1416
            retObj = sGrammar.getGlobalNotationDecl(declToTraverse.localpart);
 
1417
            break;
 
1418
        case TYPEDECL_TYPE :
 
1419
            retObj = sGrammar.getGlobalTypeDecl(declToTraverse.localpart);
 
1420
            break;
 
1421
        }
 
1422
        
 
1423
        // if the component is parsed, return it
 
1424
        if (retObj != null)
 
1425
            return retObj;
 
1426
        
 
1427
        XSDocumentInfo schemaWithDecl = null;
 
1428
        Element decl = null;
 
1429
        XSDocumentInfo declDoc = null;
 
1430
        
 
1431
        // the component is not parsed, try to find a DOM element for it
 
1432
        String declKey = declToTraverse.uri == null? ","+declToTraverse.localpart:
 
1433
            declToTraverse.uri+","+declToTraverse.localpart;
 
1434
        switch (declType) {
 
1435
        case ATTRIBUTE_TYPE :
 
1436
            decl = (Element)fUnparsedAttributeRegistry.get(declKey);
 
1437
            declDoc = (XSDocumentInfo)fUnparsedAttributeRegistrySub.get(declKey);
 
1438
            break;
 
1439
        case ATTRIBUTEGROUP_TYPE :
 
1440
            decl = (Element)fUnparsedAttributeGroupRegistry.get(declKey);
 
1441
            declDoc = (XSDocumentInfo)fUnparsedAttributeGroupRegistrySub.get(declKey);
 
1442
            break;
 
1443
        case ELEMENT_TYPE :
 
1444
            decl = (Element)fUnparsedElementRegistry.get(declKey);
 
1445
            declDoc = (XSDocumentInfo)fUnparsedElementRegistrySub.get(declKey);
 
1446
            break;
 
1447
        case GROUP_TYPE :
 
1448
            decl = (Element)fUnparsedGroupRegistry.get(declKey);
 
1449
            declDoc = (XSDocumentInfo)fUnparsedGroupRegistrySub.get(declKey);
 
1450
            break;
 
1451
        case IDENTITYCONSTRAINT_TYPE :
 
1452
            decl = (Element)fUnparsedIdentityConstraintRegistry.get(declKey);
 
1453
            declDoc = (XSDocumentInfo)fUnparsedIdentityConstraintRegistrySub.get(declKey);
 
1454
            break;
 
1455
        case NOTATION_TYPE :
 
1456
            decl = (Element)fUnparsedNotationRegistry.get(declKey);
 
1457
            declDoc = (XSDocumentInfo)fUnparsedNotationRegistrySub.get(declKey);
 
1458
            break;
 
1459
        case TYPEDECL_TYPE :
 
1460
            decl = (Element)fUnparsedTypeRegistry.get(declKey);
 
1461
            declDoc = (XSDocumentInfo)fUnparsedTypeRegistrySub.get(declKey);
 
1462
            break;
 
1463
        default:
 
1464
            reportSchemaError("Internal-Error", new Object [] {"XSDHandler asked to locate component of type " + declType + "; it does not recognize this type!"}, elmNode);
 
1465
        }
 
1466
        
 
1467
        // no DOM element found, so the component can't be located
 
1468
        if (decl == null) {
 
1469
            reportSchemaError("src-resolve", new Object[]{declToTraverse.rawname, COMP_TYPE[declType]}, elmNode);
 
1470
            return null;
 
1471
        }
 
1472
        
 
1473
        // get the schema doc containing the component to be parsed
 
1474
        // it should always return non-null value, but since null-checking
 
1475
        // comes for free, let's be safe and check again
 
1476
        schemaWithDecl = findXSDocumentForDecl(currSchema, decl, declDoc);
 
1477
        if (schemaWithDecl == null) {
 
1478
            // cannot get to this schema from the one containing the requesting decl
 
1479
            String code = declToTraverse.uri == null ? "src-resolve.4.1" : "src-resolve.4.2";
 
1480
            reportSchemaError(code, new Object[]{fDoc2SystemId.get(currSchema.fSchemaElement), declToTraverse.uri, declToTraverse.rawname}, elmNode);
 
1481
            return null;
 
1482
        }
 
1483
        // a component is hidden, meaning either it's traversed, or being traversed.
 
1484
        // but we didn't find it in the grammar, so it's the latter case, and
 
1485
        // a circular reference. error!
 
1486
        if (DOMUtil.isHidden(decl, fHiddenNodes)) {
 
1487
            String code = CIRCULAR_CODES[declType];
 
1488
            if (declType == TYPEDECL_TYPE) {
 
1489
                if (SchemaSymbols.ELT_COMPLEXTYPE.equals(DOMUtil.getLocalName(decl)))
 
1490
                    code = "ct-props-correct.3";
 
1491
            }
 
1492
            // decl must not be null if we're here...
 
1493
            reportSchemaError(code, new Object [] {declToTraverse.prefix+":"+declToTraverse.localpart}, elmNode);
 
1494
            return null;
 
1495
        }
 
1496
        
 
1497
        DOMUtil.setHidden(decl, fHiddenNodes);
 
1498
        SchemaNamespaceSupport nsSupport = null;
 
1499
        // if the parent is <redefine> use the namespace delcs for it.
 
1500
        Element parent = DOMUtil.getParent(decl);
 
1501
        if (DOMUtil.getLocalName(parent).equals(SchemaSymbols.ELT_REDEFINE))
 
1502
            nsSupport = (SchemaNamespaceSupport)fRedefine2NSSupport.get(parent);
 
1503
        // back up the current SchemaNamespaceSupport, because we need to provide
 
1504
        // a fresh one to the traverseGlobal methods.
 
1505
        schemaWithDecl.backupNSSupport(nsSupport);
 
1506
        
 
1507
        // traverse the referenced global component
 
1508
        switch (declType) {
 
1509
        case ATTRIBUTE_TYPE :
 
1510
            retObj = fAttributeTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
 
1511
            break;
 
1512
        case ATTRIBUTEGROUP_TYPE :
 
1513
            retObj = fAttributeGroupTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
 
1514
            break;
 
1515
        case ELEMENT_TYPE :
 
1516
            retObj = fElementTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
 
1517
            break;
 
1518
        case GROUP_TYPE :
 
1519
            retObj = fGroupTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
 
1520
            break;
 
1521
        case IDENTITYCONSTRAINT_TYPE :
 
1522
            // identity constraints should have been parsed already...
 
1523
            // we should never get here
 
1524
            retObj = null;
 
1525
            break;
 
1526
        case NOTATION_TYPE :
 
1527
            retObj = fNotationTraverser.traverse(decl, schemaWithDecl, sGrammar);
 
1528
            break;
 
1529
        case TYPEDECL_TYPE :
 
1530
            if (DOMUtil.getLocalName(decl).equals(SchemaSymbols.ELT_COMPLEXTYPE))
 
1531
                retObj = fComplexTypeTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
 
1532
            else
 
1533
                retObj = fSimpleTypeTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
 
1534
        }
 
1535
        
 
1536
        // restore the previous SchemaNamespaceSupport, so that the caller can get
 
1537
        // proper namespace binding.
 
1538
        schemaWithDecl.restoreNSSupport();
 
1539
        
 
1540
        return retObj;
 
1541
    } // getGlobalDecl(XSDocumentInfo, int, QName):  Object
 
1542
    
 
1543
    // This method determines whether there is a group
 
1544
    // (attributeGroup) which the given one has redefined by
 
1545
    // restriction.  If so, it returns it; else it returns null.
 
1546
    // @param type:  whether what's been redefined is an
 
1547
    // attributeGroup or a group;
 
1548
    // @param name:  the QName of the component doing the redefining.
 
1549
    // @param currSchema:  schema doc in which the redefining component lives.
 
1550
    // @return:  Object representing decl redefined if present, null
 
1551
    // otherwise.
 
1552
    Object getGrpOrAttrGrpRedefinedByRestriction(int type, QName name, XSDocumentInfo currSchema, Element elmNode) {
 
1553
        String realName = name.uri != null?name.uri+","+name.localpart:
 
1554
            ","+name.localpart;
 
1555
        String nameToFind = null;
 
1556
        switch (type) {
 
1557
        case ATTRIBUTEGROUP_TYPE:
 
1558
            nameToFind = (String)fRedefinedRestrictedAttributeGroupRegistry.get(realName);
 
1559
            break;
 
1560
        case GROUP_TYPE:
 
1561
            nameToFind = (String)fRedefinedRestrictedGroupRegistry.get(realName);
 
1562
            break;
 
1563
        default:
 
1564
            return null;
 
1565
        }
 
1566
        if (nameToFind == null) return null;
 
1567
        int commaPos = nameToFind.indexOf(",");
 
1568
        QName qNameToFind = new QName(XMLSymbols.EMPTY_STRING, nameToFind.substring(commaPos+1),
 
1569
                nameToFind.substring(commaPos), (commaPos == 0)? null : nameToFind.substring(0, commaPos));
 
1570
        Object retObj = getGlobalDecl(currSchema, type, qNameToFind, elmNode);
 
1571
        if(retObj == null) {
 
1572
            switch (type) {
 
1573
            case ATTRIBUTEGROUP_TYPE:
 
1574
                reportSchemaError("src-redefine.7.2.1", new Object []{name.localpart}, elmNode);
 
1575
                break;
 
1576
            case GROUP_TYPE:
 
1577
                reportSchemaError("src-redefine.6.2.1", new Object []{name.localpart}, elmNode);
 
1578
                break;
 
1579
            }
 
1580
            return null;
 
1581
        }
 
1582
        return retObj;
 
1583
    } // getGrpOrAttrGrpRedefinedByRestriction(int, QName, XSDocumentInfo):  Object
 
1584
    
 
1585
    // Since ID constraints can occur in local elements, unless we
 
1586
    // wish to completely traverse all our DOM trees looking for ID
 
1587
    // constraints while we're building our global name registries,
 
1588
    // which seems terribly inefficient, we need to resolve keyrefs
 
1589
    // after all parsing is complete.  This we can simply do by running through
 
1590
    // fIdentityConstraintRegistry and calling traverseKeyRef on all
 
1591
    // of the KeyRef nodes.  This unfortunately removes this knowledge
 
1592
    // from the elementTraverser class (which must ignore keyrefs),
 
1593
    // but there seems to be no efficient way around this...
 
1594
    protected void resolveKeyRefs() {
 
1595
        for (int i=0; i<fKeyrefStackPos; i++) {
 
1596
            XSDocumentInfo keyrefSchemaDoc = fKeyrefsMapXSDocumentInfo[i];
 
1597
            keyrefSchemaDoc.fNamespaceSupport.makeGlobal();
 
1598
            keyrefSchemaDoc.fNamespaceSupport.setEffectiveContext( fKeyrefNamespaceContext[i] );
 
1599
            SchemaGrammar keyrefGrammar = fGrammarBucket.getGrammar(keyrefSchemaDoc.fTargetNamespace);
 
1600
            // need to set <keyref> to hidden before traversing it,
 
1601
            // because it has global scope
 
1602
                DOMUtil.setHidden(fKeyrefs[i], fHiddenNodes);
 
1603
            fKeyrefTraverser.traverse(fKeyrefs[i], fKeyrefElems[i], keyrefSchemaDoc, keyrefGrammar);
 
1604
        }
 
1605
    } // end resolveKeyRefs
 
1606
    
 
1607
    // an accessor method.  Just makes sure callers
 
1608
    // who want the Identity constraint registry vaguely know what they're about.
 
1609
    protected Hashtable getIDRegistry() {
 
1610
        return fUnparsedIdentityConstraintRegistry;
 
1611
    }
 
1612
    // an accessor method.  
 
1613
    protected Hashtable getIDRegistry_sub() {
 
1614
        return fUnparsedIdentityConstraintRegistrySub;
 
1615
    }
 
1616
    
 
1617
   
 
1618
    
 
1619
    // This method squirrels away <keyref> declarations--along with the element
 
1620
    // decls and namespace bindings they might find handy.
 
1621
    protected void storeKeyRef (Element keyrefToStore, XSDocumentInfo schemaDoc,
 
1622
            XSElementDecl currElemDecl) {
 
1623
        String keyrefName = DOMUtil.getAttrValue(keyrefToStore, SchemaSymbols.ATT_NAME);
 
1624
        if (keyrefName.length() != 0) {
 
1625
            String keyrefQName = schemaDoc.fTargetNamespace == null?
 
1626
                    "," + keyrefName: schemaDoc.fTargetNamespace+","+keyrefName;
 
1627
            checkForDuplicateNames(keyrefQName, fUnparsedIdentityConstraintRegistry, fUnparsedIdentityConstraintRegistrySub, keyrefToStore, schemaDoc);
 
1628
        }
 
1629
        // now set up all the registries we'll need...
 
1630
        
 
1631
        // check array sizes
 
1632
        if (fKeyrefStackPos == fKeyrefs.length) {
 
1633
            Element [] elemArray = new Element [fKeyrefStackPos + INC_KEYREF_STACK_AMOUNT];
 
1634
            System.arraycopy(fKeyrefs, 0, elemArray, 0, fKeyrefStackPos);
 
1635
            fKeyrefs = elemArray;
 
1636
            XSElementDecl [] declArray = new XSElementDecl [fKeyrefStackPos + INC_KEYREF_STACK_AMOUNT];
 
1637
            System.arraycopy(fKeyrefElems, 0, declArray, 0, fKeyrefStackPos);
 
1638
            fKeyrefElems = declArray;
 
1639
            String[][] stringArray = new String [fKeyrefStackPos + INC_KEYREF_STACK_AMOUNT][];
 
1640
            System.arraycopy(fKeyrefNamespaceContext, 0, stringArray, 0, fKeyrefStackPos);
 
1641
            fKeyrefNamespaceContext = stringArray;
 
1642
            
 
1643
            XSDocumentInfo [] xsDocumentInfo = new XSDocumentInfo [fKeyrefStackPos + INC_KEYREF_STACK_AMOUNT];
 
1644
            System.arraycopy(fKeyrefsMapXSDocumentInfo, 0, xsDocumentInfo, 0, fKeyrefStackPos);
 
1645
            fKeyrefsMapXSDocumentInfo = xsDocumentInfo;
 
1646
            
 
1647
        }
 
1648
        fKeyrefs[fKeyrefStackPos] = keyrefToStore;
 
1649
        fKeyrefElems[fKeyrefStackPos] = currElemDecl;
 
1650
        fKeyrefNamespaceContext[fKeyrefStackPos] = schemaDoc.fNamespaceSupport.getEffectiveLocalContext();
 
1651
        
 
1652
        fKeyrefsMapXSDocumentInfo[fKeyrefStackPos++] = schemaDoc; 
 
1653
    } // storeKeyref (Element, XSDocumentInfo, XSElementDecl): void
 
1654
    
 
1655
    
 
1656
    /**
 
1657
     * resolveSchema method is responsible for resolving location of the schema (using XMLEntityResolver),
 
1658
     * and if it was succefully resolved getting the schema Document.
 
1659
     * @param desc
 
1660
     * @param mustResolve
 
1661
     * @param referElement
 
1662
     * @return A schema Element or null.
 
1663
     */
 
1664
    private Element resolveSchema(XSDDescription desc, boolean mustResolve,
 
1665
                                  Element referElement, boolean usePairs) {
 
1666
        XMLInputSource schemaSource = null;
 
1667
        try {
 
1668
            Hashtable pairs = usePairs ? fLocationPairs : EMPTY_TABLE;
 
1669
            schemaSource = XMLSchemaLoader.resolveDocument(desc, pairs, fEntityResolver);
 
1670
        }
 
1671
        catch (IOException ex) {
 
1672
            if (mustResolve) {
 
1673
                reportSchemaError("schema_reference.4",
 
1674
                        new Object[]{desc.getLocationHints()[0]},
 
1675
                        referElement);
 
1676
            }
 
1677
            else {
 
1678
                reportSchemaWarning("schema_reference.4",
 
1679
                        new Object[]{desc.getLocationHints()[0]},
 
1680
                        referElement);
 
1681
            }
 
1682
        }
 
1683
        if (schemaSource instanceof DOMInputSource) {
 
1684
            fHiddenNodes.clear();
 
1685
            Node node = ((DOMInputSource)schemaSource).getNode();
 
1686
 
 
1687
            if (node instanceof Document) {
 
1688
                return DOMUtil.getRoot((Document) node);
 
1689
            }
 
1690
            else if (node instanceof Element) {
 
1691
                return (Element) node;
 
1692
            }
 
1693
            else {
 
1694
                return null;
 
1695
            }
 
1696
        } // DOMInputSource
 
1697
        else if (schemaSource instanceof SAXInputSource) {
 
1698
            XMLReader parser = ((SAXInputSource)schemaSource).getXMLReader();
 
1699
            InputSource inputSource = ((SAXInputSource)schemaSource).getInputSource(); 
 
1700
            boolean namespacePrefixes = false;
 
1701
            if (parser != null) {
 
1702
                try {
 
1703
                    namespacePrefixes = parser.getFeature(NAMESPACE_PREFIXES);
 
1704
                }
 
1705
                catch (SAXException se) {}
 
1706
            }
 
1707
            else {
 
1708
                try {
 
1709
                    parser = XMLReaderFactory.createXMLReader();
 
1710
                }
 
1711
                // If something went wrong with the factory
 
1712
                // just use our own SAX parser.
 
1713
                catch (SAXException se) {
 
1714
                    parser = new SAXParser();
 
1715
                }
 
1716
                try {
 
1717
                    parser.setFeature(NAMESPACE_PREFIXES, true);
 
1718
                    namespacePrefixes = true;
 
1719
                }
 
1720
                catch (SAXException se) {}
 
1721
            }
 
1722
            // If XML names and Namespace URIs are already internalized we
 
1723
            // can avoid running them through the SymbolTable.
 
1724
            boolean stringsInternalized = false;
 
1725
            try {
 
1726
                stringsInternalized = parser.getFeature(STRING_INTERNING);
 
1727
            }
 
1728
            catch (SAXException exc) {
 
1729
                // The feature isn't recognized or getting it is not supported.
 
1730
                // In either case, assume that strings are not internalized.
 
1731
            }
 
1732
            if (fXSContentHandler == null) {
 
1733
                fXSContentHandler = new SchemaContentHandler();
 
1734
            }
 
1735
            fXSContentHandler.reset(fSchemaParser, fSymbolTable, 
 
1736
                    namespacePrefixes, stringsInternalized);
 
1737
            parser.setContentHandler(fXSContentHandler);
 
1738
            parser.setErrorHandler(fErrorReporter.getSAXErrorHandler());
 
1739
            try {
 
1740
                parser.parse(inputSource);  
 
1741
            }
 
1742
            catch (SAXException se) {
 
1743
                return null;
 
1744
            }
 
1745
            catch (IOException ioe) {
 
1746
                return null;
 
1747
            }
 
1748
            Document root = fXSContentHandler.getDocument();
 
1749
            if (root == null) {
 
1750
                // something went wrong right off the hop
 
1751
                return null;
 
1752
            }
 
1753
            return DOMUtil.getRoot(root);          
 
1754
        }       
 
1755
        return getSchemaDocument(desc.getTargetNamespace(), schemaSource, mustResolve, desc.getContextType(), referElement);
 
1756
    } // getSchema(String, String, String, boolean, short):  Document
 
1757
    
 
1758
    /**
 
1759
     * getSchemaDocument method uses XMLInputSource to parse a schema document.
 
1760
     * @param schemaNamespace
 
1761
     * @param schemaSource
 
1762
     * @param mustResolve
 
1763
     * @param referType
 
1764
     * @param referElement
 
1765
     * @return A schema Element.
 
1766
     */
 
1767
    private Element getSchemaDocument(String schemaNamespace, XMLInputSource schemaSource,
 
1768
            boolean mustResolve, short referType, Element referElement) {
 
1769
        
 
1770
        boolean hasInput = true;
 
1771
        // contents of this method will depend on the system we adopt for entity resolution--i.e., XMLEntityHandler, EntityHandler, etc.
 
1772
        Element schemaElement = null;
 
1773
        try {
 
1774
            // when the system id and byte stream and character stream
 
1775
            // of the input source are all null, it's
 
1776
            // impossible to find the schema document. so we skip in
 
1777
            // this case. otherwise we'll receive some NPE or
 
1778
            // file not found errors. but schemaHint=="" is perfectly
 
1779
            // legal for import.
 
1780
            if (schemaSource != null &&
 
1781
                    (schemaSource.getSystemId() != null ||
 
1782
                            schemaSource.getByteStream() != null ||
 
1783
                            schemaSource.getCharacterStream() != null)) {
 
1784
                
 
1785
                // When the system id of the input source is used, first try to
 
1786
                // expand it, and check whether the same document has been
 
1787
                // parsed before. If so, return the document corresponding to
 
1788
                // that system id.
 
1789
                XSDKey key = null;
 
1790
                String schemaId = null;
 
1791
                if (referType != XSDDescription.CONTEXT_PREPARSE){
 
1792
                    schemaId = XMLEntityManager.expandSystemId(schemaSource.getSystemId(), schemaSource.getBaseSystemId(), false);
 
1793
                    key = new XSDKey(schemaId, referType, schemaNamespace);
 
1794
                    if((schemaElement = (Element)fTraversed.get(key)) != null) {
 
1795
                        fLastSchemaWasDuplicate = true;
 
1796
                        return schemaElement;
 
1797
                    }
 
1798
                }
 
1799
                
 
1800
                fSchemaParser.parse(schemaSource);
 
1801
                schemaElement = fSchemaParser.getDocument2() == null ? null: DOMUtil.getRoot(fSchemaParser.getDocument2());
 
1802
                
 
1803
                // now we need to store the mapping information from system id
 
1804
                // to the document. also from the document to the system id.
 
1805
                if (key != null)
 
1806
                    fTraversed.put(key, schemaElement );
 
1807
                if (schemaId != null)
 
1808
                    fDoc2SystemId.put(schemaElement, schemaId );
 
1809
                fLastSchemaWasDuplicate = false;
 
1810
                return schemaElement;
 
1811
            }
 
1812
            else {
 
1813
                hasInput = false;
 
1814
            }
 
1815
        }
 
1816
        catch (IOException ex) {
 
1817
        }
 
1818
        
 
1819
        // either an error occured (exception), or empty input source was
 
1820
        // returned, we need to report an error or a warning
 
1821
        if (mustResolve) {
 
1822
            if (hasInput) {
 
1823
                reportSchemaError("schema_reference.4",
 
1824
                        new Object[]{schemaSource.getSystemId()},
 
1825
                        referElement);
 
1826
            }
 
1827
            else {
 
1828
                reportSchemaError("schema_reference.4",
 
1829
                        new Object[]{schemaSource == null ? "" : schemaSource.getSystemId()},
 
1830
                        referElement);
 
1831
            }
 
1832
        }
 
1833
        else if (hasInput) {
 
1834
            reportSchemaWarning("schema_reference.4",
 
1835
                    new Object[]{schemaSource.getSystemId()},
 
1836
                    referElement);
 
1837
        }
 
1838
        
 
1839
        fLastSchemaWasDuplicate = false;
 
1840
        return null;
 
1841
    } // getSchema(String, XMLInputSource, boolean, boolean): Document
 
1842
    
 
1843
    // initialize all the traversers.
 
1844
    // this should only need to be called once during the construction
 
1845
    // of this object; it creates the traversers that will be used to
 
1846
    
 
1847
    // construct schemaGrammars.
 
1848
    private void createTraversers() {
 
1849
        fAttributeChecker = new XSAttributeChecker(this);
 
1850
        fAttributeGroupTraverser = new XSDAttributeGroupTraverser(this, fAttributeChecker);
 
1851
        fAttributeTraverser = new XSDAttributeTraverser(this, fAttributeChecker);
 
1852
        fComplexTypeTraverser = new XSDComplexTypeTraverser(this, fAttributeChecker);
 
1853
        fElementTraverser = new XSDElementTraverser(this, fAttributeChecker);
 
1854
        fGroupTraverser = new XSDGroupTraverser(this, fAttributeChecker);
 
1855
        fKeyrefTraverser = new XSDKeyrefTraverser(this, fAttributeChecker);
 
1856
        fNotationTraverser = new XSDNotationTraverser(this, fAttributeChecker);
 
1857
        fSimpleTypeTraverser = new XSDSimpleTypeTraverser(this, fAttributeChecker);
 
1858
        fUniqueOrKeyTraverser = new XSDUniqueOrKeyTraverser(this, fAttributeChecker);
 
1859
        fWildCardTraverser = new XSDWildcardTraverser(this, fAttributeChecker);
 
1860
    } // createTraversers()
 
1861
    
 
1862
    // before parsing a schema, need to clear registries associated with
 
1863
    // parsing schemas
 
1864
    void prepareForParse() {
 
1865
        fTraversed.clear();
 
1866
        fDoc2SystemId.clear();
 
1867
        fHiddenNodes.clear();
 
1868
        fLastSchemaWasDuplicate = false;
 
1869
    }
 
1870
    
 
1871
    // before traversing a schema's parse tree, need to reset all traversers and
 
1872
    // clear all registries
 
1873
    void prepareForTraverse() {
 
1874
        fUnparsedAttributeRegistry.clear();
 
1875
        fUnparsedAttributeGroupRegistry.clear();
 
1876
        fUnparsedElementRegistry.clear();
 
1877
        fUnparsedGroupRegistry.clear();
 
1878
        fUnparsedIdentityConstraintRegistry.clear();
 
1879
        fUnparsedNotationRegistry.clear();
 
1880
        fUnparsedTypeRegistry.clear();
 
1881
        
 
1882
        fUnparsedAttributeRegistrySub.clear();
 
1883
        fUnparsedAttributeGroupRegistrySub.clear();
 
1884
        fUnparsedElementRegistrySub.clear();
 
1885
        fUnparsedGroupRegistrySub.clear();
 
1886
        fUnparsedIdentityConstraintRegistrySub.clear();
 
1887
        fUnparsedNotationRegistrySub.clear();
 
1888
        fUnparsedTypeRegistrySub.clear();
 
1889
        
 
1890
        fXSDocumentInfoRegistry.clear();
 
1891
        fDependencyMap.clear();
 
1892
        fDoc2XSDocumentMap.clear();
 
1893
        fRedefine2XSDMap.clear();
 
1894
        fRedefine2NSSupport.clear();
 
1895
        fAllTNSs.removeAllElements();
 
1896
        fImportMap.clear();
 
1897
        fRoot = null;
 
1898
        
 
1899
        // clear local element stack
 
1900
        for (int i = 0; i < fLocalElemStackPos; i++) {
 
1901
            fParticle[i] = null;
 
1902
            fLocalElementDecl[i] = null;
 
1903
            fLocalElementDecl_schema[i] = null;
 
1904
            fLocalElemNamespaceContext[i] = null;
 
1905
        }
 
1906
        fLocalElemStackPos = 0;
 
1907
        
 
1908
        // and do same for keyrefs.
 
1909
        for (int i = 0; i < fKeyrefStackPos; i++) {
 
1910
            fKeyrefs[i] = null;
 
1911
            fKeyrefElems[i] = null;
 
1912
            fKeyrefNamespaceContext[i] = null;
 
1913
            fKeyrefsMapXSDocumentInfo[i] = null;
 
1914
        }
 
1915
        fKeyrefStackPos = 0;
 
1916
        
 
1917
        // create traversers if necessary
 
1918
        if (fAttributeChecker == null) {
 
1919
            createTraversers();
 
1920
        }
 
1921
        
 
1922
        // reset traversers
 
1923
        fAttributeChecker.reset(fSymbolTable);
 
1924
        fAttributeGroupTraverser.reset(fSymbolTable, fValidateAnnotations);
 
1925
        fAttributeTraverser.reset(fSymbolTable, fValidateAnnotations);
 
1926
        fComplexTypeTraverser.reset(fSymbolTable, fValidateAnnotations);
 
1927
        fElementTraverser.reset(fSymbolTable, fValidateAnnotations);
 
1928
        fGroupTraverser.reset(fSymbolTable, fValidateAnnotations);
 
1929
        fKeyrefTraverser.reset(fSymbolTable, fValidateAnnotations);
 
1930
        fNotationTraverser.reset(fSymbolTable, fValidateAnnotations);
 
1931
        fSimpleTypeTraverser.reset(fSymbolTable, fValidateAnnotations);
 
1932
        fUniqueOrKeyTraverser.reset(fSymbolTable, fValidateAnnotations);
 
1933
        fWildCardTraverser.reset(fSymbolTable, fValidateAnnotations);
 
1934
        
 
1935
        fRedefinedRestrictedAttributeGroupRegistry.clear();
 
1936
        fRedefinedRestrictedGroupRegistry.clear();
 
1937
    }
 
1938
    public void setDeclPool (XSDeclarationPool declPool){
 
1939
        fDeclPool = declPool;
 
1940
    }
 
1941
    
 
1942
    public void reset(XMLComponentManager componentManager) {
 
1943
        
 
1944
        // set symbol table
 
1945
        fSymbolTable = (SymbolTable) componentManager.getProperty(SYMBOL_TABLE);
 
1946
        
 
1947
        //set entity resolver
 
1948
        fEntityResolver = (XMLEntityResolver) componentManager.getProperty(ENTITY_MANAGER);
 
1949
        XMLEntityResolver er = (XMLEntityResolver)componentManager.getProperty(ENTITY_RESOLVER);
 
1950
        if (er != null)
 
1951
            fSchemaParser.setEntityResolver(er);
 
1952
        
 
1953
        // set error reporter
 
1954
        fErrorReporter =
 
1955
            (XMLErrorReporter) componentManager.getProperty(ERROR_REPORTER);
 
1956
        try {
 
1957
            XMLErrorHandler currErrorHandler = fErrorReporter.getErrorHandler();
 
1958
            // Setting a parser property can be much more expensive
 
1959
            // than checking its value.  Don't set the ERROR_HANDLER
 
1960
            // property unless it's actually changed.
 
1961
            if (currErrorHandler != fSchemaParser.getProperty(ERROR_HANDLER)) {
 
1962
                fSchemaParser.setProperty(ERROR_HANDLER, (currErrorHandler != null) ? currErrorHandler : new DefaultErrorHandler());
 
1963
                if (fAnnotationValidator != null) {
 
1964
                    fAnnotationValidator.setProperty(ERROR_HANDLER, (currErrorHandler != null) ? currErrorHandler : new DefaultErrorHandler());
 
1965
                }
 
1966
            }
 
1967
        } catch (XMLConfigurationException e) {
 
1968
        }
 
1969
        
 
1970
        try {
 
1971
            fValidateAnnotations = componentManager.getFeature(VALIDATE_ANNOTATIONS);
 
1972
        } catch (XMLConfigurationException e) {
 
1973
            fValidateAnnotations = false;
 
1974
        }
 
1975
        
 
1976
        try {
 
1977
            fHonourAllSchemaLocations = componentManager.getFeature(HONOUR_ALL_SCHEMALOCATIONS);
 
1978
        } catch (XMLConfigurationException e) {
 
1979
            fHonourAllSchemaLocations = false;
 
1980
        }
 
1981
 
 
1982
        try {
 
1983
            fSchemaParser.setFeature(
 
1984
                    CONTINUE_AFTER_FATAL_ERROR,
 
1985
                    fErrorReporter.getFeature(CONTINUE_AFTER_FATAL_ERROR));
 
1986
        } catch (XMLConfigurationException e) {
 
1987
        }
 
1988
        
 
1989
        try {
 
1990
            fSchemaParser.setFeature(
 
1991
                    ALLOW_JAVA_ENCODINGS,
 
1992
                    componentManager.getFeature(ALLOW_JAVA_ENCODINGS));
 
1993
        } catch (XMLConfigurationException e) {
 
1994
        }
 
1995
        try {
 
1996
            fSchemaParser.setFeature(
 
1997
                    STANDARD_URI_CONFORMANT_FEATURE,
 
1998
                    componentManager.getFeature(STANDARD_URI_CONFORMANT_FEATURE));
 
1999
        } catch (XMLConfigurationException e) {
 
2000
        }
 
2001
        
 
2002
        try {
 
2003
            fGrammarPool =
 
2004
                (XMLGrammarPool) componentManager.getProperty(XMLGRAMMAR_POOL);
 
2005
        } catch (XMLConfigurationException e) {
 
2006
            fGrammarPool = null;
 
2007
        }
 
2008
        // security features
 
2009
        try {
 
2010
            fSchemaParser.setFeature( DISALLOW_DOCTYPE,
 
2011
                    componentManager.getFeature(DISALLOW_DOCTYPE));
 
2012
        } catch (XMLConfigurationException e) {
 
2013
        }
 
2014
        try {
 
2015
            Object security = componentManager.getProperty(SECURITY_MANAGER);
 
2016
            if (security != null){
 
2017
                fSchemaParser.setProperty(SECURITY_MANAGER, security);
 
2018
            }
 
2019
        } catch (XMLConfigurationException e) {
 
2020
        }
 
2021
        
 
2022
    } // reset(XMLComponentManager)
 
2023
    
 
2024
    
 
2025
    /**
 
2026
     * Traverse all the deferred local elements. This method should be called
 
2027
     * by traverseSchemas after we've done with all the global declarations.
 
2028
     */
 
2029
    void traverseLocalElements() {
 
2030
        fElementTraverser.fDeferTraversingLocalElements = false;
 
2031
        
 
2032
        for (int i = 0; i < fLocalElemStackPos; i++) {
 
2033
            Element currElem = fLocalElementDecl[i];
 
2034
            //XSDocumentInfo currSchema = (XSDocumentInfo)fDoc2XSDocumentMap.get(DOMUtil.getDocument(currElem));
 
2035
            //XSDocumentInfo currSchema = (XSDocumentInfo)fDoc2XSDocumentMap.get(DOMUtil.getRoot(DOMUtil.getDocument(currElem)));
 
2036
            XSDocumentInfo currSchema = fLocalElementDecl_schema[i];
 
2037
            SchemaGrammar currGrammar = fGrammarBucket.getGrammar(currSchema.fTargetNamespace);
 
2038
            fElementTraverser.traverseLocal (fParticle[i], currElem, currSchema, currGrammar, fAllContext[i], fParent[i], fLocalElemNamespaceContext[i]);
 
2039
            // If it's an empty particle, remove it from the containing component.
 
2040
            if (fParticle[i].fType == XSParticleDecl.PARTICLE_EMPTY) {
 
2041
                XSModelGroupImpl group = null;
 
2042
                if (fParent[i] instanceof XSComplexTypeDecl) {
 
2043
                    XSParticle p = ((XSComplexTypeDecl)fParent[i]).getParticle();
 
2044
                    if (p != null)
 
2045
                        group = (XSModelGroupImpl)p.getTerm();
 
2046
                }
 
2047
                else {
 
2048
                    group = ((XSGroupDecl)fParent[i]).fModelGroup;
 
2049
                }
 
2050
                if (group != null)
 
2051
                    removeParticle(group, fParticle[i]);
 
2052
            }
 
2053
        }
 
2054
    }
 
2055
    
 
2056
    private boolean removeParticle(XSModelGroupImpl group, XSParticleDecl particle) {
 
2057
        XSParticleDecl member;
 
2058
        for (int i = 0; i < group.fParticleCount; i++) {
 
2059
            member = group.fParticles[i];
 
2060
            if (member == particle) {
 
2061
                for (int j = i; j < group.fParticleCount-1; j++)
 
2062
                    group.fParticles[j] = group.fParticles[j+1];
 
2063
                group.fParticleCount--;
 
2064
                return true;
 
2065
            }
 
2066
            if (member.fType == XSParticleDecl.PARTICLE_MODELGROUP) {
 
2067
                if (removeParticle((XSModelGroupImpl)member.fValue, particle))
 
2068
                    return true;
 
2069
            }
 
2070
        }
 
2071
        return false;
 
2072
    }
 
2073
    
 
2074
    // the purpose of this method is to keep up-to-date structures
 
2075
    // we'll need for the feferred traversal of local elements.
 
2076
    void fillInLocalElemInfo(Element elmDecl,
 
2077
            XSDocumentInfo schemaDoc,
 
2078
            int allContextFlags,
 
2079
            XSObject parent,
 
2080
            XSParticleDecl particle) {
 
2081
        
 
2082
        // if the stack is full, increase the size
 
2083
        if (fParticle.length == fLocalElemStackPos) {
 
2084
            // increase size
 
2085
            XSParticleDecl[] newStackP = new XSParticleDecl[fLocalElemStackPos+INC_STACK_SIZE];
 
2086
            System.arraycopy(fParticle, 0, newStackP, 0, fLocalElemStackPos);
 
2087
            fParticle = newStackP;
 
2088
            Element[] newStackE = new Element[fLocalElemStackPos+INC_STACK_SIZE];
 
2089
            System.arraycopy(fLocalElementDecl, 0, newStackE, 0, fLocalElemStackPos);
 
2090
            fLocalElementDecl = newStackE;
 
2091
            XSDocumentInfo [] newStackE_schema = new XSDocumentInfo[fLocalElemStackPos+INC_STACK_SIZE];
 
2092
            System.arraycopy(fLocalElementDecl_schema, 0, newStackE_schema, 0, fLocalElemStackPos);
 
2093
            fLocalElementDecl_schema = newStackE_schema;
 
2094
            int[] newStackI = new int[fLocalElemStackPos+INC_STACK_SIZE];
 
2095
            System.arraycopy(fAllContext, 0, newStackI, 0, fLocalElemStackPos);
 
2096
            fAllContext = newStackI;
 
2097
            XSObject[] newStackC = new XSObject[fLocalElemStackPos+INC_STACK_SIZE];
 
2098
            System.arraycopy(fParent, 0, newStackC, 0, fLocalElemStackPos);
 
2099
            fParent = newStackC;
 
2100
            String [][] newStackN = new String [fLocalElemStackPos+INC_STACK_SIZE][];
 
2101
            System.arraycopy(fLocalElemNamespaceContext, 0, newStackN, 0, fLocalElemStackPos);
 
2102
            fLocalElemNamespaceContext = newStackN;
 
2103
        }
 
2104
        
 
2105
        fParticle[fLocalElemStackPos] = particle;
 
2106
        fLocalElementDecl[fLocalElemStackPos] = elmDecl;
 
2107
        fLocalElementDecl_schema[fLocalElemStackPos] = schemaDoc;
 
2108
        fAllContext[fLocalElemStackPos] = allContextFlags;
 
2109
        fParent[fLocalElemStackPos] = parent;
 
2110
        fLocalElemNamespaceContext[fLocalElemStackPos++] = schemaDoc.fNamespaceSupport.getEffectiveLocalContext();
 
2111
    } // end fillInLocalElemInfo(...)
 
2112
    
 
2113
    /** This method makes sure that
 
2114
     * if this component is being redefined that it lives in the
 
2115
     * right schema.  It then renames the component correctly.  If it
 
2116
     * detects a collision--a duplicate definition--then it complains.
 
2117
     * Note that redefines must be handled carefully:  if there
 
2118
     * is a collision, it may be because we're redefining something we know about
 
2119
     * or because we've found the thing we're redefining.
 
2120
     */
 
2121
    void checkForDuplicateNames(String qName,
 
2122
                Hashtable registry, Hashtable registry_sub, Element currComp,
 
2123
                        XSDocumentInfo currSchema) {
 
2124
        Object objElem = null;
 
2125
        // REVISIT:  when we add derivation checking, we'll have to make
 
2126
        // sure that ID constraint collisions don't necessarily result in error messages.
 
2127
        if ((objElem = registry.get(qName)) == null) {
 
2128
            // just add it in!
 
2129
            registry.put(qName, currComp);
 
2130
            registry_sub.put(qName, currSchema);
 
2131
            
 
2132
        }
 
2133
        else {
 
2134
            Element collidingElem = (Element)objElem;
 
2135
            XSDocumentInfo collidingElemSchema = (XSDocumentInfo)registry_sub.get(qName);
 
2136
            if (collidingElem == currComp) return;
 
2137
            Element elemParent = null;
 
2138
            XSDocumentInfo redefinedSchema = null;
 
2139
            // case where we've collided with a redefining element
 
2140
            // (the parent of the colliding element is a redefine)
 
2141
            boolean collidedWithRedefine = true;
 
2142
            if ((DOMUtil.getLocalName((elemParent = DOMUtil.getParent(collidingElem))).equals(SchemaSymbols.ELT_REDEFINE))) {
 
2143
                redefinedSchema = (XSDocumentInfo)(fRedefine2XSDMap.get(elemParent));
 
2144
                // case where we're a redefining element.
 
2145
            }
 
2146
            else if ((DOMUtil.getLocalName(DOMUtil.getParent(currComp)).equals(SchemaSymbols.ELT_REDEFINE))) {
 
2147
                redefinedSchema = collidingElemSchema;
 
2148
                collidedWithRedefine = false;
 
2149
            }
 
2150
            if (redefinedSchema != null) { //redefinition involved somehow
 
2151
                // If both components belong to the same document then
 
2152
                // report an error and return.
 
2153
                if(collidingElemSchema == currSchema){
 
2154
                    reportSchemaError("sch-props-correct.2", new Object[]{qName}, currComp);
 
2155
                    return;
 
2156
                }
 
2157
                
 
2158
                String newName = qName.substring(qName.lastIndexOf(',')+1)+REDEF_IDENTIFIER;
 
2159
                if (redefinedSchema == currSchema) { // object comp. okay here
 
2160
                    // now have to do some renaming...
 
2161
                    currComp.setAttribute(SchemaSymbols.ATT_NAME, newName);
 
2162
                    if (currSchema.fTargetNamespace == null){
 
2163
                        registry.put(","+newName, currComp);
 
2164
                        registry_sub.put(","+newName, currSchema);
 
2165
                    }
 
2166
                    else{
 
2167
                        registry.put(currSchema.fTargetNamespace+","+newName, currComp);
 
2168
                        registry_sub.put(currSchema.fTargetNamespace+","+newName, currSchema);
 
2169
                    }
 
2170
                    // and take care of nested redefines by calling recursively:
 
2171
                    if (currSchema.fTargetNamespace == null)
 
2172
                        checkForDuplicateNames(","+newName, registry, registry_sub, currComp, currSchema);
 
2173
                    else
 
2174
                        checkForDuplicateNames(currSchema.fTargetNamespace+","+newName, registry, registry_sub, currComp, currSchema);
 
2175
                }
 
2176
                else { // we may be redefining the wrong schema
 
2177
                    if (collidedWithRedefine) {
 
2178
                        if (currSchema.fTargetNamespace == null)
 
2179
                            checkForDuplicateNames(","+newName, registry, registry_sub, currComp, currSchema);
 
2180
                        else
 
2181
                            checkForDuplicateNames(currSchema.fTargetNamespace+","+newName, registry, registry_sub, currComp, currSchema);
 
2182
                    }
 
2183
                    else {
 
2184
                        // error that redefined element in wrong schema
 
2185
                        reportSchemaError("sch-props-correct.2", new Object [] {qName}, currComp);
 
2186
                    }
 
2187
                }
 
2188
            }
 
2189
            else {
 
2190
                // we've just got a flat-out collision
 
2191
                reportSchemaError("sch-props-correct.2", new Object []{qName}, currComp);
 
2192
            }
 
2193
        }
 
2194
    } // checkForDuplicateNames(String, Hashtable, Element, XSDocumentInfo):void
 
2195
    
 
2196
    // the purpose of this method is to take the component of the
 
2197
    // specified type and rename references to itself so that they
 
2198
    // refer to the object being redefined.  It takes special care of
 
2199
    // <group>s and <attributeGroup>s to ensure that information
 
2200
    // relating to implicit restrictions is preserved for those
 
2201
    // traversers.
 
2202
    private void renameRedefiningComponents(XSDocumentInfo currSchema,
 
2203
            Element child, String componentType,
 
2204
            String oldName, String newName) {
 
2205
        if (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE)) {
 
2206
            Element grandKid = DOMUtil.getFirstChildElement(child);
 
2207
            if (grandKid == null) {
 
2208
                reportSchemaError("src-redefine.5.a.a", null, child);
 
2209
            }
 
2210
            else {
 
2211
                String grandKidName = DOMUtil.getLocalName(grandKid);
 
2212
                if (grandKidName.equals(SchemaSymbols.ELT_ANNOTATION)) {
 
2213
                    grandKid = DOMUtil.getNextSiblingElement(grandKid);
 
2214
                }
 
2215
                if (grandKid == null) {
 
2216
                    reportSchemaError("src-redefine.5.a.a", null, child);
 
2217
                }
 
2218
                else {
 
2219
                    grandKidName = DOMUtil.getLocalName(grandKid);
 
2220
                    if (!grandKidName.equals(SchemaSymbols.ELT_RESTRICTION)) {
 
2221
                        reportSchemaError("src-redefine.5.a.b", new Object[]{grandKidName}, child);
 
2222
                    }
 
2223
                    else {
 
2224
                        Object[] attrs = fAttributeChecker.checkAttributes(grandKid, false, currSchema);
 
2225
                        QName derivedBase = (QName)attrs[XSAttributeChecker.ATTIDX_BASE];
 
2226
                        if (derivedBase == null ||
 
2227
                                derivedBase.uri != currSchema.fTargetNamespace ||
 
2228
                                !derivedBase.localpart.equals(oldName)) {
 
2229
                            reportSchemaError("src-redefine.5.a.c",
 
2230
                                    new Object[]{grandKidName,
 
2231
                                    (currSchema.fTargetNamespace==null?"":currSchema.fTargetNamespace)
 
2232
                                    + "," + oldName},
 
2233
                                    child);
 
2234
                        }
 
2235
                        else {
 
2236
                            // now we have to do the renaming...
 
2237
                            if (derivedBase.prefix != null && derivedBase.prefix.length() > 0)
 
2238
                                grandKid.setAttribute( SchemaSymbols.ATT_BASE,
 
2239
                                        derivedBase.prefix + ":" + newName );
 
2240
                            else
 
2241
                                grandKid.setAttribute( SchemaSymbols.ATT_BASE, newName );
 
2242
                            //                            return true;
 
2243
                        }
 
2244
                        fAttributeChecker.returnAttrArray(attrs, currSchema);
 
2245
                    }
 
2246
                }
 
2247
            }
 
2248
        }
 
2249
        else if (componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) {
 
2250
            Element grandKid = DOMUtil.getFirstChildElement(child);
 
2251
            if (grandKid == null) {
 
2252
                reportSchemaError("src-redefine.5.b.a", null, child);
 
2253
            }
 
2254
            else {
 
2255
                if (DOMUtil.getLocalName(grandKid).equals(SchemaSymbols.ELT_ANNOTATION)) {
 
2256
                    grandKid = DOMUtil.getNextSiblingElement(grandKid);
 
2257
                }
 
2258
                if (grandKid == null) {
 
2259
                    reportSchemaError("src-redefine.5.b.a", null, child);
 
2260
                }
 
2261
                else {
 
2262
                    // have to go one more level down; let another pass worry whether complexType is valid.
 
2263
                    Element greatGrandKid = DOMUtil.getFirstChildElement(grandKid);
 
2264
                    if (greatGrandKid == null) {
 
2265
                        reportSchemaError("src-redefine.5.b.b", null, grandKid);
 
2266
                    }
 
2267
                    else {
 
2268
                        String greatGrandKidName = DOMUtil.getLocalName(greatGrandKid);
 
2269
                        if (greatGrandKidName.equals(SchemaSymbols.ELT_ANNOTATION)) {
 
2270
                            greatGrandKid = DOMUtil.getNextSiblingElement(greatGrandKid);
 
2271
                        }
 
2272
                        if (greatGrandKid == null) {
 
2273
                            reportSchemaError("src-redefine.5.b.b", null, grandKid);
 
2274
                        }
 
2275
                        else {
 
2276
                            greatGrandKidName = DOMUtil.getLocalName(greatGrandKid);
 
2277
                            if (!greatGrandKidName.equals(SchemaSymbols.ELT_RESTRICTION) &&
 
2278
                                    !greatGrandKidName.equals(SchemaSymbols.ELT_EXTENSION)) {
 
2279
                                reportSchemaError("src-redefine.5.b.c", new Object[]{greatGrandKidName}, greatGrandKid);
 
2280
                            }
 
2281
                            else {
 
2282
                                Object[] attrs = fAttributeChecker.checkAttributes(greatGrandKid, false, currSchema);
 
2283
                                QName derivedBase = (QName)attrs[XSAttributeChecker.ATTIDX_BASE];
 
2284
                                if (derivedBase == null ||
 
2285
                                        derivedBase.uri != currSchema.fTargetNamespace ||
 
2286
                                        !derivedBase.localpart.equals(oldName)) {
 
2287
                                    reportSchemaError("src-redefine.5.b.d",
 
2288
                                            new Object[]{greatGrandKidName,
 
2289
                                            (currSchema.fTargetNamespace==null?"":currSchema.fTargetNamespace)
 
2290
                                            + "," + oldName},
 
2291
                                            greatGrandKid);
 
2292
                                }
 
2293
                                else {
 
2294
                                    // now we have to do the renaming...
 
2295
                                    if (derivedBase.prefix != null && derivedBase.prefix.length() > 0)
 
2296
                                        greatGrandKid.setAttribute( SchemaSymbols.ATT_BASE,
 
2297
                                                derivedBase.prefix + ":" + newName );
 
2298
                                    else
 
2299
                                        greatGrandKid.setAttribute( SchemaSymbols.ATT_BASE,
 
2300
                                                newName );
 
2301
                                    //                                    return true;
 
2302
                                }
 
2303
                            }
 
2304
                        }
 
2305
                    }
 
2306
                }
 
2307
            }
 
2308
        }
 
2309
        else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
 
2310
            String processedBaseName = (currSchema.fTargetNamespace == null)?
 
2311
                    ","+oldName:currSchema.fTargetNamespace+","+oldName;
 
2312
            int attGroupRefsCount = changeRedefineGroup(processedBaseName, componentType, newName, child, currSchema);
 
2313
            if (attGroupRefsCount > 1) {
 
2314
                reportSchemaError("src-redefine.7.1", new Object []{new Integer(attGroupRefsCount)}, child);
 
2315
            }
 
2316
            else if (attGroupRefsCount == 1) {
 
2317
                //                return true;
 
2318
            }
 
2319
            else
 
2320
                if (currSchema.fTargetNamespace == null)
 
2321
                    fRedefinedRestrictedAttributeGroupRegistry.put(processedBaseName, ","+newName);
 
2322
                else
 
2323
                    fRedefinedRestrictedAttributeGroupRegistry.put(processedBaseName, currSchema.fTargetNamespace+","+newName);
 
2324
        }
 
2325
        else if (componentType.equals(SchemaSymbols.ELT_GROUP)) {
 
2326
            String processedBaseName = (currSchema.fTargetNamespace == null)?
 
2327
                    ","+oldName:currSchema.fTargetNamespace+","+oldName;
 
2328
            int groupRefsCount = changeRedefineGroup(processedBaseName, componentType, newName, child, currSchema);
 
2329
            if (groupRefsCount > 1) {
 
2330
                reportSchemaError("src-redefine.6.1.1", new Object []{new Integer(groupRefsCount)}, child);
 
2331
            }
 
2332
            else if (groupRefsCount == 1) {
 
2333
                //                return true;
 
2334
            }
 
2335
            else {
 
2336
                if (currSchema.fTargetNamespace == null)
 
2337
                    fRedefinedRestrictedGroupRegistry.put(processedBaseName, ","+newName);
 
2338
                else
 
2339
                    fRedefinedRestrictedGroupRegistry.put(processedBaseName, currSchema.fTargetNamespace+","+newName);
 
2340
            }
 
2341
        }
 
2342
        else {
 
2343
            reportSchemaError("Internal-Error", new Object [] {"could not handle this particular <redefine>; please submit your schemas and instance document in a bug report!"}, child);
 
2344
        }
 
2345
        // if we get here then we must have reported an error and failed somewhere...
 
2346
        //        return false;
 
2347
    } // renameRedefiningComponents(XSDocumentInfo, Element, String, String, String):void
 
2348
    
 
2349
    // this method takes a name of the form a:b, determines the URI mapped
 
2350
    // to by a in the current SchemaNamespaceSupport object, and returns this
 
2351
    // information in the form (nsURI,b) suitable for lookups in the global
 
2352
    // decl Hashtables.
 
2353
    // REVISIT: should have it return QName, instead of String. this would
 
2354
    //          save lots of string concatenation time. we can use
 
2355
    //          QName#equals() to compare two QNames, and use QName directly
 
2356
    //          as a key to the SymbolHash.
 
2357
    //          And when the DV's are ready to return compiled values from
 
2358
    //          validate() method, we should just call QNameDV.validate()
 
2359
    //          in this method.
 
2360
    private String findQName(String name, XSDocumentInfo schemaDoc) {
 
2361
        SchemaNamespaceSupport currNSMap = schemaDoc.fNamespaceSupport;
 
2362
        int colonPtr = name.indexOf(':');
 
2363
        String prefix = XMLSymbols.EMPTY_STRING;
 
2364
        if (colonPtr > 0)
 
2365
            prefix = name.substring(0, colonPtr);
 
2366
        String uri = currNSMap.getURI(fSymbolTable.addSymbol(prefix));
 
2367
        String localpart = (colonPtr == 0)?name:name.substring(colonPtr+1);
 
2368
        if (prefix == XMLSymbols.EMPTY_STRING && uri == null && schemaDoc.fIsChameleonSchema)
 
2369
            uri = schemaDoc.fTargetNamespace;
 
2370
        if (uri == null)
 
2371
            return ","+localpart;
 
2372
        return uri+","+localpart;
 
2373
    } // findQName(String, XSDocumentInfo):  String
 
2374
    
 
2375
    // This function looks among the children of curr for an element of type elementSought.
 
2376
    // If it finds one, it evaluates whether its ref attribute contains a reference
 
2377
    // to originalQName.  If it does, it returns 1 + the value returned by
 
2378
    // calls to itself on all other children.  In all other cases it returns 0 plus
 
2379
    // the sum of the values returned by calls to itself on curr's children.
 
2380
    // It also resets the value of ref so that it will refer to the renamed type from the schema
 
2381
    // being redefined.
 
2382
    private int changeRedefineGroup(String originalQName, String elementSought,
 
2383
            String newName, Element curr, XSDocumentInfo schemaDoc) {
 
2384
        int result = 0;
 
2385
        for (Element child = DOMUtil.getFirstChildElement(curr);
 
2386
        child != null; child = DOMUtil.getNextSiblingElement(child)) {
 
2387
            String name = DOMUtil.getLocalName(child);
 
2388
            if (!name.equals(elementSought))
 
2389
                result += changeRedefineGroup(originalQName, elementSought, newName, child, schemaDoc);
 
2390
            else {
 
2391
                String ref = child.getAttribute( SchemaSymbols.ATT_REF );
 
2392
                if (ref.length() != 0) {
 
2393
                    String processedRef = findQName(ref, schemaDoc);
 
2394
                    if (originalQName.equals(processedRef)) {
 
2395
                        String prefix = XMLSymbols.EMPTY_STRING;
 
2396
                        int colonptr = ref.indexOf(":");
 
2397
                        if (colonptr > 0) {
 
2398
                            prefix = ref.substring(0,colonptr);
 
2399
                            child.setAttribute(SchemaSymbols.ATT_REF, prefix + ":" + newName);
 
2400
                        }
 
2401
                        else
 
2402
                            child.setAttribute(SchemaSymbols.ATT_REF, newName);
 
2403
                        result++;
 
2404
                        if (elementSought.equals(SchemaSymbols.ELT_GROUP)) {
 
2405
                            String minOccurs = child.getAttribute( SchemaSymbols.ATT_MINOCCURS );
 
2406
                            String maxOccurs = child.getAttribute( SchemaSymbols.ATT_MAXOCCURS );
 
2407
                            if (!((maxOccurs.length() == 0 || maxOccurs.equals("1"))
 
2408
                                    && (minOccurs.length() == 0 || minOccurs.equals("1")))) {
 
2409
                                reportSchemaError("src-redefine.6.1.2", new Object [] {ref}, child);
 
2410
                            }
 
2411
                        }
 
2412
                    }
 
2413
                } // if ref was null some other stage of processing will flag the error
 
2414
            }
 
2415
        }
 
2416
        return result;
 
2417
    } // changeRedefineGroup
 
2418
    
 
2419
    // this method returns the XSDocumentInfo object that contains the
 
2420
    // component corresponding to decl.  If components from this
 
2421
    // document cannot be referred to from those of currSchema, this
 
2422
    // method returns null; it's up to the caller to throw an error.
 
2423
    // @param:  currSchema:  the XSDocumentInfo object containing the
 
2424
    // decl ref'ing us.
 
2425
    // @param:  decl:  the declaration being ref'd.
 
2426
    // this method is superficial now. ---Jack
 
2427
    private XSDocumentInfo findXSDocumentForDecl(XSDocumentInfo currSchema,
 
2428
            Element decl, XSDocumentInfo decl_Doc) {
 
2429
        
 
2430
        if (DEBUG_NODE_POOL) {
 
2431
            System.out.println("DOCUMENT NS:"+ currSchema.fTargetNamespace+" hashcode:"+ ((Object)currSchema.fSchemaElement).hashCode());
 
2432
        }
 
2433
        Object temp = decl_Doc;
 
2434
        if (temp == null) {
 
2435
            // something went badly wrong; we don't know this doc?
 
2436
            return null;
 
2437
        }
 
2438
        XSDocumentInfo declDocInfo = (XSDocumentInfo)temp;
 
2439
        return declDocInfo;
 
2440
        /*********
 
2441
         Logic here is unnecessary after schema WG's recent decision to allow
 
2442
         schema components from one document to refer to components of any other,
 
2443
         so long as there's some include/import/redefine path amongst them.
 
2444
         If they rver reverse this decision the code's right here though...  - neilg
 
2445
         // now look in fDependencyMap to see if this is reachable
 
2446
          if(((Vector)fDependencyMap.get(currSchema)).contains(declDocInfo)) {
 
2447
          return declDocInfo;
 
2448
          }
 
2449
          // obviously the requesting doc didn't include, redefine or
 
2450
           // import the one containing decl...
 
2451
            return null;
 
2452
            **********/
 
2453
    } // findXSDocumentForDecl(XSDocumentInfo, Element):  XSDocumentInfo
 
2454
    
 
2455
    // returns whether more than <annotation>s occur in children of elem
 
2456
    private boolean nonAnnotationContent(Element elem) {
 
2457
        for(Element child = DOMUtil.getFirstChildElement(elem); child != null; child = DOMUtil.getNextSiblingElement(child)) {
 
2458
            if(!(DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION))) return true;
 
2459
        }
 
2460
        return false;
 
2461
    } // nonAnnotationContent(Element):  boolean
 
2462
    
 
2463
    private void setSchemasVisible(XSDocumentInfo startSchema) {
 
2464
        if (DOMUtil.isHidden(startSchema.fSchemaElement, fHiddenNodes)) {
 
2465
            // make it visible
 
2466
            DOMUtil.setVisible(startSchema.fSchemaElement, fHiddenNodes);           
 
2467
            Vector dependingSchemas = (Vector)fDependencyMap.get(startSchema);
 
2468
            for (int i = 0; i < dependingSchemas.size(); i++) {
 
2469
                setSchemasVisible((XSDocumentInfo)dependingSchemas.elementAt(i));
 
2470
            }
 
2471
        }
 
2472
        // if it's visible already than so must be its children
 
2473
    } // setSchemasVisible(XSDocumentInfo): void
 
2474
    
 
2475
    private SimpleLocator xl = new SimpleLocator();
 
2476
    
 
2477
    /**
 
2478
     * Extract location information from an Element node, and create a
 
2479
     * new SimpleLocator object from such information. Returning null means
 
2480
     * no information can be retrieved from the element.
 
2481
     */
 
2482
    public SimpleLocator element2Locator(Element e) {
 
2483
        if (!( e instanceof ElementImpl))
 
2484
            return null;
 
2485
        
 
2486
        SimpleLocator l = new SimpleLocator();
 
2487
        return element2Locator(e, l) ? l : null;
 
2488
    }
 
2489
    
 
2490
    /**
 
2491
     * Extract location information from an Element node, store such
 
2492
     * information in the passed-in SimpleLocator object, then return
 
2493
     * true. Returning false means can't extract or store such information.
 
2494
     */
 
2495
    public boolean element2Locator(Element e, SimpleLocator l) {
 
2496
        if (l == null)
 
2497
            return false;
 
2498
        if (e instanceof ElementImpl) {
 
2499
            ElementImpl ele = (ElementImpl)e;
 
2500
            // get system id from document object
 
2501
            Document doc = ele.getOwnerDocument();
 
2502
            String sid = (String)fDoc2SystemId.get(DOMUtil.getRoot(doc));
 
2503
            // line/column numbers are stored in the element node
 
2504
            int line = ele.getLineNumber();
 
2505
            int column = ele.getColumnNumber();
 
2506
            l.setValues(sid, sid, line, column, ele.getCharacterOffset());
 
2507
            return true;
 
2508
        }
 
2509
        return false;
 
2510
    }
 
2511
    
 
2512
    void reportSchemaError(String key, Object[] args, Element ele) {
 
2513
        if (element2Locator(ele, xl)) {
 
2514
            fErrorReporter.reportError(xl, XSMessageFormatter.SCHEMA_DOMAIN,
 
2515
                    key, args, XMLErrorReporter.SEVERITY_ERROR);
 
2516
        }
 
2517
        else {
 
2518
            fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN,
 
2519
                    key, args, XMLErrorReporter.SEVERITY_ERROR);
 
2520
        }
 
2521
    }
 
2522
    
 
2523
    void reportSchemaWarning(String key, Object[] args, Element ele) {
 
2524
        if (element2Locator(ele, xl)) {
 
2525
            fErrorReporter.reportError(xl, XSMessageFormatter.SCHEMA_DOMAIN,
 
2526
                    key, args, XMLErrorReporter.SEVERITY_WARNING);
 
2527
        }
 
2528
        else {
 
2529
            fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN,
 
2530
                    key, args, XMLErrorReporter.SEVERITY_WARNING);
 
2531
        }
 
2532
    }
 
2533
    
 
2534
    /**
 
2535
     * Grammar pool used for validating annotations. This will return all of the
 
2536
     * grammars from the grammar bucket. It will also return an object for the
 
2537
     * schema for schemas which will contain at least the relevant declarations
 
2538
     * for annotations.
 
2539
     */
 
2540
    private static class XSAnnotationGrammarPool implements XMLGrammarPool {
 
2541
        
 
2542
        private XSGrammarBucket fGrammarBucket;
 
2543
        private Grammar [] fInitialGrammarSet;
 
2544
        
 
2545
        public Grammar[] retrieveInitialGrammarSet(String grammarType) {
 
2546
            if (grammarType == XMLGrammarDescription.XML_SCHEMA) {
 
2547
                if (fInitialGrammarSet == null) {
 
2548
                    if (fGrammarBucket == null) {
 
2549
                        fInitialGrammarSet = new Grammar [] {SchemaGrammar.SG_Schema4Annotations};
 
2550
                    }
 
2551
                    else {
 
2552
                        SchemaGrammar [] schemaGrammars = fGrammarBucket.getGrammars();
 
2553
                        /** 
 
2554
                         * If the grammar bucket already contains the schema for schemas
 
2555
                         * then we already have the definitions for the parts relevant
 
2556
                         * to annotations.
 
2557
                         */
 
2558
                        for (int i = 0; i < schemaGrammars.length; ++i) {
 
2559
                            if (SchemaSymbols.URI_SCHEMAFORSCHEMA.equals(schemaGrammars[i].getTargetNamespace())) {
 
2560
                                fInitialGrammarSet = schemaGrammars;
 
2561
                                return fInitialGrammarSet;
 
2562
                            }
 
2563
                        }
 
2564
                        Grammar [] grammars = new Grammar[schemaGrammars.length + 1];
 
2565
                        System.arraycopy(schemaGrammars, 0, grammars, 0, schemaGrammars.length);
 
2566
                        grammars[grammars.length - 1] = SchemaGrammar.SG_Schema4Annotations;
 
2567
                        fInitialGrammarSet = grammars;
 
2568
                    }
 
2569
                }
 
2570
                return fInitialGrammarSet;
 
2571
            }
 
2572
            return new Grammar[0];
 
2573
        }
 
2574
 
 
2575
        public void cacheGrammars(String grammarType, Grammar[] grammars) {
 
2576
            
 
2577
        }
 
2578
 
 
2579
        public Grammar retrieveGrammar(XMLGrammarDescription desc) {
 
2580
            if (desc.getGrammarType() == XMLGrammarDescription.XML_SCHEMA) {
 
2581
                final String tns = ((XMLSchemaDescription) desc).getTargetNamespace();
 
2582
                if (fGrammarBucket != null) {
 
2583
                    Grammar grammar = fGrammarBucket.getGrammar(tns);
 
2584
                    if (grammar != null) {
 
2585
                        return grammar;
 
2586
                    }
 
2587
                }
 
2588
                if (SchemaSymbols.URI_SCHEMAFORSCHEMA.equals(tns)) {
 
2589
                    return SchemaGrammar.SG_Schema4Annotations;
 
2590
                }
 
2591
            }
 
2592
            return null;
 
2593
        }
 
2594
        
 
2595
        public void refreshGrammars(XSGrammarBucket gBucket) {
 
2596
            fGrammarBucket = gBucket;
 
2597
            fInitialGrammarSet = null;
 
2598
        }
 
2599
 
 
2600
        public void lockPool() {}
 
2601
 
 
2602
        public void unlockPool() {}
 
2603
 
 
2604
        public void clear() {}
 
2605
    }
 
2606
 
 
2607
    /**
 
2608
     * used to identify a reference to a schema document
 
2609
     * if the same document is referenced twice with the same key, then
 
2610
     * we only need to parse it once.
 
2611
     *
 
2612
     * When 2 XSDKey's are compared, the following table can be used to
 
2613
     * determine whether they are equal:
 
2614
     *      inc     red     imp     pre     ins
 
2615
     * inc  N/L      ?      N/L     N/L     N/L
 
2616
     * red   ?      N/L      ?       ?       ?
 
2617
     * imp  N/L      ?      N/P     N/P     N/P
 
2618
     * pre  N/L      ?      N/P     N/P     N/P
 
2619
     * ins  N/L      ?      N/P     N/P     N/P
 
2620
     *
 
2621
     * Where: N/L: duplicate when they have the same namespace and location.
 
2622
     *         ? : not clear from the spec.
 
2623
     *             REVISIT: to simplify the process, also considering
 
2624
     *             it's very rare, we treat them as not duplicate.
 
2625
     *        N/P: not possible. imp/pre/ins are referenced by namespace.
 
2626
     *             when the first time we encounter a schema document for a
 
2627
     *             namespace, we create a grammar and store it in the grammar
 
2628
     *             bucket. when we see another reference to the same namespace,
 
2629
     *             we first check whether a grammar with the same namespace is
 
2630
     *             already in the bucket, which is true in this case, so we
 
2631
     *             won't create another XSDKey.
 
2632
     *
 
2633
     * Conclusion from the table: two XSDKey's are duplicate only when all of
 
2634
     * the following are true:
 
2635
     * 1. They are both "redefine", or neither is "redefine";
 
2636
     * 2. They have the same namespace;
 
2637
     * 3. They have the same non-null location.
 
2638
     *
 
2639
     * About 3: if neither has a non-null location, then it's the case where
 
2640
     * 2 input streams are provided, but no system ID is provided. We can't tell
 
2641
     * whether the 2 streams have the same content, so we treat them as not
 
2642
     * duplicate.
 
2643
     */
 
2644
    private static class XSDKey {
 
2645
        String systemId;
 
2646
        short  referType;
 
2647
        // for inclue/redefine, this is the enclosing namespace
 
2648
        // for import/preparse/instance, this is the target namespace
 
2649
        String referNS;
 
2650
        
 
2651
        XSDKey(String systemId, short referType, String referNS) {
 
2652
            this.systemId = systemId;
 
2653
            this.referType = referType;
 
2654
            this.referNS = referNS;
 
2655
        }
 
2656
        
 
2657
        public int hashCode() {
 
2658
            // according to the description at the beginning of this class,
 
2659
            // we use the hashcode of the namespace as the hashcoe of this key.
 
2660
            return referNS == null ? 0 : referNS.hashCode();
 
2661
        }
 
2662
        
 
2663
        public boolean equals(Object obj) {
 
2664
            if (!(obj instanceof XSDKey)) {
 
2665
                return false;
 
2666
            }
 
2667
            XSDKey key = (XSDKey)obj;
 
2668
            
 
2669
            // condition 1: both are redefine
 
2670
            /** if (referType == XSDDescription.CONTEXT_REDEFINE ||
 
2671
                    key.referType == XSDDescription.CONTEXT_REDEFINE) {
 
2672
                if (referType != key.referType)
 
2673
                    return false;
 
2674
            }**/
 
2675
            
 
2676
            // condition 2: same namespace
 
2677
            if (referNS != key.referNS)
 
2678
                return false;
 
2679
            
 
2680
            // condition 3: same non-null location
 
2681
            if (systemId == null || !systemId.equals(key.systemId)) {
 
2682
                return false;
 
2683
            }
 
2684
            
 
2685
            return true;
 
2686
        }
 
2687
    }
 
2688
    
 
2689
    /**
 
2690
     * @param state
 
2691
     */
 
2692
    public void setGenerateSyntheticAnnotations(boolean state) {
 
2693
        fSchemaParser.setFeature(GENERATE_SYNTHETIC_ANNOTATIONS, state);
 
2694
    }
 
2695
    
 
2696
} // XSDHandler