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);
}
}
}
Related examples in the same category