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 (C) Intalio, Inc. All Rights Reserved.
042: *
043: * $Id: DTDResolver.java 6225 2006-09-18 10:11:39Z wguttmn $
044: */package org.exolab.castor.util;
045:
046: import java.net.URL;
047: import java.net.MalformedURLException;
048: import java.io.IOException;
049: import org.xml.sax.SAXException;
050: import org.xml.sax.EntityResolver;
051: import org.xml.sax.InputSource;
052: import org.exolab.castor.net.util.URIUtils;
053:
054: /**
055: * Entity resolver for various DTD/schema. Holds information and performs
056: * resolving on a variety of DTD and schema, both those defined by Castor and
057: * those used by Castor and cached by it.
058: * <p>
059: * The following DTD and XML schema are supported:
060: * <ul>
061: * <li>Castor mapping DTD/Schema
062: * <li>Castor JDO configuration DTD/Schema
063: * <li>XML Schema DTDs
064: * </ul>
065: * <p>
066: * Thie resolver can resolve both public and system identifiers, and will return
067: * an input stream into a cached resource in the Castor JAR.
068: * <p>
069: * This resolver can be used as wrapper to another entity resolver. For example,
070: * if a resolver is used for external entities in the mapping file, construct a
071: * new resolver using the {@link #DTDResolver(EntityResolver)} constructor.
072: * <p>
073: *
074: * @author <a href="mailto:arkin@intalio.com">Assaf Arkin</a>
075: * @version $Revision: 6225 $ $Date: 2005-12-13 14:58:48 -0700 (Tue, 13 Dec 2005) $
076: */
077: public class DTDResolver implements EntityResolver {
078:
079: /**
080: * Holds information about a given DTD of XML Schema.
081: */
082: static class DTDInfo {
083:
084: /**
085: * The public identifier. Null if unknown.
086: */
087: private final String publicId;
088:
089: /**
090: * The system identifier. Null if unknown.
091: */
092: private final String systemId;
093:
094: /**
095: * The resource name, if a copy of the document is available.
096: */
097: private final String resource;
098:
099: /**
100: * Creates an instance of DTDInfo.
101: *
102: * @param publicId public id
103: * @param systemId system id
104: * @param namespace namespace
105: * @param prefix prefix
106: * @param resource resource
107: */
108: DTDInfo(final String publicId, final String systemId,
109: final String namespace, final String prefix,
110: final String resource) {
111: this .publicId = publicId;
112: this .systemId = systemId;
113: this .resource = resource;
114: }
115: }
116:
117: /**
118: * Defines information about a variety of DTDs, both those defined by Castor
119: * and those defined elsewhere and cached by Castor.
120: */
121: private final DTDInfo[] _dtdInfo = new DTDInfo[] {
122: // Information for Mapping DTD and schema
123: new DTDInfo("-//EXOLAB/Castor Mapping DTD Version 1.0//EN",
124: "http://castor.exolab.org/mapping.dtd",
125: "castor.exolab.org", "castor",
126: "/org/exolab/castor/mapping/mapping.dtd"),
127: new DTDInfo(
128: "-//EXOLAB/Castor Mapping Schema Version 1.0//EN",
129: "http://castor.exolab.org/mapping.xsd",
130: "castor.exolab.org", "castor",
131: "/org/exolab/castor/mapping/mapping.xsd"),
132: new DTDInfo("-//EXOLAB/Castor Mapping DTD Version 1.0//EN",
133: "http://castor.org/mapping.dtd", "castor.org",
134: "castor", "/org/exolab/castor/mapping/mapping.dtd"),
135: new DTDInfo(
136: "-//EXOLAB/Castor Mapping Schema Version 1.0//EN",
137: "http://castor.org/mapping.xsd", "castor.org",
138: "castor", "/org/exolab/castor/mapping/mapping.xsd"),
139: // Information for JDO configuration DTD and schema
140: new DTDInfo(
141: "-//EXOLAB/Castor JDO Configuration DTD Version 1.0//EN",
142: "http://castor.exolab.org/jdo-conf.dtd",
143: "castor.exolab.org", "castor",
144: "/org/castor/jdo/conf/jdo-conf.dtd"),
145: new DTDInfo(
146: "-//EXOLAB/Castor JDO Configuration Schema Version 1.0//EN",
147: "http://castor.exolab.org/jdo-conf.xsd",
148: "castor.exolab.org", "castor",
149: "/org/castor/jdo/conf/jdo-conf.xsd"),
150: new DTDInfo(
151: "-//EXOLAB/Castor JDO Configuration DTD Version 1.0//EN",
152: "http://castor.org/jdo-conf.dtd", "castor.org",
153: "castor", "/org/castor/jdo/conf/jdo-conf.dtd"),
154: new DTDInfo(
155: "-//EXOLAB/Castor JDO Configuration Schema Version 1.0//EN",
156: "http://castor.org/jdo-conf.xsd", "castor.org",
157: "castor", "/org/castor/jdo/conf/jdo-conf.xsd"),
158: // Resolving for XML Schema DTDs
159: new DTDInfo(
160: "-//W3C//DTD XMLSCHEMA 19991216//EN",
161: "http://www.w3.org/TR/2000/WD-xmlschema-1-20000225/structures.dtd",
162: null, null,
163: "/org/exolab/castor/util/resources/structures.dtd"),
164: new DTDInfo(
165: null,
166: "http://www.w3.org/TR/2000/WD-xmlschema-2-20000225/datatypes.dtd",
167: null, null,
168: "/org/exolab/castor/util/resources/datatypes.dtd"),
169: new DTDInfo(
170: null,
171: "http://www.w3.org/TR/2000/WD-xmlschema-1-20000225/structures.xsd",
172: null, null,
173: "/org/exolab/castor/util/resources/structures.xsd"),
174:
175: };
176:
177: /**
178: * The wrapped resolver.
179: */
180: private EntityResolver _resolver;
181:
182: /**
183: * Base URL, if known.
184: */
185: private URL _baseUrl;
186:
187: /**
188: * Constructs a new DTD resolver. This resolver wraps another resolver and
189: * will delegate all resolving not related to the Castor mapping files to
190: * that resolver. The wrapper resolver will typically be used for entities
191: * appearing in the actual mapping file.
192: */
193: public DTDResolver(EntityResolver resolver) {
194: _resolver = resolver;
195: }
196:
197: /**
198: * Constructs a new DTD resolver.
199: */
200: public DTDResolver() {
201: }
202:
203: /**
204: * Sets the base URL to use.
205: * @param baseUrl Base URL.
206: */
207: public void setBaseURL(final URL baseUrl) {
208: _baseUrl = baseUrl;
209:
210: // //-- make sure we have a document base and not
211: // //-- a full URL to an actual file
212: // if (baseUrl != null) {
213: // String urlString = baseUrl.toExternalForm();
214: // String docBase = URIUtils.getDocumentBase(urlString);
215: // if (urlString.equals(docBase)) {
216: // _baseUrl = baseUrl;
217: // }
218: // else if ((docBase != null) && (docBase.length() > 0)) {
219: // try {
220: // _baseUrl = new URL(docBase);
221: // }
222: // catch(MalformedURLException mue) {
223: // // TODO: bubble up exception instead of
224: // // rethrowing
225: // String error = "Malformed URL: " + docBase;
226: // throw new IllegalStateException(error);
227: // }
228: // }
229: // else {
230: // _baseUrl = null;
231: // }
232: // }
233: }
234:
235: /**
236: * Returns the base URL in use.
237: * @return The base URL.
238: */
239: public URL getBaseURL() {
240: return _baseUrl;
241: }
242:
243: /**
244: * Resolves public & system ids to files stored within the JAR.
245: *
246: * @see org.xml.sax.EntityResolver#resolveEntity(java.lang.String,
247: * java.lang.String)
248: */
249: public InputSource resolveEntity(final String publicId,
250: final String systemId) throws IOException, SAXException {
251: int i;
252: InputSource source = null;
253:
254: // First, resolve all the DTD/schema.
255: for (i = 0; i < _dtdInfo.length; ++i) {
256: if (publicId != null
257: && publicId.equals(_dtdInfo[i].publicId)) {
258: source = new InputSource(getClass()
259: .getResourceAsStream(_dtdInfo[i].resource));
260: source.setPublicId(publicId);
261: return source;
262: }
263: if (systemId != null
264: && systemId.equals(_dtdInfo[i].systemId)) {
265: source = new InputSource(getClass()
266: .getResourceAsStream(_dtdInfo[i].resource));
267: source.setSystemId(systemId);
268: return source;
269: }
270: }
271:
272: // If a resolver was specified, use it.
273: if (_resolver != null) {
274: source = _resolver.resolveEntity(publicId, systemId);
275: if (source != null) {
276: return source;
277: }
278: }
279:
280: // Can't resolve public id, but might be able to resolve relative
281: // system id, since we have a base URI.
282: if (systemId != null && _baseUrl != null) {
283: URL url;
284:
285: try {
286: url = new URL(_baseUrl, systemId);
287: source = new InputSource(url.openStream());
288: source.setSystemId(systemId);
289: return source;
290: } catch (MalformedURLException except) {
291: try {
292: String absURL = URIUtils.resolveAsString(systemId,
293: _baseUrl.toString());
294: url = new URL(absURL);
295: source = new InputSource(url.openStream());
296: source.setSystemId(systemId);
297: return source;
298: } catch (MalformedURLException ex2) {
299: // nothing to do
300: }
301: } catch (java.io.FileNotFoundException fnfe) {
302: try {
303: String absURL = URIUtils.resolveAsString(systemId,
304: _baseUrl.toString());
305: url = new URL(absURL);
306: source = new InputSource(url.openStream());
307: source.setSystemId(systemId);
308: return source;
309: } catch (MalformedURLException ex2) {
310: // nothing to do
311: }
312: }
313: return null;
314: }
315:
316: // No resolving.
317: return null;
318: }
319:
320: }
|