/*
* Copyright (c) 2005, Rob Gordon.
*/
package org.oddjob.launch;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* By Default, launch Oddjob using a classloader with the following:
* <ul>
* <li>Any jars in the lib directory.</li>
* <li>Any jars in the opt/lib directory.</li>
* <li>The opt/classes directory.</li>
* </ul>
*
* The launcher can also be used as a job to launch other main methods.
*
* @author Rob Gordon, Based on Ant.
*/
public class Launcher implements Runnable {
public static final String ODDJOB_HOME_PROPERTY = "oddjob.home";
public static final String ODDJOB_RUN_JAR_PROPERTY = "oddjob.run.jar";
public static final String ODDJOB_MAIN_CLASS = "org.oddjob.Main";
/** The class loader to find the main class in. */
private ClassLoader classLoader;
/** The name of the class that contains the main method. */
private String className;
/** The arguments to pass to main. */
private String[] args;
public void run() {
if (classLoader == null) {
throw new NullPointerException("No ClassLoader.");
}
if (className == null) {
throw new NullPointerException("No Class Name.");
}
ClassLoader currentLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
try {
Class<?> mainClass = classLoader.loadClass(className);
// use reflection because main is now in another
// class loader space so we can't get at it.
Method method = mainClass.getMethod("main",
new Class[] { String[].class });
method.invoke(null, (Object) args);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
Thread.currentThread().setContextClassLoader(currentLoader);
}
}
/**
* Provides the Oddjob class loader.
*
* @param currentLoader
* @param classpath
* @return
* @throws IOException
*/
static ClassLoader getClassLoader(ClassLoader currentLoader, String[] classpath)
throws IOException {
File sourceJar = Locator.getClassSource(Launcher.class);
File jarDir = sourceJar.getParentFile();
System.setProperty(ODDJOB_HOME_PROPERTY, jarDir.getCanonicalPath());
System.setProperty(ODDJOB_RUN_JAR_PROPERTY, sourceJar.getCanonicalPath());
List<File> classPathList = new ArrayList<File>();
// add the source jar
classPathList.add(sourceJar);
// expand the classpath entries.
for (String entry : classpath) {
File[] entryFiles = new FileSpec(
new File(entry)).getFiles();
classPathList.addAll(Arrays.asList(entryFiles));
}
// expand the lib directory
File[] libFiles = new FileSpec(
new File(new File(jarDir,"lib"), "*.jar")).getFiles();
classPathList.addAll(Arrays.asList(libFiles));
// add opt/classes
classPathList.add(new File(jarDir, "opt/classes"));
// expand the opt/lib directory
File[] optFiles = new FileSpec(new File(
new File(jarDir,"opt/lib"), "*.jar")).getFiles();
classPathList.addAll(Arrays.asList(optFiles));
// The full class path
ClassPathHelper classPathHelper = new ClassPathHelper(
classPathList.toArray(new File[classPathList.size()]));
URL[] urls = classPathHelper.toURLs();
classPathHelper.appendToJavaClassPath();
final String classPath = classPathHelper.toString();
ClassLoader cl = new URLClassLoader(urls, currentLoader) {
@Override
public String toString() {
return "Oddjob Launcher ClassLoader: " +
classPath;
}
};
return cl;
}
public ClassLoader getClassLoader() {
return classLoader;
}
public void setClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String[] getArgs() {
return args;
}
public void setArgs(String[] args) {
this.args = args;
}
/**
* Main method for launching Oddjob in it's own class loader.
* The parent class loader will be taken to be the current threads
* context class loader.
*
* @param args
* @throws IOException
*/
public static void main(String... args) throws IOException {
// process -D property definitions
args = new SystemPropertyArgParser().processArgs(args);
// process class path
PathParser path = new PathParser();
args = path.processArgs(args);
ClassLoader loader = getClassLoader(
Thread.currentThread().getContextClassLoader(),
path.getElements());
Launcher launcher = new Launcher();
launcher.setArgs(args);
launcher.setClassLoader(loader);
launcher.setClassName(ODDJOB_MAIN_CLASS);
launcher.run();
}
}