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