| NetUtil.java |
1 /**
2 * Distribution License:
3 * JSword is free software; you can redistribute it and/or modify it under
4 * the terms of the GNU Lesser General Public License, version 2.1 as published by
5 * the Free Software Foundation. This program is distributed in the hope
6 * that it will be useful, but WITHOUT ANY WARRANTY; without even the
7 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8 * See the GNU Lesser General Public License for more details.
9 *
10 * The License is available on the internet at:
11 * http://www.gnu.org/copyleft/lgpl.html
12 * or by writing to:
13 * Free Software Foundation, Inc.
14 * 59 Temple Place - Suite 330
15 * Boston, MA 02111-1307, USA
16 *
17 * Copyright: 2005
18 * The copyright to this program is held by it's authors.
19 *
20 * ID: $Id: NetUtil.java 2230 2012-02-08 00:00:10Z dmsmith $
21 */
22 package org.crosswire.common.util;
23
24 import java.io.BufferedReader;
25 import java.io.File;
26 import java.io.FileInputStream;
27 import java.io.FileNotFoundException;
28 import java.io.FileOutputStream;
29 import java.io.FilenameFilter;
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.io.InputStreamReader;
33 import java.io.OutputStream;
34 import java.net.JarURLConnection;
35 import java.net.MalformedURLException;
36 import java.net.URI;
37 import java.net.URISyntaxException;
38 import java.net.URL;
39 import java.net.URLConnection;
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.Date;
43 import java.util.List;
44 import java.util.jar.JarEntry;
45
46 import org.crosswire.jsword.JSMsg;
47 import org.crosswire.jsword.JSOtherMsg;
48
49 /**
50 * The NetUtil class looks after general utility stuff around the java.net
51 * package.
52 *
53 * @see gnu.lgpl.License for license details.<br>
54 * The copyright to this program is held by it's authors.
55 * @author Joe Walker [joe at eireneh dot com]
56 * @author Mark Goodwin [goodwinster at gmail dot com]
57 * @author DM Smith [dmsmith555 at yahoo dot com]
58 */
59 public final class NetUtil {
60 /**
61 * Basic constructor - ensure that we can't be instantiated
62 */
63 private NetUtil() {
64 }
65
66 /**
67 * Constant for the file: protocol or scheme
68 */
69 public static final String PROTOCOL_FILE = "file";
70
71 /**
72 * Constant for the http: protocol or scheme
73 */
74 public static final String PROTOCOL_HTTP = "http";
75
76 /**
77 * Constant for the ftp: protocol or scheme
78 */
79 public static final String PROTOCOL_FTP = "ftp";
80
81 /**
82 * Constant for the jar: protocol or scheme
83 */
84 public static final String PROTOCOL_JAR = "jar";
85
86 /**
87 * For directory listings
88 */
89 public static final String INDEX_FILE = "index.txt";
90
91 /**
92 * URL/URI separator
93 */
94 public static final String SEPARATOR = "/";
95
96 /**
97 * Separating the username from the rest of the URL/URI
98 */
99 public static final String AUTH_SEPERATOR_USERNAME = "@";
100
101 /**
102 * Separating the password from the username
103 */
104 public static final String AUTH_SEPERATOR_PASSWORD = ":";
105
106 /**
107 * The temporary suffix, used when a temporary file is needed in the
108 * system's temporary directory.
109 */
110 private static final String TEMP_SUFFIX = "tmp";
111
112 public static URI copy(URI uri) {
113 try {
114 return new URI(uri.toString());
115 } catch (URISyntaxException e) {
116 assert false : e;
117 return null;
118 }
119 }
120
121 /**
122 * If the directory does not exist, create it. Note this currently only
123 * works with file: type URIs
124 *
125 * @param orig
126 * The directory URI to create
127 */
128 public static void makeDirectory(URI orig) throws MalformedURLException {
129 checkFileURI(orig);
130
131 File file = new File(orig.getPath());
132
133 // If it is a file, except
134 if (file.isFile()) {
135 // TRANSLATOR: Error condition: A directory was expected, but a file was found. {0} is a placeholder for the file.
136 throw new MalformedURLException(JSMsg.gettext("The URL {0} is a file.", orig));
137 }
138
139 // Is it already a directory ?
140 if (!file.isDirectory()) {
141 // Create the directory and make sure it worked.
142 if (!file.mkdirs()) {
143 // TRANSLATOR: Error condition: A directory could not be created. {0} is a placeholder for the directory
144 throw new MalformedURLException(JSMsg.gettext("The URL {0} could not be created as a directory.", orig));
145 }
146 }
147 }
148
149 /**
150 * If the file does not exist, create it. Note this currently only works
151 * with file: type URIs
152 *
153 * @param orig
154 * The file URI to create
155 */
156 public static void makeFile(URI orig) throws MalformedURLException, IOException {
157 checkFileURI(orig);
158
159 File file = new File(orig.getPath());
160
161 // If it is a file, except
162 if (file.isDirectory()) {
163 // TRANSLATOR: Error condition: A file was expected, but a directory was found. {0} is a placeholder for the directory.
164 throw new MalformedURLException(JSMsg.gettext("The URL {0} is a directory.", orig));
165 }
166
167 // Is it already a directory ?
168 if (!file.isFile()) {
169 FileOutputStream fout = new FileOutputStream(file);
170 fout.close();
171
172 // Did that work?
173 if (!file.isFile()) {
174 // TRANSLATOR: Error condition: A file could not be created. {0} is a placeholder for the file
175 throw new MalformedURLException(JSMsg.gettext("The URL {0} could not be created as a file.", orig));
176 }
177 }
178 }
179
180 /**
181 * If there is a file at the other end of this URI return true.
182 *
183 * @param uri
184 * The URI to check
185 * @return true if the URI points at a file
186 */
187 public static boolean isFile(URI uri) {
188 if (uri.getScheme().equals(PROTOCOL_FILE)) {
189 return new File(uri.getPath()).isFile();
190 }
191
192 try {
193 // This will throw if the resource does not exist
194 uri.toURL().openStream().close();
195 return true;
196 } catch (IOException ex) {
197 // the resource does not exist!
198 return false;
199 }
200 }
201
202 /**
203 * If there is a directory at the other end of this URI return true. Note
204 * non file: type URI will always return false
205 *
206 * @param orig
207 * The URI to check
208 * @return true if the URI points at a file: directory
209 */
210 public static boolean isDirectory(URI orig) {
211 if (!orig.getScheme().equals(PROTOCOL_FILE)) {
212 return false;
213 }
214
215 return new File(orig.getPath()).isDirectory();
216 }
217
218 /**
219 * If there is a writable directory or file at the other end of this URI
220 * return true. Note non file: type URIs will always return false
221 *
222 * @param orig
223 * The URI to check
224 * @return true if the URI points at a writable file or directory
225 */
226 public static boolean canWrite(URI orig) {
227 if (!orig.getScheme().equals(PROTOCOL_FILE)) {
228 return false;
229 }
230
231 return new File(orig.getPath()).canWrite();
232 }
233
234 /**
235 * If there is a readable directory or file at the other end of this URI
236 * return true. Note non file: type URIs will always return false
237 *
238 * @param orig
239 * The URI to check
240 * @return true if the URI points at a readable file or directory
241 */
242 public static boolean canRead(URI orig) {
243 if (!orig.getScheme().equals(PROTOCOL_FILE)) {
244 return false;
245 }
246
247 return new File(orig.getPath()).canRead();
248 }
249
250 /**
251 * Move a URI from one place to another. Currently this only works for file:
252 * URIs, however the interface should not need to change to handle more
253 * complex URIs
254 *
255 * @param oldUri
256 * The URI to move
257 * @param newUri
258 * The destination URI
259 */
260 public static boolean move(URI oldUri, URI newUri) throws IOException {
261 checkFileURI(oldUri);
262 checkFileURI(newUri);
263
264 File oldFile = new File(oldUri.getPath());
265 File newFile = new File(newUri.getPath());
266 return oldFile.renameTo(newFile);
267 }
268
269 /**
270 * Delete a URI. Currently this only works for file: URIs, however the
271 * interface should not need to change to handle more complex URIs
272 *
273 * @param orig
274 * The URI to delete
275 */
276 public static boolean delete(URI orig) throws IOException {
277 checkFileURI(orig);
278
279 return new File(orig.getPath()).delete();
280 }
281
282 /**
283 * Return a File from the URI either by extracting from a file: URI or by
284 * downloading to a temp dir first
285 *
286 * @param uri
287 * The original URI to the file.
288 * @return The URI as a file
289 * @throws IOException
290 */
291 public static File getAsFile(URI uri) throws IOException {
292 // if the URI is already a file URI, return it
293 if (uri.getScheme().equals(PROTOCOL_FILE)) {
294 return new File(uri.getPath());
295 }
296 String hashString = (uri.toString().hashCode() + "").replace('-', 'm');
297
298 // get the location of the tempWorkingDir
299 File workingDir = getURICacheDir();
300 File workingFile = null;
301
302 if (workingDir != null && workingDir.isDirectory()) {
303 workingFile = new File(workingDir, hashString);
304 } else {
305 // If there's no working dir, we just use temp...
306 workingFile = File.createTempFile(hashString, TEMP_SUFFIX);
307 }
308 workingFile.deleteOnExit();
309
310 // copy the contents of the URI to the file
311 OutputStream output = null;
312 InputStream input = null;
313 try {
314 output = new FileOutputStream(workingFile);
315 input = uri.toURL().openStream();
316 byte[] data = new byte[512];
317 for (int read = 0; read != -1; read = input.read(data)) {
318 output.write(data, 0, read);
319 }
320 } finally {
321 try {
322 if (input != null) {
323 input.close();
324 }
325 } finally {
326 if (output != null) {
327 output.close();
328 }
329 }
330 }
331
332 // return the new file in URI form
333 return workingFile;
334 }
335
336 /**
337 * Utility to strip a string from the end of a URI.
338 *
339 * @param orig
340 * The URI to strip
341 * @param strip
342 * The text to strip from the end of the URI
343 * @return The stripped URI
344 * @exception MalformedURLException
345 * If the URI does not end in the given text
346 */
347 public static URI shortenURI(URI orig, String strip) throws MalformedURLException {
348 String file = orig.getPath();
349 char lastChar = file.charAt(file.length() - 1);
350 if (isSeparator(lastChar)) {
351 file = file.substring(0, file.length() - 1);
352 }
353
354 String test = file.substring(file.length() - strip.length());
355 if (!test.equals(strip)) {
356 throw new MalformedURLException(JSOtherMsg.lookupText("The URL {0} does not end in {1}.", orig, strip));
357 }
358
359 String newFile = file.substring(0, file.length() - strip.length());
360
361 try {
362 return new URI(orig.getScheme(), orig.getUserInfo(), orig.getHost(), orig.getPort(), newFile, "",
363 "");
364 } catch (URISyntaxException e) {
365 throw new MalformedURLException(JSOtherMsg.lookupText("The URL {0} does not end in {1}.", orig, strip));
366 }
367 }
368
369 /**
370 * Utility to add a string to the end of a URI.
371 *
372 * @param orig
373 * The URI to lengthen
374 * @param anExtra
375 * The text to add to the end of the URI
376 * @return The lengthened URI
377 */
378 public static URI lengthenURI(URI orig, String anExtra) {
379 String extra = anExtra;
380 try {
381 StringBuilder path = new StringBuilder(orig.getPath());
382 char lastChar = path.charAt(path.length() - 1);
383 char firstChar = extra.charAt(0);
384 if (isSeparator(firstChar)) {
385 if (isSeparator(lastChar)) {
386 path.append(extra.substring(1));
387 } else {
388 path.append(extra);
389 }
390 } else {
391 if (!isSeparator(lastChar)) {
392 path.append(SEPARATOR);
393 }
394 path.append(extra);
395 }
396
397 return new URI(orig.getScheme(), orig.getUserInfo(), orig.getHost(), orig.getPort(), path.toString(), orig.getQuery(), orig.getFragment());
398 } catch (URISyntaxException ex) {
399 // assert false : ex;
400 return null;
401 }
402 }
403
404 private static boolean isSeparator(char c) {
405 return c == '/' || c == '\\';
406 }
407
408 /**
409 * Attempt to obtain an InputStream from a URI. If the URI is a file scheme
410 * then just open it directly. Otherwise, call uri.toURL().openStream().
411 *
412 * @param uri
413 * The URI to attempt to read from
414 * @return An InputStream connection
415 */
416 public static InputStream getInputStream(URI uri) throws IOException {
417 // We favor the FileOutputStream
418 if (uri.getScheme().equals(PROTOCOL_FILE)) {
419 return new FileInputStream(uri.getPath());
420 }
421 return uri.toURL().openStream();
422 }
423
424 /**
425 * Attempt to obtain an OutputStream from a URI. The simple case will open
426 * it if it is local. Otherwise, it will call
427 * uri.toURL().openConnection().getOutputStream(), however in some JVMs (MS
428 * at least this fails where new FileOutputStream(url) works.
429 *
430 * @param uri
431 * The URI to attempt to write to
432 * @return An OutputStream connection
433 */
434 public static OutputStream getOutputStream(URI uri) throws IOException {
435 return getOutputStream(uri, false);
436 }
437
438 /**
439 * Attempt to obtain an OutputStream from a URI. The simple case will open
440 * it if it is local. Otherwise, it will call
441 * uri.toURL().openConnection().getOutputStream(), however in some JVMs (MS
442 * at least this fails where new FileOutputStream(url) works.
443 *
444 * @param uri
445 * The URI to attempt to write to
446 * @param append
447 * Do we write to the end of the file instead of the beginning
448 * @return An OutputStream connection
449 */
450 public static OutputStream getOutputStream(URI uri, boolean append) throws IOException {
451 // We favor the FileOutputStream method here because append
452 // is not well defined for the openConnection method
453 if (uri.getScheme().equals(PROTOCOL_FILE)) {
454 return new FileOutputStream(uri.getPath(), append);
455 }
456 URLConnection cnx = uri.toURL().openConnection();
457 cnx.setDoOutput(true);
458 return cnx.getOutputStream();
459 }
460
461 /**
462 * List the items available assuming that this URI points to a directory.
463 * <p>
464 * There are 2 methods of calculating the answer - if the URI is a file: URI
465 * then we can just use File.list(), otherwise we ask for a file inside the
466 * directory called index.txt and assume the directories contents to be
467 * listed one per line.
468 * <p>
469 * If the URI is a file: URI then we execute both methods and warn if there
470 * is a difference, but returning the values from the index.txt method.
471 */
472 public static String[] list(URI uri, URIFilter filter) throws MalformedURLException, IOException {
473 // We should probably cache this in some way? This is going
474 // to get very slow calling this often across a network
475 String[] reply = {};
476 try {
477 URI search = NetUtil.lengthenURI(uri, INDEX_FILE);
478 reply = listByIndexFile(search, filter);
479 } catch (FileNotFoundException ex) {
480 // So the index file was not found - this isn't going to work over
481 // JNLP or other systems that can't use file: URIs. But it is silly
482 // to get to picky so if there is a solution using file: then just
483 // print a warning and carry on.
484 log.warn("index file for " + uri.toString() + " was not found.");
485 if (uri.getScheme().equals(PROTOCOL_FILE)) {
486 return listByFile(uri, filter);
487 }
488 }
489
490 // if we can - check that the index file is up to date.
491 if (uri.getScheme().equals(PROTOCOL_FILE)) {
492 String[] files = listByFile(uri, filter);
493
494 // Check that the answers are the same
495 if (files.length != reply.length) {
496 log.warn("index file for " + uri.toString() + " has incorrect number of entries.");
497 } else {
498 List<String> list = Arrays.asList(files);
499 for (int i = 0; i < files.length; i++) {
500 if (!list.contains(files[i])) {
501 log.warn("file: based index found " + files[i] + " but this was not found using index file.");
502 }
503 }
504 }
505 }
506
507 return reply;
508 }
509
510 /**
511 * List all the files specified by the index file passed in.
512 *
513 * @return String[] Matching results.
514 */
515 public static String[] listByFile(URI uri, URIFilter filter) throws MalformedURLException {
516 File fdir = new File(uri.getPath());
517 if (!fdir.isDirectory()) {
518 // TRANSLATOR: Error condition: A directory was expected, but a file was found. {0} is a placeholder for the file.
519 throw new MalformedURLException(JSMsg.gettext("The URL {0} is not a directory", uri.toString()));
520 }
521
522 return fdir.list(new URIFilterFilenameFilter(filter));
523 }
524
525 /**
526 * List all the strings specified by the index file passed in. To be
527 * acceptable it must be a non-0 length string, not commented with #, and
528 * not the index file itself.
529 *
530 * @return String[] Matching results.
531 * @throws FileNotFoundException
532 */
533 public static String[] listByIndexFile(URI index) throws IOException {
534 return listByIndexFile(index, new DefaultURIFilter());
535 }
536
537 /**
538 * List all the files specified by the index file passed in. To be
539 * acceptable it:
540 * <ul>
541 * <li> must be a non-0 length string,</li>
542 * <li> not commented with #,</li>
543 * <li> not the index file itself</li>
544 * <li> and acceptable by the filter.</li>
545 * </ul>
546 *
547 * @return String[] Matching results.
548 * @throws FileNotFoundException
549 */
550 public static String[] listByIndexFile(URI index, URIFilter filter) throws IOException {
551 InputStream in = null;
552 BufferedReader din = null;
553 try {
554 in = NetUtil.getInputStream(index);
555 // Quiet Android from complaining about using the default BufferReader buffer size.
556 // The actual buffer size is undocumented. So this is a good idea any way.
557 din = new BufferedReader(new InputStreamReader(in), 8192);
558
559 // We still need to do the filtering
560 List<String> list = new ArrayList<String>();
561
562 while (true) {
563 String line = din.readLine();
564
565 if (line == null) {
566 break;
567 }
568
569 // we need to trim extraneous whitespace on the line
570 String name = line.trim();
571
572 // Is it acceptable?
573 if (name.length() > 0 && name.charAt(0) != '#' && !name.equals(INDEX_FILE) && filter.accept(name)) {
574 list.add(name);
575 }
576 }
577
578 return list.toArray(new String[list.size()]);
579 } finally {
580 IOUtil.close(din);
581 IOUtil.close(in);
582 }
583 }
584
585 /**
586 * Load up properties given by a URI.
587 *
588 * @param uri
589 * the location of the properties
590 * @return the properties given by the URI
591 * @throws IOException
592 */
593 public static PropertyMap loadProperties(URI uri) throws IOException {
594 InputStream is = null;
595 try {
596 is = NetUtil.getInputStream(uri);
597 PropertyMap prop = new PropertyMap();
598 prop.load(is);
599 is.close();
600 return prop;
601 } finally {
602 IOUtil.close(is);
603 }
604 }
605
606 /**
607 * Store the properties at the location given by the uri using the supplied
608 * title.
609 *
610 * @param properties
611 * the properties to store
612 * @param uri
613 * the location of the store
614 * @param title
615 * the label held in the properties file
616 * @throws IOException
617 */
618 public static void storeProperties(PropertyMap properties, URI uri, String title) throws IOException {
619 OutputStream out = null;
620
621 try {
622 out = NetUtil.getOutputStream(uri);
623 PropertyMap temp = new PropertyMap();
624 temp.putAll(properties);
625 temp.store(out, title);
626 } finally {
627 IOUtil.close(out);
628 }
629 }
630
631 /**
632 * @param uri
633 * the resource whose size is wanted
634 * @return the size of that resource
635 */
636 public static int getSize(URI uri) {
637 return getSize(uri, null, null);
638 }
639
640 public static int getSize(URI uri, String proxyHost) {
641 return getSize(uri, proxyHost, null);
642 }
643
644 public static int getSize(URI uri, String proxyHost, Integer proxyPort) {
645 try {
646 if (uri.getScheme().equals(PROTOCOL_HTTP)) {
647 WebResource resource = new WebResource(uri, proxyHost, proxyPort);
648 int size = resource.getSize();
649 resource.shutdown();
650 return size;
651 }
652
653 return uri.toURL().openConnection().getContentLength();
654 } catch (IOException e) {
655 return 0;
656 }
657 }
658
659 /**
660 * When was the given URI last modified. If no modification time is
661 * available then this method return the current time.
662 */
663 public static long getLastModified(URI uri) {
664 return getLastModified(uri, null, null);
665 }
666
667 public static long getLastModified(URI uri, String proxyHost) {
668 return getLastModified(uri, proxyHost, null);
669 }
670
671 public static long getLastModified(URI uri, String proxyHost, Integer proxyPort) {
672 try {
673 if (uri.getScheme().equals(PROTOCOL_HTTP)) {
674 WebResource resource = new WebResource(uri, proxyHost, proxyPort);
675 long time = resource.getLastModified();
676 resource.shutdown();
677 return time;
678 }
679
680 URLConnection urlConnection = uri.toURL().openConnection();
681 long time = urlConnection.getLastModified();
682
683 // If it were a jar then time contains the last modified date of the jar.
684 if (urlConnection instanceof JarURLConnection) {
685 // form is jar:file:.../xxx.jar!.../filename.ext
686 JarURLConnection jarConnection = (JarURLConnection) urlConnection;
687 JarEntry jarEntry = jarConnection.getJarEntry();
688 time = jarEntry.getTime();
689 }
690
691 return time;
692 } catch (IOException ex) {
693 log.warn("Failed to get modified time", ex);
694 return new Date().getTime();
695 }
696 }
697
698 /**
699 * Returns whether the left is newer than the right by comparing their last
700 * modified dates.
701 *
702 * @param left
703 * @param right
704 * @return true if the left is newer
705 */
706 public static boolean isNewer(URI left, URI right) {
707 return isNewer(left, right, null, null);
708 }
709
710 public static boolean isNewer(URI left, URI right, String proxyHost) {
711 return isNewer(left, right, proxyHost, null);
712 }
713
714 public static boolean isNewer(URI left, URI right, String proxyHost, Integer proxyPort) {
715 return NetUtil.getLastModified(left, proxyHost, proxyPort) > NetUtil.getLastModified(right, proxyHost, proxyPort);
716 }
717
718 /**
719 * Quick implementation of FilenameFilter that uses a URIFilter
720 */
721 public static class URIFilterFilenameFilter implements FilenameFilter {
722 /**
723 * Simple ctor
724 */
725 public URIFilterFilenameFilter(URIFilter filter) {
726 this.filter = filter;
727 }
728
729 /*
730 * (non-Javadoc)
731 *
732 * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String)
733 */
734 public boolean accept(File arg0, String name) {
735 return filter.accept(name);
736 }
737
738 private URIFilter filter;
739 }
740
741 /**
742 * Throw if the given URI does not use the 'file:' protocol
743 *
744 * @param uri
745 * The URI to check
746 * @throws MalformedURLException
747 * If the protocol is not file:
748 */
749 private static void checkFileURI(URI uri) throws MalformedURLException {
750 if (!uri.getScheme().equals(PROTOCOL_FILE)) {
751 // TRANSLATOR: Error condition: The URL protocol "file:" was expected, but something else was found. {0} is a placeholder for the URL.
752 throw new MalformedURLException(JSMsg.gettext("The URL {0} is not a file.", uri));
753 }
754 }
755
756 /**
757 * Returns the cache directory.
758 *
759 * @return File
760 */
761 public static File getURICacheDir() {
762 return cachedir;
763 }
764
765 /**
766 * Sets the cache directory.
767 *
768 * @param cachedir
769 * The cache directory to set
770 */
771 public static void setURICacheDir(File cachedir) {
772 NetUtil.cachedir = cachedir;
773 }
774
775 /**
776 * Get a URI version of the given file.
777 *
778 * @param file
779 * The File to turn into a URI
780 * @return a URI for the given file
781 */
782 public static URI getURI(File file) {
783 return file.toURI();
784 }
785
786 /**
787 * A URI version of <code>File.createTempFile()</code>
788 *
789 * @return A new temporary URI
790 * @throws IOException
791 * If something goes wrong creating the temp URI
792 */
793 public static URI getTemporaryURI(String prefix, String suffix) throws IOException {
794 File tempFile = File.createTempFile(prefix, suffix);
795 return getURI(tempFile);
796 }
797
798 /**
799 * Convert an URL to an URI.
800 *
801 * @param url
802 * to convert
803 * @return the URI representation of the URL
804 */
805 public static URI toURI(URL url) {
806 try {
807 return new URI(url.toExternalForm());
808 } catch (URISyntaxException e) {
809 return null;
810 }
811 }
812
813 /**
814 * Convert an URI to an URL.
815 *
816 * @param uri
817 * to convert
818 * @return the URL representation of the URI
819 */
820 public static URL toURL(URI uri) {
821 try {
822 return uri.toURL();
823 } catch (MalformedURLException e) {
824 return null;
825 }
826 }
827
828 /**
829 * Check that the directories in the version directory really represent
830 * versions.
831 */
832 public static class IsDirectoryURIFilter implements URIFilter {
833 /**
834 * Simple ctor
835 */
836 public IsDirectoryURIFilter(URI parent) {
837 this.parent = parent;
838 }
839
840 /*
841 * (non-Javadoc)
842 *
843 * @see org.crosswire.common.util.URLFilter#accept(java.lang.String)
844 */
845 public boolean accept(String name) {
846 return NetUtil.isDirectory(NetUtil.lengthenURI(parent, name));
847 }
848
849 private URI parent;
850 }
851
852 /**
853 * Where are temporary files cached.
854 */
855 private static File cachedir;
856
857 /**
858 * The log stream
859 */
860 private static final Logger log = Logger.getLogger(NetUtil.class);
861 }
862