KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > util > xml > URIResolver


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10 package org.mmbase.util.xml;
11
12 import javax.xml.transform.*;
13 import javax.xml.transform.stream.*;
14 import java.io.*;
15 import java.net.*;
16 import java.util.*;
17
18 import org.mmbase.util.SizeMeasurable;
19 import org.mmbase.util.ResourceLoader;
20 import org.mmbase.util.logging.Logger;
21 import org.mmbase.util.logging.Logging;
22
23 /**
24  * This URIResolver can be used to resolve URI's, also in TransformerFactory's.
25  *
26  * It has knowledge of a kind of path (as used by shells). Every entry
27  * of this path is labeled with a 'prefix'.
28  *
29  * This path always has at least (and on default) two entries:
30
31  <ol>
32    <li> Current working directory (prefix: none or 'file:')</li>
33    <li> MMBase configuration directory (prefix: 'mm:') </li>
34  </ol>
35
36  * Optionially you can add other dirs between these two.
37  *
38  * When you start searching in the current working dir, and the URI
39  * does not point to an existing file, it starts searching downwards in
40  * this list, until it finds a file that does exist.
41  *
42  * @author Michiel Meeuwissen.
43  * @since MMBase-1.6
44  * @version $Id: URIResolver.java,v 1.27 2006/08/24 14:39:58 michiel Exp $
45  */

46
47 public class URIResolver implements javax.xml.transform.URIResolver JavaDoc, SizeMeasurable, Serializable {
48
49
50     private static final long serialVersionUID = 1L; // increase this if object serialization changes (which we shouldn't do!)
51
private static final Logger log = Logging.getLoggerInstance(URIResolver.class);
52
53     private EntryList dirs; // prefix -> URL pairs
54
private int hashCode;
55
56
57     /**
58      * This constructor does not create an actual object that can be
59      * used. Only the hashCode is filled. This is because I liked it
60      * possible a URIResolver to be equal to a File. But 'equals' must
61      * be symmetric, and only a File can be equal to a File. It seemed
62      * stupid to extend URIResolver from File, only for this. If you
63      * want to compare a File to to an URIResolver (in Maps), you
64      * could wrap the file in such an empty URIResolver, and avoid all
65      * further overhead.
66      *
67      * @param c The directory for which this URIResolver must (not) be created.
68      * @param overhead A boolean. It is ignored. It serves only to distinct this constructor from the other one.
69      * @see org.mmbase.cache.xslt.FactoryCache
70      */

71
72     public URIResolver(URL c, boolean overhead) {
73         hashCode = c.hashCode();
74     }
75     /**
76      * Create an URIResolver for a certain directory.
77      * @param c The directory for which this URIResolver must be created.
78      */

79
80     public URIResolver(URL c) {
81         this(c, null);
82     }
83
84     /**
85      * @since MMBase-1.8
86      */

87     private static URL toURL(File f) {
88         try {
89             return f.toURL();
90         } catch (Exception JavaDoc e) {
91             return null;
92         }
93     }
94     /**
95      * @deprecated
96      */

97     public URIResolver(File f) {
98         this(toURL(f), null);
99     }
100
101     /**
102      * Create an URIResolver without support for a certain directory. (Will be taken the first root).
103      */

104     public URIResolver() {
105         this((URL) null, null);
106     }
107
108     /**
109      * @deprecated
110      */

111     public URIResolver(File f, EntryList extraDirs) {
112         this(toURL(f), extraDirs);
113     }
114
115     /**
116      * Besides the current working directory you can also supply an
117      * ordered list of URIResolver.Entry's. First in this list are the
118      * directories which must be checked first, in case no prefix is
119      * given.
120      * @param c 'Current working dir'
121      * @param extraDirs A EntryList, containing 'extra' dirs with
122      * prefixes. If not specified or null, there will still be one
123      * 'extra dir' available, namely the MMBase configuration
124      * directory (with prefix mm:)
125      */

126     public URIResolver(URL c, EntryList extraDirs) {
127         if (log.isDebugEnabled()) log.debug("Creating URI Resolver for " + c);
128         URL cwd;
129         if (c == null) {
130             File[] roots = File.listRoots();
131             if (roots != null && roots.length > 0) {
132                 try {
133                     cwd = roots[0].toURL();
134                 } catch (Exception JavaDoc e) {
135                     cwd = null;
136                 }
137             } else {
138                 log.warn("No filesystem root available, trying with 'null'");
139                 cwd = null;
140                 // will this result in anything useful?
141
// well, I don't think we will use mmbase on root-less systems anyway?
142
}
143         } else {
144             cwd = c;
145         }
146         dirs = new EntryList();
147         dirs.add(new Entry("", cwd));
148         if (extraDirs != null) {
149             dirs.addAll(extraDirs);
150         }
151         dirs.add(new Entry("mm:", ResourceLoader.getConfigurationRoot()));
152         // URIResolvers cannot be changed, the hashCode can already be calculated and stored.
153

154         if (extraDirs == null || extraDirs.size() == 0) { // only mmbase config, and root cannot change
155
if (log.isDebugEnabled()) log.debug("getting hashCode " + cwd.hashCode());
156             hashCode = cwd.hashCode();
157             // if only the cwd is set, then you alternatively use the cwd has hashCode is this way.
158
// it this way in these case it is easy to avoid constructing an URIResolver at all.
159
} else {
160             hashCode = dirs.hashCode(); // see also javadoc of List
161
}
162     }
163
164     /**
165      * Returns the working directory which was supplied in the
166      * constructor.
167      *
168      */

169     public URL getCwd() {
170         return ((Entry) dirs.get(0)).getDir();
171     }
172
173     /**
174      * Creates a 'path' string, which is a list of directories. Mainly usefull for debugging, of course.
175      *
176      * @return A String which could be used as a shell's path.
177      */

178     public String JavaDoc getPath() {
179         StringBuffer JavaDoc result = new StringBuffer JavaDoc();
180         Iterator i = dirs.iterator();
181         while (i.hasNext()) {
182             Entry entry = (Entry) i.next();
183             result.append(File.pathSeparatorChar);
184             result.append(entry.getDir().toString());
185         }
186         return result.toString();
187     }
188
189     /**
190      * Creates a List of strings, every entry is a directory prefixed with its 'prefix'. Handy during debugging.
191      *
192      * @return A List with prefix:path Strings.
193      */

194     public List getPrefixPath() {
195         List result = new ArrayList();
196         Iterator i = dirs.iterator();
197         while (i.hasNext()) {
198             Entry entry = (Entry) i.next();
199             result.add(entry.getPrefix() + entry.getDir().toString());
200         }
201         return result;
202     }
203
204     /**
205      * @deprecated
206      */

207     public File resolveToFile(String JavaDoc href) {
208         return resolveToFile(href, null);
209     }
210     /**
211      * @deprecated
212      */

213     public File resolveToFile(String JavaDoc href, String JavaDoc base) {
214         try {
215             return new File(resolveToURL(href, base).getFile());
216         } catch (Exception JavaDoc e) {
217             return null;
218         }
219     }
220
221
222
223
224
225     public URL resolveToURL(final String JavaDoc href, final String JavaDoc base) throws TransformerException {
226         if (log.isDebugEnabled()) {
227             log.debug("Using resolver " + this + " to resolve href: " + href + " base: " + base);
228         }
229         try {
230             URL baseURL;
231             if (base == null // 'base' is often 'null', but happily, this object knows about cwd itself.
232
|| base.endsWith("javax.xml.transform.stream.StreamSource")) {
233                 baseURL = getCwd();
234             } else {
235                 baseURL = resolveToURL(base, null); // resolve URIResolver's prefixes like mm:, ew: in base.
236
}
237
238             URL path = null;
239             { // check all known prefixes
240
Iterator i = dirs.iterator();
241                 while (i.hasNext()) {
242                     Entry entry = (Entry) i.next();
243                     String JavaDoc pref = entry.getPrefix();
244                     if (! "".equals(pref) && href.startsWith(pref)) { //explicitely stated!
245
path = entry.getPath(href.substring(entry.getPrefixLength()));
246                         if (log.isTraceEnabled()) {
247                             log.trace("href matches " + entry + " returning " + path);
248                         }
249                         break;
250                     }
251                     try {
252                         URL u = entry.getPath(href);
253                         if (log.isTraceEnabled()) {
254                             log.trace("Trying " + u + " " + u.getClass());
255                         }
256                         // getDoInput does not work for every connection.
257
if (u.openConnection().getInputStream() != null) {
258                             log.trace("Ok, breaking");
259                             path = u;
260                             break;
261                         }
262                     } catch (MalformedURLException mfe) {
263                         log.debug(mfe);
264                         // ignore, this might be because of a prefix, which is not yet tried.
265
} catch (java.io.IOException JavaDoc io) {
266                         log.debug(io);
267                         // ignore, try next one.
268
}
269                 }
270             }
271
272             // still not found!
273
if (path == null) {
274                 if (href.startsWith("file:")) { // don't know excactly why this is good.
275
path = new URL(baseURL, href.substring(5));
276                 } else {
277                     path = new URL(baseURL, href);
278                 }
279                 try {
280                     if (path.openConnection().getInputStream() == null) {
281                         path = null;
282                     }
283                 } catch (Exception JavaDoc e) {
284                     path = null;
285                 }
286
287             }
288             if (log.isDebugEnabled()) {
289                 log.debug("Returning " + path);
290             }
291             return path;
292
293         } catch (Exception JavaDoc e) {
294             throw new TransformerException(e);
295         }
296     }
297
298     /**
299      * Implementation of the resolve method of javax.xml.transform.URIResolver.
300      *
301      * @see javax.xml.transform.URIResolver
302      **/

303
304     public Source resolve(String JavaDoc href, String JavaDoc base) throws TransformerException {
305         try {
306             URL u = resolveToURL(href, base);
307             if (u == null) return null;
308             Source source = new StreamSource(u.openStream());
309             source.setSystemId(u.toString());
310             return source;
311         } catch (Exception JavaDoc e) {
312             throw new TransformerException(e);
313         }
314     }
315
316
317     /**
318      * URIResolver can be used as a key in Maps (Caches).
319      */

320     public int hashCode() {
321         return hashCode;
322     }
323
324     /**
325      * URIResolver can be used as a key in Maps (Caches).
326      */

327     public boolean equals(Object JavaDoc o) {
328         if (o != null && (o instanceof URIResolver)) {
329             URIResolver res = (URIResolver) o;
330             return (dirs == null ? (res.dirs == null || res.dirs.size() == 1) : dirs.equals(res.dirs));
331             // See java javadoc, lists compare every element, files equal if point to same file
332
// extraDirs == null?
333
// -> created with first constructor.
334
}
335         return false;
336     }
337
338
339     public int getByteSize() {
340         return getByteSize(new org.mmbase.util.SizeOf());
341     }
342
343     public int getByteSize(org.mmbase.util.SizeOf sizeof) {
344         return sizeof.sizeof(dirs);
345     }
346     public String JavaDoc toString() {
347         return getPrefixPath().toString();
348     }
349
350     /**
351      * This is a list of prefix/directory pairs which is used in the constructor of URIResolver.
352      */

353
354     static public class EntryList extends ArrayList {
355         public EntryList() {
356         }
357
358         /**
359          * @throws IllegalArgumentException If you don't add an Entry.
360          */

361         public boolean add(Object JavaDoc o) {
362             if (!(o instanceof Entry)) {
363                 throw new IllegalArgumentException JavaDoc("object must be of type Entry");
364             }
365             return super.add(o);
366         }
367
368         /**
369          * Adds an prefix/dir entry to the List.
370          * @return The list again, so you can easily 'chain' a few.
371          * @throws IllegalArgumentException if d is not a directory.
372          * @deprecated
373          */

374         public EntryList add(String JavaDoc p, File d) {
375             try {
376                 add(new Entry(p, d.toURI().toURL()));
377                 return this;
378             } catch (Exception JavaDoc e) {
379                 return this;
380             }
381         }
382         public EntryList add(String JavaDoc p, URL u) {
383             try {
384                 add(new Entry(p, u));
385                 return this;
386             } catch (Exception JavaDoc e) {
387                 return this;
388             }
389         }
390         /**
391          * @since MMBase-1.8.2
392          */

393         public EntryList add(String JavaDoc p, ClassLoader JavaDoc cl) {
394             try {
395                 add(new Entry(p, cl));
396                 return this;
397             } catch (Exception JavaDoc e) {
398                 return this;
399             }
400         }
401     }
402
403     /**
404      * Objects of this type connect a prefix (must normally end in :)
405      * with a File (which must be a Directory). A List of this type
406      * (EntryList) can be fed to the constructor of URIResolver.
407      *
408      */

409
410     static class Entry implements java.io.Serializable JavaDoc {
411         private static final long serialVersionUID = 1L;
412         private String JavaDoc prefix;
413         private URL dir;
414         private ClassLoader JavaDoc classLoader;
415         private int prefixLength;
416
417         Entry(String JavaDoc p, URL u) {
418             prefix = p;
419             dir = u;
420             classLoader = null;
421             prefixLength = prefix.length(); // avoid calculating it again.
422
}
423         Entry(String JavaDoc p, ClassLoader JavaDoc cl) {
424             prefix = p;
425             dir = null;
426             classLoader = cl;
427             prefixLength = prefix.length(); // avoid calculating it again.
428
}
429
430         private void writeObject(java.io.ObjectOutputStream JavaDoc out) throws java.io.IOException JavaDoc {
431             try {
432                 out.writeUTF(prefix);
433                 if (dir == null) {
434                     out.writeObject("mm");
435                 } else {
436                     out.writeObject(dir);
437                 }
438             } catch (Throwable JavaDoc t) {
439                 log.warn(t);
440             }
441         }
442         private void readObject(java.io.ObjectInputStream JavaDoc in) throws java.io.IOException JavaDoc, ClassNotFoundException JavaDoc {
443             try {
444                 prefix = in.readUTF();
445                 Object JavaDoc o = in.readObject();
446                 if ("mm".equals(o)) {
447                     classLoader = ResourceLoader.getConfigurationRoot();
448                     dir = null;
449                 } else {
450                     dir = (URL) o;
451                     classLoader = null;
452                 }
453                 log.info("dir " + dir + " claddLoader " + classLoader);
454             } catch (Throwable JavaDoc t) {
455                 log.warn(t);
456             }
457             prefixLength = prefix.length();
458         }
459
460         String JavaDoc getPrefix() {
461             return prefix;
462         }
463         URL getDir() {
464             if (dir != null) {
465                 return dir;
466             } else {
467                 return classLoader.getResource("");
468             }
469         }
470
471         /**
472          * Uses this entry to resolve a href
473          * @since MMBase-1.8.2
474          */

475         URL getPath(String JavaDoc href) throws MalformedURLException {
476             if (dir != null) {
477                 return new URL(dir, href);
478             } else {
479                 return classLoader.getResource(href);
480             }
481         }
482         int getPrefixLength() {
483             return prefixLength;
484         }
485         public String JavaDoc toString() {
486             return prefix + ":" + (dir != null ? dir.toString() : classLoader.toString());
487         }
488         public boolean equals(Object JavaDoc o) {
489             if (o instanceof File) {
490                 return dir != null && dir.equals(o);
491             } else if (o instanceof Entry) {
492                 Entry e = (Entry) o;
493                 return dir != null ?
494                     dir.equals(e.dir) :
495                     classLoader.equals(e.classLoader);
496             } else {
497                 return false;
498             }
499         }
500
501         public int hashCode() {
502             if (dir != null) {
503                 return dir.hashCode();
504             } else {
505                 return classLoader.hashCode();
506             }
507         }
508
509     }
510
511     /**
512      * For testing only
513      * @since MMBase-1.8
514      */

515     public static void main(String JavaDoc argv[]) throws Exception JavaDoc {
516
517         URIResolver resolver = new URIResolver(new URL("file:///tmp/"));
518         System.out.println("Resolving with " + resolver);
519         String JavaDoc href, base;
520
521         href = "xsl/list.xsl"; base = null;
522         System.out.println("href: " + href + " base: " + base + " --> " + resolver.resolveToURL(href, base));
523         href = "xsl/prompts.xsl"; base = "file:///home/mmbase/mmbase17/mmbase/edit/wizard/data/xsl/base.xsl";
524         System.out.println("href: " + href + " base: " + base + " --> " + resolver.resolveToURL(href, base));
525
526         FileOutputStream fos = new FileOutputStream("/tmp/uriresolver.ser");
527         ObjectOutputStream oos = new ObjectOutputStream(fos);
528         oos.writeObject(resolver);
529         oos.close();
530
531         FileInputStream fis = new FileInputStream("/tmp/uriresolver.ser");
532         ObjectInputStream ois = new ObjectInputStream(fis);
533         URIResolver resolver2 = (URIResolver) ois.readObject();
534         ois.close();
535
536         System.out.println("r " + resolver2.resolveToURL("mm:hoi", null).getProtocol());
537
538         href = "xsl/list.xsl"; base = null;
539         System.out.println("href: " + href + " base: " + base + " --> " + resolver2.resolveToURL(href, base));
540         href = "xsl/prompts.xsl"; base = "file:///home/mmbase/mmbase17/mmbase/edit/wizard/data/xsl/base.xsl";
541         System.out.println("href: " + href + " base: " + base + " --> " + resolver2.resolveToURL(href, base));
542
543
544
545     }
546
547 }
548
Popular Tags