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