Mega Code Archive

 
Categories / Java / File Input Output
 

InstallJars - a utility to download and install files, Jars and Zips

/*******************************************************************************  * Copyright (c) 2004, 2008 IBM Corporation.  * All rights reserved. This program and the accompanying materials  * are made available under the terms of the Eclipse Public License v1.0  * which accompanies this distribution, and is available at  * http://www.eclipse.org/legal/epl-v10.html  *  * Contributors:  * IBM Corporation - initial API and implementation                                         *******************************************************************************/ import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; import java.net.URLConnection; import java.util.Iterator; import java.util.Properties; import java.util.StringTokenizer; import java.util.zip.GZIPInputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; /*******************************************************************************  * * InstallJars - a utility to download and install files, Jars and Zips. * *  *   * @author Barry Feigenbaum, Ph.D. *  ******************************************************************************/ public class InstallJars {   public static final int BLOCK_SIZE = 512;   public static final int BLOCK_COUNT = 20;   // *** must be a multiple of BLOCK_SIZE ***   public static int bufferSize = 128 * (2 * BLOCK_SIZE);   // *** need to NLS enable all user messages ***   /**    * Constructor. Expand, run and verbose output requested.    */   public InstallJars() {     this(true, true, true, "InstallJars.properties", "cmd /c java");   }   /**    * Contstructor.    *     * @param expand    *          <code>true</code> if the archive is t be expanded in the target    * @param verbose    *          <code>true</code> if messages are to be generated    * @param run    *          <code>true</code> if file is to be executed    * @param propName    *          properties file with items to install    * @param javaParams    *          java parameters    */   public InstallJars(boolean expand, boolean verbose, boolean run, String propName,       String javaParams) {     setExpand(expand);     setVerbose(verbose);     setRunMode(run);     setPropFilename(propName);     setJavaParams(javaParams);   }   protected boolean verbose;   /**    * Get the verbose mode state.    *     * @return is in verbose mode    */   public boolean getVerbose() {     return verbose;   }   /**    * Set the verbose mode state.    *     * @param f    *          value    */   public void setVerbose(boolean f) {     verbose = f;   }   protected boolean run;   /**    * Get the run mode state.    *     * @return is in run mode    */   public boolean getRunMode() {     return run;   }   /**    * Set the run mode state.    *     * @param f    *          value    */   public void setRunMode(boolean f) {     run = f;   }   protected boolean expand;   /**    * Get the expand mode state.    *     * @return is expanded    */   public boolean getExpand() {     return expand;   }   /**    * Set the expand mode state.    *     * @param f    *          value    */   public void setExpand(boolean f) {     expand = f;   }   protected String propFilename;   /**    * Get the propFilename mode state.    *     * @return prooperty file name    */   public String getPropFilename() {     return propFilename;   }   /**    * Set the propFilename mode state.    *     * @param name    */   public void setPropFilename(String name) {     propFilename = name;   }   protected String javaParams = "cmd /c java";   /**    * Get the JavaParams mode state.    *     * @return java parameters    */   public String getJavaParams() {     return javaParams;   }   /**    * Set the JavaParams mode state.    *     * @param p    *          value    */   public void setJavaParams(String p) {     javaParams = p;   }   protected void print(String s) {     if (verbose) {       System.out.print(s);     }   }   protected void println(String s) {     if (verbose) {       System.out.println(s);     }   }   protected void println() {     println("");   }   /**    * Install based on a properties file<br>    *     * @return recommended classpath    * @exception IOException    *              Thrown if a JAR file access error occurs    */   public String install() throws IOException {     StringBuffer classpath = new StringBuffer();     Properties prop = new Properties();     prop.load(new BufferedInputStream(new FileInputStream(propFilename)));     for (Iterator i = prop.keySet().iterator(); i.hasNext();) {       String key = (String) i.next();       String value = prop.getProperty(key);       String xurl = null;       String xdir = null;       String xcp = null;       boolean xexpand = expand, xrun = run;       if (value != null) {         value = value.trim();         if (value.length() > 0) {           String delim = value.substring(0, 1);           StringTokenizer st = new StringTokenizer(value.substring(1), delim);           xurl = st.nextToken();           xdir = (st.hasMoreTokens() ? st.nextToken() : ".").trim();           if (xdir.length() == 0) {             xdir = ".";           }           xcp = (st.hasMoreTokens() ? st.nextToken() : xdir).trim();           if (xcp.length() == 0) {             xcp = xdir;           }           classpath.append(xcp);           classpath.append(";");           while (st.hasMoreTokens()) {             String xoption = st.nextToken().trim();             if (xoption.equalsIgnoreCase("expand")) {               xexpand = true;             } else if (xoption.equalsIgnoreCase("noexpand")) {               xexpand = false;             } else if (xoption.equalsIgnoreCase("run")) {               xrun = true;             } else if (xoption.equalsIgnoreCase("norun")) {               xrun = false;             } else {               throw new IllegalArgumentException("invalid install property - " + key + "=" + value);             }           }         }       }       if (xurl == null || xurl.length() == 0) {         throw new IllegalArgumentException("missing install property - " + key + "=" + value);       }       System.out.print("\nInstalling " + key);       if (verbose) {         System.out.print(" using URL=" + xurl + "; target=" + xdir + "; classpath=" + xcp + "; "             + (xexpand ? "expand" : "noexpand") + "; " + (xrun ? "run" : "norun"));       }       System.out.println("...");       installFile(xurl, xdir, xexpand, xrun);     }     return classpath.toString();   }   /**    * Install a Zip/Jar file.    *     * @param fileUrl    *          The file/zip/jar file    * @param targetPath    *          root of directory or file to install into    * @param doExpand    * @param doRun    * @exception IOException    *              Thrown if a JAR file access error occurs    */   public void installFile(String fileUrl, String targetPath, boolean doExpand, boolean doRun)       throws IOException {     String targetFilename = new File(targetPath).getCanonicalPath().replace('\\', '/');     println("Installing in " + targetFilename);     URL url = new URL(fileUrl);     URLConnection conn = url.openConnection();     // System.out.println("Conn = " + conn);     String ctype = conn.getContentType();     println("Content type is " + ctype);     String extension = getExtension(fileUrl);     if (extension.equals("class")) {       installClass(conn, targetFilename, doExpand, doRun);       // println("Installed class file " + fileUrl + "; please run");     } else if (extension.equalsIgnoreCase("zip")) {       installZip(conn, targetFilename, doExpand, doRun);       // println("Installed ZIP file " + fileUrl + "; ZIP expanded");     } else if (extension.equalsIgnoreCase("gz")) {       installGZip(conn, targetFilename, doExpand, doRun);       // println("Installed GZIP file " + fileUrl + "; ZIP expanded");     } else if (extension.equalsIgnoreCase("jar")) {       installJar(conn, targetFilename, doExpand, doRun);       // System.out.println("Installed JAR file " + fileUrl + "; please add to       // CLASSPATH");     } else {       throw new IllegalArgumentException("Unknown extension - " + extension);     }   }   public void installClass(URLConnection conn, String target, boolean doExpand, boolean doRun)       throws IOException {     // doExpand not used on htis type     print("Installing class file " + target + " from " + conn.getURL().toExternalForm());     copyStream(conn, target);     println();     if (doRun) {       runTarget(target, false);     }   }   protected void runTarget(String target, boolean isJar) throws IOException {     // *** add run code ***     if (isJar) {       System.out.println("runTarget(" + target + "," + isJar + ") not currently implemented");     } else {       try {         String name = removeExtension(getFile(target));         String cp = "-cp " + removeFile(target);         String command = javaParams + " " + cp + " " + name + " >" + name + ".out 2>" + name             + ".err";         // String command = javaParams + " " + cp + " " + name;         System.out.println("Running " + command + "...");         Process p = Runtime.getRuntime().exec(command);         int rc = p.waitFor();         System.out.println("Return code=" + rc);       } catch (Exception e) {         System.out.println("Exception - " + e.getMessage());       }     }   }   public void installJar(URLConnection conn, String target, boolean doExpand, boolean doRun)       throws IOException {     if (doExpand) {       println("Expanding JAR file " + target + " from " + conn.getURL().toExternalForm());       // *** may need to specialize for JAR format ***       ZipInputStream zis = new ZipInputStream(new BufferedInputStream(conn.getInputStream(),           BLOCK_SIZE * BLOCK_COUNT));       int count = 0;       prepDirs(target, true);       try {         while (zis.available() > 0) {           ZipEntry ze = zis.getNextEntry();           copyEntry(target, zis, ze);           count++;         }       } finally {         try {           zis.close();         } catch (IOException ioe) {         }       }       println("Installed " + count + " files/directories");     } else {       print("Installing JAR file " + target + " from " + conn.getURL().toExternalForm());       copyStream(conn, target);       println();       if (doRun) {         runTarget(target, true);       }     }   }   public void installZip(URLConnection conn, String target, boolean doExpand, boolean doRun)       throws IOException {     // doRun not used on htis type     if (doExpand) {       String ctype = conn.getContentType();       if (!ctype.equals("application/zip")) {         throw new IllegalArgumentException("Unkexpected content type - " + ctype);       }       println("Expanding ZIP file to " + target + " from " + conn.getURL().toExternalForm());       ZipInputStream zis = new ZipInputStream(new BufferedInputStream(conn.getInputStream(),           BLOCK_SIZE * BLOCK_COUNT));       int count = 0;       prepDirs(target, true);       try {         for (ZipEntry ze = zis.getNextEntry(); ze != null; ze = zis.getNextEntry()) {           copyEntry(target, zis, ze);           // zis.closeEntry();           count++;         }       } finally {         try {           zis.close();         } catch (IOException ioe) {         }       }       println("Installed " + count + " files/directories");     } else {       print("Installing ZIP file " + target + " from " + conn.getURL().toExternalForm());       copyStream(conn, target);       println();     }   }   public void installGZip(URLConnection conn, String target, boolean doExpand, boolean doRun)       throws IOException {     // doRun not used on htis type     if (doExpand) {       String ctype = conn.getContentType();       if (!ctype.equals("application/x-tar")) {         throw new IllegalArgumentException("Unkexpected content type - " + ctype);       }       print("Expanding GZIP file to " + target + " from " + conn.getURL().toExternalForm());       prepDirs(target, false);       GZIPInputStream zis = new GZIPInputStream(new BufferedInputStream(conn.getInputStream(),           BLOCK_SIZE * BLOCK_COUNT));       try {         // BufferedOutputStream os = new BufferedOutputStream(new         // FileOutputStream(target), BLOCK_SIZE * BLOCK_COUNT);         // try {         // byte[] buf = new byte[bufferSize];         // for (int size = zis.read(buf, 0, buf.length), count = 0;         // size >= 0;         // size = zis.read(buf, 0, buf.length), count++) {         // //if (count % 4 == 0) print(".");         // os.write(buf, 0, size);         // }         // }         // finally {         // try { os.flush(); os.close(); } catch (IOException ioe) {}         // }         pumpGZip(target, zis);       } finally {         try {           zis.close();         } catch (IOException ioe) {         }       }       println();     } else {       print("Installing GZIP file " + target + " from " + conn.getURL().toExternalForm());       copyStream(conn, target);       println();     }   }   /** Copy a zip entry. */   protected void copyEntry(String target, ZipInputStream zis, ZipEntry ze) throws IOException {     String name = ze.getName();     boolean isDir = false;     if (name.endsWith("/")) {       name = name.substring(0, name.length() - 1);       isDir = true;     }     String path = target + File.separator + name;     path = path.replace('\\', '/');     String mod = ze.getSize() > 0 ? ("[" + ze.getCompressedSize() + ":" + ze.getSize() + "]") : "";     print("Expanding " + ze + mod + " to " + path);     prepDirs(path, isDir);     if (!isDir) {       BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(path), BLOCK_SIZE           * BLOCK_COUNT);       try {         byte[] buf = new byte[bufferSize];         for (int size = zis.read(buf, 0, buf.length), count = 0; size >= 0; size = zis.read(buf, 0,             buf.length), count++) {           // if (count % 4 == 0) print(".");           os.write(buf, 0, size);         }       } finally {         try {           os.flush();           os.close();         } catch (IOException ioe) {         }       }     }     println();   }   public void copyStream(URLConnection conn, String target) throws IOException {     prepDirs(target, false);     BufferedInputStream is = new BufferedInputStream(conn.getInputStream(), BLOCK_SIZE         * BLOCK_COUNT);     BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(target), BLOCK_SIZE         * BLOCK_COUNT);     byte[] buf = new byte[bufferSize];     for (int size = is.read(buf), count = 0; size >= 0; size = is.read(buf), count++) {       // if (count % 4 == 0) print(".");       os.write(buf, 0, size);     }     os.flush();     os.close();     is.close();   }   protected static final int OFFSET_NAME = 0;   protected static final int OFFSET_MODE = OFFSET_NAME + 100;   protected static final int OFFSET_UID = OFFSET_MODE + 8;   protected static final int OFFSET_GID = OFFSET_UID + 8;   protected static final int OFFSET_SIZE = OFFSET_GID + 8;   protected static final int OFFSET_MTIME = OFFSET_SIZE + 12;   protected static final int OFFSET_CHKSUM = OFFSET_MTIME + 12;   protected static final int OFFSET_TYPE = OFFSET_CHKSUM + 8;   protected static final int OFFSET_LINKNAME = OFFSET_TYPE + 1;   protected static final int OFFSET_MAGIC = OFFSET_LINKNAME + 100;   protected static final int OFFSET_VERSION = OFFSET_MAGIC + 6;   protected static final int OFFSET_UNAME = OFFSET_VERSION + 2;   protected static final int OFFSET_GNAME = OFFSET_UNAME + 32;   protected static final int OFFSET_DEVMAJOR = OFFSET_GNAME + 32;   protected static final int OFFSET_DEVMINOR = OFFSET_DEVMAJOR + 8;   protected static final int OFFSET_PREFIX = OFFSET_DEVMINOR + 8;   protected static final int OFFSET_END = OFFSET_PREFIX + 155;   protected static final String MAGIC = "USTAR";   protected void pumpGZip(String target, GZIPInputStream zis) throws IOException {     String curName = null;     long curSize = 0, remainingSize = 0;     char curType = 0;     int curMajor = 0, curMinor = 0;     boolean inFile = false;     BufferedOutputStream curOs = null;     int instFiles = 0, instDirs = 0;     byte[] buf = new byte[bufferSize];     top: while (true) {       int loaded = loadBytes(buf, zis);       if (loaded < 0) {         break;       }       // System.out.println("pumpGZip: loaded=" + loaded);       // process each buffer of data       for (int index = 0; index < loaded; index += BLOCK_SIZE) {         // System.out.println("pumpGZip: infile=" + inFile + ", remaining=" +         // remainingSize);         if (inFile && remainingSize > 0) { // process body part           int xsize = Math.min((int) remainingSize, BLOCK_SIZE);           if (curOs != null) {             curOs.write(buf, index, xsize);           }           remainingSize -= xsize;         } else { // process header block           if (inFile) {             inFile = false;             if (curOs != null) {               try {                 curOs.flush();                 curOs.close();               } catch (IOException ioe) {               }               println();             }           }           if (isEmptyBlock(buf, index)) { // check logical end of archive             break top;           }           // System.out.println("pumpGZip: header=" + (new String(buf, 0, index,           // 512)));           curName = extractString(buf, index + OFFSET_NAME, 100);           curType = extractChar(buf, index + OFFSET_TYPE);           curSize = extractLong(buf, index + OFFSET_SIZE, 12);           remainingSize = curSize;           if (remainingSize > Integer.MAX_VALUE) {             throw new IOException("entry size too large - " + remainingSize);           }           String mod = "";           String magic = extractString(buf, index + OFFSET_MAGIC, 6);           if (magic.equals(MAGIC)) {             curName = extractString(buf, index + OFFSET_PREFIX, 155) + curName;             extractInt(buf, index + OFFSET_VERSION, 2);             curMajor = extractInt(buf, index + OFFSET_DEVMAJOR, 8);             curMinor = extractInt(buf, index + OFFSET_DEVMINOR, 8);             if (curMajor > 0 || curMinor > 0) {               mod = "[" + curMajor + '.' + curMinor + "]";             }           }           // System.out.println("pumpGZip: " +           // magic + "," +           // curName + "," +           // curType + "," +           // curSize + "," +           // curVersion + "," +           // curMajor + "," +           // curMinor);           String path = target + File.separator + curName;           path = path.replace('\\', '/');           curOs = null;           if (curType == 0 || curType == '0') { // a file             print("Copying " + curName + mod + " to " + path);             prepDirs(path, false);             curOs = new BufferedOutputStream(new FileOutputStream(path), BLOCK_SIZE * BLOCK_COUNT);             inFile = true;             instFiles++;           } else if (curType == '1' || curType == '2') { // a link             if (curSize > 0) {               throw new IOException("link entries cannot have content - " + curSize);             }             println("Link ignored - " + curName + mod);           } else if (curType == '5') { // a directory             if (path.endsWith("/")) {               path = path.substring(0, path.length() - 1);             }             println("Mkdir " + curName + mod + " to " + path);             prepDirs(path, true);             instDirs++;           } else {             if (curSize > 0) {               // throw new IOException("entry type " + curType + " cannot have a               // content - size=" + curSize);               inFile = true;             }             print("Entry type " + curType + " ignored - " + curName + mod);           }         }       }     }     println("Installed " + instFiles + " files and " + instDirs + " directories");   }   protected int loadBytes(byte[] buf, GZIPInputStream zis) throws IOException {     int loaded = -1;     for (int size = zis.read(buf, 0, buf.length), count = 0; size > 0; size = zis.read(buf, loaded,         buf.length - loaded), count++) {       // if (count % 4 == 0) print(".");       // System.out.println("loadBytes: loaded=" + loaded);       if (loaded < 0) {         loaded = 0;       }       loaded += size;     }     return loaded;   }   protected boolean isEmptyBlock(byte[] buf, int index) {     boolean r = true;     for (int i = 0; r && i < BLOCK_SIZE; i++) {       r = buf[index++] == 0;     }     // System.out.println("isEmptyBlock: " + r);     return r;   }   protected char extractChar(byte[] buf, int index) throws IOException {     return (char) buf[index];   }   protected int extractInt(byte[] buf, int index, int length) throws IOException {     return (int) extractLong(buf, index, length);   }   protected long extractLong(byte[] buf, int index, int length) throws IOException {     String xsize = extractString(buf, index, length);     long v = 0;     for (int i = 0; i < xsize.length(); i++) {       char c = xsize.charAt(i);       if (c != ' ') {         if (c < '0' || c > '7') {           throw new IOException("non-octal digit found - " + c);         }         v = v * 8 + (c - '0');       }     }     return v;   }   protected String extractString(byte[] buf, int index, int length) throws IOException {     StringBuffer sb = new StringBuffer();     for (int i = 0, xindex = index; i < length; i++, xindex++) {       int c = buf[xindex];       if (c == 0) {         break;       }       sb.append((char) c);     }     // System.out.println("extractString(" + index + "," + length + "): " +     // sb.toString());     return sb.toString();   }   protected String getFile(String name) {     int posn = name.lastIndexOf("/");     return posn > 0 ? name.substring(posn + 1) : name;   }   protected String removeFile(String name) {     int posn = name.lastIndexOf("/");     return posn > 0 ? name.substring(0, posn) : name;   }   protected String removeExtension(String name) {     int posn1 = name.lastIndexOf("/");     int posn2 = name.lastIndexOf(".");     return (posn2 > 0 && posn2 > posn1) ? name.substring(0, posn2) : name;   }   protected String extraceFile(String name) {     int posn = name.lastIndexOf(File.separator);     return posn >= 0 ? name.substring(posn + 1) : null;   }   protected String getExtension(String name) {     int posn = name.lastIndexOf('.');     return posn >= 0 ? name.substring(posn + 1) : "";   }   protected void prepDirs(String name) {     prepDirs(name, expand);   }   protected void prepDirs(String name, boolean includeLast) {     File f = new File(includeLast ? name : removeFile(name));     // System.out.print("(Making " + f + ")");     f.mkdirs();   }   protected void printUsage() {     println("Effective command: " + getClass().getName() + " " + propFilename         + (expand ? " -expand" : " -noexpand") + (run ? " -run" : " -norun") + " -java \""         + javaParams + "\"" + (verbose ? " -verbose" : " -quiet "));   }   /** Print command help text. */   protected static void printHelp() {     System.out.println();     System.out         .println("Usage: java "             + InstallJars.class.getName()             + " {propFilename} {-expand | -noexpand} {-run | -norun} {-quiet | -verbose} {-java <params>}");     System.out.println("Where:");     System.out         .println("  propFilename    path to properties file (default=InstallJars.properties)");     System.out.println("  -expand         expand any top level JAR/ZIP/GZIP (default)");     System.out.println("  -noexpand       do not expand any top level JAR/ZIP/GZIP");     System.out.println("  -run            run class or JAR files (default)");     System.out.println("  -norun          do not run class or JAR files");     System.out.println("  -verbose        output progress messages (default)");     System.out.println("  -quiet          suppress most messages");     System.out.println("  -java           sets java runtime paramters");     System.out.println();     System.out.println("Properties file entry format: name=!url{!target{!classpath{!option}...}}");     System.out.println("Where:");     System.out.println("  name      name displayed while installing");     System.out.println("  url       source of items to download and install");     System.out.println("  target    root of install directory or file (default=.)");     System.out         .println("  classpath class path entry to use for this directrory or file (default=target}");     System.out.println("  option    one of the following options: expand, noexpand, run, norun");     System.out.println("            if omitted, the command line default is used");     System.out.println("! is a delimiter, the first non-whitespace character is used.");     System.out.println("Options expand and run may not apply to all types of files.");   }   /**    * Main command line entry point.    *     * @param args    */   public static void main(final String[] args) {     if (args.length == 0) {       printHelp();       System.exit(0);     }     String propName = null;     boolean expand = true;     boolean verbose = true;     boolean run = true;     String params = "cmd /c java";     // process arguments     for (int i = 0; i < args.length; i++) {       String arg = args[i];       if (arg.charAt(0) == '-') { // switch         arg = arg.substring(1);         if (arg.equalsIgnoreCase("quiet")) {           verbose = false;         } else if (arg.equalsIgnoreCase("verbose")) {           verbose = true;         } else if (arg.equalsIgnoreCase("expand")) {           expand = true;         } else if (arg.equalsIgnoreCase("noexpand")) {           expand = false;         } else if (arg.equalsIgnoreCase("run")) {           run = true;         } else if (arg.equalsIgnoreCase("norun")) {           run = false;         } else if (arg.equalsIgnoreCase("java")) {           run = false;           if (i < args.length - 1) {             params = args[++i];           }         } else {           System.err.println("Invalid switch - " + arg);           System.exit(1);         }       } else {         if (propName == null) {           propName = arg;         } else {           System.err.println("Too many parameters - " + arg);           System.exit(1);         }       }     }     if (propName == null) {       propName = "InstallJars.properties";     }     // do the install     try {       InstallJars ij = new InstallJars(expand, verbose, run, propName, params);       ij.printUsage();       String cp = ij.install();       System.out.println("\nRecomended additions to your classpath - " + cp);     } catch (Exception e) {       System.err.println("\n" + e.getClass().getName() + ": " + e.getMessage());       if (verbose) {         e.printStackTrace(); // *** debug ***       }       System.exit(2);     }   } }