001: package net.sf.saxon.query;
002:
003: import net.sf.saxon.StandardURIResolver;
004: import net.sf.saxon.trans.StaticError;
005: import net.sf.saxon.trans.XPathException;
006:
007: import javax.xml.transform.stream.StreamSource;
008: import java.io.BufferedInputStream;
009: import java.io.IOException;
010: import java.io.InputStream;
011: import java.io.InputStreamReader;
012: import java.net.URI;
013: import java.net.URISyntaxException;
014: import java.net.URL;
015: import java.net.URLConnection;
016:
017: /**
018: * This class is the standard ModuleURIResolver used to implement the "import module" declaration
019: * in a Query Prolog. It is used when no user-defined ModuleURIResolver has been specified, or when
020: * the user-defined ModuleURIResolver decides to delegate to the standard ModuleURIResolver.
021: * @author Michael H. Kay
022: */
023:
024: public class StandardModuleURIResolver implements ModuleURIResolver {
025:
026: /**
027: * Resolve a module URI and associated location hints.
028: * @param moduleURI The module namespace URI of the module to be imported; or null when
029: * loading a non-library module.
030: * @param baseURI The base URI of the module containing the "import module" declaration;
031: * null if no base URI is known
032: * @param locations The set of URIs specified in the "at" clause of "import module",
033: * which serve as location hints for the module
034: * @return an array of StreamSource objects each identifying the contents of a module to be
035: * imported. Each StreamSource must contain a
036: * non-null absolute System ID which will be used as the base URI of the imported module,
037: * and either an InputSource or a Reader representing the text of the module. The method
038: * may also return null, in which case the system attempts to resolve the URI using the
039: * standard module URI resolver.
040: * @throws net.sf.saxon.trans.XPathException if the module cannot be located
041: */
042:
043: public StreamSource[] resolve(String moduleURI, String baseURI,
044: String[] locations) throws XPathException {
045: if (locations.length == 0) {
046: StaticError err = new StaticError(
047: "Cannot locate module for namespace " + moduleURI);
048: err.setErrorCode("XQST0059");
049: throw err;
050: } else {
051: // One or more locations given: import modules from all these locations
052: StreamSource[] sources = new StreamSource[locations.length];
053: for (int m = 0; m < locations.length; m++) {
054: String href = locations[m];
055: URI absoluteURI;
056: try {
057: absoluteURI = StandardURIResolver.makeAbsolute(
058: href, baseURI);
059: } catch (URISyntaxException err) {
060: StaticError se = new StaticError(
061: "Cannot resolve relative URI " + href, err);
062: se.setErrorCode("XQST0059");
063: throw se;
064: }
065: sources[m] = getQuerySource(absoluteURI);
066: }
067: return sources;
068: }
069: }
070:
071: /**
072: * Get a StreamSource object representing the source of a query, given its URI.
073: * This method attempts to discover the encoding by reading any HTTP headers.
074: * If the encoding can be determined, it returns a StreamSource containing a Reader that
075: * performs the required decoding. Otherwise, it returns a StreamSource containing an
076: * InputSource, leaving the caller to sort out encoding problems.
077: * @param absoluteURI the absolute URI of the source query
078: * @return a StreamSource containing a Reader or InputSource, as well as a systemID representing
079: * the base URI of the query.
080: * @throws net.sf.saxon.trans.StaticError if the URIs are invalid or cannot be resolved or dereferenced, or
081: * if any I/O error occurs
082: */
083:
084: public static StreamSource getQuerySource(URI absoluteURI)
085: throws StaticError {
086:
087: try {
088: InputStream is;
089: URL absoluteURL = absoluteURI.toURL();
090: URLConnection connection = absoluteURL.openConnection();
091: connection.connect();
092: is = connection.getInputStream();
093:
094: if (!is.markSupported()) {
095: is = new BufferedInputStream(is);
096: }
097:
098: // Get any external (HTTP) encoding label.
099: String contentType;
100: String encoding = null;
101:
102: // The file:// URL scheme gives no useful information...
103: if (!"file".equals(connection.getURL().getProtocol())) {
104:
105: // Use the contentType from the HTTP header if available
106: contentType = connection.getContentType();
107:
108: if (contentType != null) {
109: int pos = contentType.indexOf("charset");
110: if (pos >= 0) {
111: pos = contentType.indexOf('=', pos + 7);
112: if (pos >= 0) {
113: contentType = contentType
114: .substring(pos + 1);
115: }
116: if ((pos = contentType.indexOf(';')) > 0) {
117: contentType = contentType.substring(0, pos);
118: }
119:
120: // attributes can have comment fields (RFC 822)
121: if ((pos = contentType.indexOf('(')) > 0) {
122: contentType = contentType.substring(0, pos);
123: }
124: // ... and values may be quoted
125: if ((pos = contentType.indexOf('"')) > 0) {
126: contentType = contentType.substring(
127: pos + 1, contentType.indexOf('"',
128: pos + 2));
129: }
130: encoding = contentType.trim();
131: }
132: }
133: }
134: StreamSource ss = new StreamSource();
135: if (encoding == null) {
136: ss.setInputStream(is);
137: } else {
138: ss.setReader(new InputStreamReader(is, encoding));
139: }
140: ss.setSystemId(absoluteURL.toString());
141: return ss;
142: } catch (IOException err) {
143: StaticError se = new StaticError(err);
144: se.setErrorCode("XQST0059");
145: throw se;
146: }
147:
148: }
149: }
150:
151: //
152: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
153: // you may not use this file except in compliance with the License. You may obtain a copy of the
154: // License at http://www.mozilla.org/MPL/
155: //
156: // Software distributed under the License is distributed on an "AS IS" basis,
157: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
158: // See the License for the specific language governing rights and limitations under the License.
159: //
160: // The Original Code is: all this file.
161: //
162: // The Initial Developer of the Original Code is Michael H. Kay
163: //
164: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
165: //
166: // Contributor(s): none.
167: //
|