KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xerces > internal > impl > xs > traversers > XSDHandler


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 1999-2004 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Xerces" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation and was
52  * originally based on software copyright (c) 1999, International
53  * Business Machines, Inc., http://www.apache.org. For more
54  * information on the Apache Software Foundation, please see
55  * <http://www.apache.org/>.
56  */

57
58 package com.sun.org.apache.xerces.internal.impl.xs.traversers;
59
60 import java.io.IOException JavaDoc;
61 import java.util.Hashtable JavaDoc;
62 import java.util.Stack JavaDoc;
63 import java.util.Vector JavaDoc;
64
65 import javax.xml.transform.Source JavaDoc;
66 import javax.xml.transform.Transformer JavaDoc;
67 import javax.xml.transform.TransformerException JavaDoc;
68 import javax.xml.transform.TransformerFactory JavaDoc;
69 import javax.xml.transform.dom.DOMSource JavaDoc;
70 import javax.xml.transform.sax.SAXSource JavaDoc;
71 import javax.xml.transform.sax.SAXResult JavaDoc;
72 import javax.xml.transform.stream.StreamSource JavaDoc;
73
74 import com.sun.org.apache.xerces.internal.impl.Constants;
75 import com.sun.org.apache.xerces.internal.impl.XMLEntityManager;
76 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
77 import com.sun.org.apache.xerces.internal.impl.xs.SchemaGrammar;
78 import com.sun.org.apache.xerces.internal.impl.xs.SchemaNamespaceSupport;
79 import com.sun.org.apache.xerces.internal.impl.xs.SchemaSymbols;
80 import com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaException;
81 import com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader;
82 import com.sun.org.apache.xerces.internal.impl.xs.XSComplexTypeDecl;
83 import com.sun.org.apache.xerces.internal.impl.xs.XSDDescription;
84 import com.sun.org.apache.xerces.internal.impl.xs.XSDeclarationPool;
85 import com.sun.org.apache.xerces.internal.impl.xs.XSElementDecl;
86 import com.sun.org.apache.xerces.internal.impl.xs.XSGrammarBucket;
87 import com.sun.org.apache.xerces.internal.impl.xs.XSGroupDecl;
88 import com.sun.org.apache.xerces.internal.impl.xs.XSMessageFormatter;
89 import com.sun.org.apache.xerces.internal.impl.xs.XSModelGroupImpl;
90 import com.sun.org.apache.xerces.internal.impl.xs.XSParticleDecl;
91 import com.sun.org.apache.xerces.internal.impl.xs.opti.ElementImpl;
92 import com.sun.org.apache.xerces.internal.impl.xs.opti.SchemaDOM;
93 import com.sun.org.apache.xerces.internal.impl.xs.opti.SchemaDOMParser;
94 import com.sun.org.apache.xerces.internal.impl.xs.opti.SchemaParsingConfig;
95 import com.sun.org.apache.xerces.internal.impl.xs.util.SimpleLocator;
96 import com.sun.org.apache.xerces.internal.parsers.SAXParser;
97 import com.sun.org.apache.xerces.internal.util.DOMUtil;
98 import com.sun.org.apache.xerces.internal.util.SecurityManager;
99 import com.sun.org.apache.xerces.internal.util.SAX2XNI;
100 import com.sun.org.apache.xerces.internal.util.SymbolTable;
101 import com.sun.org.apache.xerces.internal.util.XMLInputSourceAdaptor;
102 import com.sun.org.apache.xerces.internal.util.XMLSymbols;
103 import com.sun.org.apache.xerces.internal.xni.QName;
104 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool;
105 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
106 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
107 import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver;
108 import com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler;
109 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
110 import com.sun.org.apache.xerces.internal.xs.XSObject;
111 import org.w3c.dom.Document JavaDoc;
112 import org.w3c.dom.Element JavaDoc;
113 import org.w3c.dom.Node JavaDoc;
114 import org.xml.sax.XMLReader JavaDoc;
115 import org.xml.sax.SAXException JavaDoc;
116
117 /**
118  * The purpose of this class is to co-ordinate the construction of a
119  * grammar object corresponding to a schema. To do this, it must be
120  * prepared to parse several schema documents (for instance if the
121  * schema document originally referred to contains <include> or
122  * <redefined> information items). If any of the schemas imports a
123  * schema, other grammars may be constructed as a side-effect.
124  *
125  * @author Neil Graham, IBM
126  * @author Pavani Mukthipudi, Sun Microsystems
127  * @version $Id: XSDHandler.java,v 1.75 2004/02/03 17:27:45 sandygao Exp $
128  */

129 public class XSDHandler {
130
131     /** Feature identifier: allow java encodings */
132     protected static final String JavaDoc ALLOW_JAVA_ENCODINGS =
133         Constants.XERCES_FEATURE_PREFIX + Constants.ALLOW_JAVA_ENCODINGS_FEATURE;
134
135     /** Feature identifier: continue after fatal error */
136     protected static final String JavaDoc CONTINUE_AFTER_FATAL_ERROR =
137         Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE;
138
139     /** Feature identifier: allow java encodings */
140     protected static final String JavaDoc STANDARD_URI_CONFORMANT_FEATURE =
141         Constants.XERCES_FEATURE_PREFIX + Constants.STANDARD_URI_CONFORMANT_FEATURE;
142         
143     /** Feature: disallow doctype*/
144     protected static final String JavaDoc DISALLOW_DOCTYPE =
145         Constants.XERCES_FEATURE_PREFIX + Constants.DISALLOW_DOCTYPE_DECL_FEATURE;
146
147     /** Property identifier: error handler. */
148     protected static final String JavaDoc ERROR_HANDLER =
149         Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY;
150
151     /** Property identifier: JAXP schema source. */
152     protected static final String JavaDoc JAXP_SCHEMA_SOURCE =
153         Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE;
154
155     /** Property identifier: entity resolver. */
156     public static final String JavaDoc ENTITY_RESOLVER =
157     Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
158     
159     private static final String JavaDoc SECURE_PROCESSING =
160         Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
161     
162     /** Property identifier: entity manager. */
163     protected static final String JavaDoc ENTITY_MANAGER =
164             Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;
165     
166     /** Property identifier: error reporter. */
167     public static final String JavaDoc ERROR_REPORTER =
168         Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
169         
170     /** Property identifier: grammar pool. */
171     public static final String JavaDoc XMLGRAMMAR_POOL =
172         Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;
173         
174     /** Property identifier: symbol table. */
175     public static final String JavaDoc SYMBOL_TABLE =
176         Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
177         
178     protected static final String JavaDoc SECURITY_MANAGER =
179         Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
180
181     /**
182      * Property identifier: security manager.
183      */

184     protected static final boolean DEBUG_NODE_POOL = false;
185                               
186     // Data
187

188     // different sorts of declarations; should make lookup and
189
// traverser calling more efficient/less bulky.
190
final static int ATTRIBUTE_TYPE = 1;
191     final static int ATTRIBUTEGROUP_TYPE = 2;
192     final static int ELEMENT_TYPE = 3;
193     final static int GROUP_TYPE = 4;
194     final static int IDENTITYCONSTRAINT_TYPE = 5;
195     final static int NOTATION_TYPE = 6;
196     final static int TYPEDECL_TYPE = 7;
197
198     // this string gets appended to redefined names; it's purpose is to be
199
// as unlikely as possible to cause collisions.
200
public final static String JavaDoc REDEF_IDENTIFIER = "_fn3dktizrknc9pi";
201
202     //
203
//protected data that can be accessable by any traverser
204
// stores <notation> decl
205
protected Hashtable JavaDoc fNotationRegistry = new Hashtable JavaDoc();
206
207     protected XSDeclarationPool fDeclPool = null;
208
209     // are java encodings allowed?
210
private boolean fAllowJavaEncodings = false;
211     
212     // enforcing strict uri?
213
private boolean fStrictURI = false;
214     
215     /**
216      * <p>Security manager in effect.</p>
217      *
218      * <p>Protected to allow access by any traverser.</p>
219      */

220     protected SecurityManager JavaDoc fSecureProcessing = null;
221
222     // These tables correspond to the symbol spaces defined in the
223
// spec.
224
// They are keyed with a QName (that is, String("URI,localpart) and
225
// their values are nodes corresponding to the given name's decl.
226
// By asking the node for its ownerDocument and looking in
227
// XSDocumentInfoRegistry we can easily get the corresponding
228
// XSDocumentInfo object.
229
private Hashtable JavaDoc fUnparsedAttributeRegistry = new Hashtable JavaDoc();
230     private Hashtable JavaDoc fUnparsedAttributeGroupRegistry = new Hashtable JavaDoc();
231     private Hashtable JavaDoc fUnparsedElementRegistry = new Hashtable JavaDoc();
232     private Hashtable JavaDoc fUnparsedGroupRegistry = new Hashtable JavaDoc();
233     private Hashtable JavaDoc fUnparsedIdentityConstraintRegistry = new Hashtable JavaDoc();
234     private Hashtable JavaDoc fUnparsedNotationRegistry = new Hashtable JavaDoc();
235     private Hashtable JavaDoc fUnparsedTypeRegistry = new Hashtable JavaDoc();
236     // this is keyed with a documentNode (or the schemaRoot nodes
237
// contained in the XSDocumentInfo objects) and its value is the
238
// XSDocumentInfo object corresponding to that document.
239
// Basically, the function of this registry is to be a link
240
// between the nodes we fetch from calls to the fUnparsed*
241
// arrays and the XSDocumentInfos they live in.
242
private Hashtable JavaDoc fXSDocumentInfoRegistry = new Hashtable JavaDoc();
243
244     // this hashtable is keyed on by XSDocumentInfo objects. Its values
245
// are Vectors containing the XSDocumentInfo objects <include>d,
246
// <import>ed or <redefine>d by the key XSDocumentInfo.
247
private Hashtable JavaDoc fDependencyMap = new Hashtable JavaDoc();
248
249     // this hashtable is keyed on by a target namespace. Its values
250
// are Vectors containing namespaces imported by schema documents
251
// with the key target namespace.
252
// if an imprted schema has absent namespace, the value "null" is stored.
253
private Hashtable JavaDoc fImportMap = new Hashtable JavaDoc();
254     // all namespaces that imports other namespaces
255
// if the importing schema has absent namespace, empty string is stored.
256
// (because the key of a hashtable can't be null.)
257
private Vector JavaDoc fAllTNSs = new Vector JavaDoc();
258     // stores instance document mappings between namespaces and schema hints
259
private Hashtable JavaDoc fLocationPairs = null;
260
261     // convenience methods
262
private String JavaDoc null2EmptyString(String JavaDoc ns) {
263         return ns == null ? XMLSymbols.EMPTY_STRING : ns;
264     }
265     private String JavaDoc emptyString2Null(String JavaDoc ns) {
266         return ns == XMLSymbols.EMPTY_STRING ? null : ns;
267     }
268
269     // This vector stores strings which are combinations of the
270
// publicId and systemId of the inputSource corresponding to a
271
// schema document. This combination is used so that the user's
272
// EntityResolver can provide a consistent way of identifying a
273
// schema document that is included in multiple other schemas.
274
private Hashtable JavaDoc fTraversed = new Hashtable JavaDoc();
275
276     // this hashtable contains a mapping from Document to its systemId
277
// this is useful to resolve a uri relative to the referring document
278
private Hashtable JavaDoc fDoc2SystemId = new Hashtable JavaDoc();
279
280     // the primary XSDocumentInfo we were called to parse
281
private XSDocumentInfo fRoot = null;
282
283     // This hashtable's job is to act as a link between the document
284
// node at the root of the parsed schema's tree and its
285
// XSDocumentInfo object.
286
private Hashtable JavaDoc fDoc2XSDocumentMap = new Hashtable JavaDoc();
287
288     // map between <redefine> elements and the XSDocumentInfo
289
// objects that correspond to the documents being redefined.
290
private Hashtable JavaDoc fRedefine2XSDMap = new Hashtable JavaDoc();
291     
292     // map between <redefine> elements and the namespace support
293
private Hashtable JavaDoc fRedefine2NSSupport = new Hashtable JavaDoc();
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 JavaDoc fRedefinedRestrictedAttributeGroupRegistry = new Hashtable JavaDoc();
301     private Hashtable JavaDoc fRedefinedRestrictedGroupRegistry = new Hashtable JavaDoc();
302
303     // a variable storing whether the last schema document
304
// processed (by getSchema) was a duplicate.
305
private boolean fLastSchemaWasDuplicate;
306
307     // the XMLErrorReporter
308
private XMLErrorReporter fErrorReporter;
309     private XMLEntityResolver fEntityResolver;
310
311     // the XSAttributeChecker
312
private XSAttributeChecker fAttributeChecker;
313
314     // the symbol table
315
private SymbolTable fSymbolTable;
316
317     // the GrammarResolver
318
private XSGrammarBucket fGrammarBucket;
319     
320     // the Grammar description
321
private XSDDescription fSchemaGrammarDescription;
322     
323     // the Grammar Pool
324
private XMLGrammarPool fGrammarPool;
325
326     //************ Traversers **********
327
XSDAttributeGroupTraverser fAttributeGroupTraverser;
328     XSDAttributeTraverser fAttributeTraverser;
329     XSDComplexTypeTraverser fComplexTypeTraverser;
330     XSDElementTraverser fElementTraverser;
331     XSDGroupTraverser fGroupTraverser;
332     XSDKeyrefTraverser fKeyrefTraverser;
333     XSDNotationTraverser fNotationTraverser;
334     XSDSimpleTypeTraverser fSimpleTypeTraverser;
335     XSDUniqueOrKeyTraverser fUniqueOrKeyTraverser;
336     XSDWildcardTraverser fWildCardTraverser;
337
338     //DOMParser fSchemaParser;
339
SchemaParsingConfig fSchemaParser;
340
341     // these data members are needed for the deferred traversal
342
// of local elements.
343

344     // the initial size of the array to store deferred local elements
345
private static final int INIT_STACK_SIZE = 30;
346     // the incremental size of the array to store deferred local elements
347
private static final int INC_STACK_SIZE = 10;
348     // current position of the array (# of deferred local elements)
349
private int fLocalElemStackPos = 0;
350
351     private XSParticleDecl[] fParticle = new XSParticleDecl[INIT_STACK_SIZE];
352     private Element JavaDoc[] fLocalElementDecl = new Element JavaDoc[INIT_STACK_SIZE];
353     private int[] fAllContext = new int[INIT_STACK_SIZE];
354     private XSObject[] fParent = new XSObject[INIT_STACK_SIZE];
355     private String JavaDoc [][] fLocalElemNamespaceContext = new String JavaDoc [INIT_STACK_SIZE][1];
356
357     // these data members are needed for the deferred traversal
358
// of keyrefs.
359

360     // the initial size of the array to store deferred keyrefs
361
private static final int INIT_KEYREF_STACK = 2;
362     // the incremental size of the array to store deferred keyrefs
363
private static final int INC_KEYREF_STACK_AMOUNT = 2;
364     // current position of the array (# of deferred keyrefs)
365
private int fKeyrefStackPos = 0;
366
367     private Element JavaDoc [] fKeyrefs = new Element JavaDoc[INIT_KEYREF_STACK];
368     private XSElementDecl [] fKeyrefElems = new XSElementDecl [INIT_KEYREF_STACK];
369     private String JavaDoc [][] fKeyrefNamespaceContext = new String JavaDoc[INIT_KEYREF_STACK][1];
370
371     // Constructors
372
public XSDHandler(){
373         fSchemaParser = new SchemaParsingConfig();
374     }
375
376     // it should be possible to use the same XSDHandler to parse
377
// multiple schema documents; this will allow one to be
378
// constructed.
379
public XSDHandler (XSGrammarBucket gBucket) {
380         this();
381         fGrammarBucket = gBucket;
382
383         // Note: don't use SchemaConfiguration internally
384
// we will get stack overflaw because
385
// XMLSchemaValidator will be instantiating XSDHandler...
386
fSchemaGrammarDescription = new XSDDescription();
387     } // end constructor
388

389
390     
391
392     /**
393      * This method initiates the parse of a schema. It will likely be
394      * called from the Validator and it will make the
395      * resulting grammar available; it returns a reference to this object just
396      * in case. A reset(XMLComponentManager) must be called before this methods is called.
397      * @param is
398      * @param desc
399      * @param locationPairs
400      * @return
401      * @throws IOException
402      */

403     public SchemaGrammar parseSchema(Source JavaDoc source, XSDDescription desc,
404                                      Hashtable JavaDoc locationPairs)
405             throws IOException JavaDoc {
406         fLocationPairs = locationPairs;
407                
408         if (fSchemaParser != null) {
409             fSchemaParser.resetNodePool();
410         }
411         
412         SchemaGrammar grammar = null;
413         String JavaDoc schemaNamespace = null;
414         short referType = desc.getContextType();
415         // if loading using JAXP schemaSource property, or using grammar caching loadGrammar
416
// the desc.targetNamespace is always null.
417
// Therefore we should not attempt to find out if
418
// the schema is already in the bucket, since in the case we have
419
// no namespace schema in the bucket, findGrammar will always return the
420
// no namespace schema.
421
if (referType != XSDDescription.CONTEXT_PREPARSE){
422             // first try to find it in the bucket/pool, return if one is found
423
grammar = findGrammar(desc);
424             if (grammar != null)
425                 return grammar;
426             schemaNamespace = desc.getTargetNamespace();
427             // handle empty string URI as null
428
if (schemaNamespace != null) {
429                 schemaNamespace = fSymbolTable.addSymbol(schemaNamespace);
430             }
431         }
432
433         // before parsing a schema, need to clear registries associated with
434
// parsing schemas
435
prepareForParse();
436
437         // first phase: construct trees.
438
Document JavaDoc schemaRoot = getSchema(schemaNamespace, source,
439                                         referType == XSDDescription.CONTEXT_PREPARSE,
440                                         referType, null);
441         if (schemaRoot == null) {
442             // something went wrong right off the hop
443
return null;
444         }
445         if ( referType == XSDDescription.CONTEXT_PREPARSE) {
446             Element JavaDoc schemaElem = DOMUtil.getRoot(schemaRoot);
447             schemaNamespace = DOMUtil.getAttrValue(schemaElem, SchemaSymbols.ATT_TARGETNAMESPACE);
448             if(schemaNamespace != null && schemaNamespace.length() > 0) {
449                 // Since now we've discovered a namespace, we need to update xsd key
450
// and store this schema in traversed schemas bucket
451
schemaNamespace = fSymbolTable.addSymbol(schemaNamespace);
452                 desc.setTargetNamespace(schemaNamespace);
453             }
454             else {
455                 schemaNamespace = null;
456             }
457             grammar = findGrammar(desc);
458             if (grammar != null)
459                 return grammar;
460             String JavaDoc schemaId = source.getSystemId();
461             XSDKey key = new XSDKey(schemaId, referType, schemaNamespace);
462             fTraversed.put(key, schemaRoot );
463             if (schemaId != null) {
464                 fDoc2SystemId.put(schemaRoot, schemaId );
465             }
466         }
467
468         // before constructing trees and traversing a schema, need to reset
469
// all traversers and clear all registries
470
prepareForTraverse();
471
472         fRoot = constructTrees(schemaRoot, source.getSystemId(), desc);
473         if (fRoot == null) {
474             return null;
475         }
476
477         // second phase: fill global registries.
478
buildGlobalNameRegistries();
479
480         // third phase: call traversers
481
traverseSchemas();
482
483         // fourth phase: handle local element decls
484
traverseLocalElements();
485
486         // fifth phase: handle Keyrefs
487
resolveKeyRefs();
488
489         // sixth phase: validate attribute of non-schema namespaces
490
// REVISIT: skip this for now. we really don't want to do it.
491
//fAttributeChecker.checkNonSchemaAttributes(fGrammarBucket);
492

493         // seventh phase: store imported grammars
494
// for all grammars with <import>s
495
for (int i = fAllTNSs.size() - 1; i >= 0; i--) {
496             // get its target namespace
497
String JavaDoc tns = (String JavaDoc)fAllTNSs.elementAt(i);
498             // get all namespaces it imports
499
Vector JavaDoc ins = (Vector JavaDoc)fImportMap.get(tns);
500             // get the grammar
501
SchemaGrammar sg = fGrammarBucket.getGrammar(emptyString2Null(tns));
502             if (sg == null)
503                 continue;
504             SchemaGrammar isg;
505             // for imported namespace
506
int count = 0;
507             for (int j = 0; j < ins.size(); j++) {
508                 // get imported grammar
509
isg = fGrammarBucket.getGrammar((String JavaDoc)ins.elementAt(j));
510                 // reuse the same vector
511
if (isg != null)
512                     ins.setElementAt(isg, count++);
513             }
514             ins.setSize(count);
515             // set the imported grammars
516
sg.setImportedGrammars(ins);
517         }
518
519         // and return.
520
return fGrammarBucket.getGrammar(fRoot.fTargetNamespace);
521     } // end parseSchema
522

523     /**
524      * Pull the grammar out of the bucket simply using
525      * its TNS as a key
526      */

527     SchemaGrammar getGrammar(String JavaDoc tns) {
528         return fGrammarBucket.getGrammar(tns);
529     }
530
531     /**
532      * First try to find a grammar in the bucket, if failed, consult the
533      * grammar pool. If a grammar is found in the pool, then add it (and all
534      * imported ones) into the bucket.
535      */

536     protected SchemaGrammar findGrammar(XSDDescription desc) {
537         SchemaGrammar sg = fGrammarBucket.getGrammar(desc.getTargetNamespace());
538         if (sg == null) {
539             if (fGrammarPool != null) {
540                 sg = (SchemaGrammar)fGrammarPool.retrieveGrammar(desc);
541                 if (sg != null) {
542                     // put this grammar into the bucket, along with grammars
543
// imported by it (directly or indirectly)
544
if (!fGrammarBucket.putGrammar(sg, true)) {
545                         // REVISIT: a conflict between new grammar(s) and grammars
546
// in the bucket. What to do? A warning? An exception?
547
reportSchemaWarning("GrammarConflict", null, null);
548                         sg = null;
549                     }
550                 }
551             }
552         }
553         return sg;
554     }
555     
556     // may wish to have setter methods for ErrorHandler,
557
// EntityResolver...
558

559     private static final String JavaDoc[][] NS_ERROR_CODES = {
560         {"src-include.2.1", "src-include.2.1"},
561         {"src-redefine.3.1", "src-redefine.3.1"},
562         {"src-import.3.1", "src-import.3.2"},
563         null,
564         {"TargetNamespace.1", "TargetNamespace.2"},
565         {"TargetNamespace.1", "TargetNamespace.2"},
566         {"TargetNamespace.1", "TargetNamespace.2"},
567         {"TargetNamespace.1", "TargetNamespace.2"}
568     };
569     
570     private static final String JavaDoc[] ELE_ERROR_CODES = {
571         "src-include.1", "src-redefine.2", "src-import.2", "schema_reference.4",
572         "schema_reference.4", "schema_reference.4", "schema_reference.4", "schema_reference.4"
573     };
574     
575     // This method does several things:
576
// It constructs an instance of an XSDocumentInfo object using the
577
// schemaRoot node. Then, for each <include>,
578
// <redefine>, and <import> children, it attempts to resolve the
579
// requested schema document, initiates a DOM parse, and calls
580
// itself recursively on that document's root. It also records in
581
// the DependencyMap object what XSDocumentInfo objects its XSDocumentInfo
582
// depends on.
583
// It also makes sure the targetNamespace of the schema it was
584
// called to parse is correct.
585
protected XSDocumentInfo constructTrees(Document JavaDoc schemaRoot, String JavaDoc locationHint, XSDDescription desc) {
586         if (schemaRoot == null) return null;
587         String JavaDoc callerTNS = desc.getTargetNamespace();
588         short referType = desc.getContextType();
589         
590         XSDocumentInfo currSchemaInfo = null;
591         try {
592             // note that attributes are freed at end of traverseSchemas()
593
currSchemaInfo = new XSDocumentInfo(schemaRoot, fAttributeChecker, fSymbolTable);
594         } catch (XMLSchemaException se) {
595             reportSchemaError(ELE_ERROR_CODES[referType],
596                               new Object JavaDoc[]{locationHint},
597                               DOMUtil.getRoot(schemaRoot));
598             return null;
599         }
600         // targetNamespace="" is not valid, issue a warning, and ignore it
601
if (currSchemaInfo.fTargetNamespace != null &&
602             currSchemaInfo.fTargetNamespace.length() == 0) {
603             reportSchemaWarning("EmptyTargetNamespace",
604                                 new Object JavaDoc[]{locationHint},
605                                 DOMUtil.getRoot(schemaRoot));
606             currSchemaInfo.fTargetNamespace = null;
607         }
608
609         if (callerTNS != null) {
610             // the second index to the NS_ERROR_CODES array
611
// if the caller/expected NS is not absent, we use the first column
612
int secondIdx = 0;
613             // for include and redefine
614
if (referType == XSDDescription.CONTEXT_INCLUDE ||
615                 referType == XSDDescription.CONTEXT_REDEFINE) {
616                 // if the referred document has no targetNamespace,
617
// it's a chameleon schema
618
if (currSchemaInfo.fTargetNamespace == null) {
619                     currSchemaInfo.fTargetNamespace = callerTNS;
620                     currSchemaInfo.fIsChameleonSchema = true;
621                 }
622                 // if the referred document has a target namespace differing
623
// from the caller, it's an error
624
else if (callerTNS != currSchemaInfo.fTargetNamespace) {
625                     reportSchemaError(NS_ERROR_CODES[referType][secondIdx],
626                                       new Object JavaDoc [] {callerTNS, currSchemaInfo.fTargetNamespace},
627                                       DOMUtil.getRoot(schemaRoot));
628                     return null;
629                 }
630             }
631             // for instance and import, the two NS's must be the same
632
else if (referType != XSDDescription.CONTEXT_PREPARSE && callerTNS != currSchemaInfo.fTargetNamespace) {
633                 reportSchemaError(NS_ERROR_CODES[referType][secondIdx],
634                                   new Object JavaDoc [] {callerTNS, currSchemaInfo.fTargetNamespace},
635                                   DOMUtil.getRoot(schemaRoot));
636                 return null;
637             }
638         }
639         // now there is no caller/expected NS, it's an error for the referred
640
// document to have a target namespace, unless we are preparsing a schema
641
else if (currSchemaInfo.fTargetNamespace != null) {
642             // set the target namespace of the description
643
if (referType == XSDDescription.CONTEXT_PREPARSE) {
644                 desc.setTargetNamespace(currSchemaInfo.fTargetNamespace);
645                 callerTNS = currSchemaInfo.fTargetNamespace;
646             }
647             else {
648                 // the second index to the NS_ERROR_CODES array
649
// if the caller/expected NS is absent, we use the second column
650
int secondIdx = 1;
651                 reportSchemaError(NS_ERROR_CODES[referType][secondIdx],
652                                   new Object JavaDoc [] {callerTNS, currSchemaInfo.fTargetNamespace},
653                                   DOMUtil.getRoot(schemaRoot));
654                 return null;
655             }
656         }
657         // the other cases (callerTNS == currSchemaInfo.fTargetNamespce == null)
658
// are valid
659

660         // a schema document can always access it's own target namespace
661
currSchemaInfo.addAllowedNS(currSchemaInfo.fTargetNamespace);
662
663         SchemaGrammar sg = null;
664         
665         if (referType == XSDDescription.CONTEXT_INCLUDE ||
666             referType == XSDDescription.CONTEXT_REDEFINE) {
667             sg = fGrammarBucket.getGrammar(currSchemaInfo.fTargetNamespace);
668         }
669         else {
670             sg = new SchemaGrammar(currSchemaInfo.fTargetNamespace, desc.makeClone(), fSymbolTable);
671             fGrammarBucket.putGrammar(sg);
672         }
673
674         // store the document and its location
675
// REVISIT: don't expose the DOM tree
676
//sg.addDocument(currSchemaInfo.fSchemaDoc, (String)fDoc2SystemId.get(currSchemaInfo));
677
sg.addDocument(null, (String JavaDoc)fDoc2SystemId.get(currSchemaInfo.fSchemaDoc));
678             
679         fDoc2XSDocumentMap.put(schemaRoot, currSchemaInfo);
680
681         Vector JavaDoc dependencies = new Vector JavaDoc();
682         Element JavaDoc rootNode = DOMUtil.getRoot(schemaRoot);
683
684         Document JavaDoc newSchemaRoot = null;
685         for (Element JavaDoc child = DOMUtil.getFirstChildElement(rootNode);
686             child != null;
687             child = DOMUtil.getNextSiblingElement(child)) {
688             String JavaDoc schemaNamespace=null;
689             String JavaDoc schemaHint=null;
690             String JavaDoc localName = DOMUtil.getLocalName(child);
691             
692             short refType = -1;
693             
694             if (localName.equals(SchemaSymbols.ELT_ANNOTATION))
695                 continue;
696             else if (localName.equals(SchemaSymbols.ELT_IMPORT)) {
697                 refType = XSDDescription.CONTEXT_IMPORT;
698                 // have to handle some validation here too!
699
// call XSAttributeChecker to fill in attrs
700
Object JavaDoc[] importAttrs = fAttributeChecker.checkAttributes(child, true, currSchemaInfo);
701                 schemaHint = (String JavaDoc)importAttrs[XSAttributeChecker.ATTIDX_SCHEMALOCATION];
702                 schemaNamespace = (String JavaDoc)importAttrs[XSAttributeChecker.ATTIDX_NAMESPACE];
703                 if (schemaNamespace != null)
704                     schemaNamespace = fSymbolTable.addSymbol(schemaNamespace);
705                 // a document can't import another document with the same namespace
706
if (schemaNamespace == currSchemaInfo.fTargetNamespace) {
707                     reportSchemaError("src-import.1.1", new Object JavaDoc [] {schemaNamespace}, child);
708                 }
709
710                 // check contents and process optional annotations
711
Element JavaDoc importChild = DOMUtil.getFirstChildElement(child);
712                 if(importChild != null ) {
713                     String JavaDoc importComponentType = DOMUtil.getLocalName(importChild);
714                     if (importComponentType.equals(SchemaSymbols.ELT_ANNOTATION)) {
715                         // promoting annotations to parent component
716
sg.addAnnotation(
717                             fElementTraverser.traverseAnnotationDecl(importChild, importAttrs, true, currSchemaInfo));
718                     } else {
719                         reportSchemaError("s4s-elt-must-match.1", new Object JavaDoc [] {localName, "annotation?", importComponentType}, child);
720                     }
721                     if(DOMUtil.getNextSiblingElement(importChild) != null) {
722                         reportSchemaError("s4s-elt-must-match.1", new Object JavaDoc [] {localName, "annotation?", DOMUtil.getLocalName(DOMUtil.getNextSiblingElement(importChild))}, child);
723                     }
724                 }
725                 fAttributeChecker.returnAttrArray(importAttrs, currSchemaInfo);
726                 
727                 // if this namespace has been imported by this document,
728
// ignore the <import> statement
729
if (currSchemaInfo.isAllowedNS(schemaNamespace))
730                     continue;
731
732                 // a schema document can access it's imported namespaces
733
currSchemaInfo.addAllowedNS(schemaNamespace);
734                 
735                 // also record the fact that one namespace imports another one
736
// convert null to ""
737
String JavaDoc tns = null2EmptyString(currSchemaInfo.fTargetNamespace);
738                 // get all namespaces imported by this one
739
Vector JavaDoc ins = (Vector JavaDoc)fImportMap.get(tns);
740                 // if no namespace was imported, create new Vector
741
if (ins == null) {
742                     // record that this one imports other(s)
743
fAllTNSs.addElement(tns);
744                     ins = new Vector JavaDoc();
745                     fImportMap.put(tns, ins);
746                     ins.addElement(schemaNamespace);
747                 }
748                 else if (!ins.contains(schemaNamespace)){
749                     ins.addElement(schemaNamespace);
750                 }
751
752                 fSchemaGrammarDescription.reset();
753                 fSchemaGrammarDescription.setContextType(XSDDescription.CONTEXT_IMPORT);
754                 fSchemaGrammarDescription.setBaseSystemId((String JavaDoc)fDoc2SystemId.get(schemaRoot));
755                 fSchemaGrammarDescription.setLocationHints(new String JavaDoc[]{schemaHint});
756                 fSchemaGrammarDescription.setTargetNamespace(schemaNamespace);
757
758                 // if a grammar with the same namespace exists (or being
759
// built), ignore this one (don't traverse it).
760
if (findGrammar(fSchemaGrammarDescription) != null)
761                     continue;
762                 newSchemaRoot = resolveSchema(fSchemaGrammarDescription, false, child);
763             }
764             else if ((localName.equals(SchemaSymbols.ELT_INCLUDE)) ||
765                      (localName.equals(SchemaSymbols.ELT_REDEFINE))) {
766                 // validation for redefine/include will be the same here; just
767
// make sure TNS is right (don't care about redef contents
768
// yet).
769
Object JavaDoc[] includeAttrs = fAttributeChecker.checkAttributes(child, true, currSchemaInfo);
770                 schemaHint = (String JavaDoc)includeAttrs[XSAttributeChecker.ATTIDX_SCHEMALOCATION];
771                 // store the namespace decls of the redefine element
772
if (localName.equals(SchemaSymbols.ELT_REDEFINE)) {
773                     fRedefine2NSSupport.put(child, new SchemaNamespaceSupport(currSchemaInfo.fNamespaceSupport));
774                 }
775
776                 // check annotations. Must do this here to avoid having to
777
// re-parse attributes later
778
if(localName.equals(SchemaSymbols.ELT_INCLUDE)) {
779                     Element JavaDoc includeChild = DOMUtil.getFirstChildElement(child);
780                     if(includeChild != null ) {
781                         String JavaDoc includeComponentType = DOMUtil.getLocalName(includeChild);
782                         if (includeComponentType.equals(SchemaSymbols.ELT_ANNOTATION)) {
783                             // promoting annotations to parent component
784
sg.addAnnotation(
785                                 fElementTraverser.traverseAnnotationDecl(includeChild, includeAttrs, true, currSchemaInfo));
786                         } else {
787                             reportSchemaError("s4s-elt-must-match.1", new Object JavaDoc [] {localName, "annotation?", includeComponentType}, child);
788                         }
789                         if(DOMUtil.getNextSiblingElement(includeChild) != null) {
790                             reportSchemaError("s4s-elt-must-match.1", new Object JavaDoc [] {localName, "annotation?", DOMUtil.getLocalName(DOMUtil.getNextSiblingElement(includeChild))}, child);
791                         }
792                     }
793                 }
794                 else {
795                     for (Element JavaDoc redefinedChild = DOMUtil.getFirstChildElement(child);
796                             redefinedChild != null;
797                             redefinedChild = DOMUtil.getNextSiblingElement(redefinedChild)) {
798                         String JavaDoc redefinedComponentType = DOMUtil.getLocalName(redefinedChild);
799                         if (redefinedComponentType.equals(SchemaSymbols.ELT_ANNOTATION)) {
800                             // promoting annotations to parent component
801
sg.addAnnotation(
802                                 fElementTraverser.traverseAnnotationDecl(redefinedChild, includeAttrs, true, currSchemaInfo));
803                             DOMUtil.setHidden(redefinedChild);
804                         }
805                         // catch all other content errors later
806
}
807                 }
808                 fAttributeChecker.returnAttrArray(includeAttrs, currSchemaInfo);
809                 // schemaLocation is required on <include> and <redefine>
810
if (schemaHint == null) {
811                     reportSchemaError("s4s-att-must-appear", new Object JavaDoc [] {
812                                       "<include> or <redefine>", "schemaLocation"},
813                                       child);
814                 }
815                 // pass the systemId of the current document as the base systemId
816
boolean mustResolve = false;
817                 refType = XSDDescription.CONTEXT_INCLUDE;
818                 if(localName.equals(SchemaSymbols.ELT_REDEFINE)) {
819                     mustResolve = nonAnnotationContent(child);
820                     refType = XSDDescription.CONTEXT_REDEFINE;
821                 }
822                 fSchemaGrammarDescription.reset();
823                 fSchemaGrammarDescription.setContextType(refType);
824                 fSchemaGrammarDescription.setBaseSystemId((String JavaDoc)fDoc2SystemId.get(schemaRoot));
825                 fSchemaGrammarDescription.setLocationHints(new String JavaDoc[]{schemaHint});
826                 fSchemaGrammarDescription.setTargetNamespace(callerTNS);
827                 newSchemaRoot = resolveSchema(fSchemaGrammarDescription, mustResolve, child);
828                 schemaNamespace = currSchemaInfo.fTargetNamespace;
829             }
830             else {
831                 // no more possibility of schema references in well-formed
832
// schema...
833
break;
834             }
835
836             // If the schema is duplicate, we needn't call constructTrees() again.
837
// To handle mutual <include>s
838
XSDocumentInfo newSchemaInfo = null;
839             if (fLastSchemaWasDuplicate) {
840                 newSchemaInfo = (XSDocumentInfo)fDoc2XSDocumentMap.get(newSchemaRoot);
841             }
842             else {
843                 newSchemaInfo = constructTrees(newSchemaRoot, schemaHint, fSchemaGrammarDescription);
844             }
845
846             if (localName.equals(SchemaSymbols.ELT_REDEFINE) &&
847                 newSchemaInfo != null) {
848                 // must record which schema we're redefining so that we can
849
// rename the right things later!
850
fRedefine2XSDMap.put(child, newSchemaInfo);
851             }
852             if (newSchemaRoot != null) {
853                 if (newSchemaInfo != null)
854                     dependencies.addElement(newSchemaInfo);
855                 newSchemaRoot = null;
856             }
857         }
858         
859         fDependencyMap.put(currSchemaInfo, dependencies);
860         return currSchemaInfo;
861     } // end constructTrees
862

863     // This method builds registries for all globally-referenceable
864
// names. A registry will be built for each symbol space defined
865
// by the spec. It is also this method's job to rename redefined
866
// components, and to record which components redefine others (so
867
// that implicit redefinitions of groups and attributeGroups can be handled).
868
protected void buildGlobalNameRegistries() {
869         /* Starting with fRoot, we examine each child of the schema
870          * element. Skipping all imports and includes, we record the names
871          * of all other global components (and children of <redefine>). We
872          * also put <redefine> names in a registry that we look through in
873          * case something needs renaming. Once we're done with a schema we
874          * set its Document node to hidden so that we don't try to traverse
875          * it again; then we look to its Dependency map entry. We keep a
876          * stack of schemas that we haven't yet finished processing; this
877          * is a depth-first traversal.
878          */

879         Stack JavaDoc schemasToProcess = new Stack JavaDoc();
880         schemasToProcess.push(fRoot);
881         while (!schemasToProcess.empty()) {
882             XSDocumentInfo currSchemaDoc =
883             (XSDocumentInfo)schemasToProcess.pop();
884             Document JavaDoc currDoc = currSchemaDoc.fSchemaDoc;
885             if (DOMUtil.isHidden(currDoc)) {
886                 // must have processed this already!
887
continue;
888             }
889             Element JavaDoc currRoot = DOMUtil.getRoot(currDoc);
890
891             // process this schema's global decls
892
boolean dependenciesCanOccur = true;
893             for (Element JavaDoc globalComp =
894                  DOMUtil.getFirstChildElement(currRoot);
895                 globalComp != null;
896                 globalComp = DOMUtil.getNextSiblingElement(globalComp)) {
897                 // this loop makes sure the <schema> element ordering is
898
// also valid.
899
if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_ANNOTATION)) {
900                     //skip it; traverse it later
901
continue;
902                 }
903                 else if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_INCLUDE) ||
904                          DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_IMPORT)) {
905                     if (!dependenciesCanOccur) {
906                         reportSchemaError("s4s-elt-invalid-content.3", new Object JavaDoc [] {DOMUtil.getLocalName(globalComp)}, globalComp);
907                     }
908                     // we've dealt with this; mark as traversed
909
DOMUtil.setHidden(globalComp);
910                 }
911                 else if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_REDEFINE)) {
912                     if (!dependenciesCanOccur) {
913                         reportSchemaError("s4s-elt-invalid-content.3", new Object JavaDoc [] {DOMUtil.getLocalName(globalComp)}, globalComp);
914                     }
915                     for (Element JavaDoc redefineComp = DOMUtil.getFirstChildElement(globalComp);
916                         redefineComp != null;
917                         redefineComp = DOMUtil.getNextSiblingElement(redefineComp)) {
918                         String JavaDoc lName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME);
919                         if (lName.length() == 0) // an error we'll catch later
920
continue;
921                         String JavaDoc qName = currSchemaDoc.fTargetNamespace == null ?
922                                        ","+lName:
923                                        currSchemaDoc.fTargetNamespace +","+lName;
924                         String JavaDoc componentType = DOMUtil.getLocalName(redefineComp);
925                         if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
926                             checkForDuplicateNames(qName, fUnparsedAttributeGroupRegistry, redefineComp, currSchemaDoc);
927                             // the check will have changed our name;
928
String JavaDoc targetLName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME)+REDEF_IDENTIFIER;
929                             // and all we need to do is error-check+rename our kkids:
930
renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_ATTRIBUTEGROUP,
931                                                        lName, targetLName);
932                         }
933                         else if ((componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) ||
934                                  (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE))) {
935                             checkForDuplicateNames(qName, fUnparsedTypeRegistry, redefineComp, currSchemaDoc);
936                             // the check will have changed our name;
937
String JavaDoc targetLName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME) + REDEF_IDENTIFIER;
938                             // and all we need to do is error-check+rename our kkids:
939
if (componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) {
940                                 renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_COMPLEXTYPE,
941                                                            lName, targetLName);
942                             }
943                             else { // must be simpleType
944
renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_SIMPLETYPE,
945                                                            lName, targetLName);
946                             }
947                         }
948                         else if (componentType.equals(SchemaSymbols.ELT_GROUP)) {
949                             checkForDuplicateNames(qName, fUnparsedGroupRegistry, redefineComp, currSchemaDoc);
950                             // the check will have changed our name;
951
String JavaDoc targetLName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME)+REDEF_IDENTIFIER;
952                             // and all we need to do is error-check+rename our kids:
953
renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_GROUP,
954                                                        lName, targetLName);
955                         }
956                     } // end march through <redefine> children
957
// and now set as traversed
958
//DOMUtil.setHidden(globalComp);
959
}
960                 else {
961                     dependenciesCanOccur = false;
962                     String JavaDoc lName = DOMUtil.getAttrValue(globalComp, SchemaSymbols.ATT_NAME);
963                     if (lName.length() == 0) // an error we'll catch later
964
continue;
965                     String JavaDoc qName = currSchemaDoc.fTargetNamespace == null?
966                                    ","+lName:
967                                    currSchemaDoc.fTargetNamespace +","+lName;
968                     String JavaDoc componentType = DOMUtil.getLocalName(globalComp);
969                     if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTE)) {
970                         checkForDuplicateNames(qName, fUnparsedAttributeRegistry, globalComp, currSchemaDoc);
971                     }
972                     else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
973                         checkForDuplicateNames(qName, fUnparsedAttributeGroupRegistry, globalComp, currSchemaDoc);
974                     }
975                     else if ((componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) ||
976                              (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE))) {
977                         checkForDuplicateNames(qName, fUnparsedTypeRegistry, globalComp, currSchemaDoc);
978                     }
979                     else if (componentType.equals(SchemaSymbols.ELT_ELEMENT)) {
980                         checkForDuplicateNames(qName, fUnparsedElementRegistry, globalComp, currSchemaDoc);
981                     }
982                     else if (componentType.equals(SchemaSymbols.ELT_GROUP)) {
983                         checkForDuplicateNames(qName, fUnparsedGroupRegistry, globalComp, currSchemaDoc);
984                     }
985                     else if (componentType.equals(SchemaSymbols.ELT_NOTATION)) {
986                         checkForDuplicateNames(qName, fUnparsedNotationRegistry, globalComp, currSchemaDoc);
987                     }
988                 }
989             } // end for
990

991             // now we're done with this one!
992
DOMUtil.setHidden(currDoc);
993             // now add the schemas this guy depends on
994
Vector JavaDoc currSchemaDepends = (Vector JavaDoc)fDependencyMap.get(currSchemaDoc);
995             for (int i = 0; i < currSchemaDepends.size(); i++) {
996                 schemasToProcess.push(currSchemaDepends.elementAt(i));
997             }
998         } // while
999
} // end buildGlobalNameRegistries
1000

1001    // Beginning at the first schema processing was requested for
1002
// (fRoot), this method
1003
// examines each child (global schema information item) of each
1004
// schema document (and of each <redefine> element)
1005
// corresponding to an XSDocumentInfo object. If the
1006
// readOnly field on that node has not been set, it calls an
1007
// appropriate traverser to traverse it. Once all global decls in
1008
// an XSDocumentInfo object have been traversed, it marks that object
1009
// as traversed (or hidden) in order to avoid infinite loops. It completes
1010
// when it has visited all XSDocumentInfo objects in the
1011
// DependencyMap and marked them as traversed.
1012
protected void traverseSchemas() {
1013        // the process here is very similar to that in
1014
// buildGlobalRegistries, except we can't set our schemas as
1015
// hidden for a second time; so make them all visible again
1016
// first!
1017
setSchemasVisible(fRoot);
1018        Stack JavaDoc schemasToProcess = new Stack JavaDoc();
1019        schemasToProcess.push(fRoot);
1020        while (!schemasToProcess.empty()) {
1021            XSDocumentInfo currSchemaDoc =
1022                (XSDocumentInfo)schemasToProcess.pop();
1023            Document JavaDoc currDoc = currSchemaDoc.fSchemaDoc;
1024            SchemaGrammar currSG = fGrammarBucket.getGrammar(currSchemaDoc.fTargetNamespace);
1025            if (DOMUtil.isHidden(currDoc)) {
1026                // must have processed this already!
1027
continue;
1028            }
1029            Element JavaDoc currRoot = DOMUtil.getRoot(currDoc);
1030
1031            // traverse this schema's global decls
1032
for (Element JavaDoc globalComp =
1033                 DOMUtil.getFirstVisibleChildElement(currRoot);
1034                globalComp != null;
1035                globalComp = DOMUtil.getNextVisibleSiblingElement(globalComp)) {
1036                // We'll always want to set this as hidden!
1037
DOMUtil.setHidden(globalComp);
1038                String JavaDoc componentType = DOMUtil.getLocalName(globalComp);
1039                // includes and imports will not show up here!
1040
if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_REDEFINE)) {
1041                    // use the namespace decls for the redefine, instead of for the parent <schema>
1042
currSchemaDoc.backupNSSupport((SchemaNamespaceSupport)fRedefine2NSSupport.get(globalComp));
1043                    for (Element JavaDoc redefinedComp = DOMUtil.getFirstVisibleChildElement(globalComp);
1044                        redefinedComp != null;
1045                        redefinedComp = DOMUtil.getNextVisibleSiblingElement(redefinedComp)) {
1046                        String JavaDoc redefinedComponentType = DOMUtil.getLocalName(redefinedComp);
1047                        DOMUtil.setHidden(redefinedComp);
1048                        if (redefinedComponentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
1049                            fAttributeGroupTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG);
1050                        }
1051                        else if (redefinedComponentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) {
1052                            fComplexTypeTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG);
1053                        }
1054                        else if (redefinedComponentType.equals(SchemaSymbols.ELT_GROUP)) {
1055                            fGroupTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG);
1056                        }
1057                        else if (redefinedComponentType.equals(SchemaSymbols.ELT_SIMPLETYPE)) {
1058                            fSimpleTypeTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG);
1059                        }
1060                        // annotations will have been processed already; this is now
1061
// unnecessary
1062
//else if (redefinedComponentType.equals(SchemaSymbols.ELT_ANNOTATION)) {
1063
// fElementTraverser.traverseAnnotationDecl(redefinedComp, null, true, currSchemaDoc);
1064
//}
1065
else {
1066                            reportSchemaError("s4s-elt-must-match.1", new Object JavaDoc [] {DOMUtil.getLocalName(globalComp), "(annotation | (simpleType | complexType | group | attributeGroup))*", redefinedComponentType}, redefinedComp);
1067                        }
1068                    } // end march through <redefine> children
1069
currSchemaDoc.restoreNSSupport();
1070                }
1071                else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTE)) {
1072                    fAttributeTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
1073                }
1074                else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
1075                    fAttributeGroupTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
1076                }
1077                else if (componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) {
1078                    fComplexTypeTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
1079                }
1080                else if (componentType.equals(SchemaSymbols.ELT_ELEMENT)) {
1081                    fElementTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
1082                }
1083                else if (componentType.equals(SchemaSymbols.ELT_GROUP)) {
1084                    fGroupTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
1085                }
1086                else if (componentType.equals(SchemaSymbols.ELT_NOTATION)) {
1087                    fNotationTraverser.traverse(globalComp, currSchemaDoc, currSG);
1088                }
1089                else if (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE)) {
1090                    fSimpleTypeTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
1091                }
1092                else if (componentType.equals(SchemaSymbols.ELT_ANNOTATION)) {
1093                    currSG.addAnnotation(fElementTraverser.traverseAnnotationDecl(globalComp, currSchemaDoc.getSchemaAttrs(), true, currSchemaDoc));
1094                }
1095                else {
1096                    reportSchemaError("s4s-elt-invalid-content.1", new Object JavaDoc [] {SchemaSymbols.ELT_SCHEMA, DOMUtil.getLocalName(globalComp)}, globalComp);
1097                }
1098            } // end for
1099

1100            // now we're done with this one!
1101
currSchemaDoc.returnSchemaAttrs();
1102            DOMUtil.setHidden(currDoc);
1103            // now add the schemas this guy depends on
1104
Vector JavaDoc currSchemaDepends = (Vector JavaDoc)fDependencyMap.get(currSchemaDoc);
1105            for (int i = 0; i < currSchemaDepends.size(); i++) {
1106                schemasToProcess.push(currSchemaDepends.elementAt(i));
1107            }
1108        } // while
1109
} // end traverseSchemas
1110

1111    // store whether we have reported an error about that no grammar
1112
// is found for the given namespace uri
1113
private Vector JavaDoc fReportedTNS = null;
1114    // check whether we need to report an error against the given uri.
1115
// if we have reported an error, then we don't need to report again;
1116
// otherwise we reported the error, and remember this fact.
1117
private final boolean needReportTNSError(String JavaDoc uri) {
1118        if (fReportedTNS == null)
1119            fReportedTNS = new Vector JavaDoc();
1120        else if (fReportedTNS.contains(uri))
1121            return false;
1122        fReportedTNS.addElement(uri);
1123        return true;
1124    }
1125    
1126    private static final String JavaDoc[] COMP_TYPE = {
1127        null, // index 0
1128
"attribute declaration",
1129        "attribute group",
1130        "element declaration",
1131        "group",
1132        "identity constraint",
1133        "notation",
1134        "type definition",
1135    };
1136
1137    private static final String JavaDoc[] CIRCULAR_CODES = {
1138        "Internal-Error",
1139        "Internal-Error",
1140        "src-attribute_group.3",
1141        "e-props-correct.6",
1142        "mg-props-correct.2",
1143        "Internal-Error",
1144        "Internal-Error",
1145        "st-props-correct.2", //or ct-props-correct.3
1146
};
1147
1148    // since it is forbidden for traversers to talk to each other
1149
// directly (except wen a traverser encounters a local declaration),
1150
// this provides a generic means for a traverser to call
1151
// for the traversal of some declaration. An XSDocumentInfo is
1152
// required because the XSDocumentInfo that the traverser is traversing
1153
// may bear no relation to the one the handler is operating on.
1154
// This method will:
1155
// 1. See if a global definition matching declToTraverse exists;
1156
// 2. if so, determine if there is a path from currSchema to the
1157
// schema document where declToTraverse lives (i.e., do a lookup
1158
// in DependencyMap);
1159
// 3. depending on declType (which will be relevant to step 1 as
1160
// well), call the appropriate traverser with the appropriate
1161
// XSDocumentInfo object.
1162
// This method returns whatever the traverser it called returned;
1163
// this will be an Object of some kind
1164
// that lives in the Grammar.
1165
protected Object JavaDoc getGlobalDecl(XSDocumentInfo currSchema,
1166                                   int declType,
1167                                   QName declToTraverse,
1168                                   Element JavaDoc elmNode) {
1169
1170        if (DEBUG_NODE_POOL) {
1171            System.out.println("TRAVERSE_GL: "+declToTraverse.toString());
1172        }
1173        // from the schema spec, all built-in types are present in all schemas,
1174
// so if the requested component is a type, and could be found in the
1175
// default schema grammar, we should return that type.
1176
// otherwise (since we would support user-defined schema grammar) we'll
1177
// use the normal way to get the decl
1178
if (declToTraverse.uri != null &&
1179            declToTraverse.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA) {
1180            if (declType == TYPEDECL_TYPE) {
1181                Object JavaDoc retObj = SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(declToTraverse.localpart);
1182                if (retObj != null)
1183                    return retObj;
1184            }
1185        }
1186
1187        // now check whether this document can access the requsted namespace
1188
if (!currSchema.isAllowedNS(declToTraverse.uri)) {
1189            // cannot get to this schema from the one containing the requesting decl
1190
if (currSchema.needReportTNSError(declToTraverse.uri)) {
1191                String JavaDoc code = declToTraverse.uri == null ? "src-resolve.4.1" : "src-resolve.4.2";
1192                reportSchemaError(code, new Object JavaDoc[]{fDoc2SystemId.get(currSchema.fSchemaDoc), declToTraverse.uri, declToTraverse.rawname}, elmNode);
1193            }
1194            return null;
1195        }
1196
1197        // check whether there is grammar for the requested namespace
1198
SchemaGrammar sGrammar = fGrammarBucket.getGrammar(declToTraverse.uri);
1199        if (sGrammar == null) {
1200            if (needReportTNSError(declToTraverse.uri))
1201                reportSchemaError("src-resolve", new Object JavaDoc[]{declToTraverse.rawname, COMP_TYPE[declType]}, elmNode);
1202            return null;
1203        }
1204
1205        // if there is such grammar, check whether the requested component is in the grammar
1206
Object JavaDoc retObj = null;
1207        switch (declType) {
1208        case ATTRIBUTE_TYPE :
1209            retObj = sGrammar.getGlobalAttributeDecl(declToTraverse.localpart);
1210            break;
1211        case ATTRIBUTEGROUP_TYPE :
1212            retObj = sGrammar.getGlobalAttributeGroupDecl(declToTraverse.localpart);
1213            break;
1214        case ELEMENT_TYPE :
1215            retObj = sGrammar.getGlobalElementDecl(declToTraverse.localpart);
1216            break;
1217        case GROUP_TYPE :
1218            retObj = sGrammar.getGlobalGroupDecl(declToTraverse.localpart);
1219            break;
1220        case IDENTITYCONSTRAINT_TYPE :
1221            retObj = sGrammar.getIDConstraintDecl(declToTraverse.localpart);
1222            break;
1223        case NOTATION_TYPE :
1224            retObj = sGrammar.getGlobalNotationDecl(declToTraverse.localpart);
1225            break;
1226        case TYPEDECL_TYPE :
1227            retObj = sGrammar.getGlobalTypeDecl(declToTraverse.localpart);
1228            break;
1229        }
1230
1231        // if the component is parsed, return it
1232
if (retObj != null)
1233            return retObj;
1234
1235        XSDocumentInfo schemaWithDecl = null;
1236        Element JavaDoc decl = null;
1237
1238        // the component is not parsed, try to find a DOM element for it
1239
String JavaDoc declKey = declToTraverse.uri == null? ","+declToTraverse.localpart:
1240                         declToTraverse.uri+","+declToTraverse.localpart;
1241        switch (declType) {
1242        case ATTRIBUTE_TYPE :
1243            decl = (Element JavaDoc)fUnparsedAttributeRegistry.get(declKey);
1244            break;
1245        case ATTRIBUTEGROUP_TYPE :
1246            decl = (Element JavaDoc)fUnparsedAttributeGroupRegistry.get(declKey);
1247            break;
1248        case ELEMENT_TYPE :
1249            decl = (Element JavaDoc)fUnparsedElementRegistry.get(declKey);
1250            break;
1251        case GROUP_TYPE :
1252            decl = (Element JavaDoc)fUnparsedGroupRegistry.get(declKey);
1253            break;
1254        case IDENTITYCONSTRAINT_TYPE :
1255            decl = (Element JavaDoc)fUnparsedIdentityConstraintRegistry.get(declKey);
1256            break;
1257        case NOTATION_TYPE :
1258            decl = (Element JavaDoc)fUnparsedNotationRegistry.get(declKey);
1259            break;
1260        case TYPEDECL_TYPE :
1261            decl = (Element JavaDoc)fUnparsedTypeRegistry.get(declKey);
1262            break;
1263        default:
1264            reportSchemaError("Internal-Error", new Object JavaDoc [] {"XSDHandler asked to locate component of type " + declType + "; it does not recognize this type!"}, elmNode);
1265        }
1266        
1267        // no DOM element found, so the component can't be located
1268
if (decl == null) {
1269            reportSchemaError("src-resolve", new Object JavaDoc[]{declToTraverse.rawname, COMP_TYPE[declType]}, elmNode);
1270            return null;
1271        }
1272
1273        // get the schema doc containing the component to be parsed
1274
// it should always return non-null value, but since null-checking
1275
// comes for free, let's be safe and check again
1276
schemaWithDecl = findXSDocumentForDecl(currSchema, decl);
1277        if (schemaWithDecl == null) {
1278            // cannot get to this schema from the one containing the requesting decl
1279
String JavaDoc code = declToTraverse.uri == null ? "src-resolve.4.1" : "src-resolve.4.2";
1280            reportSchemaError(code, new Object JavaDoc[]{fDoc2SystemId.get(currSchema.fSchemaDoc), declToTraverse.uri, declToTraverse.rawname}, elmNode);
1281            return null;
1282        }
1283        // a component is hidden, meaning either it's traversed, or being traversed.
1284
// but we didn't find it in the grammar, so it's the latter case, and
1285
// a circular reference. error!
1286
if (DOMUtil.isHidden(decl)) {
1287            String JavaDoc code = CIRCULAR_CODES[declType];
1288            if (declType == TYPEDECL_TYPE) {
1289                if (SchemaSymbols.ELT_COMPLEXTYPE.equals(DOMUtil.getLocalName(decl)))
1290                    code = "ct-props-correct.3";
1291            }
1292            // decl must not be null if we're here...
1293
reportSchemaError(code, new Object JavaDoc [] {declToTraverse.prefix+":"+declToTraverse.localpart}, elmNode);
1294            return null;
1295        }
1296
1297        // hide the element node before traversing it
1298
DOMUtil.setHidden(decl);
1299
1300        SchemaNamespaceSupport nsSupport = null;
1301        // if the parent is <redefine> use the namespace delcs for it.
1302
Element JavaDoc parent = DOMUtil.getParent(decl);
1303        if (DOMUtil.getLocalName(parent).equals(SchemaSymbols.ELT_REDEFINE))
1304            nsSupport = (SchemaNamespaceSupport)fRedefine2NSSupport.get(parent);
1305        // back up the current SchemaNamespaceSupport, because we need to provide
1306
// a fresh one to the traverseGlobal methods.
1307
schemaWithDecl.backupNSSupport(nsSupport);
1308
1309        // traverse the referenced global component
1310
switch (declType) {
1311        case ATTRIBUTE_TYPE :
1312            retObj = fAttributeTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
1313            break;
1314        case ATTRIBUTEGROUP_TYPE :
1315            retObj = fAttributeGroupTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
1316            break;
1317        case ELEMENT_TYPE :
1318            retObj = fElementTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
1319            break;
1320        case GROUP_TYPE :
1321            retObj = fGroupTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
1322            break;
1323        case IDENTITYCONSTRAINT_TYPE :
1324            // identity constraints should have been parsed already...
1325
// we should never get here
1326
retObj = null;
1327            break;
1328        case NOTATION_TYPE :
1329            retObj = fNotationTraverser.traverse(decl, schemaWithDecl, sGrammar);
1330            break;
1331        case TYPEDECL_TYPE :
1332            if (DOMUtil.getLocalName(decl).equals(SchemaSymbols.ELT_COMPLEXTYPE))
1333                retObj = fComplexTypeTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
1334            else
1335                retObj = fSimpleTypeTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
1336        }
1337
1338        // restore the previous SchemaNamespaceSupport, so that the caller can get
1339
// proper namespace binding.
1340
schemaWithDecl.restoreNSSupport();
1341
1342        return retObj;
1343    } // getGlobalDecl(XSDocumentInfo, int, QName): Object
1344

1345    // This method determines whether there is a group
1346
// (attributeGroup) which the given one has redefined by
1347
// restriction. If so, it returns it; else it returns null.
1348
// @param type: whether what's been redefined is an
1349
// attributeGroup or a group;
1350
// @param name: the QName of the component doing the redefining.
1351
// @param currSchema: schema doc in which the redefining component lives.
1352
// @return: Object representing decl redefined if present, null
1353
// otherwise.
1354
Object JavaDoc getGrpOrAttrGrpRedefinedByRestriction(int type, QName name, XSDocumentInfo currSchema, Element JavaDoc elmNode) {
1355        String JavaDoc realName = name.uri != null?name.uri+","+name.localpart:
1356                ","+name.localpart;
1357        String JavaDoc nameToFind = null;
1358        switch (type) {
1359        case ATTRIBUTEGROUP_TYPE:
1360            nameToFind = (String JavaDoc)fRedefinedRestrictedAttributeGroupRegistry.get(realName);
1361            break;
1362        case GROUP_TYPE:
1363            nameToFind = (String JavaDoc)fRedefinedRestrictedGroupRegistry.get(realName);
1364            break;
1365        default:
1366            return null;
1367        }
1368        if (nameToFind == null) return null;
1369        int commaPos = nameToFind.indexOf(",");
1370        QName qNameToFind = new QName(XMLSymbols.EMPTY_STRING, nameToFind.substring(commaPos+1),
1371            nameToFind.substring(commaPos), (commaPos == 0)? null : nameToFind.substring(0, commaPos));
1372        Object JavaDoc retObj = getGlobalDecl(currSchema, type, qNameToFind, elmNode);
1373        if(retObj == null) {
1374            switch (type) {
1375            case ATTRIBUTEGROUP_TYPE:
1376                reportSchemaError("src-redefine.7.2.1", new Object JavaDoc []{name.localpart}, elmNode);
1377                break;
1378            case GROUP_TYPE:
1379                reportSchemaError("src-redefine.6.2.1", new Object JavaDoc []{name.localpart}, elmNode);
1380                break;
1381            }
1382            return null;
1383        }
1384        return retObj;
1385    } // getGrpOrAttrGrpRedefinedByRestriction(int, QName, XSDocumentInfo): Object
1386

1387    // Since ID constraints can occur in local elements, unless we
1388
// wish to completely traverse all our DOM trees looking for ID
1389
// constraints while we're building our global name registries,
1390
// which seems terribly inefficient, we need to resolve keyrefs
1391
// after all parsing is complete. This we can simply do by running through
1392
// fIdentityConstraintRegistry and calling traverseKeyRef on all
1393
// of the KeyRef nodes. This unfortunately removes this knowledge
1394
// from the elementTraverser class (which must ignore keyrefs),
1395
// but there seems to be no efficient way around this...
1396
protected void resolveKeyRefs() {
1397        for (int i=0; i<fKeyrefStackPos; i++) {
1398            Document JavaDoc keyrefDoc = DOMUtil.getDocument(fKeyrefs[i]);
1399            XSDocumentInfo keyrefSchemaDoc = (XSDocumentInfo)fDoc2XSDocumentMap.get(keyrefDoc);
1400            keyrefSchemaDoc.fNamespaceSupport.makeGlobal();
1401            keyrefSchemaDoc.fNamespaceSupport.setEffectiveContext( fKeyrefNamespaceContext[i] );
1402            SchemaGrammar keyrefGrammar = fGrammarBucket.getGrammar(keyrefSchemaDoc.fTargetNamespace);
1403            // need to set <keyref> to hidden before traversing it,
1404
// because it has global scope
1405
DOMUtil.setHidden(fKeyrefs[i]);
1406            fKeyrefTraverser.traverse(fKeyrefs[i], fKeyrefElems[i], keyrefSchemaDoc, keyrefGrammar);
1407        }
1408    } // end resolveKeyRefs
1409

1410    // an accessor method. Just makes sure callers
1411
// who want the Identity constraint registry vaguely know what they're about.
1412
protected Hashtable JavaDoc getIDRegistry() {
1413        return fUnparsedIdentityConstraintRegistry;
1414    }
1415
1416    // This method squirrels away <keyref> declarations--along with the element
1417
// decls and namespace bindings they might find handy.
1418
protected void storeKeyRef (Element JavaDoc keyrefToStore, XSDocumentInfo schemaDoc,
1419                                XSElementDecl currElemDecl) {
1420        String JavaDoc keyrefName = DOMUtil.getAttrValue(keyrefToStore, SchemaSymbols.ATT_NAME);
1421        if (keyrefName.length() != 0) {
1422            String JavaDoc keyrefQName = schemaDoc.fTargetNamespace == null?
1423                                 "," + keyrefName: schemaDoc.fTargetNamespace+","+keyrefName;
1424            checkForDuplicateNames(keyrefQName, fUnparsedIdentityConstraintRegistry, keyrefToStore, schemaDoc);
1425        }
1426        // now set up all the registries we'll need...
1427

1428        // check array sizes
1429
if (fKeyrefStackPos == fKeyrefs.length) {
1430            Element JavaDoc [] elemArray = new Element JavaDoc [fKeyrefStackPos + INC_KEYREF_STACK_AMOUNT];
1431            System.arraycopy(fKeyrefs, 0, elemArray, 0, fKeyrefStackPos);
1432            fKeyrefs = elemArray;
1433            XSElementDecl [] declArray = new XSElementDecl [fKeyrefStackPos + INC_KEYREF_STACK_AMOUNT];
1434            System.arraycopy(fKeyrefElems, 0, declArray, 0, fKeyrefStackPos);
1435            fKeyrefElems = declArray;
1436            String JavaDoc[][] stringArray = new String JavaDoc [fKeyrefStackPos + INC_KEYREF_STACK_AMOUNT][];
1437            System.arraycopy(fKeyrefNamespaceContext, 0, stringArray, 0, fKeyrefStackPos);
1438            fKeyrefNamespaceContext = stringArray;
1439        }
1440        fKeyrefs[fKeyrefStackPos] = keyrefToStore;
1441        fKeyrefElems[fKeyrefStackPos] = currElemDecl;
1442        fKeyrefNamespaceContext[fKeyrefStackPos++] = schemaDoc.fNamespaceSupport.getEffectiveLocalContext();
1443    } // storeKeyref (Element, XSDocumentInfo, XSElementDecl): void
1444

1445    
1446    /**
1447     * resolveSchema method is responsible for resolving location of the schema (using XMLEntityResolver),
1448     * and if it was succefully resolved getting the schema Document.
1449     * @param desc
1450     * @param mustResolve
1451     * @param referElement
1452     * @return A schema Document or null.
1453     */

1454    private Document JavaDoc resolveSchema(XSDDescription desc,
1455                               boolean mustResolve, Element JavaDoc referElement) {
1456        XMLInputSource schemaSource=null;
1457        try {
1458            schemaSource = XMLSchemaLoader.resolveDocument(desc, fLocationPairs, fEntityResolver);
1459        }
1460        catch (IOException JavaDoc ex) {
1461            if (mustResolve) {
1462                reportSchemaError("schema_reference.4",
1463                                  new Object JavaDoc[]{desc.getLocationHints()[0]},
1464                                  referElement);
1465            }
1466            else {
1467                reportSchemaWarning("schema_reference.4",
1468                                    new Object JavaDoc[]{desc.getLocationHints()[0]},
1469                                    referElement);
1470            }
1471        }
1472        return getSchema(desc.getTargetNamespace(),
1473            schemaSource.toSource(), mustResolve, desc.getContextType(), referElement);
1474    } // getSchema(String, String, String, boolean, short): Document
1475

1476    /**
1477     * getSchemaDocument method uses XMLInputSource to parse a schema document.
1478     * @param schemaNamespace
1479     * @param schemaSource
1480     * @param mustResolve
1481     * @param referType
1482     * @param referElement
1483     * @return A schema Document.
1484     */

1485    private Document JavaDoc getSchema(String JavaDoc schemaNamespace, Source JavaDoc schemaSource,
1486                               boolean mustResolve, short referType, Element JavaDoc referElement) {
1487
1488        boolean hasInput = true;
1489        // contents of this method will depend on the system we adopt for entity resolution--i.e., XMLEntityHandler, EntityHandler, etc.
1490
Document JavaDoc schemaDoc = null;
1491        try {
1492            // when the system id and byte stream and character stream
1493
// of the input source are all null, it's
1494
// impossible to find the schema document. so we skip in
1495
// this case. otherwise we'll receive some NPE or
1496
// file not found errors. but schemaHint=="" is perfectly
1497
// legal for import.
1498
if (schemaSource != null ) {
1499
1500                // When the system id of the input source is used, first try to
1501
// expand it, and check whether the same document has been
1502
// parsed before. If so, return the document corresponding to
1503
// that system id.
1504
XSDKey key = null;
1505                String JavaDoc schemaId = null;
1506                if (referType != XSDDescription.CONTEXT_PREPARSE){
1507                    schemaId = schemaSource.getSystemId();
1508                    key = new XSDKey(schemaId, referType, schemaNamespace);
1509                    if ((schemaDoc = (Document JavaDoc)fTraversed.get(key)) != null) {
1510                        fLastSchemaWasDuplicate = true;
1511                        return schemaDoc;
1512                    }
1513                }
1514                if( schemaSource instanceof XMLInputSourceAdaptor ) {
1515                    // If this is the first schema this Handler has
1516
// parsed, it has to construct a DOMParser
1517
fSchemaParser.parse(((XMLInputSourceAdaptor)schemaSource).fSource);
1518                    schemaDoc = fSchemaParser.getDocument();
1519                } else
1520                if( schemaSource instanceof DOMSource JavaDoc ) {
1521                    // Xerces needs a special kind of DOM, so
1522
// we have to clone it into that form otherwise
1523
// things won't work.
1524
// TODO: this dependency to a particular DOM implementation
1525
// should be fixed.
1526
// but then SchemaDOM doesn't support importNode,
1527
// so here we just rely on IdentityTransformer
1528
try {
1529                        Transformer JavaDoc t = TransformerFactory.newInstance().newTransformer();
1530                        SchemaDOMParser p = new SchemaDOMParser(fErrorReporter);
1531                        t.transform( schemaSource, new SAXResult JavaDoc(new SAX2XNI(p)) );
1532                        schemaDoc = p.getDocument();
1533                    } catch( TransformerException JavaDoc e ) {
1534                        // impossible.
1535
e.printStackTrace();
1536                        throw new InternalError JavaDoc();
1537                    }
1538                } else
1539                if( schemaSource instanceof StreamSource JavaDoc ) {
1540                    fSchemaParser.parse(new XMLInputSource((StreamSource JavaDoc)schemaSource));
1541                    schemaDoc = fSchemaParser.getDocument();
1542                } else
1543                if( schemaSource instanceof SAXSource JavaDoc ) {
1544                    SAXSource JavaDoc ss = (SAXSource JavaDoc)schemaSource;
1545                    XMLReader JavaDoc reader = ss.getXMLReader();
1546                    if(reader==null) {
1547                        reader = new SAXParser();
1548                        try {
1549                            reader.setFeature("http://xml.org/sax/features/namespaces",true);
1550                            reader.setFeature("http://xml.org/sax/features/namespace-prefixes",true);
1551                        } catch( SAXException JavaDoc e ) {
1552                            // impossible
1553
e.printStackTrace();
1554                            throw new InternalError JavaDoc();
1555                        }
1556                    }
1557                    SchemaDOMParser p = new SchemaDOMParser(fErrorReporter);
1558                    reader.setContentHandler(new SAX2XNI(p));
1559                    reader.setErrorHandler(fErrorReporter.getSAXErrorHandler());
1560                    try {
1561                        reader.parse(ss.getInputSource());
1562                        schemaDoc = p.getDocument();
1563                    } catch( SAXException JavaDoc e ) {
1564                        ; // should have already been reported.
1565
}
1566                } else {
1567                    throw new IllegalArgumentException JavaDoc(schemaSource.getClass().getName());
1568                }
1569
1570                // now we need to store the mapping information from system id
1571
// to the document. also from the document to the system id.
1572
if (key != null)
1573                    fTraversed.put(key, schemaDoc );
1574                if (schemaId != null)
1575                    fDoc2SystemId.put(schemaDoc, schemaId );
1576                fLastSchemaWasDuplicate = false;
1577                return schemaDoc;
1578            }
1579            else {
1580                hasInput = false;
1581            }
1582        }
1583        catch (IOException JavaDoc ex) {
1584        }
1585        
1586        // either an error occured (exception), or empty input source was
1587
// returned, we need to report an error or a warning
1588
if (mustResolve) {
1589            if (hasInput) {
1590                reportSchemaError("schema_reference.4",
1591                                  new Object JavaDoc[]{schemaSource.getSystemId()},
1592                                  referElement);
1593            }
1594            else {
1595                reportSchemaError("schema_reference.4",
1596                                  new Object JavaDoc[]{schemaSource == null ? "" : schemaSource.getSystemId()},
1597                                  referElement);
1598            }
1599        }
1600
1601        fLastSchemaWasDuplicate = false;
1602        return null;
1603    } // getSchema(String, XMLInputSource, boolean, boolean): Document
1604

1605    // initialize all the traversers.
1606
// this should only need to be called once during the construction
1607
// of this object; it creates the traversers that will be used to
1608

1609    // construct schemaGrammars.
1610
private void createTraversers() {
1611        fAttributeChecker = new XSAttributeChecker(this);
1612        fAttributeGroupTraverser = new XSDAttributeGroupTraverser(this, fAttributeChecker);
1613        fAttributeTraverser = new XSDAttributeTraverser(this, fAttributeChecker);
1614        fComplexTypeTraverser = new XSDComplexTypeTraverser(this, fAttributeChecker);
1615        fElementTraverser = new XSDElementTraverser(this, fAttributeChecker);
1616        fGroupTraverser = new XSDGroupTraverser(this, fAttributeChecker);
1617        fKeyrefTraverser = new XSDKeyrefTraverser(this, fAttributeChecker);
1618        fNotationTraverser = new XSDNotationTraverser(this, fAttributeChecker);
1619        fSimpleTypeTraverser = new XSDSimpleTypeTraverser(this, fAttributeChecker);
1620        fUniqueOrKeyTraverser = new XSDUniqueOrKeyTraverser(this, fAttributeChecker);
1621        fWildCardTraverser = new XSDWildcardTraverser(this, fAttributeChecker);
1622    } // createTraversers()
1623

1624    // before parsing a schema, need to clear registries associated with
1625
// parsing schemas
1626
void prepareForParse() {
1627        fTraversed.clear();
1628        fDoc2SystemId.clear();
1629        fLastSchemaWasDuplicate = false;
1630    }
1631
1632    // before traversing a schema's parse tree, need to reset all traversers and
1633
// clear all registries
1634
void prepareForTraverse() {
1635        fUnparsedAttributeRegistry.clear();
1636        fUnparsedAttributeGroupRegistry.clear();
1637        fUnparsedElementRegistry.clear();
1638        fUnparsedGroupRegistry.clear();
1639        fUnparsedIdentityConstraintRegistry.clear();
1640        fUnparsedNotationRegistry.clear();
1641        fUnparsedTypeRegistry.clear();
1642
1643        fXSDocumentInfoRegistry.clear();
1644        fDependencyMap.clear();
1645        fDoc2XSDocumentMap.clear();
1646        fRedefine2XSDMap.clear();
1647        fRedefine2NSSupport.clear();
1648        fAllTNSs.removeAllElements();
1649        fImportMap.clear();
1650        fRoot = null;
1651
1652        // clear local element stack
1653
for (int i = 0; i < fLocalElemStackPos; i++) {
1654            fParticle[i] = null;
1655            fLocalElementDecl[i] = null;
1656            fLocalElemNamespaceContext[i] = null;
1657        }
1658        fLocalElemStackPos = 0;
1659
1660        // and do same for keyrefs.
1661
for (int i = 0; i < fKeyrefStackPos; i++) {
1662            fKeyrefs[i] = null;
1663            fKeyrefElems[i] = null;
1664            fKeyrefNamespaceContext[i] = null;
1665        }
1666        fKeyrefStackPos = 0;
1667
1668        // create traversers if necessary
1669
if (fAttributeChecker == null) {
1670            createTraversers();
1671        }
1672
1673        // reset traversers
1674
fAttributeChecker.reset(fSymbolTable);
1675        fAttributeGroupTraverser.reset(fSymbolTable);
1676        fAttributeTraverser.reset(fSymbolTable);
1677        fComplexTypeTraverser.reset(fSymbolTable);
1678        fElementTraverser.reset(fSymbolTable);
1679        fGroupTraverser.reset(fSymbolTable);
1680        fKeyrefTraverser.reset(fSymbolTable);
1681        fNotationTraverser.reset(fSymbolTable);
1682        fSimpleTypeTraverser.reset(fSymbolTable);
1683        fUniqueOrKeyTraverser.reset(fSymbolTable);
1684        fWildCardTraverser.reset(fSymbolTable);
1685
1686        fRedefinedRestrictedAttributeGroupRegistry.clear();
1687        fRedefinedRestrictedGroupRegistry.clear();
1688    }
1689    public void setDeclPool (XSDeclarationPool declPool){
1690        fDeclPool = declPool;
1691    }
1692
1693    public void reset(XMLComponentManager componentManager) {
1694
1695        // set symbol table
1696
fSymbolTable = (SymbolTable) componentManager.getProperty(SYMBOL_TABLE);
1697        
1698        fSecureProcessing = null;
1699        if( componentManager!=null ) {
1700            try {
1701                fSecureProcessing = (SecurityManager JavaDoc) componentManager.getProperty(SECURE_PROCESSING);
1702            } catch (XMLConfigurationException xmlConfigurationException) {
1703                ;
1704            }
1705        }
1706        
1707    //set entity resolver
1708
fEntityResolver = (XMLEntityResolver) componentManager.getProperty(ENTITY_MANAGER);
1709        XMLEntityResolver er = (XMLEntityResolver)componentManager.getProperty(ENTITY_RESOLVER);
1710        if (er != null)
1711            fSchemaParser.setEntityResolver(er);
1712        
1713        // set error reporter
1714
fErrorReporter =
1715            (XMLErrorReporter) componentManager.getProperty(ERROR_REPORTER);
1716        try {
1717            XMLErrorHandler currErrorHandler = fErrorReporter.getErrorHandler();
1718            // Setting a parser property can be much more expensive
1719
// than checking its value. Don't set the ERROR_HANDLER
1720
// property unless it's actually changed.
1721
if (currErrorHandler != fSchemaParser.getProperty(ERROR_HANDLER)) {
1722                fSchemaParser.setProperty(ERROR_HANDLER, currErrorHandler);
1723            }
1724        } catch (XMLConfigurationException e) {
1725        }
1726
1727        try {
1728            fSchemaParser.setFeature(
1729                CONTINUE_AFTER_FATAL_ERROR,
1730                fErrorReporter.getFeature(CONTINUE_AFTER_FATAL_ERROR));
1731        } catch (XMLConfigurationException e) {
1732        }
1733
1734        try {
1735            fSchemaParser.setFeature(
1736                ALLOW_JAVA_ENCODINGS,
1737                componentManager.getFeature(ALLOW_JAVA_ENCODINGS));
1738        } catch (XMLConfigurationException e) {
1739        }
1740        try {
1741            fSchemaParser.setFeature(
1742                STANDARD_URI_CONFORMANT_FEATURE,
1743                componentManager.getFeature(STANDARD_URI_CONFORMANT_FEATURE));
1744        } catch (XMLConfigurationException e) {
1745        }
1746
1747        try {
1748            fGrammarPool =
1749                (XMLGrammarPool) componentManager.getProperty(XMLGRAMMAR_POOL);
1750        } catch (XMLConfigurationException e) {
1751            fGrammarPool = null;
1752        }
1753        // security features
1754
try {
1755            fSchemaParser.setFeature( DISALLOW_DOCTYPE,
1756                componentManager.getFeature(DISALLOW_DOCTYPE));
1757        } catch (XMLConfigurationException e) {
1758        }
1759        try {
1760            Object JavaDoc security = componentManager.getProperty(SECURITY_MANAGER);
1761            if (security != null){
1762                fSchemaParser.setProperty(SECURITY_MANAGER, security);
1763            }
1764        } catch (XMLConfigurationException e) {
1765        }
1766
1767    } // reset(XMLComponentManager)
1768

1769
1770    /**
1771     * Traverse all the deferred local elements. This method should be called
1772     * by traverseSchemas after we've done with all the global declarations.
1773     */

1774    void traverseLocalElements() {
1775        fElementTraverser.fDeferTraversingLocalElements = false;
1776
1777        for (int i = 0; i < fLocalElemStackPos; i++) {
1778            Element JavaDoc currElem = fLocalElementDecl[i];
1779            XSDocumentInfo currSchema = (XSDocumentInfo)fDoc2XSDocumentMap.get(DOMUtil.getDocument(currElem));
1780            SchemaGrammar currGrammar = fGrammarBucket.getGrammar(currSchema.fTargetNamespace);
1781            fElementTraverser.traverseLocal (fParticle[i], currElem, currSchema, currGrammar, fAllContext[i], fParent[i]);
1782            // If it's an empty particle, remove it from the containing component.
1783
if (fParticle[i].fType == XSParticleDecl.PARTICLE_EMPTY) {
1784                XSModelGroupImpl group;
1785                if (fParent[i] instanceof XSComplexTypeDecl)
1786                    group = (XSModelGroupImpl)((XSComplexTypeDecl)fParent[i]).getParticle().getTerm();
1787                else
1788                    group = ((XSGroupDecl)fParent[i]).fModelGroup;
1789                removeParticle(group, fParticle[i]);
1790            }
1791        }
1792    }
1793
1794    private boolean removeParticle(XSModelGroupImpl group, XSParticleDecl particle) {
1795        XSParticleDecl member;
1796        for (int i = 0; i < group.fParticleCount; i++) {
1797            member = group.fParticles[i];
1798            if (member == particle) {
1799                for (int j = i; j < group.fParticleCount-1; j++)
1800                    group.fParticles[j] = group.fParticles[j+1];
1801                group.fParticleCount--;
1802                return true;
1803            }
1804            if (member.fType == XSParticleDecl.PARTICLE_MODELGROUP) {
1805                if (removeParticle((XSModelGroupImpl)member.fValue, particle))
1806                    return true;
1807            }
1808        }
1809        return false;
1810    }
1811
1812    // the purpose of this method is to keep up-to-date structures
1813
// we'll need for the feferred traversal of local elements.
1814
void fillInLocalElemInfo(Element JavaDoc elmDecl,
1815                             XSDocumentInfo schemaDoc,
1816                             int allContextFlags,
1817                             XSObject parent,
1818                             XSParticleDecl particle) {
1819
1820        // if the stack is full, increase the size
1821
if (fParticle.length == fLocalElemStackPos) {
1822            // increase size
1823
XSParticleDecl[] newStackP = new XSParticleDecl[fLocalElemStackPos+INC_STACK_SIZE];
1824            System.arraycopy(fParticle, 0, newStackP, 0, fLocalElemStackPos);
1825            fParticle = newStackP;
1826            Element JavaDoc[] newStackE = new Element JavaDoc[fLocalElemStackPos+INC_STACK_SIZE];
1827            System.arraycopy(fLocalElementDecl, 0, newStackE, 0, fLocalElemStackPos);
1828            fLocalElementDecl = newStackE;
1829            int[] newStackI = new int[fLocalElemStackPos+INC_STACK_SIZE];
1830            System.arraycopy(fAllContext, 0, newStackI, 0, fLocalElemStackPos);
1831            fAllContext = newStackI;
1832            XSObject[] newStackC = new XSObject[fLocalElemStackPos+INC_STACK_SIZE];
1833            System.arraycopy(fParent, 0, newStackC, 0, fLocalElemStackPos);
1834            fParent = newStackC;
1835            String JavaDoc [][] newStackN = new String JavaDoc [fLocalElemStackPos+INC_STACK_SIZE][];
1836            System.arraycopy(fLocalElemNamespaceContext, 0, newStackN, 0, fLocalElemStackPos);
1837            fLocalElemNamespaceContext = newStackN;
1838        }
1839
1840        fParticle[fLocalElemStackPos] = particle;
1841        fLocalElementDecl[fLocalElemStackPos] = elmDecl;
1842        fAllContext[fLocalElemStackPos] = allContextFlags;
1843        fParent[fLocalElemStackPos] = parent;
1844        fLocalElemNamespaceContext[fLocalElemStackPos++] = schemaDoc.fNamespaceSupport.getEffectiveLocalContext();
1845    } // end fillInLocalElemInfo(...)
1846

1847    /** This method makes sure that
1848     * if this component is being redefined that it lives in the
1849     * right schema. It then renames the component correctly. If it
1850     * detects a collision--a duplicate definition--then it complains.
1851     * Note that redefines must be handled carefully: if there
1852     * is a collision, it may be because we're redefining something we know about
1853     * or because we've found the thing we're redefining.
1854     */

1855    void checkForDuplicateNames(String JavaDoc qName,
1856                                Hashtable JavaDoc registry, Element JavaDoc currComp,
1857                                XSDocumentInfo currSchema) {
1858        Object JavaDoc objElem = null;
1859        // REVISIT: when we add derivation checking, we'll have to make
1860
// sure that ID constraint collisions don't necessarily result in error messages.
1861
if ((objElem = registry.get(qName)) == null) {
1862            // just add it in!
1863
registry.put(qName, currComp);
1864        }
1865        else {
1866            Element JavaDoc collidingElem = (Element JavaDoc)objElem;
1867            if (collidingElem == currComp) return;
1868            Element JavaDoc elemParent = null;
1869            XSDocumentInfo redefinedSchema = null;
1870            // case where we've collided with a redefining element
1871
// (the parent of the colliding element is a redefine)
1872
boolean collidedWithRedefine = true;
1873            if ((DOMUtil.getLocalName((elemParent = DOMUtil.getParent(collidingElem))).equals(SchemaSymbols.ELT_REDEFINE))) {
1874                redefinedSchema = (XSDocumentInfo)(fRedefine2XSDMap.get(elemParent));
1875                // case where we're a redefining element.
1876
}
1877            else if ((DOMUtil.getLocalName(DOMUtil.getParent(currComp)).equals(SchemaSymbols.ELT_REDEFINE))) {
1878                redefinedSchema = (XSDocumentInfo)(fDoc2XSDocumentMap.get(DOMUtil.getDocument(collidingElem)));
1879                collidedWithRedefine = false;
1880            }
1881            if (redefinedSchema != null) { //redefinition involved somehow
1882
// If both components belong to the same document then
1883
// report an error and return.
1884
if (fDoc2XSDocumentMap.get(DOMUtil.getDocument(collidingElem)) == currSchema) {
1885                    reportSchemaError("sch-props-correct.2", new Object JavaDoc[]{qName}, currComp);
1886                    return;
1887                }
1888
1889                String JavaDoc newName = qName.substring(qName.lastIndexOf(',')+1)+REDEF_IDENTIFIER;
1890                if (redefinedSchema == currSchema) { // object comp. okay here
1891
// now have to do some renaming...
1892
currComp.setAttribute(SchemaSymbols.ATT_NAME, newName);
1893                    if (currSchema.fTargetNamespace == null)
1894                        registry.put(","+newName, currComp);
1895                    else
1896                        registry.put(currSchema.fTargetNamespace+","+newName, currComp);
1897                    // and take care of nested redefines by calling recursively:
1898
if (currSchema.fTargetNamespace == null)
1899                        checkForDuplicateNames(","+newName, registry, currComp, currSchema);
1900                    else
1901                        checkForDuplicateNames(currSchema.fTargetNamespace+","+newName, registry, currComp, currSchema);
1902                }
1903                else { // we may be redefining the wrong schema
1904
if (collidedWithRedefine) {
1905                        if (currSchema.fTargetNamespace == null)
1906                            checkForDuplicateNames(","+newName, registry, currComp, currSchema);
1907                        else
1908                            checkForDuplicateNames(currSchema.fTargetNamespace+","+newName, registry, currComp, currSchema);
1909                    }
1910                    else {
1911                        // error that redefined element in wrong schema
1912
reportSchemaError("sch-props-correct.2", new Object JavaDoc [] {qName}, currComp);
1913                    }
1914                }
1915            }
1916            else {
1917                // we've just got a flat-out collision
1918
reportSchemaError("sch-props-correct.2", new Object JavaDoc []{qName}, currComp);
1919            }
1920        }
1921    } // checkForDuplicateNames(String, Hashtable, Element, XSDocumentInfo):void
1922

1923    // the purpose of this method is to take the component of the
1924
// specified type and rename references to itself so that they
1925
// refer to the object being redefined. It takes special care of
1926
// <group>s and <attributeGroup>s to ensure that information
1927
// relating to implicit restrictions is preserved for those
1928
// traversers.
1929
private void renameRedefiningComponents(XSDocumentInfo currSchema,
1930                                            Element JavaDoc child, String JavaDoc componentType,
1931                                            String JavaDoc oldName, String JavaDoc newName) {
1932        if (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE)) {
1933            Element JavaDoc grandKid = DOMUtil.getFirstChildElement(child);
1934            if (grandKid == null) {
1935                reportSchemaError("src-redefine.5.a.a", null, child);
1936            }
1937            else {
1938                String JavaDoc grandKidName = DOMUtil.getLocalName(grandKid);
1939                if (grandKidName.equals(SchemaSymbols.ELT_ANNOTATION)) {
1940                    grandKid = DOMUtil.getNextSiblingElement(grandKid);
1941                }
1942                if (grandKid == null) {
1943                    reportSchemaError("src-redefine.5.a.a", null, child);
1944                }
1945                else {
1946                    grandKidName = DOMUtil.getLocalName(grandKid);
1947                    if (!grandKidName.equals(SchemaSymbols.ELT_RESTRICTION)) {
1948                        reportSchemaError("src-redefine.5.a.b", new Object JavaDoc[]{grandKidName}, child);
1949                    }
1950                    else {
1951                        Object JavaDoc[] attrs = fAttributeChecker.checkAttributes(grandKid, false, currSchema);
1952                        QName derivedBase = (QName)attrs[XSAttributeChecker.ATTIDX_BASE];
1953                        if (derivedBase == null ||
1954                            derivedBase.uri != currSchema.fTargetNamespace ||
1955                            !derivedBase.localpart.equals(oldName)) {
1956                            reportSchemaError("src-redefine.5.a.c",
1957                                              new Object JavaDoc[]{grandKidName,
1958                                                           (currSchema.fTargetNamespace==null?"":currSchema.fTargetNamespace)
1959                                                           + "," + oldName},
1960                                              child);
1961                        }
1962                        else {
1963                            // now we have to do the renaming...
1964
if (derivedBase.prefix != null && derivedBase.prefix.length() > 0)
1965                                grandKid.setAttribute( SchemaSymbols.ATT_BASE,
1966                                                       derivedBase.prefix + ":" + newName );
1967                            else
1968                                grandKid.setAttribute( SchemaSymbols.ATT_BASE, newName );
1969// return true;
1970
}
1971                        fAttributeChecker.returnAttrArray(attrs, currSchema);
1972                    }
1973                }
1974            }
1975        }
1976        else if (componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) {
1977            Element JavaDoc grandKid = DOMUtil.getFirstChildElement(child);
1978            if (grandKid == null) {
1979                reportSchemaError("src-redefine.5.b.a", null, child);
1980            }
1981            else {
1982                if (DOMUtil.getLocalName(grandKid).equals(SchemaSymbols.ELT_ANNOTATION)) {
1983                    grandKid = DOMUtil.getNextSiblingElement(grandKid);
1984                }
1985                if (grandKid == null) {
1986                    reportSchemaError("src-redefine.5.b.a", null, child);
1987                }
1988                else {
1989                    // have to go one more level down; let another pass worry whether complexType is valid.
1990
Element JavaDoc greatGrandKid = DOMUtil.getFirstChildElement(grandKid);
1991                    if (greatGrandKid == null) {
1992                        reportSchemaError("src-redefine.5.b.b", null, grandKid);
1993                    }
1994                    else {
1995                        String JavaDoc greatGrandKidName = DOMUtil.getLocalName(greatGrandKid);
1996                        if (greatGrandKidName.equals(SchemaSymbols.ELT_ANNOTATION)) {
1997                            greatGrandKid = DOMUtil.getNextSiblingElement(greatGrandKid);
1998                        }
1999                        if (greatGrandKid == null) {
2000                            reportSchemaError("src-redefine.5.b.b", null, grandKid);
2001                        }
2002                        else {
2003                            greatGrandKidName = DOMUtil.getLocalName(greatGrandKid);
2004                            if (!greatGrandKidName.equals(SchemaSymbols.ELT_RESTRICTION) &&
2005                                 !greatGrandKidName.equals(SchemaSymbols.ELT_EXTENSION)) {
2006                                reportSchemaError("src-redefine.5.b.c", new Object JavaDoc[]{greatGrandKidName}, greatGrandKid);
2007                            }
2008                            else {
2009                                Object JavaDoc[] attrs = fAttributeChecker.checkAttributes(greatGrandKid, false, currSchema);
2010                                QName derivedBase = (QName)attrs[XSAttributeChecker.ATTIDX_BASE];
2011                                if (derivedBase == null ||
2012                                    derivedBase.uri != currSchema.fTargetNamespace ||
2013                                    !derivedBase.localpart.equals(oldName)) {
2014                                    reportSchemaError("src-redefine.5.b.d",
2015                                                      new Object JavaDoc[]{greatGrandKidName,
2016                                                                   (currSchema.fTargetNamespace==null?"":currSchema.fTargetNamespace)
2017                                                                   + "," + oldName},
2018                                                      greatGrandKid);
2019                                }
2020                                else {
2021                                    // now we have to do the renaming...
2022
if (derivedBase.prefix != null && derivedBase.prefix.length() > 0)
2023                                        greatGrandKid.setAttribute( SchemaSymbols.ATT_BASE,
2024                                                                    derivedBase.prefix + ":" + newName );
2025                                    else
2026                                        greatGrandKid.setAttribute( SchemaSymbols.ATT_BASE,
2027                                                                    newName );
2028// return true;
2029
}
2030                            }
2031                        }
2032                    }
2033                }
2034            }
2035        }
2036        else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
2037            String JavaDoc processedBaseName = (currSchema.fTargetNamespace == null)?
2038                                       ","+oldName:currSchema.fTargetNamespace+","+oldName;
2039            int attGroupRefsCount = changeRedefineGroup(processedBaseName, componentType, newName, child, currSchema);
2040            if (attGroupRefsCount > 1) {
2041                reportSchemaError("src-redefine.7.1", new Object JavaDoc []{new Integer JavaDoc(attGroupRefsCount)}, child);
2042            }
2043            else if (attGroupRefsCount == 1) {
2044// return true;
2045
}
2046            else
2047                if (currSchema.fTargetNamespace == null)
2048                fRedefinedRestrictedAttributeGroupRegistry.put(processedBaseName, ","+newName);
2049            else
2050                fRedefinedRestrictedAttributeGroupRegistry.put(processedBaseName, currSchema.fTargetNamespace+","+newName);
2051        }
2052        else if (componentType.equals(SchemaSymbols.ELT_GROUP)) {
2053            String JavaDoc processedBaseName = (currSchema.fTargetNamespace == null)?
2054                                       ","+oldName:currSchema.fTargetNamespace+","+oldName;
2055            int groupRefsCount = changeRedefineGroup(processedBaseName, componentType, newName, child, currSchema);
2056            if (groupRefsCount > 1) {
2057                reportSchemaError("src-redefine.6.1.1", new Object JavaDoc []{new Integer JavaDoc(groupRefsCount)}, child);
2058            }
2059            else if (groupRefsCount == 1) {
2060// return true;
2061
}
2062            else {
2063                if (currSchema.fTargetNamespace == null)
2064                    fRedefinedRestrictedGroupRegistry.put(processedBaseName, ","+newName);
2065                else
2066                    fRedefinedRestrictedGroupRegistry.put(processedBaseName, currSchema.fTargetNamespace+","+newName);
2067            }
2068        }
2069        else {
2070            reportSchemaError("Internal-Error", new Object JavaDoc [] {"could not handle this particular <redefine>; please submit your schemas and instance document in a bug report!"}, child);
2071        }
2072        // if we get here then we must have reported an error and failed somewhere...
2073
// return false;
2074
} // renameRedefiningComponents(XSDocumentInfo, Element, String, String, String):void
2075

2076    // this method takes a name of the form a:b, determines the URI mapped
2077
// to by a in the current SchemaNamespaceSupport object, and returns this
2078
// information in the form (nsURI,b) suitable for lookups in the global
2079
// decl Hashtables.
2080
// REVISIT: should have it return QName, instead of String. this would
2081
// save lots of string concatenation time. we can use
2082
// QName#equals() to compare two QNames, and use QName directly
2083
// as a key to the SymbolHash.
2084
// And when the DV's are ready to return compiled values from
2085
// validate() method, we should just call QNameDV.validate()
2086
// in this method.
2087
private String JavaDoc findQName(String JavaDoc name, XSDocumentInfo schemaDoc) {
2088        SchemaNamespaceSupport currNSMap = schemaDoc.fNamespaceSupport;
2089        int colonPtr = name.indexOf(':');
2090        String JavaDoc prefix = XMLSymbols.EMPTY_STRING;
2091        if (colonPtr > 0)
2092            prefix = name.substring(0, colonPtr);
2093        String JavaDoc uri = currNSMap.getURI(fSymbolTable.addSymbol(prefix));
2094        String JavaDoc localpart = (colonPtr == 0)?name:name.substring(colonPtr+1);
2095        if (prefix == XMLSymbols.EMPTY_STRING && uri == null && schemaDoc.fIsChameleonSchema)
2096            uri = schemaDoc.fTargetNamespace;
2097        if (uri == null)
2098            return ","+localpart;
2099        return uri+","+localpart;
2100    } // findQName(String, XSDocumentInfo): String
2101

2102    // This function looks among the children of curr for an element of type elementSought.
2103
// If it finds one, it evaluates whether its ref attribute contains a reference
2104
// to originalQName. If it does, it returns 1 + the value returned by
2105
// calls to itself on all other children. In all other cases it returns 0 plus
2106
// the sum of the values returned by calls to itself on curr's children.
2107
// It also resets the value of ref so that it will refer to the renamed type from the schema
2108
// being redefined.
2109
private int changeRedefineGroup(String JavaDoc originalQName, String JavaDoc elementSought,
2110                                    String JavaDoc newName, Element JavaDoc curr, XSDocumentInfo schemaDoc) {
2111        int result = 0;
2112        for (Element JavaDoc child = DOMUtil.getFirstChildElement(curr);
2113            child != null; child = DOMUtil.getNextSiblingElement(child)) {
2114            String JavaDoc name = DOMUtil.getLocalName(child);
2115            if (!name.equals(elementSought))
2116                result += changeRedefineGroup(originalQName, elementSought, newName, child, schemaDoc);
2117            else {
2118                String JavaDoc ref = child.getAttribute( SchemaSymbols.ATT_REF );
2119                if (ref.length() != 0) {
2120                    String JavaDoc processedRef = findQName(ref, schemaDoc);
2121                    if (originalQName.equals(processedRef)) {
2122                        String JavaDoc prefix = XMLSymbols.EMPTY_STRING;
2123                        int colonptr = ref.indexOf(":");
2124                        if (colonptr > 0) {
2125                            prefix = ref.substring(0,colonptr);
2126                            child.setAttribute(SchemaSymbols.ATT_REF, prefix + ":" + newName);
2127                        }
2128                        else
2129                            child.setAttribute(SchemaSymbols.ATT_REF, newName);
2130                        result++;
2131                        if (elementSought.equals(SchemaSymbols.ELT_GROUP)) {
2132                            String JavaDoc minOccurs = child.getAttribute( SchemaSymbols.ATT_MINOCCURS );
2133                            String JavaDoc maxOccurs = child.getAttribute( SchemaSymbols.ATT_MAXOCCURS );
2134                            if (!((maxOccurs.length() == 0 || maxOccurs.equals("1"))
2135                                  && (minOccurs.length() == 0 || minOccurs.equals("1")))) {
2136                                reportSchemaError("src-redefine.6.1.2", new Object JavaDoc [] {ref}, child);
2137                            }
2138                        }
2139                    }
2140                } // if ref was null some other stage of processing will flag the error
2141
}
2142        }
2143        return result;
2144    } // changeRedefineGroup
2145

2146    // this method returns the XSDocumentInfo object that contains the
2147
// component corresponding to decl. If components from this
2148
// document cannot be referred to from those of currSchema, this
2149
// method returns null; it's up to the caller to throw an error.
2150
// @param: currSchema: the XSDocumentInfo object containing the
2151
// decl ref'ing us.
2152
// @param: decl: the declaration being ref'd.
2153
private XSDocumentInfo findXSDocumentForDecl(XSDocumentInfo currSchema,
2154                                                 Element JavaDoc decl) {
2155
2156        if (DEBUG_NODE_POOL) {
2157            System.out.println("DOCUMENT NS:"+ currSchema.fTargetNamespace+" hashcode:"+ ((Object JavaDoc)currSchema.fSchemaDoc).hashCode());
2158        }
2159        Document JavaDoc declDoc = DOMUtil.getDocument(decl);
2160        Object JavaDoc temp = fDoc2XSDocumentMap.get(declDoc);
2161        if (temp == null) {
2162            // something went badly wrong; we don't know this doc?
2163
return null;
2164        }
2165        XSDocumentInfo declDocInfo = (XSDocumentInfo)temp;
2166        return declDocInfo;
2167        /*********
2168        Logic here is unnecessary after schema WG's recent decision to allow
2169        schema components from one document to refer to components of any other,
2170        so long as there's some include/import/redefine path amongst them.
2171        If they rver reverse this decision the code's right here though... - neilg
2172        // now look in fDependencyMap to see if this is reachable
2173        if(((Vector)fDependencyMap.get(currSchema)).contains(declDocInfo)) {
2174            return declDocInfo;
2175        }
2176        // obviously the requesting doc didn't include, redefine or
2177        // import the one containing decl...
2178        return null;
2179        **********/

2180    } // findXSDocumentForDecl(XSDocumentInfo, Element): XSDocumentInfo
2181

2182    // returns whether more than <annotation>s occur in children of elem
2183
private boolean nonAnnotationContent(Element JavaDoc elem) {
2184        for(Element JavaDoc child = DOMUtil.getFirstChildElement(elem); child != null; child = DOMUtil.getNextSiblingElement(child)) {
2185            if(!(DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION))) return true;
2186        }
2187        return false;
2188    } // nonAnnotationContent(Element): boolean
2189

2190    private void setSchemasVisible(XSDocumentInfo startSchema) {
2191        if (DOMUtil.isHidden(startSchema.fSchemaDoc)) {
2192            // make it visible
2193
DOMUtil.setVisible(startSchema.fSchemaDoc);
2194            Vector JavaDoc dependingSchemas = (Vector JavaDoc)fDependencyMap.get(startSchema);
2195            for (int i = 0; i < dependingSchemas.size(); i++) {
2196                setSchemasVisible((XSDocumentInfo)dependingSchemas.elementAt(i));
2197            }
2198        }
2199        // if it's visible already than so must be its children
2200
} // setSchemasVisible(XSDocumentInfo): void
2201

2202    private SimpleLocator xl = new SimpleLocator();
2203    
2204    /**
2205     * Extract location information from an Element node, and create a
2206     * new SimpleLocator object from such information. Returning null means
2207     * no information can be retrieved from the element.
2208     */

2209    public SimpleLocator element2Locator(Element JavaDoc e) {
2210        if (!( e instanceof ElementImpl))
2211            return null;
2212        
2213        SimpleLocator l = new SimpleLocator();
2214        return element2Locator(e, l) ? l : null;
2215    }
2216    
2217    /**
2218     * Extract location information from an Element node, store such
2219     * information in the passed-in SimpleLocator object, then return
2220     * true. Returning false means can't extract or store such information.
2221     */

2222    public boolean element2Locator(Element JavaDoc e, SimpleLocator l) {
2223        if (l == null)
2224            return false;
2225        if (e instanceof ElementImpl) {
2226            ElementImpl ele = (ElementImpl)e;
2227            // get system id from document object
2228
Document JavaDoc doc = ele.getOwnerDocument();
2229            String JavaDoc sid = (String JavaDoc)fDoc2SystemId.get(doc);
2230            // line/column numbers are stored in the element node
2231
int line = ele.getLineNumber();
2232            int column = ele.getColumnNumber();
2233            l.setValues(sid, sid, line, column);
2234            return true;
2235        }
2236        return false;
2237    }
2238    
2239    void reportSchemaError(String JavaDoc key, Object JavaDoc[] args, Element JavaDoc ele) {
2240        if (element2Locator(ele, xl)) {
2241            fErrorReporter.reportError(xl, XSMessageFormatter.SCHEMA_DOMAIN,
2242                                       key, args, XMLErrorReporter.SEVERITY_ERROR);
2243        }
2244        else {
2245            fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN,
2246                                       key, args, XMLErrorReporter.SEVERITY_ERROR);
2247        }
2248    }
2249
2250    void reportSchemaWarning(String JavaDoc key, Object JavaDoc[] args, Element JavaDoc ele) {
2251        if (element2Locator(ele, xl)) {
2252            fErrorReporter.reportError(xl, XSMessageFormatter.SCHEMA_DOMAIN,
2253                                       key, args, XMLErrorReporter.SEVERITY_WARNING);
2254        }
2255        else {
2256            fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN,
2257                                       key, args, XMLErrorReporter.SEVERITY_WARNING);
2258        }
2259    }
2260
2261    /**
2262     * used to identify a reference to a schema document
2263     * if the same document is referenced twice with the same key, then
2264     * we only need to parse it once.
2265     *
2266     * When 2 XSDKey's are compared, the following table can be used to
2267     * determine whether they are equal:
2268     * inc red imp pre ins
2269     * inc N/L ? N/L N/L N/L
2270     * red ? N/L ? ? ?
2271     * imp N/L ? N/P N/P N/P
2272     * pre N/L ? N/P N/P N/P
2273     * ins N/L ? N/P N/P N/P
2274     *
2275     * Where: N/L: duplicate when they have the same namespace and location.
2276     * ? : not clear from the spec.
2277     * REVISIT: to simplify the process, also considering
2278     * it's very rare, we treat them as not duplicate.
2279     * N/P: not possible. imp/pre/ins are referenced by namespace.
2280     * when the first time we encounter a schema document for a
2281     * namespace, we create a grammar and store it in the grammar
2282     * bucket. when we see another reference to the same namespace,
2283     * we first check whether a grammar with the same namespace is
2284     * already in the bucket, which is true in this case, so we
2285     * won't create another XSDKey.
2286     *
2287     * Conclusion from the table: two XSDKey's are duplicate only when all of
2288     * the following are true:
2289     * 1. They are both "redefine", or neither is "redefine";
2290     * 2. They have the same namespace;
2291     * 3. They have the same non-null location.
2292     *
2293     * About 3: if neither has a non-null location, then it's the case where
2294     * 2 input streams are provided, but no system ID is provided. We can't tell
2295     * whether the 2 streams have the same content, so we treat them as not
2296     * duplicate.
2297     */

2298    private static class XSDKey {
2299        String JavaDoc systemId;
2300        short referType;
2301        // for inclue/redefine, this is the enclosing namespace
2302
// for import/preparse/instance, this is the target namespace
2303
String JavaDoc referNS;
2304
2305        XSDKey(String JavaDoc systemId, short referType, String JavaDoc referNS) {
2306            this.systemId = systemId;
2307            this.referType = referType;
2308            this.referNS = referNS;
2309        }
2310        
2311        public int hashCode() {
2312            // according to the description at the beginning of this class,
2313
// we use the hashcode of the namespace as the hashcoe of this key.
2314
return referNS == null ? 0 : referNS.hashCode();
2315        }
2316
2317        public boolean equals(Object JavaDoc obj) {
2318            if (!(obj instanceof XSDKey)) {
2319                return false;
2320            }
2321            XSDKey key = (XSDKey)obj;
2322            
2323            // condition 1: both are redefine
2324
if (referType == XSDDescription.CONTEXT_REDEFINE ||
2325                key.referType == XSDDescription.CONTEXT_REDEFINE) {
2326                if (referType != key.referType)
2327                    return false;
2328            }
2329            
2330            // condition 2: same namespace
2331
if (referNS != key.referNS)
2332                return false;
2333            
2334            // condition 3: same non-null locatoin
2335
if (systemId == null || !systemId.equals(key.systemId)) {
2336                return false;
2337            }
2338
2339            return true;
2340        }
2341    }
2342    
2343} // XSDHandler
2344
Popular Tags