View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.ws.commons.schema;
21  
22  import java.io.IOException;
23  import java.io.Reader;
24  import java.security.PrivilegedActionException;
25  import java.security.PrivilegedExceptionAction;
26  import java.util.ArrayList;
27  import java.util.Collection;
28  import java.util.HashMap;
29  import java.util.Iterator;
30  import java.util.List;
31  import java.util.Map;
32  import java.util.Stack;
33  
34  import javax.xml.namespace.QName;
35  import javax.xml.parsers.DocumentBuilder;
36  import javax.xml.parsers.DocumentBuilderFactory;
37  import javax.xml.parsers.ParserConfigurationException;
38  import javax.xml.transform.Source;
39  import javax.xml.transform.dom.DOMSource;
40  import javax.xml.transform.sax.SAXSource;
41  import javax.xml.transform.stream.StreamSource;
42  
43  import org.apache.ws.commons.schema.constants.Constants;
44  import org.apache.ws.commons.schema.extensions.ExtensionRegistry;
45  import org.apache.ws.commons.schema.resolver.CollectionURIResolver;
46  import org.apache.ws.commons.schema.resolver.DefaultURIResolver;
47  import org.apache.ws.commons.schema.resolver.URIResolver;
48  import org.apache.ws.commons.schema.utils.DOMUtil;
49  import org.apache.ws.commons.schema.utils.NamespacePrefixList;
50  import org.apache.ws.commons.schema.utils.TargetNamespaceValidator;
51  import org.w3c.dom.Document;
52  import org.w3c.dom.Element;
53  import org.w3c.dom.Node;
54  import org.xml.sax.InputSource;
55  import org.xml.sax.SAXException;
56  import org.xml.sax.EntityResolver;
57  
58  /**
59   * Contains a cache of XML Schema definition language (XSD).
60   *
61   */
62  public final class XmlSchemaCollection {
63  
64      // the default extension registry
65      private ExtensionRegistry extReg = new ExtensionRegistry();
66  
67      public ExtensionRegistry getExtReg() {
68          return extReg;
69      }
70  
71      public void setExtReg(ExtensionRegistry extReg) {
72          this.extReg = extReg;
73      }
74  
75      /**
76       * This map contains a list of Schema objects keyed in by their namespaces
77       * When resolving schemas, this map will be checked for the presence of the schema
78       * first
79       */
80      private Map knownNamespaceMap = new HashMap();
81  
82      /**
83       * get the namespace map
84       * @return a map of previously known XMLSchema objects keyed by their namespace (String)
85       */
86      public Map getKnownNamespaceMap() {
87  		return knownNamespaceMap;
88  	}
89  
90      /**
91       * sets the known namespace map
92       * @param knownNamespaceMap a map of previously known XMLSchema objects keyed by their namespace (String)
93       */
94  	public void setKnownNamespaceMap(Map knownNamespaceMap) {
95  		this.knownNamespaceMap = knownNamespaceMap;
96  	}
97  	
98  	
99  	/**
100 	 * Key that identifies a schema in a collection, composed of a targetNamespace
101 	 * and a system ID. 
102 	 */
103     public static class SchemaKey {
104         private final String namespace;
105         private final String systemId;
106         SchemaKey(String pNamespace, String pSystemId) {
107             namespace = pNamespace == null ? Constants.NULL_NS_URI : pNamespace;
108             systemId = pSystemId == null ? "" : pSystemId;
109         }
110         
111         String getNamespace() { return namespace; }
112         
113         String getSystemId() { return systemId; }
114         
115         public int hashCode() {
116             final int PRIME = 31;
117             return (PRIME + namespace.hashCode()) * PRIME + systemId.hashCode();
118         }
119         
120         public boolean equals(Object obj) {
121             if (this == obj)
122                 return true;
123             if (obj == null)
124                 return false;
125             if (getClass() != obj.getClass())
126                 return false;
127             final SchemaKey other = (SchemaKey) obj;
128             return namespace.equals(other.namespace)  &&  systemId.equals(other.systemId);
129         }
130         
131         public String toString() {
132             return Constants.NULL_NS_URI.equals(namespace) ?
133                     systemId : ("{" + namespace + "}" + systemId);
134         }
135     }
136 
137     /**
138      * Map of included schemas.
139      */
140     private Map schemas = new HashMap();
141 
142 
143     /**
144      * base URI is used as the base for loading the
145      * imports
146      */
147     String baseUri = null;
148     /**
149      * In-scope namespaces for XML processing
150      */
151     private NamespacePrefixList namespaceContext;
152 
153     /**
154      * An org.xml.sax.EntityResolver that is used to
155      * resolve the imports/includes
156      */
157     private URIResolver schemaResolver = new DefaultURIResolver();
158 
159 	XmlSchema xsd = new XmlSchema(XmlSchema.SCHEMA_NS, this);
160 
161     /**
162      * stack to track imports (to prevent recursion)
163      */
164     Stack stack = new Stack();
165 
166     /**
167      * Set the base URI. This is used when schemas need to be
168      * loaded from relative locations
169      * @param baseUri  baseUri for this collection.
170      */
171     public void setBaseUri(String baseUri) {
172         this.baseUri = baseUri;
173         if(schemaResolver instanceof CollectionURIResolver) {
174         	CollectionURIResolver resolverWithBase = 
175         		(CollectionURIResolver) schemaResolver;
176         	resolverWithBase.setCollectionBaseURI(baseUri);
177         }
178     }
179 
180     /**
181      * Register a custom URI resolver
182      * @param schemaResolver   resolver
183      */
184     public void setSchemaResolver(URIResolver schemaResolver) {
185         this.schemaResolver = schemaResolver;
186     }
187 
188     /**
189      * Retrieve the custom URI resolver, if any.
190      * @return the current resolver.
191      */
192     public URIResolver getSchemaResolver() {
193 		return schemaResolver;
194 	}
195 
196     /**
197      * This section should comply to the XMLSchema specification; see
198      * <a href="http://www.w3.org/TR/2004/PER-xmlschema-2-20040318/datatypes.html#built-in-datatypes">
199      *  http://www.w3.org/TR/2004/PER-xmlschema-2-20040318/datatypes.html#built-in-datatypes</a>.
200      * This needs to be inspected by another pair of eyes
201      */
202     public void init() {
203     	
204     	/*
205     	 * Defined in section 4.
206     	 */
207     	addSimpleType(xsd, Constants.XSD_ANYSIMPLETYPE.getLocalPart());
208     	addSimpleType(xsd, Constants.XSD_ANYTYPE.getLocalPart());
209     	
210         /*
211         Primitive types
212 
213         3.2.1 string
214         3.2.2 boolean
215         3.2.3 decimal
216         3.2.4 float
217         3.2.5 double
218         3.2.6 duration
219         3.2.7 dateTime
220         3.2.8 time
221         3.2.9 date
222         3.2.10 gYearMonth
223         3.2.11 gYear
224         3.2.12 gMonthDay
225         3.2.13 gDay
226         3.2.14 gMonth
227         3.2.15 hexBinary
228         3.2.16 base64Binary
229         3.2.17 anyURI
230         3.2.18 QName
231         3.2.19 NOTATION
232         */
233         addSimpleType(xsd, Constants.XSD_STRING.getLocalPart());
234         addSimpleType(xsd, Constants.XSD_BOOLEAN.getLocalPart());
235         addSimpleType(xsd, Constants.XSD_FLOAT.getLocalPart());
236         addSimpleType(xsd, Constants.XSD_DOUBLE.getLocalPart());
237         addSimpleType(xsd, Constants.XSD_QNAME.getLocalPart());
238         addSimpleType(xsd, Constants.XSD_DECIMAL.getLocalPart());
239         addSimpleType(xsd, Constants.XSD_DURATION.getLocalPart());
240         addSimpleType(xsd, Constants.XSD_DATE.getLocalPart());
241         addSimpleType(xsd, Constants.XSD_TIME.getLocalPart());
242         addSimpleType(xsd, Constants.XSD_DATETIME.getLocalPart());
243         addSimpleType(xsd, Constants.XSD_DAY.getLocalPart());
244         addSimpleType(xsd, Constants.XSD_MONTH.getLocalPart());
245         addSimpleType(xsd, Constants.XSD_MONTHDAY.getLocalPart());
246         addSimpleType(xsd, Constants.XSD_YEAR.getLocalPart());
247         addSimpleType(xsd, Constants.XSD_YEARMONTH.getLocalPart());
248         addSimpleType(xsd, Constants.XSD_NOTATION.getLocalPart());
249         addSimpleType(xsd, Constants.XSD_HEXBIN.getLocalPart());
250         addSimpleType(xsd, Constants.XSD_BASE64.getLocalPart());
251         addSimpleType(xsd, Constants.XSD_ANYURI.getLocalPart());
252 
253 
254         /*
255          3.3.1 normalizedString
256         3.3.2 token
257         3.3.3 language
258         3.3.4 NMTOKEN
259         3.3.5 NMTOKENS
260         3.3.6 Name
261         3.3.7 NCName
262         3.3.8 ID
263         3.3.9 IDREF
264         3.3.10 IDREFS
265         3.3.11 ENTITY
266         3.3.12 ENTITIES
267         3.3.13 integer
268         3.3.14 nonPositiveInteger
269         3.3.15 negativeInteger
270         3.3.16 long
271         3.3.17 int
272         3.3.18 short
273         3.3.19 byte
274         3.3.20 nonNegativeInteger
275         3.3.21 unsignedLong
276         3.3.22 unsignedInt
277         3.3.23 unsignedShort
278         3.3.24 unsignedByte
279         3.3.25 positiveInteger
280         */
281 
282          //derived types from decimal
283         addSimpleType(xsd, Constants.XSD_LONG.getLocalPart());
284         addSimpleType(xsd, Constants.XSD_SHORT.getLocalPart());
285         addSimpleType(xsd, Constants.XSD_BYTE.getLocalPart());
286         addSimpleType(xsd, Constants.XSD_INTEGER.getLocalPart());
287         addSimpleType(xsd, Constants.XSD_INT.getLocalPart());
288         addSimpleType(xsd, Constants.XSD_POSITIVEINTEGER.getLocalPart());
289         addSimpleType(xsd, Constants.XSD_NEGATIVEINTEGER.getLocalPart());
290         addSimpleType(xsd, Constants.XSD_NONPOSITIVEINTEGER.getLocalPart());
291         addSimpleType(xsd, Constants.XSD_NONNEGATIVEINTEGER.getLocalPart());
292         addSimpleType(xsd, Constants.XSD_UNSIGNEDBYTE.getLocalPart());
293         addSimpleType(xsd, Constants.XSD_UNSIGNEDINT.getLocalPart());
294         addSimpleType(xsd, Constants.XSD_UNSIGNEDLONG.getLocalPart());
295         addSimpleType(xsd, Constants.XSD_UNSIGNEDSHORT.getLocalPart());
296 
297         //derived types from string
298         addSimpleType(xsd, Constants.XSD_NAME.getLocalPart());
299         addSimpleType(xsd, Constants.XSD_NORMALIZEDSTRING.getLocalPart());
300         addSimpleType(xsd, Constants.XSD_NCNAME.getLocalPart());
301         addSimpleType(xsd, Constants.XSD_NMTOKEN.getLocalPart());
302         addSimpleType(xsd, Constants.XSD_NMTOKENS.getLocalPart());
303         addSimpleType(xsd, Constants.XSD_ENTITY.getLocalPart());
304         addSimpleType(xsd, Constants.XSD_ENTITIES.getLocalPart());
305         addSimpleType(xsd, Constants.XSD_ID.getLocalPart());
306         addSimpleType(xsd, Constants.XSD_IDREF.getLocalPart());
307         addSimpleType(xsd, Constants.XSD_IDREFS.getLocalPart());
308         addSimpleType(xsd, Constants.XSD_LANGUAGE.getLocalPart());
309         addSimpleType(xsd, Constants.XSD_TOKEN.getLocalPart());
310 
311         //SchemaKey key = new SchemaKey(XmlSchema.SCHEMA_NS, null);
312         //addSchema(key, xsd);
313 
314         // look for a system property to see whether we have a registered
315         // extension registry class. if so we'll instantiate a new one
316         // and set it as the extension registry
317         //if there is an error, we'll just print out a message and move on.
318 
319         if (System.getProperty(Constants.SystemConstants.EXTENSION_REGISTRY_KEY)!= null){
320             try {
321                 Class clazz = Class.forName(System.getProperty(Constants.SystemConstants.EXTENSION_REGISTRY_KEY));
322                 this.extReg = (ExtensionRegistry)clazz.newInstance();
323             } catch (ClassNotFoundException e) {
324                 System.err.println("The specified extension registry class cannot be found!");
325             } catch (InstantiationException e) {
326                 System.err.println("The specified extension registry class cannot be instantiated!");
327             } catch (IllegalAccessException e) {
328                 System.err.println("The specified extension registry class cannot be accessed!");
329             }
330         }
331     }
332 
333     boolean containsSchema(SchemaKey pKey) {
334         return schemas.containsKey(pKey);
335     }
336 
337     
338     /**
339      * gets a schema from the external namespace map
340      * @param namespace
341      * @return
342      */
343     XmlSchema getKnownSchema(String namespace) {
344         return (XmlSchema) knownNamespaceMap.get(namespace);
345     }
346     
347     /**
348      * Get a schema given a SchemaKey
349      * @param pKey
350      * @return
351      */
352     XmlSchema getSchema(SchemaKey pKey) {
353         return (XmlSchema) schemas.get(pKey);
354     }
355 
356     void addSchema(SchemaKey pKey, XmlSchema pSchema) {
357         if (schemas.containsKey(pKey)) {
358             throw new IllegalStateException("A schema with target namespace "
359                     + pKey.getNamespace() + " and system ID " + pKey.getSystemId()
360                     + " is already present.");
361         }
362         schemas.put(pKey, pSchema);
363     }
364 
365     private void addSimpleType(XmlSchema schema,String typeName){
366         XmlSchemaSimpleType type;
367         type = new XmlSchemaSimpleType(schema);
368         type.setName(typeName);
369         schema.addType(type);
370     }
371     public XmlSchema read(Reader r, ValidationEventHandler veh) {
372         return read(new InputSource(r), veh);
373     }
374 
375     XmlSchema read(final InputSource inputSource, ValidationEventHandler veh,
376             TargetNamespaceValidator namespaceValidator) {
377         try {
378             DocumentBuilderFactory docFac = DocumentBuilderFactory.newInstance();
379             docFac.setNamespaceAware(true);
380             final DocumentBuilder builder = docFac.newDocumentBuilder();
381              /* specify ER on doc builder */ 
382             if (entityResolver != null) builder.setEntityResolver(entityResolver); 
383             Document doc = null;
384             doc = parse_doPriv(inputSource, builder, doc);
385             return read(doc, inputSource.getSystemId(), veh, namespaceValidator);
386         } catch (ParserConfigurationException e) {
387             throw new XmlSchemaException(e.getMessage());
388         } catch (IOException e) {
389             throw new XmlSchemaException(e.getMessage());
390         } catch (SAXException e) {
391             throw new XmlSchemaException(e.getMessage());
392         }
393     }
394 
395     private Document parse_doPriv(final InputSource inputSource, final DocumentBuilder builder, Document doc) throws IOException, SAXException {
396         try {
397             doc = (Document) java.security.AccessController.doPrivileged(
398                     new PrivilegedExceptionAction() {
399                         public Object run() throws IOException, SAXException {
400                             return builder.parse(inputSource);
401                         }
402                     }
403             );
404         } catch (PrivilegedActionException e) {
405             Exception exception = e.getException();
406             if(exception instanceof IOException) {
407                 throw (IOException) exception;
408             }
409             if(exception instanceof SAXException) {
410                 throw (SAXException) exception;
411             }
412         }
413         return doc;
414     }
415 
416     /**
417      * Read an XML schema into the collection from a SAX InputSource.
418      * Schemas in a collection must be unique in the concatenation of system ID and
419      * targetNamespace. In this API, the systemID is taken from the source.
420      * @param inputSource the XSD document.
421      * @param veh handler that is called back for validation.
422      * @return the XML schema object.
423      */
424     public XmlSchema read(InputSource inputSource, ValidationEventHandler veh) {
425         return read(inputSource, veh, null);
426     }
427     
428     /**
429      * Read an XML schema into the collection from a TRaX source. 
430      * Schemas in a collection must be unique in the concatenation of system ID and
431      * targetNamespace. In this API, the systemID is taken from the Source.
432      * @param source the XSD document.
433      * @param veh handler that is called back for validation.
434      * @return the XML schema object.
435      */
436     public XmlSchema read(Source source, ValidationEventHandler veh) {
437         if (source instanceof SAXSource) {
438             return read(((SAXSource) source).getInputSource(), veh);
439         } else if (source instanceof DOMSource) {
440             Node node = ((DOMSource) source).getNode();
441             if (node instanceof Document) {
442                 node = ((Document) node).getDocumentElement();
443             }
444             return read((Document) node, veh);
445         } else if (source instanceof StreamSource) {
446             StreamSource ss = (StreamSource) source;
447             InputSource isource = new InputSource(ss.getSystemId());
448             isource.setByteStream(ss.getInputStream());
449             isource.setCharacterStream(ss.getReader());
450             isource.setPublicId(ss.getPublicId());
451             return read(isource, veh);
452         } else {
453             InputSource isource = new InputSource(source.getSystemId());
454             return read(isource, veh);
455         }
456     }
457 
458     /**
459      * Read an XML schema into the collection from a DOM document. 
460      * Schemas in a collection must be unique in the concatenation of system ID and
461      * targetNamespace. In this API, the systemID is taken from the document.
462      * @param doc the XSD document.
463      * @param veh handler that is called back for validation.
464      * @return the XML schema object.
465      */
466     public XmlSchema read(Document doc, ValidationEventHandler veh) {
467         SchemaBuilder builder = new SchemaBuilder(this, null);
468         return builder.build(doc, null, veh);
469     }
470 
471    
472     /**
473      * Read an XML Schema into the collection from a DOM element. Schemas in a collection
474      * must be unique in the concatentation of System ID and targetNamespace. The system ID will 
475      * be empty for this API.
476      * @param elem the DOM element for the schema.
477      * @return the XmlSchema
478      */
479     public XmlSchema read(Element elem) {
480         SchemaBuilder builder = new SchemaBuilder(this, null);
481         XmlSchema xmlSchema = builder.handleXmlSchemaElement(elem, null);
482         xmlSchema.setInputEncoding(DOMUtil.getXmlEncoding(elem.getOwnerDocument()));
483         return xmlSchema;
484     }
485 
486     /**
487      * Read an XML Schema from a complete XSD XML DOM Document into this collection.
488      * Schemas in a collection must be unique in
489      * the concatenation of SystemId and targetNamespace.
490      * @param doc The schema document.
491      * @param systemId System ID for this schema.
492      * @param veh handler to be called to check validity of the schema.
493      * @return the schema object.
494      */
495     public XmlSchema read(Document doc, String systemId, ValidationEventHandler veh) {
496         return read(doc, systemId, veh, null);
497     }
498 
499     /**
500      * Read an XML Schema from a complete XSD XML DOM Document into this collection.
501      *  Schemas in a collection must be unique in
502      * the concatenation of SystemId and targetNamespace.
503      * @param doc Source document.
504      * @param systemId System id.
505      * @param veh Stub for future capability to handle validation errors.
506      * @param validator object that is called back to check validity of the target namespace.
507      * @return the schema object.
508      */
509     public XmlSchema read(Document doc, String systemId, ValidationEventHandler veh,
510             TargetNamespaceValidator validator) {
511         SchemaBuilder builder = new SchemaBuilder(this, validator);
512         XmlSchema schema = builder.build(doc, systemId, veh);
513         schema.setInputEncoding(DOMUtil.getInputEncoding(doc));
514 		return schema;
515     }
516 
517     /**
518      * Read a schema from a DOM tree into the collection. The schemas in a collection must be unique
519      * in the concatenation of the target namespace and the system ID.  
520      * @param elem xs:schema DOM element.
521      * @param systemId System id.
522      * @return the schema object.
523      */
524     public XmlSchema read(Element elem, String systemId) {
525         SchemaBuilder builder = new SchemaBuilder(this, null);
526         XmlSchema xmlSchema = builder.handleXmlSchemaElement(elem, systemId);
527         xmlSchema.setInputEncoding(DOMUtil.getInputEncoding(elem.getOwnerDocument()));
528         return xmlSchema;
529     }
530     
531     /**
532      * Creates new XmlSchemaCollection
533      */
534     public XmlSchemaCollection() {
535         init();
536     }
537 
538     /**
539      * Retrieve a set containing the XmlSchema instances with the given system ID.
540      * In general, this will return a single instance, or none. However,
541      * if the schema has no targetNamespace attribute and was included
542      * from schemata with different target namespaces, then it may
543      * occur, that multiple schema instances with different logical
544      * target namespaces may be returned.
545      * @param systemId  the system id for this  schema
546      * @return array of XmlSchema objects
547      */
548     public XmlSchema[] getXmlSchema(String systemId) {
549         if (systemId == null) {
550             systemId = "";
551         }
552         final List result = new ArrayList();
553         for (Iterator iter = schemas.entrySet().iterator();  iter.hasNext();  ) {
554             Map.Entry entry = (Map.Entry) iter.next();
555             if (((SchemaKey) entry.getKey()).getSystemId().equals(systemId)) {
556                 result.add(entry.getValue());
557             }
558         }
559         return (XmlSchema[]) result.toArray(new XmlSchema[result.size()]);
560     }
561 
562     /**
563      * Returns an array of all the XmlSchemas in this collection.
564      * @return the list of XmlSchema objects
565      */
566     public XmlSchema[] getXmlSchemas() {
567         Collection c = schemas.values();
568         return (XmlSchema[]) c.toArray(new XmlSchema[c.size()]);
569     }
570 
571     
572     /**
573      * Retrieve a global element from the schema collection. 
574      * @param qname the element QName.
575      * @return the element object, or null.
576      */
577     public XmlSchemaElement getElementByQName(QName qname) {
578 		String uri = qname.getNamespaceURI();
579 		for (Iterator iter = schemas.entrySet().iterator(); iter.hasNext();) {
580 			Map.Entry entry = (Map.Entry) iter.next();
581 			if (((SchemaKey) entry.getKey()).getNamespace().equals(uri)) {
582 				XmlSchemaElement element = ((XmlSchema) entry.getValue())
583 						.getElementByName(qname);
584 				if (element != null) {
585 					return element;
586 				}
587 			}
588 		}
589 		return null;
590 	}
591 
592     /**
593      * Retrieve a global type from the schema collection.
594      * @param schemaTypeName the QName of the type.
595      * @return the type object, or null.
596      */
597     public XmlSchemaType getTypeByQName(QName schemaTypeName) {
598 		String uri = schemaTypeName.getNamespaceURI();
599 		for (Iterator iter = schemas.entrySet().iterator(); iter.hasNext();) {
600 			Map.Entry entry = (Map.Entry) iter.next();
601 			if (((SchemaKey) entry.getKey()).getNamespace().equals(uri)) {
602 				XmlSchemaType type = ((XmlSchema) entry.getValue())
603 						.getTypeByName(schemaTypeName);
604 				if (type != null) {
605 					return type;
606 				}
607 			}
608 		}
609 		return null;
610 	}
611     
612     /**
613      * Find a global attribute by QName in this collection of schemas.
614      * @param schemaAttributeName the name of the attribute.
615      * @return the attribute or null.
616      */
617     public XmlSchemaAttribute getAttributeByQName(QName schemaAttributeName) {
618         String uri = schemaAttributeName.getNamespaceURI();
619         for (Iterator iter = schemas.entrySet().iterator();  iter.hasNext();  ) {
620             Map.Entry entry = (Map.Entry) iter.next();
621             if (((SchemaKey) entry.getKey()).getNamespace().equals(uri)) {
622                 XmlSchemaAttribute attribute = ((XmlSchema) entry.getValue()).getAttributeByName(schemaAttributeName);
623                 if (attribute != null) {
624                     return attribute;
625                 }
626         }
627         }
628         return null;
629     }
630     
631     /**
632      * Return the schema from this collection for a particular targetNamespace.
633      * @param uri target namespace URI.
634      * @return the schema.
635      */
636     public XmlSchema schemaForNamespace(String uri) {
637         for (Iterator iter = schemas.entrySet().iterator();  iter.hasNext();  ) {
638             Map.Entry entry = (Map.Entry) iter.next();
639             if (((SchemaKey) entry.getKey()).getNamespace().equals(uri)) {
640                 return (XmlSchema) entry.getValue();
641             }
642         }
643         return null;
644     }
645 
646     Map unresolvedTypes = new HashMap();
647 
648     void addUnresolvedType(QName type, TypeReceiver receiver) {
649         ArrayList receivers = (ArrayList)unresolvedTypes.get(type);
650         if (receivers == null) {
651             receivers = new ArrayList();
652             unresolvedTypes.put(type, receivers);
653         }
654         receivers.add(receiver);
655     }
656 
657     void resolveType(QName typeName, XmlSchemaType type) {
658         ArrayList receivers = (ArrayList)unresolvedTypes.get(typeName);
659         if (receivers == null)
660             return;
661         for (Iterator i = receivers.iterator(); i.hasNext();) {
662             TypeReceiver receiver = (TypeReceiver) i.next();
663             receiver.setType(type);
664         }
665         unresolvedTypes.remove(typeName);
666     }
667 
668     /**
669      * Retrieve the namespace context.
670      * @return the namespace context.
671      */
672     public NamespacePrefixList getNamespaceContext() {
673         return namespaceContext;
674     }
675 
676     /**
677      * Set the namespace context for this collection, which controls the assignment of
678      * namespace prefixes to namespaces.
679      * @param namespaceContext the context.
680      */
681     public void setNamespaceContext(NamespacePrefixList namespaceContext) {
682         this.namespaceContext = namespaceContext;
683     }
684 
685     /**
686      * Push a schema onto the stack of schemas.
687      *  This function, while public, is probably not useful outside of 
688      * the implementation.
689      * @param pKey the schema key.
690      */
691     public void push(SchemaKey pKey) {
692         stack.push(pKey);
693     }
694 
695     /**
696      * Pop the stack of schemas. This function, while public, is probably not useful outside of 
697      * the implementation.
698      */
699     public void pop() {
700         stack.pop();
701     }
702 
703     /**
704      * Return an indication of whether a particular schema is in the working stack of 
705      * schemas. This function, while public, is probably not useful outside of 
706      * the implementation.
707      * @param pKey schema key
708      * @return true if the schema is in the stack.
709      */
710     public boolean check(SchemaKey pKey) {
711         return (stack.indexOf(pKey)==-1);
712     }
713 
714 	public String toString() {
715     	return super.toString() + "[" + schemas.toString() + "]";
716     }
717 
718     private EntityResolver entityResolver;
719 
720     public EntityResolver getEntityResolver() {
721         return entityResolver;
722     }
723 
724     public void setEntityResolver(EntityResolver entityResolver) {
725         this.entityResolver = entityResolver;
726     }
727 
728 }