blob: a6d6af47ca0239cfbb8224868630839d890b14dc [file] [log] [blame]
package org.eclipse.cdt.testplugin;
// copied from startup.jar. planned to be removed soon
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import java.net.*;
import java.lang.reflect.*;
import java.io.*;
import java.util.*;
/**
* Startup class for Eclipse. Creates a class loader using
* supplied URL of platform installation, loads and calls
* the Eclipse Boot Loader. The startup arguments are as follows:
* <dl>
* <dd>
* -application &lt;id&gt;: the identifier of the application to run
* </dd>
* <dd>
* -boot &lt;location&gt;: the location, expressed as a URL, of the platform's boot.jar
* </dd>
* <dd>
* -consolelog : enables log to the console. Handy when combined with -debug
* </dd>
* <dd>
* -data &lt;location&gt;: sets the workspace location and the default location for projects
* </dd>
* <dd>
* -debug [options file]: turns on debug mode for the platform and optionally specifies a location
* for the .options file. This file indicates what debug points are available for a
* plug-in and whether or not they are enabled. If a location is not specified, the platform searches
* for the .options file under the install directory
* </dd>
* <dd>
* -dev [entries]: turns on dev mode and optionally specifies comma-separated class path entries
* which are added to the class path of each plug-in
* </dd>
* <dd>
* -keyring &lt;location&gt;: the location of the authorization database on disk. This argument
* has to be used together with the -password argument
* </dd>
* <dd>
* -password &lt;passwd&gt;: the password for the authorization database
* </dd>
* <dd>
* -plugins &lt;location&gt;: The arg is a URL pointing to a file which specs the plugin
* path for the platform. The file is in property file format where the keys are user-defined
* names and the values are comma separated lists of either explicit paths to plugin.xml
* files or directories containing plugins. (e.g., .../eclipse/plugins).
* </dd>
* <dd>
* -ws &lt;window system&gt;: sets the window system value
* </dd>
* </dl>
*/
public class Main {
/**
* Indicates whether this instance is running in debug mode.
*/
protected boolean debug = false;
/**
* The location of the launcher to run.
*/
protected String bootLocation = null;
/**
* The identifier of the application to run.
*/
protected String application;
/**
* The path for finding find plugins.
*/
protected URL pluginPathLocation;
/**
* The boot path location.
*/
protected String location;
/**
* Indicates whether items for UNinstallation should be looked for.
*/
protected boolean uninstall = false;
/**
* The item to be uninstalled.
*/
protected String uninstallCookie;
/**
* The class path entries.
*/
protected String devClassPath = null;
/**
* Indicates whether this instance is running in development mode.
*/
protected boolean inDevelopmentMode = false;
// static token describing how to take down the splash screen
private static String endSplash = null;
// constants
private static final String APPLICATION = "-application";
private static final String BOOT = "-boot";
private static final String DEBUG = "-debug";
private static final String DEV = "-dev";
private static final String ENDSPLASH = "-endsplash";
private static final String UNINSTALL = "-uninstall";
private static final String PI_BOOT = "org.eclipse.core.boot";
private static final String BOOTLOADER = "org.eclipse.core.boot.BootLoader";
private static final String UPDATELOADER = "org.eclipse.core.internal.boot.LaunchInfo";
// The project containing the boot loader code. This is used to construct
// the correct class path for running in VAJ and VAME.
private static final String PROJECT_NAME = "Eclipse Core Boot";
private static boolean inVAJ;
static {
try {
Class.forName("com.ibm.uvm.lang.ProjectClassLoader");
inVAJ = true;
} catch (Exception e) {
inVAJ = false;
}
}
private static boolean inVAME;
static {
try {
Class.forName("com.ibm.eclipse.core.VAME");
inVAME = true;
} catch (Exception e) {
inVAME = false;
}
}
/**
* Executes the launch.
*
* @return the result of performing the launch
* @param args command-line arguments
* @exception Exception thrown if a problem occurs during the launch
*/
protected Object basicRun(String[] args) throws Exception {
Class clazz = getBootLoader(bootLocation);
Method method = clazz.getDeclaredMethod("run", new Class[] { String.class, URL.class, String.class, String[].class });
try {
return method.invoke(clazz, new Object[] { application, pluginPathLocation, location, args });
} catch (InvocationTargetException e) {
if (e.getTargetException() instanceof Error)
throw (Error) e.getTargetException();
else
throw e;
}
}
/**
* Returns the result of converting a list of comma-separated tokens into an array
*
* @return the array of string tokens
* @param prop the initial comma-separated string
*/
private String[] getArrayFromList(String prop) {
if (prop == null || prop.trim().equals(""))
return new String[0];
Vector list = new Vector();
StringTokenizer tokens = new StringTokenizer(prop, ",");
while (tokens.hasMoreTokens()) {
String token = tokens.nextToken().trim();
if (!token.equals(""))
list.addElement(token);
}
return list.isEmpty() ? new String[0] : (String[]) list.toArray(new String[0]);
}
/**
* Creates and returns a platform <code>BootLoader</code> which can be used to start
* up and run the platform. The given base, if not <code>null</code>,
* is the location of the boot loader code. If the value is <code>null</code>
* then the boot loader is located relative to this class.
*
* @return the new boot loader
* @param base the location of the boot loader
*/
public Class getBootLoader(String base) throws Exception {
URLClassLoader loader = new URLClassLoader(getBootPath(base), null);
return loader.loadClass(BOOTLOADER);
}
/**
* Returns the <code>URL</code>-based class path describing where the boot classes
* are located when running in development mode.
*
* @return the url-based class path
* @param base the base location
* @exception MalformedURLException if a problem occurs computing the class path
*/
protected URL[] getDevPath(URL base) throws MalformedURLException {
URL url;
String devBase = base.toExternalForm();
if (!inDevelopmentMode) {
url = new URL(devBase + "boot.jar");
return new URL[] {url};
}
String[] locations = getArrayFromList(devClassPath);
ArrayList result = new ArrayList(locations.length);
for (int i = 0; i < locations.length; i++) {
String spec = devBase + locations[i];
char lastChar = spec.charAt(spec.length() - 1);
if ((spec.endsWith(".jar") || (lastChar == '/' || lastChar == '\\')))
url = new URL (spec);
else
url = new URL(spec + "/");
//make sure URL exists before adding to path
if (new java.io.File(url.getFile()).exists())
result.add(url);
}
url = new URL(devBase + "boot.jar");
if (new java.io.File(url.getFile()).exists())
result.add(url);
return (URL[])result.toArray(new URL[result.size()]);
}
/**
* Returns the <code>URL</code>-based class path describing where the boot classes are located.
*
* @return the url-based class path
* @param base the base location
* @exception MalformedURLException if a problem occurs computing the class path
*/
protected URL[] getBootPath(String base) throws MalformedURLException {
URL url = null;
// if the given location is not null, assume it is correct and use it.
if (base != null) {
url = new URL(base);
if (debug)
System.out.println("Boot URL: " + url.toExternalForm());
return new URL[] {url};
}
// Create a URL based on the location of this class' code.
// strip off jar file and/or last directory to get
// to the directory containing projects.
URL[] result = null;
url = getClass().getProtectionDomain().getCodeSource().getLocation();
String path = url.getFile();
if (path.endsWith(".jar"))
path = path.substring(0, path.lastIndexOf("/"));
else
if (path.endsWith("/"))
path = path.substring(0, path.length() - 1);
if (inVAJ || inVAME) {
int ix = path.lastIndexOf("/");
path = path.substring(0, ix + 1);
path = path + PROJECT_NAME + "/";
url = new URL(url.getProtocol(), url.getHost(), url.getPort(), path);
result = new URL[] {url};
} else {
path = searchForPlugins(path);
path = searchForBoot(path);
// add on any dev path elements
url = new URL(url.getProtocol(), url.getHost(), url.getPort(), path);
result = getDevPath(url);
}
if (debug) {
System.out.println("Boot URL:");
for (int i = 0; i < result.length; i++)
System.out.println(" " + result[i].toExternalForm());
}
return result;
}
/**
* Searches for a plugins root starting at a given location. If one is
* found then this location is returned; otherwise an empty string is
* returned.
*
* @return the location where plugins were found, or an empty string
* @param start the location to begin searching at
*/
protected String searchForPlugins(String start) {
File path = new File(start);
while (path != null) {
File test = new File(path, "plugins");
if (test.exists())
return test.toString();
path = path.getParentFile();
path = (path == null || path.length() == 1) ? null : path;
}
return "";
}
/**
* Searches for a boot directory starting at a given location. If one
* is found then this location is returned; otherwise an empty string
* is returned.
*
* @return the location where plugins were found, or an empty string
* @param start the location to begin searching at
*/
protected String searchForBoot(String start) {
FileFilter filter = new FileFilter() {
public boolean accept(File candidate) {
return candidate.getName().startsWith(PI_BOOT);
}
};
File[] boots = new File(start).listFiles(filter);
String result = null;
String maxVersion = null;
for (int i = 0; i < boots.length; i++) {
String name = boots[i].getName();
int index = name.lastIndexOf('_');
if (index == -1) {
result = boots[i].getAbsolutePath();
i = boots.length;
} else {
if (index > 0) {
String version = name.substring(index + 1);
if (maxVersion == null) {
result = boots[i].getAbsolutePath();
maxVersion = version;
} else
if (maxVersion.compareTo(version) == -1) {
result = boots[i].getAbsolutePath();
maxVersion = version;
}
}
}
}
if (result == null)
throw new RuntimeException("Could not find bootstrap code. Check location of boot plug-in or specify -boot.");
return result.replace(File.separatorChar, '/') + "/";
}
/**
* Returns the update loader for the given boot path.
*
* @return the update loader
* @param base the boot path base
* @exception Exception thrown is a problem occurs determining this loader
*/
public Class getUpdateLoader(String base) throws Exception {
URLClassLoader loader = new URLClassLoader(getBootPath(base), null);
return loader.loadClass(UPDATELOADER);
}
/**
* Runs the platform with the given arguments. The arguments must identify
* an application to run (e.g., <code>-application com.example.application</code>).
* After running the application <code>System.exit(N)</code> is executed.
* The value of N is derived from the value returned from running the application.
* If the application's return value is an <code>Integer</code>, N is this value.
* In all other cases, N = 0.
* <p>
* Clients wishing to run the platform without a following <code>System.exit</code>
* call should use <code>run()</code>.
*
* @see #run
*
* @param args the command line arguments
*/
public static void main(String[] args) {
Object result = null;
try {
result = new Main().run(args);
} catch (Throwable e) {
// try and take down the splash screen.
endSplash();
System.out.println("Exception launching the Eclipse Platform:");
e.printStackTrace();
}
int exitCode = result instanceof Integer ? ((Integer) result).intValue() : 0;
System.exit(exitCode);
}
/**
* Tears down the currently-displayed splash screen.
*/
public static void endSplash() {
if (endSplash == null)
return;
try {
Runtime.getRuntime().exec(endSplash);
} catch (Exception e) {
}
}
/**
* Runs this launcher with the arguments specified in the given string.
*
* @param argString the arguments string
* @exception Exception thrown if a problem occurs during launching
*/
public static void main(String argString) throws Exception {
Vector list = new Vector(5);
for (StringTokenizer tokens = new StringTokenizer(argString, " "); tokens.hasMoreElements();)
list.addElement((String) tokens.nextElement());
main((String[]) list.toArray(new String[list.size()]));
}
/**
* Processes the command line arguments
*
* @return the arguments to pass through to the launched application
* @param args the command line arguments
*/
protected String[] processCommandLine(String[] args) throws Exception {
int[] configArgs = new int[100];
configArgs[0] = -1; // need to initialize the first element to something that could not be an index.
int configArgIndex = 0;
for (int i = 0; i < args.length; i++) {
boolean found = false;
// check for args without parameters (i.e., a flag arg)
// check if debug should be enabled for the entire platform
if (args[i].equalsIgnoreCase(DEBUG)) {
debug = true;
// passed thru this arg (i.e., do not set found = true
continue;
}
// check if development mode should be enabled for the entire platform
// If this is the last arg or there is a following arg (i.e., arg+1 has a leading -),
// simply enable development mode. Otherwise, assume that that the following arg is
// actually some additional development time class path entries. This will be processed below.
if (args[i].equalsIgnoreCase(DEV) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) {
inDevelopmentMode = true;
// do not mark the arg as found so it will be passed through
continue;
}
// done checking for args. Remember where an arg was found
if (found) {
configArgs[configArgIndex++] = i;
continue;
}
// check for args with parameters. If we are at the last argument or if the next one
// has a '-' as the first character, then we can't have an arg with a parm so continue.
if (i == args.length - 1 || args[i + 1].startsWith("-"))
continue;
String arg = args[++i];
// look for the laucher to run
if (args[i - 1].equalsIgnoreCase(BOOT)) {
bootLocation = arg;
found = true;
}
// look for the development mode and class path entries.
if (args[i - 1].equalsIgnoreCase(DEV)) {
inDevelopmentMode = true;
devClassPath = arg;
continue;
}
// look for the application to run
if (args[i - 1].equalsIgnoreCase(APPLICATION)) {
application = arg;
found = true;
}
// look for token to use to end the splash screen
if (args[i - 1].equalsIgnoreCase(ENDSPLASH)) {
endSplash = arg;
continue;
}
// look for items to uninstall
if (args[i - 1].equalsIgnoreCase(UNINSTALL)) {
uninstall = true;
uninstallCookie = arg;
found = true;
}
// done checking for args. Remember where an arg was found
if (found) {
configArgs[configArgIndex++] = i - 1;
configArgs[configArgIndex++] = i;
}
}
// remove all the arguments consumed by this argument parsing
if (configArgIndex == 0)
return args;
String[] passThruArgs = new String[args.length - configArgIndex];
configArgIndex = 0;
int j = 0;
for (int i = 0; i < args.length; i++) {
if (i == configArgs[configArgIndex])
configArgIndex++;
else
passThruArgs[j++] = args[i];
}
return passThruArgs;
}
/**
* Runs the application to be launched.
*
* @return the return value from the launched application
* @param args the arguments to pass to the application
* @exception thrown if a problem occurs during launching
*/
public Object run(String[] args) throws Exception {
String[] passThruArgs = processCommandLine(args);
if (uninstall)
return updateRun(UNINSTALL, uninstallCookie, passThruArgs);
else
return basicRun(passThruArgs);
}
/**
* Performs an update run.
*
* @return the return value from the update loader
* @param flag flag to give to the update loader
* @param value value to give to the update loader
* @param args arguments to give to the update loader.
* @exception Exception thrown if a problem occurs during execution
*/
protected Object updateRun(String flag, String value, String[] args) throws Exception {
Class clazz = getUpdateLoader(bootLocation);
Method method = clazz.getDeclaredMethod("run", new Class[] { String.class, String.class, String.class, String[].class });
try {
return method.invoke(clazz, new Object[] { flag, value, location, args });
} catch (InvocationTargetException e) {
if (e.getTargetException() instanceof Error)
throw (Error) e.getTargetException();
else
throw e;
}
}
}