Back to index

wims  3.65+svn20090927
FileUtilities.java
Go to the documentation of this file.
00001 /* Utilities used to manipulate files
00002 
00003  Copyright (c) 2004-2008 The Regents of the University of California.
00004  All rights reserved.
00005  Permission is hereby granted, without written agreement and without
00006  license or royalty fees, to use, copy, modify, and distribute this
00007  software and its documentation for any purpose, provided that the above
00008  copyright notice and the following two paragraphs appear in all copies
00009  of this software.
00010 
00011  IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
00012  FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
00013  ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
00014  THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
00015  SUCH DAMAGE.
00016 
00017  THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
00018  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00019  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
00020  PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
00021  CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
00022  ENHANCEMENTS, OR MODIFICATIONS.
00023 
00024  PT_COPYRIGHT_VERSION_2
00025  COPYRIGHTENDKEY
00026 
00027  */
00028 package ptolemy.util;
00029 
00030 import java.io.BufferedInputStream;
00031 import java.io.BufferedOutputStream;
00032 import java.io.BufferedReader;
00033 import java.io.File;
00034 import java.io.FileOutputStream;
00035 import java.io.FileWriter;
00036 import java.io.IOException;
00037 import java.io.InputStream;
00038 import java.io.InputStreamReader;
00039 import java.io.PrintWriter;
00040 import java.io.Writer;
00041 import java.net.URI;
00042 import java.net.URL;
00043 import java.util.Enumeration;
00044 import java.util.jar.JarEntry;
00045 import java.util.jar.JarFile;
00046 
00047 // Avoid importing any packages from ptolemy.* here so that we
00048 // can ship Ptplot.
00051 
00062 public class FileUtilities {
00065     private FileUtilities() {
00066     }
00067 
00070 
00079     public static boolean binaryCopyURLToFile(URL sourceURL,
00080             File destinationFile) throws IOException {
00081         URL destinationURL = destinationFile.getCanonicalFile().toURI().toURL();
00082 
00083         if (sourceURL.sameFile(destinationURL)) {
00084             return false;
00085         }
00086 
00087         // If sourceURL is of the form file:./foo, then we need to try again.
00088         File sourceFile = new File(sourceURL.getFile());
00089 
00090         // If the sourceURL is not a jar URL, then check to see if we
00091         // have the same file.
00092         // FIXME: should we check for !/ and !\ everywhere?
00093         if ((sourceFile.getPath().indexOf("!/") == -1)
00094                 && (sourceFile.getPath().indexOf("!\\") == -1)) {
00095             try {
00096                 if (sourceFile.getCanonicalFile().toURI().toURL().sameFile(
00097                         destinationURL)) {
00098                     return false;
00099                 }
00100             } catch (IOException ex) {
00101                 // JNLP Jar urls sometimes throw an exception here.
00102                 // IOException constructor does not take a cause
00103                 IOException ioException = new IOException(
00104                         "Cannot find canonical file name of '" + sourceFile
00105                                 + "'");
00106                 ioException.initCause(ex);
00107                 throw ioException;
00108             }
00109         }
00110 
00111         _binaryCopyStream(sourceURL.openStream(), destinationFile);
00112 
00113         return true;
00114     }
00115 
00124     public static void extractJarFile(String jarFileName, String directoryName)
00125             throws IOException {
00126         JarFile jarFile = new JarFile(jarFileName);
00127         Enumeration entries = jarFile.entries();
00128         while (entries.hasMoreElements()) {
00129             JarEntry jarEntry = (JarEntry) entries.nextElement();
00130             File destinationFile = new File(directoryName, jarEntry.getName());
00131             if (jarEntry.isDirectory()) {
00132                 if (!destinationFile.isDirectory() && !destinationFile.mkdirs()) {
00133                     throw new IOException("Warning, failed to create "
00134                             + "directory for \"" + destinationFile + "\".");
00135                 }
00136             } else {
00137                 _binaryCopyStream(jarFile.getInputStream(jarEntry),
00138                         destinationFile);
00139             }
00140         }
00141     }
00142 
00150     public static void main(String[] args) {
00151         if (args.length < 1 || args.length > 2) {
00152             System.err.println("Usage: java -classpath $PTII "
00153                     + "ptolemy.util.FileUtilities jarFile [directory]\n"
00154                     + "where jarFile is the name of the jar file\n"
00155                     + "and directory is the optional directory in which to "
00156                     + "extract.");
00157             StringUtilities.exit(2);
00158         }
00159         String jarFileName = args[0];
00160         String directoryName = null;
00161         if (args.length >= 2) {
00162             directoryName = args[1];
00163         }
00164         try {
00165             extractJarFile(jarFileName, directoryName);
00166         } catch (Throwable throwable) {
00167             System.err.println("Failed to extract \"" + jarFileName + "\"");
00168             throwable.printStackTrace();
00169             StringUtilities.exit(3);
00170         }
00171     }
00172 
00199     public static File nameToFile(String name, URI base) {
00200         if ((name == null) || name.trim().equals("")) {
00201             return null;
00202         }
00203 
00204         File file = new File(name);
00205 
00206         if (!file.isAbsolute()) {
00207             // Try to resolve the base directory.
00208             if (base != null) {
00209                 URI newURI = base.resolve(name);
00210 
00211                 //file = new File(newURI);
00212                 String urlString = newURI.getPath();
00213                 file = new File(StringUtilities.substitute(urlString, "%20",
00214                         " "));
00215             }
00216         }
00217         return file;
00218     }
00219 
00249     public static URL nameToURL(String name, URI baseDirectory,
00250             ClassLoader classLoader) throws IOException {
00251         if ((name == null) || name.trim().equals("")) {
00252             return null;
00253         }
00254 
00255         // If the name begins with "$CLASSPATH", or
00256         // "xxxxxxCLASSPATHxxxxxx",then attempt to open the file
00257         // relative to the classpath.
00258         // NOTE: Use the dummy variable constant set up in the constructor.
00259         if (name.startsWith(_CLASSPATH_VALUE) || name.startsWith("$CLASSPATH")) {
00260             // Try relative to classpath.
00261             String classpathKey;
00262 
00263             if (name.startsWith(_CLASSPATH_VALUE)) {
00264                 classpathKey = _CLASSPATH_VALUE;
00265             } else {
00266                 classpathKey = "$CLASSPATH";
00267             }
00268 
00269             String trimmedName = name.substring(classpathKey.length() + 1);
00270 
00271             if (classLoader == null) {
00272                 String referenceClassName = "ptolemy.util.FileUtilities";
00273 
00274                 try {
00275                     // WebStart: We might be in the Swing Event thread, so
00276                     // Thread.currentThread().getContextClassLoader()
00277                     // .getResource(entry) probably will not work so we
00278                     // use a marker class.
00279                     Class referenceClass = Class.forName(referenceClassName);
00280                     classLoader = referenceClass.getClassLoader();
00281                 } catch (Exception ex) {
00282                     // IOException constructor does not take a cause
00283                     IOException ioException = new IOException(
00284                             "Cannot look up class \"" + referenceClassName
00285                                     + "\" or get its ClassLoader.");
00286                     ioException.initCause(ex);
00287                     throw ioException;
00288                 }
00289             }
00290 
00291             // Use Thread.currentThread()... for Web Start.
00292             URL result = classLoader.getResource(trimmedName);
00293 
00294             if (result == null) {
00295                 throw new IOException("Cannot find file '" + trimmedName
00296                         + "' in classpath");
00297             }
00298 
00299             return result;
00300         }
00301 
00302         File file = new File(name);
00303 
00304         if (file.isAbsolute()) {
00305             if (!file.canRead()) {
00306                 // FIXME: This is a hack.
00307                 // Expanding the configuration with Ptolemy II installed
00308                 // in a directory with spaces in the name fails on
00309                 // JAIImageReader because PtolemyII.jpg is passed in
00310                 // to this method as C:\Program%20Files\Ptolemy\...
00311                 file = new File(StringUtilities.substitute(name, "%20", " "));
00312 
00313                 URL possibleJarURL = null;
00314 
00315                 if (!file.canRead()) {
00316                     // ModelReference and FilePortParameters sometimes
00317                     // have paths that have !/ in them.
00318                     possibleJarURL = ClassUtilities.jarURLEntryResource(name);
00319 
00320                     if (possibleJarURL != null) {
00321                         file = new File(possibleJarURL.getFile());
00322                     }
00323                 }
00324 
00325                 if (!file.canRead()) {
00326                     throw new IOException("Cannot read file '"
00327                             + name
00328                             + "' or '"
00329                             + StringUtilities.substitute(name, "%20", " ")
00330                             + "'"
00331                             + ((possibleJarURL == null) ? "" : (" or '"
00332                                     + possibleJarURL.getFile() + "")));
00333                 }
00334             }
00335 
00336             return file.toURI().toURL();
00337         } else {
00338             // Try relative to the base directory.
00339             if (baseDirectory != null) {
00340                 // Try to resolve the URI.
00341                 URI newURI;
00342 
00343                 try {
00344                     newURI = baseDirectory.resolve(name);
00345                 } catch (Exception ex) {
00346                     // FIXME: Another hack
00347                     // This time, if we try to open some of the JAI
00348                     // demos that have actors that have defaults FileParameters
00349                     // like "$PTII/doc/img/PtolemyII.jpg", then resolve()
00350                     // bombs.
00351                     String name2 = StringUtilities.substitute(name, "%20", " ");
00352                     try {
00353                         newURI = baseDirectory.resolve(name2);
00354                         name = name2;
00355                     } catch (Exception ex2) {
00356                         IOException io = new IOException(
00357                                 "Problem with URI format in '"
00358                                         + name
00359                                         + "'. "
00360                                         + "and '"
00361                                         + name2
00362                                         + "' "
00363                                         + "This can happen if the file name "
00364                                         + "is not absolute"
00365                                         + "and is not present relative to the "
00366                                         + "directory in which the specified model "
00367                                         + "was read (which was '"
00368                                         + baseDirectory + "')");
00369                         io.initCause(ex2);
00370                         throw io;
00371                     }
00372                 }
00373 
00374                 String urlString = newURI.toString();
00375 
00376                 try {
00377                     // Adding another '/' for remote execution.
00378                     if ((newURI.getScheme() != null)
00379                             && (newURI.getAuthority() == null)) {
00380                         urlString = urlString.substring(0, 6) + "//"
00381                                 + urlString.substring(6);
00382 
00383                         //} else {
00384                         // urlString = urlString.substring(0, 6) + "/"
00385                         // + urlString.substring(6);
00386                     }
00387                     return new URL(urlString);
00388                 } catch (Exception ex3) {
00389                     try {
00390                         // Under Webstart, opening
00391                         // hoc/demo/ModelReference/ModelReference.xml
00392                         // requires this because the URL is relative.
00393                         return new URL(baseDirectory.toURL(), urlString);
00394                     } catch (Exception ex4) {
00395 
00396                         try {
00397                             // Under Webstart, ptalon, EightChannelFFT
00398                             // requires this.
00399                             return new URL(baseDirectory.toURL(), newURI.toString());
00400                         } catch (Exception ex5) {
00401                             // Ignore
00402                         }
00403 
00404                         IOException io = new IOException(
00405                                 "Problem with URI format in '"
00406                                 + urlString
00407                                 + "'. "
00408                                 + "This can happen if the '"
00409                                 + urlString
00410                                 + "' is not absolute"
00411                                 + " and is not present relative to the directory"
00412                                 + " in which the specified model was read"
00413                                 + " (which was '" + baseDirectory + "')");
00414                         io.initCause(ex3);
00415                         throw io;
00416                     }
00417                 }
00418             }
00419 
00420             // As a last resort, try an absolute URL.
00421 
00422             URL url = new URL(name);
00423 
00424             // If we call new URL("http", null, /foo);
00425             // then we get "http:/foo", which should be "http://foo"
00426             // This change suggested by Dan Higgins and Kevin Kruland
00427             // See kepler/src/util/URLToLocalFile.java
00428             try {
00429                 String fixedURLAsString = url.toString().replaceFirst(
00430                         "(https?:)//?", "$1//");
00431                 url = new URL(fixedURLAsString);
00432             } catch (Exception e) {
00433                 // Ignore
00434             }
00435             return url;
00436         }
00437     }
00438 
00456     public static BufferedReader openForReading(String name, URI base,
00457             ClassLoader classLoader) throws IOException {
00458         if ((name == null) || name.trim().equals("")) {
00459             return null;
00460         }
00461 
00462         if (name.trim().equals("System.in")) {
00463             if (STD_IN == null) {
00464                 STD_IN = new BufferedReader(new InputStreamReader(System.in));
00465             }
00466 
00467             return STD_IN;
00468         }
00469 
00470 
00471 
00472         // Not standard input. Try URL mechanism.
00473         URL url = nameToURL(name, base, classLoader);
00474 
00475         if (url == null) {
00476             throw new IOException("Could not convert \"" + name
00477                     + "\" with base \"" + base + "\" to a URL.");
00478         }
00479 
00480         InputStreamReader inputStreamReader = null;
00481         try {
00482             inputStreamReader = new InputStreamReader(url.openStream());
00483         } catch (IOException ex) {
00484             // Try it as a jar url.
00485             // WebStart ptalon MapReduce needs this.
00486             try {
00487                 URL possibleJarURL = ClassUtilities.jarURLEntryResource(url.toString());
00488                 if (possibleJarURL != null) {
00489                     inputStreamReader = new InputStreamReader(possibleJarURL.openStream());
00490                 }
00491                 // If possibleJarURL is null, this throws an exception,
00492                 // which we ignore and report the first exception (ex)
00493                 return new BufferedReader(inputStreamReader);
00494             } catch (Exception ex2) {
00495                 try {
00496                     if (inputStreamReader != null) {
00497                         inputStreamReader.close();
00498                     }
00499                 } catch (IOException ex3) {
00500                     // Ignore
00501                 }
00502                 IOException ioException = new IOException("Failed to open \""
00503                         + url + "\".");
00504                 ioException.initCause(ex);
00505                 throw ioException;
00506             }
00507         }
00508 
00509         return new BufferedReader(inputStreamReader);
00510     }
00511 
00533     public static Writer openForWriting(String name, URI base, boolean append)
00534             throws IOException {
00535         if ((name == null) || name.trim().equals("")) {
00536             return null;
00537         }
00538 
00539         if (name.trim().equals("System.out")) {
00540             if (STD_OUT == null) {
00541                 STD_OUT = new PrintWriter(System.out);
00542             }
00543 
00544             return STD_OUT;
00545         }
00546 
00547         File file = nameToFile(name, base);
00548         return new FileWriter(file, append);
00549     }
00550 
00553 
00557     public static BufferedReader STD_IN = null;
00558 
00562     public static PrintWriter STD_OUT = null;
00563 
00566 
00575     private static void _binaryCopyStream(InputStream inputStream,
00576             File destinationFile) throws IOException {
00577         // Copy the source file.
00578         BufferedInputStream input = null;
00579 
00580         try {
00581             input = new BufferedInputStream(inputStream);
00582 
00583             BufferedOutputStream output = null;
00584 
00585             try {
00586                 File parent = destinationFile.getParentFile();
00587                 if (parent != null && !parent.exists()) {
00588                     if (!parent.mkdirs()) {
00589                         throw new IOException("Failed to create directories "
00590                                 + "for \"" + parent + "\".");
00591                     }
00592                 }
00593 
00594                 output = new BufferedOutputStream(new FileOutputStream(
00595                         destinationFile));
00596 
00597                 int c;
00598 
00599                 while ((c = input.read()) != -1) {
00600                     output.write(c);
00601                 }
00602             } finally {
00603                 if (output != null) {
00604                     try {
00605                         output.close();
00606                     } catch (Throwable throwable) {
00607                         throw new RuntimeException(throwable);
00608                     }
00609                 }
00610             }
00611         } finally {
00612             if (input != null) {
00613                 try {
00614                     input.close();
00615                 } catch (Throwable throwable) {
00616                     throw new RuntimeException(throwable);
00617                 }
00618             }
00619         }
00620     }
00621 
00624 
00632     private static String _CLASSPATH_VALUE = "xxxxxxCLASSPATHxxxxxx";
00633 }