001: //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/trunk/src/org/deegree/framework/xml/schema/XMLSchema.java $
002: /*---------------- FILE HEADER ------------------------------------------
003:
004: This file is part of deegree.
005: Copyright (C) 2001-2008 by:
006: EXSE, Department of Geography, University of Bonn
007: http://www.giub.uni-bonn.de/deegree/
008: lat/lon GmbH
009: http://www.lat-lon.de
010:
011: This library is free software; you can redistribute it and/or
012: modify it under the terms of the GNU Lesser General Public
013: License as published by the Free Software Foundation; either
014: version 2.1 of the License, or (at your option) any later version.
015:
016: This library is distributed in the hope that it will be useful,
017: but WITHOUT ANY WARRANTY; without even the implied warranty of
018: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: Lesser General Public License for more details.
020:
021: You should have received a copy of the GNU Lesser General Public
022: License along with this library; if not, write to the Free Software
023: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024:
025: Contact:
026:
027: Andreas Poth
028: lat/lon GmbH
029: Aennchenstraße 19
030: 53177 Bonn
031: Germany
032: E-Mail: poth@lat-lon.de
033:
034: Prof. Dr. Klaus Greve
035: Department of Geography
036: University of Bonn
037: Meckenheimer Allee 166
038: 53115 Bonn
039: Germany
040: E-Mail: greve@giub.uni-bonn.de
041:
042: ---------------------------------------------------------------------------*/
043: package org.deegree.framework.xml.schema;
044:
045: import java.net.URI;
046: import java.util.HashMap;
047: import java.util.Iterator;
048: import java.util.Map;
049:
050: import org.deegree.datatypes.QualifiedName;
051: import org.deegree.framework.log.ILogger;
052: import org.deegree.framework.log.LoggerFactory;
053:
054: /**
055: * Represents an XML schema document.
056: *
057: * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </a>
058: * @author last edited by: $Author: apoth $
059: *
060: * @version $Revision: 9339 $, $Date: 2007-12-27 04:31:52 -0800 (Thu, 27 Dec 2007) $
061: */
062: public class XMLSchema {
063:
064: private final static ILogger LOG = LoggerFactory
065: .getLogger(XMLSchema.class);
066:
067: private URI targetNamespace;
068:
069: // keys: QualifiedName (element names), values: ElementDeclaration
070: private Map<QualifiedName, ElementDeclaration> elementMap = new HashMap<QualifiedName, ElementDeclaration>();
071:
072: // keys: QualifiedName (type names), values: TypeDeclaration
073: private Map<QualifiedName, TypeDeclaration> typeMap = new HashMap<QualifiedName, TypeDeclaration>();
074:
075: // keys: QualifiedName (type names), values: ComplexTypeDeclaration
076: private Map<QualifiedName, ComplexTypeDeclaration> complexTypeMap = new HashMap<QualifiedName, ComplexTypeDeclaration>();
077:
078: // keys: QualifiedName (type names), values: SimpleTypeDeclaration
079: private Map<QualifiedName, SimpleTypeDeclaration> simpleTypeMap = new HashMap<QualifiedName, SimpleTypeDeclaration>();
080:
081: /**
082: * Creates a new <code>XMLSchema</code> instance from the given parameters.
083: *
084: * @param targetNamespace
085: * @param simpleTypes
086: * @param complexTypes
087: * @param elementDeclarations
088: * @throws XMLSchemaException
089: */
090: public XMLSchema(URI targetNamespace,
091: SimpleTypeDeclaration[] simpleTypes,
092: ComplexTypeDeclaration[] complexTypes,
093: ElementDeclaration[] elementDeclarations)
094: throws XMLSchemaException {
095: this .targetNamespace = targetNamespace;
096: for (int i = 0; i < elementDeclarations.length; i++) {
097: elementMap.put(elementDeclarations[i].getName(),
098: elementDeclarations[i]);
099: }
100: for (int i = 0; i < simpleTypes.length; i++) {
101: simpleTypeMap.put(simpleTypes[i].getName(), simpleTypes[i]);
102: typeMap.put(simpleTypes[i].getName(), simpleTypes[i]);
103: }
104: for (int i = 0; i < complexTypes.length; i++) {
105: complexTypeMap.put(complexTypes[i].getName(),
106: complexTypes[i]);
107: typeMap.put(complexTypes[i].getName(), complexTypes[i]);
108: }
109: resolveReferences();
110: }
111:
112: /**
113: * Returns the target namespace of the schema document.
114: *
115: * @return the target namespace
116: */
117: public URI getTargetNamespace() {
118: return this .targetNamespace;
119: }
120:
121: /**
122: * Returns all <code>ElementDeclaration</code>s that are defined in the schema.
123: *
124: * @return all ElementDeclarations that are defined in the schema
125: */
126: public ElementDeclaration[] getElementDeclarations() {
127: return this .elementMap.values().toArray(
128: new ElementDeclaration[this .elementMap.size()]);
129: }
130:
131: /**
132: * Returns all <code>SimpleTypeDeclaration</code>s that are defined in the schema.
133: *
134: * @return all SimpleTypeDeclarations that are defined in the schema
135: */
136: public SimpleTypeDeclaration[] getSimpleTypeDeclarations() {
137: return this .simpleTypeMap.values().toArray(
138: new SimpleTypeDeclaration[this .simpleTypeMap.size()]);
139: }
140:
141: /**
142: * Returns all <code>ComplexTypeDeclaration</code>s that are defined in the schema.
143: *
144: * @return all ComplexTypeDeclarations that are defined in the schema
145: */
146: public ComplexTypeDeclaration[] getComplexTypeDeclarations() {
147: return this .complexTypeMap.values().toArray(
148: new ComplexTypeDeclaration[this .complexTypeMap.size()]);
149: }
150:
151: /**
152: * Looks up the <code>ElementDeclaration</code> for the given <code>QualifiedName</code>.
153: *
154: * @param qName
155: * the QualifiedName to look up
156: * @return the ElementDeclaration, if an element with the given name is defined in the schema,
157: * null otherwise
158: */
159: public ElementDeclaration getElementDeclaration(QualifiedName qName) {
160: return this .elementMap.get(qName);
161: }
162:
163: /**
164: * Looks up the <code>TypeDeclaration</code> for the given <code>QualifiedName</code>.
165: *
166: * @param qName
167: * the QualifiedName to look up
168: * @return the TypeDeclaration, if a type with the given name is defined in the schema, null
169: * otherwise
170: */
171: public TypeDeclaration getTypeDeclaration(QualifiedName qName) {
172: return this .typeMap.get(qName);
173: }
174:
175: /**
176: * Looks up the <code>SimpleTypeDeclaration</code> for the given <code>QualifiedName</code>.
177: *
178: * @param qName
179: * the QualifiedName to look up
180: * @return the SimpleTypeDeclaration, if a simple type with the given name is defined in the
181: * schema, null otherwise
182: */
183: public SimpleTypeDeclaration getSimpleTypeDeclaration(
184: QualifiedName qName) {
185: return this .simpleTypeMap.get(qName);
186: }
187:
188: /**
189: * Looks up the <code>ComplexTypeDeclaration</code> for the given <code>QualifiedName</code>.
190: *
191: * @param qName
192: * the QualifiedName to look up
193: * @return the ComplexTypeDeclaration, if a complex type with the given name is defined in the
194: * schema, null otherwise
195: */
196: public ComplexTypeDeclaration getComplexTypeDeclaration(
197: QualifiedName qName) {
198: return this .complexTypeMap.get(qName);
199: }
200:
201: /**
202: * Looks up the <code>ElementDeclaration</code> for the given local name (without namespace).
203: *
204: * @param name
205: * the (unqualified) name to look up
206: * @return the ElementDeclaration, if an element with the given name is defined in the schema,
207: * null otherwise
208: */
209: public ElementDeclaration getElementDeclaration(String name) {
210: return getElementDeclaration(new QualifiedName(name,
211: this .targetNamespace));
212: }
213:
214: /**
215: * Looks up the <code>TypeDeclaration</code> for the given local name (without namespace).
216: *
217: * @param name
218: * the (unqualified) name to look up
219: * @return the TypeDeclaration, if a type with the given name is defined in the schema, null
220: * otherwise
221: */
222: public TypeDeclaration getTypeDeclaration(String name) {
223: return getTypeDeclaration(new QualifiedName(name,
224: this .targetNamespace));
225: }
226:
227: /**
228: * Looks up the <code>SimpleTypeDeclaration</code> for the given local name (without
229: * namespace).
230: *
231: * @param name
232: * the (unqualified) name to look up
233: * @return the SimpleTypeDeclaration, if a simple type with the given name is defined in the
234: * schema, null otherwise
235: */
236: public SimpleTypeDeclaration getSimpleTypeDeclaration(String name) {
237: return getSimpleTypeDeclaration(new QualifiedName(name,
238: this .targetNamespace));
239: }
240:
241: /**
242: * Looks up the <code>ComplexTypeDeclaration</code> for the given local name (without
243: * namespace).
244: *
245: * @param name
246: * the (unqualified) name to look up
247: * @return the ComplexTypeDeclaration, if a complex type with the given name is defined in the
248: * schema, null otherwise
249: */
250: public ComplexTypeDeclaration getComplexTypeDeclaration(String name) {
251: return getComplexTypeDeclaration(new QualifiedName(name,
252: this .targetNamespace));
253: }
254:
255: private void resolveReferences()
256: throws UnresolvableReferenceException {
257: LOG.logDebug("Resolving references for namespace '"
258: + this .targetNamespace + "'.");
259: Iterator iter = elementMap.values().iterator();
260: while (iter.hasNext()) {
261: resolveReferences((ElementDeclaration) iter.next());
262: }
263: iter = typeMap.values().iterator();
264: while (iter.hasNext()) {
265: resolveReferences((TypeDeclaration) iter.next());
266: }
267: }
268:
269: private void resolveReferences(ElementDeclaration element)
270: throws UnresolvableReferenceException {
271: LOG.logDebug("Resolving references in element declaration '"
272: + element.getName().getLocalName() + "'.");
273: ElementReference substitutionGroup = element
274: .getSubstitutionGroup();
275: if (substitutionGroup != null) {
276: resolveElement(substitutionGroup);
277: }
278: TypeReference typeReference = element.getType();
279: resolveType(typeReference);
280: }
281:
282: private void resolveReferences(TypeDeclaration typeDeclaration)
283: throws UnresolvableReferenceException {
284: LOG.logDebug("Resolving references in type declaration '"
285: + typeDeclaration.getName().getLocalName() + "'.");
286: if (typeDeclaration instanceof SimpleTypeDeclaration) {
287: LOG.logDebug("SimpleType.");
288: SimpleTypeDeclaration simpleType = (SimpleTypeDeclaration) typeDeclaration;
289: TypeReference typeReference = simpleType
290: .getRestrictionBaseType();
291: if (typeReference != null) {
292: LOG.logDebug("restriction base='"
293: + typeReference.getName() + "'");
294: try {
295: resolveType(typeReference);
296: } catch (XMLSchemaException e) {
297: throw new UndefinedXSDTypeException(
298: "Declaration of type '"
299: + typeDeclaration.getName()
300: + "' derives type '"
301: + typeReference.getName()
302: + "' which is not a defined simple type.");
303: }
304: }
305: } else {
306: LOG.logDebug("ComplexType.");
307: ComplexTypeDeclaration complexType = (ComplexTypeDeclaration) typeDeclaration;
308: TypeReference typeReference = complexType
309: .getExtensionBaseType();
310: if (typeReference != null) {
311: LOG.logDebug("extension base='"
312: + typeReference.getName() + "'");
313: try {
314: resolveType(typeReference);
315: } catch (XMLSchemaException e) {
316: throw new UndefinedXSDTypeException(
317: "Declaration of type '"
318: + typeDeclaration.getName()
319: + "' derives type '"
320: + typeReference.getName()
321: + "' which is not a defined complex type.");
322: }
323: }
324: ElementDeclaration[] elements = complexType
325: .getExplicitElements();
326: for (int i = 0; i < elements.length; i++) {
327: resolveReferences(elements[i]);
328: }
329: }
330: }
331:
332: private void resolveElement(ElementReference elementReference)
333: throws UndefinedElementException {
334: if (!elementReference.isResolved()) {
335: LOG.logDebug("Resolving reference to element '"
336: + elementReference.getName().getLocalName() + "'.");
337: if (elementReference.getName().isInNamespace(
338: this .targetNamespace)) {
339: ElementDeclaration element = elementMap
340: .get(elementReference.getName());
341: if (element == null) {
342: LOG.logDebug("Cannot be resolved!");
343: throw new UndefinedElementException("Element '"
344: + elementReference.getName()
345: + "' is not defined.");
346: }
347: LOG.logDebug("OK.");
348: elementReference.resolve(element);
349: } else {
350: LOG.logDebug("Skipped (not in target namespace).");
351: elementReference.resolve();
352: }
353: }
354: }
355:
356: private void resolveType(TypeReference typeReference)
357: throws UnresolvableReferenceException {
358: if (!typeReference.isResolved()) {
359: if (typeReference.isAnonymous()) {
360: LOG.logDebug("Inline type...");
361: // type is defined inline
362: TypeDeclaration type = typeReference
363: .getTypeDeclaration();
364: typeReference.resolve();
365: if (type instanceof ComplexTypeDeclaration) {
366: ComplexTypeDeclaration complexType = (ComplexTypeDeclaration) type;
367: ElementDeclaration[] subElements = complexType
368: .getExplicitElements();
369: for (int i = 0; i < subElements.length; i++) {
370: resolveReferences(subElements[i]);
371: }
372: }
373: } else {
374: LOG.logDebug("Resolving reference to type: '"
375: + typeReference.getName() + "'...");
376: if (typeReference.getName().isInNamespace(
377: this .targetNamespace)) {
378: TypeDeclaration type = typeMap.get(typeReference
379: .getName());
380: if (type == null) {
381: LOG.logDebug("Cannot be resolved!");
382: throw new UndefinedXSDTypeException("Type '"
383: + typeReference.getName()
384: + "' is not a defined type.");
385: }
386: LOG.logDebug("OK.");
387: typeReference.resolve(type);
388: } else {
389: LOG
390: .logDebug("Skipped (not in target / schema namespace).");
391: }
392: }
393: }
394: }
395:
396: @Override
397: public String toString() {
398: StringBuffer sb = new StringBuffer(
399: "XML Schema targetNamespace='");
400: sb.append(targetNamespace);
401: sb.append("'\n");
402: sb.append("\n*** ");
403: sb.append(elementMap.size());
404: sb.append(" global element declarations ***\n");
405: Iterator elementIter = elementMap.values().iterator();
406: while (elementIter.hasNext()) {
407: ElementDeclaration element = (ElementDeclaration) elementIter
408: .next();
409: sb.append(element.toString(""));
410: }
411: sb.append("\n*** ");
412: sb.append(simpleTypeMap.size());
413: sb.append(" global simple type declarations ***\n");
414: Iterator simpleTypeIter = simpleTypeMap.values().iterator();
415: while (simpleTypeIter.hasNext()) {
416: SimpleTypeDeclaration type = (SimpleTypeDeclaration) simpleTypeIter
417: .next();
418: sb.append(type.toString(""));
419: }
420: sb.append("\n*** ");
421: sb.append(complexTypeMap.size());
422: sb.append(" global complex type declarations ***\n");
423: Iterator complexTypeIter = complexTypeMap.values().iterator();
424: while (complexTypeIter.hasNext()) {
425: ComplexTypeDeclaration type = (ComplexTypeDeclaration) complexTypeIter
426: .next();
427: sb.append(type.toString(""));
428: }
429: return sb.toString();
430: }
431: }
|