1 /* XSLURIResolver.java --
2 Copyright (C) 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 package gnu.xml.transform;
41 import java.io.InputStream;
42 import java.io.IOException;
43 import java.io.Reader;
44 import java.net.MalformedURLException;
46 import java.net.URLConnection;
47 import java.util.HashMap;
49 import javax.xml.parsers.DocumentBuilder;
50 import javax.xml.parsers.DocumentBuilderFactory;
51 import javax.xml.transform.ErrorListener;
52 import javax.xml.transform.Source;
53 import javax.xml.transform.TransformerException;
54 import javax.xml.transform.URIResolver;
55 import javax.xml.transform.dom.DOMSource;
56 import javax.xml.transform.sax.SAXSource;
57 import javax.xml.transform.stream.StreamSource;
58 import org.w3c.dom.Document;
59 import org.w3c.dom.Node;
60 import org.xml.sax.InputSource;
61 import org.xml.sax.SAXException;
62 import org.xml.sax.XMLReader;
63 import gnu.xml.dom.DomDocument;
64 import gnu.xml.dom.ls.SAXEventSink;
65 import gnu.xml.dom.ls.ReaderInputStream;
68 * URI resolver for XSLT.
69 * This resolver parses external entities into DOMSources. It
70 * maintains a cache of URIs to DOMSources to avoid expensive re-parsing.
72 * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
75 implements URIResolver
78 final Map<String,Long> lastModifiedCache = new HashMap<String,Long>();
79 final Map<String,Node> nodeCache = new HashMap<String,Node>();
80 DocumentBuilder builder;
81 URIResolver userResolver;
82 ErrorListener userListener;
84 void setUserResolver(URIResolver userResolver)
86 this.userResolver = userResolver;
89 void setUserListener(ErrorListener userListener)
91 this.userListener = userListener;
99 lastModifiedCache.clear();
103 public Source resolve(String href, String base)
104 throws TransformerException
106 Source source = null;
107 if (userResolver != null)
109 source = userResolver.resolve(base, href);
111 return resolveDOM(source, href, base);
114 DOMSource resolveDOM(Source source, String base, String href)
115 throws TransformerException
117 if (source != null && source instanceof DOMSource)
119 return (DOMSource) source;
121 String systemId = (source == null) ? null : source.getSystemId();
122 long lastModified = 0L, lastLastModified = 0L;
127 InputStream in = null;
128 if (source != null && source instanceof StreamSource)
130 StreamSource ss = (StreamSource) source;
131 in = ss.getInputStream();
134 Reader reader = ss.getReader();
137 in = new ReaderInputStream(reader);
141 else if (source != null && source instanceof SAXSource)
143 SAXSource ss = (SAXSource) source;
144 InputSource input = ss.getInputSource();
147 if (systemId == null)
148 systemId = input.getSystemId();
149 XMLReader reader = ss.getXMLReader();
151 return parse(input, reader);
156 URL url = resolveURL(systemId, base, href);
159 systemId = url.toString();
160 node = nodeCache.get(systemId);
161 // Is the resource up to date?
162 URLConnection conn = url.openConnection();
163 Long llm = lastModifiedCache.get(systemId);
166 lastLastModified = llm.longValue();
167 conn.setIfModifiedSince(lastLastModified);
170 lastModified = conn.getLastModified();
173 lastModified <= lastLastModified)
175 // Resource unchanged
176 return new DOMSource(node, systemId);
180 // Resource new or modified
181 in = conn.getInputStream();
182 nodeCache.put(systemId, node);
183 lastModifiedCache.put(systemId, new Long(lastModified));
188 throw new TransformerException("can't resolve URL: " +
192 InputSource input = new InputSource(in);
193 input.setSystemId(systemId);
194 DocumentBuilder builder = getDocumentBuilder();
195 node = builder.parse(input);
196 return new DOMSource(node, systemId);
198 catch (IOException e)
200 throw new TransformerException(e);
202 catch (SAXException e)
204 throw new TransformerException(e);
208 URL resolveURL(String systemId, String base, String href)
214 if (systemId != null)
218 url = new URL(systemId);
220 catch (MalformedURLException e)
222 // Try building from base + href
229 URL baseURL = new URL(base);
230 url = new URL(baseURL, href);
232 else if (href != null)
239 throw new MalformedURLException(systemId);
244 catch (MalformedURLException e)
246 // Fall back to local filesystem
254 int lsi = base.lastIndexOf(File.separatorChar);
255 if (lsi != -1 && lsi < base.length() - 1)
257 base = base.substring(0, lsi);
259 File baseFile = new File(base);
260 file = new File(baseFile, href);
262 else if (href != null)
264 file = new File(href);
266 return (file == null) ? null : file.toURL();
270 DocumentBuilder getDocumentBuilder()
271 throws TransformerException
277 DocumentBuilderFactory factory =
278 DocumentBuilderFactory.newInstance();
279 factory.setNamespaceAware(true);
280 factory.setExpandEntityReferences(true);
281 builder = factory.newDocumentBuilder();
283 if (userResolver != null)
285 builder.setEntityResolver(new URIResolverEntityResolver(userResolver));
287 if (userListener != null)
289 builder.setErrorHandler(new ErrorListenerErrorHandler(userListener));
295 throw new TransformerException(e);
299 DOMSource parse(InputSource source, XMLReader reader)
300 throws SAXException, IOException
302 SAXEventSink eventSink = new SAXEventSink();
303 eventSink.setReader(reader);
304 eventSink.setNamespaceAware(true);
305 reader.setContentHandler(eventSink);
306 reader.setDTDHandler(eventSink);
307 reader.setProperty("http://xml.org/sax/properties/lexical-handler",
309 reader.setProperty("http://xml.org/sax/properties/declaration-handler",
311 // XXX entityResolver
313 reader.parse(source);
314 Document doc = eventSink.getDocument();
315 String systemId = source.getSystemId();
316 if (systemId != null && doc instanceof DomDocument)
317 ((DomDocument) doc).setDocumentURI(systemId);
318 return new DOMSource(doc, systemId);