001: /**
002: * Redistribution and use of this software and associated documentation
003: * ("Software"), with or without modification, are permitted provided
004: * that the following conditions are met:
005: *
006: * 1. Redistributions of source code must retain copyright
007: * statements and notices. Redistributions must also contain a
008: * copy of this document.
009: *
010: * 2. Redistributions in binary form must reproduce the
011: * above copyright notice, this list of conditions and the
012: * following disclaimer in the documentation and/or other
013: * materials provided with the distribution.
014: *
015: * 3. The name "Exolab" must not be used to endorse or promote
016: * products derived from this Software without prior written
017: * permission of Intalio, Inc. For written permission,
018: * please contact info@exolab.org.
019: *
020: * 4. Products derived from this Software may not be called "Exolab"
021: * nor may "Exolab" appear in their names without prior written
022: * permission of Intalio, Inc. Exolab is a registered
023: * trademark of Intalio, Inc.
024: *
025: * 5. Due credit should be given to the Exolab Project
026: * (http://www.exolab.org/).
027: *
028: * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
029: * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
030: * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
031: * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
032: * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
033: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
034: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
035: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
036: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
037: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
038: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
039: * OF THE POSSIBILITY OF SUCH DAMAGE.
040: *
041: * Copyright 1999-2002 (C) Intalio, Inc. All Rights Reserved.
042: *
043: * $Id: SchemaReader.java 6230 2006-09-19 07:56:07Z wguttmn $
044: */package org.exolab.castor.xml.schema.reader;
045:
046: import java.io.Reader;
047: import java.io.IOException;
048:
049: import org.exolab.castor.net.URIException;
050: import org.exolab.castor.net.URILocation;
051: import org.exolab.castor.net.URIResolver;
052: import org.exolab.castor.util.Configuration;
053: import org.exolab.castor.util.LocalConfiguration;
054: import org.exolab.castor.util.NestedIOException;
055:
056: import org.exolab.castor.xml.schema.Schema;
057: import org.exolab.castor.xml.XMLException;
058:
059: import org.xml.sax.InputSource;
060: import org.xml.sax.EntityResolver;
061: import org.xml.sax.Parser;
062: import org.xml.sax.SAXException;
063: import org.xml.sax.SAXParseException;
064: import org.xml.sax.ErrorHandler;
065:
066: /**
067: * A class for reading XML Schemas
068: *
069: * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
070: * @version $Revision: 6230 $ $Date: 2004-10-05 14:27:10 -0600 (Tue, 05 Oct 2004) $
071: **/
072: public class SchemaReader {
073:
074: /**
075: * The Castor Configuration
076: */
077: private Configuration _config = null;
078:
079: /**
080: * XML Parser instance
081: */
082: private Parser _parser = null;
083:
084: /**
085: * SAX InputSource to Schema
086: */
087: private InputSource _source = null;
088:
089: /**
090: * SAX EntityResolver
091: */
092: private EntityResolver _resolver = null;
093:
094: /**
095: * SAX ErrorHandler
096: */
097: private ErrorHandler _errorHandler = null;
098:
099: /**
100: * The resolver to be used for resolving href
101: */
102: private URIResolver _uriResolver;
103:
104: /**
105: * A flag that indicates that included schemas should be cached
106: * instead of being inlined [which is the default behavior as specified
107: * by the XML Schema Specification].
108: *
109: */
110: private boolean _cacheIncludedSchemas = false;
111:
112: private Schema _schema = null;
113:
114: private boolean _validate = true;
115:
116: /**
117: * Creates a new SchemaReader
118: */
119: private SchemaReader() throws IOException {
120: //-- get default parser from Configuration
121:
122: _config = LocalConfiguration.getInstance();
123:
124: Parser parser = null;
125:
126: parser = _config.getParser();
127:
128: if (parser == null) {
129: throw new IOException(
130: "fatal error: unable to create SAX parser.");
131: }
132:
133: _parser = parser;
134: } //-- SchemaReader
135:
136: /**
137: * Creates a new SchemaReader for the given InputSource
138: *
139: * @param source the InputSource to read the Schema from.
140: **/
141: public SchemaReader(InputSource source) throws IOException {
142: this ();
143:
144: if (source == null)
145: throw new IllegalArgumentException(
146: "InputSource cannot be null");
147:
148: _source = source;
149:
150: } //-- SchemaReader
151:
152: /**
153: * Creates a new SchemaReader for the given Reader
154: *
155: * @param reader the Reader to read the Schema from.
156: * @param filename for reporting errors.
157: **/
158: public SchemaReader(Reader reader, String filename)
159: throws IOException {
160: this ();
161:
162: if (reader == null) {
163: String err = "The argument 'reader' must not be null.";
164: throw new IllegalArgumentException(err);
165: }
166:
167: _source = new InputSource(reader);
168: if (filename == null)
169: filename = reader.toString();
170: _source.setPublicId(filename);
171:
172: } //-- SchemaReader
173:
174: /**
175: * Creates a new SchemaReader for the given URL
176: *
177: * @param url the URL string
178: **/
179: public SchemaReader(String url) throws IOException {
180: this ();
181: if (url == null) {
182: String err = "The argument 'url' must not be null.";
183: throw new IllegalArgumentException(err);
184: }
185: _source = new InputSource(url);
186:
187: } //-- SchemaReader
188:
189: /**
190: * Reads the Schema from the source and returns the Schema
191: * object model.
192: *
193: * <BR />
194: * <B>Note:</B> Subsequent calls to this method will simply
195: * return a cached copy of the Schema object. To read a new
196: * Schema object, create a new Reader.
197: *
198: * @return the new Schema created from the source of this SchemaReader
199: **/
200: public Schema read() throws IOException {
201: if (_schema != null)
202: return _schema;
203: SchemaUnmarshaller schemaUnmarshaller = null;
204:
205: try {
206: SchemaUnmarshallerState state = new SchemaUnmarshallerState();
207: state.setConfiguration(_config);
208: state.cacheIncludedSchemas = _cacheIncludedSchemas;
209: schemaUnmarshaller = new SchemaUnmarshaller(state);
210: if (_uriResolver != null)
211: schemaUnmarshaller.setURIResolver(_uriResolver);
212:
213: //-- make sure we mark the URI as processed for cyclic
214: //-- imports/includes
215: String uri = _source.getSystemId();
216: if (uri != null) {
217: URIResolver resolver = schemaUnmarshaller
218: .getURIResolver();
219: try {
220: URILocation location = resolver.resolve(uri, null);
221: if (location != null)
222: uri = location.toString();
223: } catch (URIException except) {
224: throw new NestedIOException(except);
225: }
226: state.markAsProcessed(uri, schemaUnmarshaller
227: .getSchema());
228: }
229:
230: Sax2ComponentReader handler = new Sax2ComponentReader(
231: schemaUnmarshaller);
232: _parser.setDocumentHandler(handler);
233:
234: if (_errorHandler == null)
235: _parser.setErrorHandler(handler);
236: else
237: _parser.setErrorHandler(_errorHandler);
238:
239: if (_resolver != null)
240: _parser.setEntityResolver(_resolver);
241: _parser.parse(_source);
242: } catch (XMLException ex) {
243: handleException(ex);
244: } catch (org.xml.sax.SAXException sx) {
245: handleException(sx);
246: }
247:
248: _schema = schemaUnmarshaller.getSchema();
249:
250: if (_validate) {
251: try {
252: _schema.validate();
253: } catch (org.exolab.castor.xml.ValidationException vx) {
254: throw new NestedIOException(vx);
255: }
256: }
257:
258: return _schema;
259:
260: } //-- read
261:
262: /**
263: * Sets the ErrorHandler.
264: *
265: * @param errorHandler
266: **/
267: public void setErrorHandler(ErrorHandler errorHandler) {
268: _errorHandler = errorHandler;
269: } //-- setErrorHandler
270:
271: /**
272: * Sets wheter or not to cache the included xml schemas
273: * instead of inlining them as specified by the XML Schema
274: * specification.
275: *
276: * @param cache true to cache the included XML Schemas.
277: **/
278: public void setCacheIncludedSchemas(boolean cache) {
279: _cacheIncludedSchemas = cache;
280: } //-- setErrorHandler
281:
282: /**
283: * Sets whether or not post-read validation should
284: * occur. By default, validation is enabled. Note
285: * that certain read validation cannot be disabled.
286: *
287: * @param validate a boolean that when true will force
288: * a call to Schema#validate after the schema is read.
289: **/
290: public void setValidation(boolean validate) {
291: _validate = validate;
292: } //-- setValidation
293:
294: /**
295: * Sets the EntityResolver used to resolve SYSTEM Identifier.
296: * If the entity resolver is null, the default one will be used.
297: *
298: * @param resolver the EntityResolver to use.
299: */
300: public void setEntityResolver(EntityResolver resolver) {
301: _resolver = resolver;
302: }
303:
304: /**
305: * Sets the URIResolver used to resolve hrefs.
306: * If the entity resolver is null, the default one will be used.
307: *
308: * @param uriresolver the URIResolver to use.
309: */
310: public void setURIResolver(URIResolver uriresolver) {
311: _uriResolver = uriresolver;
312: }
313:
314: /**
315: * Handle an exception which is one of our own XMLExceptions.
316: * @param xmlException the XMLException to handle.
317: * @throws IOException
318: */
319: private void handleException(XMLException xmlException)
320: throws IOException {
321: throw new NestedIOException(xmlException);
322: } //-- handleException
323:
324: /**
325: * Handle an exception which is a foreign SAXException.
326: * @param sx The SAXException to handle.
327: * @throws IOException
328: */
329: private void handleException(SAXException sx) throws IOException {
330: Exception except = sx.getException();
331: if (except == null) {
332: except = sx;
333: } else if (except instanceof SAXParseException) {
334: SAXParseException spe = (SAXParseException) except;
335: String filename = spe.getSystemId();
336: if (filename == null)
337: filename = spe.getPublicId();
338: if (filename == null)
339: filename = "<filename unavailable>";
340:
341: String err = spe.getMessage();
342:
343: err += "; " + filename + " [ line: " + spe.getLineNumber();
344: err += ", column: " + spe.getColumnNumber() + ']';
345: throw new NestedIOException(err, except);
346: } else if (except instanceof XMLException) {
347: handleException((XMLException) except);
348: }
349:
350: throw new NestedIOException(except);
351:
352: } //-- handleException
353:
354: } //-- SchemaReader
|