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