OSDN Git Service

libjava/ChangeLog:
[pf3gnuchains/gcc-fork.git] / libjava / classpath / gnu / xml / transform / XSLURIResolver.java
1 /* XSLURIResolver.java -- 
2    Copyright (C) 2004 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
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)
9 any later version.
10
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.
15
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
19 02110-1301 USA.
20
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
24 combination.
25
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. */
37
38 package gnu.xml.transform;
39
40 import java.io.File;
41 import java.io.InputStream;
42 import java.io.IOException;
43 import java.io.Reader;
44 import java.net.MalformedURLException;
45 import java.net.URL;
46 import java.net.URLConnection;
47 import java.util.HashMap;
48 import java.util.Map;
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;
66
67 /**
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.
71  *
72  * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
73  */
74 class XSLURIResolver
75   implements URIResolver
76 {
77
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;
83
84   void setUserResolver(URIResolver userResolver)
85   {
86     this.userResolver = userResolver;
87   }
88
89   void setUserListener(ErrorListener userListener)
90   {
91     this.userListener = userListener;
92   }
93
94   /**
95    * Clear the cache.
96    */
97   void flush()
98   {
99     lastModifiedCache.clear();
100     nodeCache.clear();
101   }
102
103   public Source resolve(String href, String base)
104     throws TransformerException
105   {
106     Source source = null;
107     if (userResolver != null)
108       {
109         source = userResolver.resolve(base, href);
110       }
111     return resolveDOM(source, href, base);
112   }
113
114   DOMSource resolveDOM(Source source, String base, String href)
115     throws TransformerException
116   {
117     if (source != null && source instanceof DOMSource)
118       {
119         return (DOMSource) source;
120       }
121     String systemId = (source == null) ? null : source.getSystemId();
122     long lastModified = 0L, lastLastModified = 0L;
123
124     try
125       {
126         Node node = null;
127         InputStream in = null;
128         if (source != null && source instanceof StreamSource)
129           {
130             StreamSource ss = (StreamSource) source;
131             in = ss.getInputStream();
132             if (in == null)
133               {
134                 Reader reader = ss.getReader();
135                 if (reader != null)
136                   {
137                     in = new ReaderInputStream(reader);
138                   }
139               }
140           }
141         else if (source != null && source instanceof SAXSource)
142           {
143             SAXSource ss = (SAXSource) source;
144             InputSource input = ss.getInputSource();
145             if (input != null)
146               {
147                 if (systemId == null)
148                   systemId = input.getSystemId();
149                 XMLReader reader = ss.getXMLReader();
150                 if (reader != null)
151                   return parse(input, reader);
152               }
153           }
154         if (in == null)
155           {
156             URL url = resolveURL(systemId, base, href);
157             if (url != null)
158               {
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);
164                 if (llm != null)
165                   {
166                     lastLastModified = llm.longValue();
167                     conn.setIfModifiedSince(lastLastModified);
168                   }
169                 conn.connect();
170                 lastModified = conn.getLastModified();
171                 if (node != null && 
172                     lastModified > 0L &&
173                     lastModified <= lastLastModified)
174                   {
175                     // Resource unchanged
176                     return new DOMSource(node, systemId);
177                   }
178                 else
179                   {
180                     // Resource new or modified
181                     in = conn.getInputStream();
182                     nodeCache.put(systemId, node);
183                     lastModifiedCache.put(systemId, new Long(lastModified));
184                   }
185               }
186             else
187               {
188                 throw new TransformerException("can't resolve URL: " +
189                                                systemId);
190               }
191           }
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);
197       }
198     catch (IOException e)
199       {
200         throw new TransformerException(e);
201       }
202     catch (SAXException e)
203       {
204         throw new TransformerException(e);
205       }
206   }
207
208   URL resolveURL(String systemId, String base, String href)
209     throws IOException
210   {
211     URL url = null;
212     try
213       {
214         if (systemId != null)
215           {
216             try
217               {
218                 url = new URL(systemId);
219               }
220             catch (MalformedURLException e)
221               {
222                 // Try building from base + href
223               }
224           }
225         if (url == null)
226           {
227             if (base != null)
228               {
229                 URL baseURL = new URL(base);
230                 url = new URL(baseURL, href);
231               }
232             else if (href != null)
233               {
234                 url = new URL(href);
235               }
236             else
237               {
238                 // See below
239                 throw new MalformedURLException(systemId);
240               }
241           }
242         return url;
243       }
244     catch (MalformedURLException e)
245       {
246         // Fall back to local filesystem
247         File file = null;
248         if (href == null)
249           {
250             href = systemId;
251           }
252         if (base != null)
253           {
254             int lsi = base.lastIndexOf(File.separatorChar);
255             if (lsi != -1 && lsi < base.length() - 1)
256               {
257                 base = base.substring(0, lsi);
258               }
259             File baseFile = new File(base);
260             file = new File(baseFile, href);
261           }
262         else if (href != null)
263           {
264             file = new File(href);
265           }
266         return (file == null) ? null : file.toURL();
267       }
268   }
269   
270   DocumentBuilder getDocumentBuilder()
271     throws TransformerException
272   {
273     try
274       {
275         if (builder == null)
276           {
277             DocumentBuilderFactory factory =
278               DocumentBuilderFactory.newInstance();
279             factory.setNamespaceAware(true);
280             factory.setExpandEntityReferences(true);
281             builder = factory.newDocumentBuilder();
282           }
283         if (userResolver != null)
284           {
285             builder.setEntityResolver(new URIResolverEntityResolver(userResolver));
286           }
287         if (userListener != null)
288           {
289             builder.setErrorHandler(new ErrorListenerErrorHandler(userListener));
290           }
291         return builder;
292       }
293     catch (Exception e)
294       {
295         throw new TransformerException(e);
296       }
297   }
298
299   DOMSource parse(InputSource source, XMLReader reader)
300     throws SAXException, IOException
301   {
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",
308             eventSink);
309     reader.setProperty("http://xml.org/sax/properties/declaration-handler",
310             eventSink);
311     // XXX entityResolver
312     // XXX errorHandler
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);
319   }
320   
321 }
322