InstallJars.java Source code

Java tutorial

Introduction

Here is the source code for InstallJars.java

Source

/*******************************************************************************
 * 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);
        }
    }
}