View Javadoc
1   /**
2    * Redistribution and use of this software and associated documentation ("Software"), with or
3    * without modification, are permitted provided that the following conditions are met:
4    *
5    * 1. Redistributions of source code must retain copyright statements and notices. Redistributions
6    * must also contain a copy of this document.
7    *
8    * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
9    * conditions and the following disclaimer in the documentation and/or other materials provided with
10   * the distribution.
11   *
12   * 3. The name "Exolab" must not be used to endorse or promote products derived from this Software
13   * without prior written permission of Intalio, Inc. For written permission, please contact
14   * info@exolab.org.
15   *
16   * 4. Products derived from this Software may not be called "Exolab" nor may "Exolab" appear in
17   * their names without prior written permission of Intalio, Inc. Exolab is a registered trademark of
18   * Intalio, Inc.
19   *
20   * 5. Due credit should be given to the Exolab Project (http://www.exolab.org/).
21   *
22   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR
23   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS
25   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
29   * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   *
31   * Copyright 1999-2004 (C) Intalio, Inc. All Rights Reserved.
32   *
33   * $Id$
34   */
35  
36  package org.exolab.castor.xml.schema.reader;
37  
38  import org.exolab.castor.net.URIException;
39  import org.exolab.castor.net.URILocation;
40  import org.exolab.castor.net.URIResolver;
41  import org.exolab.castor.xml.AttributeSet;
42  import org.exolab.castor.xml.XMLException;
43  import org.exolab.castor.xml.schema.Schema;
44  import org.exolab.castor.xml.schema.SchemaContext;
45  import org.exolab.castor.xml.schema.SchemaException;
46  import org.exolab.castor.xml.schema.SchemaNames;
47  import org.xml.sax.Locator;
48  import org.xml.sax.Parser;
49  
50  public class ImportUnmarshaller extends ComponentReader {
51  
52  
53    public ImportUnmarshaller(final SchemaContext schemaContext, final Schema schema,
54        final AttributeSet atts, final URIResolver uriResolver, final Locator locator,
55        final SchemaUnmarshallerState state) throws XMLException {
56      super(schemaContext);
57      setURIResolver(uriResolver);
58  
59      URILocation uri = null;
60      
61      // -- Get schemaLocation
62      String schemaLocation = atts.getValue(SchemaNames.SCHEMALOCATION_ATTR);
63      
64      // -- Get namespace
65      String namespace = atts.getValue("namespace");
66  
67      if ((schemaLocation == null) && (namespace == null)) {
68        // -- A legal <import/> element...just return
69        return;
70      }
71  
72      boolean hasLocation = (schemaLocation != null);
73      if (hasLocation) {
74  
75        if (schemaLocation.indexOf("\\") != -1) {
76          String err = "'" + schemaLocation + "' is not a valid URI as defined by IETF RFC 2396.";
77          err += "The URI mustn't contain '\\'.";
78          throw new SchemaException(err);
79        }
80  
81        if (namespace == null)
82          namespace = "";
83  
84        uri = derive(locator, schemaLocation);
85        if (uri != null) {
86          schemaLocation = uri.getAbsoluteURI();
87        }
88      } else {
89        schemaLocation = namespace;
90        try {
91          uri = getURIResolver().resolveURN(namespace);
92        } catch (URIException urix) {
93          throw new XMLException(urix);
94        }
95        if (uri == null) {
96          String err =
97              "Unable to resolve Schema corresponding " + "to namespace '" + namespace + "'.";
98          throw new SchemaException(err);
99  
100       }
101     }
102 
103     // -- Make sure targetNamespace is not the same as the
104     // -- importing schema, see section 4.2.3 in the
105     // -- XML Schema Recommendation
106     if (namespace.equals(schema.getTargetNamespace())) {
107       throw new SchemaException(
108           "the 'namespace' attribute in the <import> element cannot be the same of the targetNamespace of the global schema");
109     }
110 
111     // -- Schema object to hold import schema
112     boolean addSchema = false;
113     Schema importedSchema = schema.getImportedSchema(namespace, true);
114 
115     // -- Have we already imported this XML Schema file?
116     if (state.processed(schemaLocation)) {
117       if (importedSchema == null)
118         schema.addImportedSchema(state.getSchema(schemaLocation));
119       return;
120     }
121 
122     boolean alreadyLoaded = false;
123     if (importedSchema == null) {
124       if (uri instanceof SchemaLocation) {
125         importedSchema = ((SchemaLocation) uri).getSchema();
126         schema.addImportedSchema(importedSchema);
127         alreadyLoaded = true;
128       } else {
129         importedSchema = new Schema();
130         addSchema = true;
131       }
132     } else {
133       // check schema location, if different, allow merge
134       if (hasLocation) {
135         String tmpLocation = importedSchema.getSchemaLocation();
136         alreadyLoaded =
137             schemaLocation.equals(tmpLocation) || importedSchema.includeProcessed(schemaLocation);
138         // -- keep track of the original schemaLocation as an include
139         if (!alreadyLoaded) {
140           importedSchema.addInclude(tmpLocation);
141         }
142       } else {
143         // -- only namespace can be used, no way to distinguish
144         // -- multiple imports...mark as alreadyLoaded
145         // -- see W3C XML Schema 1.0 Recommendation (part 1)
146         // -- section 4.2.3...
147         // -- <quote>... Given that the schemaLocation [attribute] is only
148         // -- a hint, it is open to applications to ignore all but the
149         // -- first <import> for a given namespace, regardless of the
150         // -- <em>actual value</em> of schemaLocation, but such a strategy
151         // -- risks missing useful information when new schemaLocations
152         // -- are offered.</quote>
153         alreadyLoaded = true;
154       }
155     }
156 
157     state.markAsProcessed(schemaLocation, importedSchema);
158 
159     if (alreadyLoaded)
160       return;
161 
162     // -- Parser Schema
163     Parser parser = createParser("import");
164     
165     // -- Create Schema object and setup unmarshaller
166     SchemaUnmarshaller schemaUnmarshaller = new SchemaUnmarshaller(getSchemaContext(), state);
167     schemaUnmarshaller.setURIResolver(getURIResolver());
168     schemaUnmarshaller.setSchema(importedSchema);
169     
170     // parse schema
171     parseSchema(parser, schemaUnmarshaller, uri, schemaLocation, "import");
172 
173     // -- Add schema to list of imported schemas (if not already present)
174     if (addSchema) {
175       importedSchema.setSchemaLocation(schemaLocation);
176       schema.addImportedSchema(importedSchema);
177     }
178   }
179 
180 
181   /**
182    * Sets the name of the element that this UnknownUnmarshaller handles
183    **/
184   public String elementName() {
185     return SchemaNames.IMPORT;
186   }
187 
188   /**
189    * Returns the Object created by this ComponentReader
190    * 
191    * @return the Object created by this ComponentReader
192    **/
193   public Object getObject() {
194     return null;
195   }
196 
197 }