blob: 6f33cb000080556b7bcf90c79812a1ad79d1a907 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2002 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM - Initial API and implementation
******************************************************************************/
package org.eclipse.core.internal.boot;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.*;
import java.util.*;
import org.eclipse.core.boot.BootLoader;
import org.eclipse.core.boot.IPlatformRunnable;
/**
* Special boot loader class for the Eclipse Platform. This class cannot
* be instantiated; all functionality is provided by static methods.
* <p>
* The Eclipse Platform makes heavy use of Java class loaders for
* loading plug-ins. Even the Platform Core Runtime itself, including
* the <code>Platform</code> class, needs to be loaded by a special
* class loader. The upshot is that a client program (such as a Java main
* program, a servlet) cannot directly reference even the
* <code>Platform</code> class. Instead, a client must use this
* loader class for initializing the platform, invoking functionality
* defined in plug-ins, and shutting down the platform when done.
* </p>
*
* @see org.eclipse.core.runtime.Platform
*/
public final class InternalBootLoader {
private static boolean running = false;
private static boolean starting = false;
private static String[] commandLine;
private static ClassLoader loader = null;
private static String baseLocation = null; // -data argument (workspace location)
private static String installLocation = null; // -install argument (product install location)
private static String applicationR10 = null; // R1.0 compatibility
private static URL installURL = null;
private static boolean debugRequested = false;
private static String devClassPath = null;
private static String debugOptionsFilename = null;
private static Properties options = null;
private static boolean inDevelopmentMode = false;
private static PlatformConfiguration currentPlatformConfiguration = null;
// state for tracking the Platform context (e.g., the OS, Window system, locale, architecture, ...)
private static String nl = null;
private static String ws = null;
private static String os = null;
private static String arch = null;
private static final String PLATFORM_ENTRYPOINT = "org.eclipse.core.internal.runtime.InternalPlatform"; //$NON-NLS-1$
private static final String BOOTNAME = "org.eclipse.core.boot"; //$NON-NLS-1$
/*package*/ static final String RUNTIMENAME = "org.eclipse.core.runtime"; //$NON-NLS-1$
private static final String PLUGINSDIR = "plugins/"; //$NON-NLS-1$
private static final String LIBRARY = "library"; //$NON-NLS-1$
private static final String EXPORT = "export"; //$NON-NLS-1$
private static final String EXPORT_PUBLIC = "public"; //$NON-NLS-1$
private static final String EXPORT_PROTECTED = "protected"; //$NON-NLS-1$
private static final String META_AREA = ".metadata"; //$NON-NLS-1$
private static final String WORKSPACE = "workspace"; //$NON-NLS-1$
private static final String PLUGIN_PATH = ".plugin-path"; //$NON-NLS-1$
private static String BOOTDIR;
private static final String RUNTIMEDIR = PLUGINSDIR + RUNTIMENAME + "/"; //$NON-NLS-1$
private static final String OPTIONS = ".options"; //$NON-NLS-1$
// While we recognize the SunOS operating system, we change
// this internally to be Solaris.
private static final String INTERNAL_OS_SUNOS = "SunOS"; //$NON-NLS-1$
// While we recognize the i386 architecture, we change
// this internally to be x86.
private static final String INTERNAL_ARCH_I386 = "i386"; //$NON-NLS-1$
private static boolean useClassLoaderProperties = false;
private static String classLoaderPropertiesFilename = null;
/**
* Execution options for the Runtime plug-in. They are defined here because
* we need to load them into the PlatformClassLoader which is created by the
* boot system. Users should see these options as Runtime options since there
* boot does not figure into normal Platform operation.
*/
private static final String PI_RUNTIME = "org.eclipse.core.runtime"; //$NON-NLS-1$
private static final String OPTION_STARTTIME = PI_RUNTIME + "/starttime"; //$NON-NLS-1$
private static final String OPTION_LOADER_DEBUG = PI_RUNTIME + "/loader/debug"; //$NON-NLS-1$
private static final String OPTION_LOADER_SHOW_CREATE = PI_RUNTIME + "/loader/debug/create"; //$NON-NLS-1$
private static final String OPTION_LOADER_SHOW_ACTIVATE = PI_RUNTIME + "/loader/debug/activateplugin"; //$NON-NLS-1$
private static final String OPTION_LOADER_SHOW_ACTIONS = PI_RUNTIME + "/loader/debug/actions"; //$NON-NLS-1$
private static final String OPTION_LOADER_SHOW_SUCCESS = PI_RUNTIME + "/loader/debug/success"; //$NON-NLS-1$
private static final String OPTION_LOADER_SHOW_FAILURE = PI_RUNTIME + "/loader/debug/failure"; //$NON-NLS-1$
private static final String OPTION_LOADER_FILTER_CLASS = PI_RUNTIME + "/loader/debug/filter/class"; //$NON-NLS-1$
private static final String OPTION_LOADER_FILTER_LOADER = PI_RUNTIME + "/loader/debug/filter/loader"; //$NON-NLS-1$
private static final String OPTION_LOADER_FILTER_RESOURCE = PI_RUNTIME + "/loader/debug/filter/resource"; //$NON-NLS-1$
private static final String OPTION_LOADER_FILTER_NATIVE = PI_RUNTIME + "/loader/debug/filter/native"; //$NON-NLS-1$
private static final String OPTION_URL_DEBUG = PI_RUNTIME+ "/url/debug"; //$NON-NLS-1$
private static final String OPTION_URL_DEBUG_CONNECT = PI_RUNTIME+ "/url/debug/connect"; //$NON-NLS-1$
private static final String OPTION_URL_DEBUG_CACHE_LOOKUP = PI_RUNTIME+ "/url/debug/cachelookup"; //$NON-NLS-1$
private static final String OPTION_URL_DEBUG_CACHE_COPY = PI_RUNTIME+ "/url/debug/cachecopy"; //$NON-NLS-1$
private static final String OPTION_UPDATE_DEBUG = PI_RUNTIME+ "/update/debug"; //$NON-NLS-1$
private static final String OPTION_CONFIGURATION_DEBUG = PI_RUNTIME+ "/config/debug"; //$NON-NLS-1$
// command line arguments
private static final String DEBUG = "-debug"; //$NON-NLS-1$
private static final String DATA = "-data"; //$NON-NLS-1$
private static final String INSTALL = "-install"; //$NON-NLS-1$
private static final String DEV = "-dev"; //$NON-NLS-1$
private static final String WS = "-ws"; //$NON-NLS-1$
private static final String OS = "-os"; //$NON-NLS-1$
private static final String ARCH = "-arch"; //$NON-NLS-1$
private static final String NL = "-nl"; //$NON-NLS-1$
private static final String CLASSLOADER_PROPERTIES = "-classloaderProperties"; //$NON-NLS-1$
/**
* Private constructor to block instance creation.
*/
private InternalBootLoader() {
}
private static void assertNotRunning() {
if (running)
throw new RuntimeException(Policy.bind("platform.mustNotBeRunning")); //$NON-NLS-1$
}
private static void assertRunning() {
if (!running)
throw new RuntimeException(Policy.bind("platform.notRunning")); //$NON-NLS-1$
}
/**
* Configure the class loader for the runtime plug-in.
*/
private static PlatformClassLoader configurePlatformLoader() {
Object[] loadPath = getPlatformClassLoaderPath();
URL base = null;
try {
base = new URL(PlatformURLBaseConnection.PLATFORM_URL_STRING+RUNTIMEDIR);
} catch (MalformedURLException e) {
//proceed without runtime plugin in platform loader -- is this possible?
}
return new PlatformClassLoader((URL[]) loadPath[0], (URLContentFilter[]) loadPath[1], InternalBootLoader.class.getClassLoader(), base);
}
/**
* @see BootLoader
*/
public static boolean containsSavedPlatform(String location) {
return new File(location + "/" + META_AREA).exists(); //$NON-NLS-1$
}
/**
* convert a list of comma-separated tokens into an array
*/
private static String[] getArrayFromList(String prop) {
if (prop == null || prop.trim().equals("")) //$NON-NLS-1$
return new String[0];
Vector list = new Vector();
StringTokenizer tokens = new StringTokenizer(prop, ","); //$NON-NLS-1$
while (tokens.hasMoreTokens()) {
String token = tokens.nextToken().trim();
if (!token.equals("")) //$NON-NLS-1$
list.addElement(token);
}
return list.isEmpty() ? new String[0] : (String[]) list.toArray(new String[0]);
}
private static boolean getBooleanOption(String option, boolean defaultValue) {
String optionValue = options.getProperty(option);
return (optionValue == null) ? defaultValue : optionValue.equalsIgnoreCase("true"); //$NON-NLS-1$
}
/**
* @see BootLoader#getCommandLineArgs
*/
public static String[] getCommandLineArgs() {
return commandLine;
}
/**
* @see BootLoader
*/
public static PlatformConfiguration getCurrentPlatformConfiguration() {
return PlatformConfiguration.getCurrent();
}
/**
* @see BootLoader
*/
public static URL getInstallURL() {
if (installURL != null)
return installURL;
// See if install location was explicitly specified
// Note: in the regular launch sequence, if the argument was not specified
// on the launch, Main.java is actually defaulting this relative to
// itself. The resulting behavior is consistent with the default
// behavior in 1.0 (with all program files being co-located in the
// eclipse/ install directory). However, the new behavior takes into
// account an update scenario where we may in fact be executing
// InternalBootLoader that was loaded from some other location.
if (installLocation != null && !installLocation.trim().equals("")) { //$NON-NLS-1$
try {
installURL = new URL(installLocation);
if (debugRequested)
System.out.println("Install URL:\n "+installURL.toExternalForm()); //$NON-NLS-1$
return installURL;
} catch(MalformedURLException e) {
//fall through to code below
}
}
// Install location was not specified, or we failed to create a URL.
// Get the location of this class and compute the install location.
// this involves striping off last element (jar or directory)
URL url = InternalBootLoader.class.getProtectionDomain().getCodeSource().getLocation();
String path = decode(url.getFile());
if (path.endsWith("/")) //$NON-NLS-1$
path = path.substring(0, path.length() - 1);
int ix = path.lastIndexOf('/');
//strip off boot jar/bin, boot plugin and plugins dir. Be sure to leave a trailing /
path = path.substring(0, ix);
ix = path.lastIndexOf('/');
path = path.substring(0, ix);
ix = path.lastIndexOf('/');
path = path.substring(0, ix + 1);
try {
if (url.getProtocol().equals("jar")) //$NON-NLS-1$
installURL = new URL(path);
else
installURL = new URL(url.getProtocol(), url.getHost(), url.getPort(), path);
if (debugRequested)
System.out.println("Install URL: "+installURL.toExternalForm()); //$NON-NLS-1$
} catch (MalformedURLException e) {
throw new RuntimeException(Policy.bind("error.fatal", e.getMessage())); //$NON-NLS-1$
}
return installURL;
}
/**
* Initialize the BOOTDIR variable. This code is copied from the getInstallURL() code and
* should be merged. */
static void initializeBootDir() {
URL url = InternalBootLoader.class.getProtectionDomain().getCodeSource().getLocation();
BOOTDIR = decode(url.getFile());
if (BOOTDIR.endsWith("/")) //$NON-NLS-1$
BOOTDIR = BOOTDIR.substring(0, BOOTDIR.length() - 1);
int index = BOOTDIR.lastIndexOf('/');
//strip off boot jar/bin, boot plugin and plugins dir. Be sure to leave a trailing /
BOOTDIR = BOOTDIR.substring(0, index+1);
}
/**
* Returns a string representation of the given URL String. This converts
* escaped sequences (%..) in the URL into the appropriate characters.
* NOTE: due to class visibility there is a copy of this method
* in Main (the launcher)
*/
public static String decode(String urlString) {
//try to use Java 1.4 method if available
try {
Class clazz = URLDecoder.class;
Method method = clazz.getDeclaredMethod("decode", new Class[] {String.class, String.class});//$NON-NLS-1$
//first encode '+' characters, because URLDecoder incorrectly converts
//them to spaces on certain class library implementations.
if (urlString.indexOf('+') >= 0) {
int len = urlString.length();
StringBuffer buf = new StringBuffer(len);
for (int i = 0; i < len; i++) {
char c = urlString.charAt(i);
if (c == '+')
buf.append("%2B");//$NON-NLS-1$
else
buf.append(c);
}
urlString = buf.toString();
}
Object result = method.invoke(null, new Object[] {urlString, "UTF-8"});//$NON-NLS-1$
if (result != null)
return (String)result;
} catch (Exception e) {
//JDK 1.4 method not found -- fall through and decode by hand
}
//decode URL by hand
boolean replaced = false;
byte[] encodedBytes = urlString.getBytes();
int encodedLength = encodedBytes.length;
byte[] decodedBytes = new byte[encodedLength];
int decodedLength = 0;
for (int i = 0; i < encodedLength; i++) {
byte b = encodedBytes[i];
if (b == '%') {
byte enc1 = encodedBytes[++i];
byte enc2 = encodedBytes[++i];
b = (byte) ((hexToByte(enc1) << 4) + hexToByte(enc2));
replaced = true;
}
decodedBytes[decodedLength++] = b;
}
if (!replaced)
return urlString;
try {
return new String(decodedBytes, 0, decodedLength, "UTF-8");//$NON-NLS-1$
} catch (UnsupportedEncodingException e) {
//use default encoding
return new String(decodedBytes, 0, decodedLength);
}
}
private static String[] getListOption(String option) {
String filter = options.getProperty(option);
if (filter == null)
return new String[0];
List result = new ArrayList(5);
StringTokenizer tokenizer = new StringTokenizer(filter, " ,\t\n\r\f"); //$NON-NLS-1$
while (tokenizer.hasMoreTokens())
result.add(tokenizer.nextToken());
return (String[]) result.toArray(new String[result.size()]);
}
/**
* @see BootLoader
*/
public static String getOSArch() {
return arch;
}
/**
* @see BootLoader
*/
public static String getNL() {
return nl;
}
/**
* @see BootLoader
*/
public static String getOS() {
return os;
}
/**
* @see BootLoader
*/
public static PlatformConfiguration getPlatformConfiguration(URL url) throws IOException {
return new PlatformConfiguration(url);
}
private static Object[] getPlatformClassLoaderPath() {
PlatformConfiguration config = getCurrentPlatformConfiguration();
PlatformConfiguration.BootDescriptor bd = config.getPluginBootDescriptor(RUNTIMENAME);
String execBase = bd.getPluginDirectoryURL().toExternalForm();
if (execBase == null)
execBase = getInstallURL() + RUNTIMEDIR;
// build a list alternating lib spec and export spec
ArrayList libSpecs = new ArrayList(5);
String[] exportAll = new String[] { "*" }; //$NON-NLS-1$
// add in any development mode class paths and the export all filter
if (DelegatingURLClassLoader.devClassPath != null) {
String[] specs = getArrayFromList(DelegatingURLClassLoader.devClassPath);
// convert dev class path into url strings
for (int j = 0; j < specs.length; j++) {
libSpecs.add(execBase + specs[j] + "/"); //$NON-NLS-1$
libSpecs.add(exportAll);
}
}
ArrayList list = new ArrayList(5);
String[] libs = bd.getLibraries();
for (int i=0; i<libs.length; i++) {
list.add(libs[i]);
list.add(exportAll);
}
// add in the class path entries spec'd in the config.
for (Iterator i = list.iterator(); i.hasNext();) {
String library = (String) i.next();
String[] filters = (String[]) i.next();
// convert plugin.xml library entries to url strings
String libSpec = execBase + library.replace(File.separatorChar, '/');
if (!libSpec.endsWith("/")) { //$NON-NLS-1$
if (libSpec.startsWith(PlatformURLHandler.PROTOCOL + PlatformURLHandler.PROTOCOL_SEPARATOR))
libSpec += PlatformURLHandler.JAR_SEPARATOR;
else
libSpec = PlatformURLHandler.JAR + PlatformURLHandler.PROTOCOL_SEPARATOR + libSpec + PlatformURLHandler.JAR_SEPARATOR;
}
libSpecs.add(libSpec);
libSpecs.add(filters);
}
// create path entries for libraries
ArrayList urls = new ArrayList(5);
ArrayList cfs = new ArrayList(5);
for (Iterator it = libSpecs.iterator(); it.hasNext();) {
try {
urls.add(new URL((String) it.next()));
cfs.add(new URLContentFilter((String[]) it.next()));
} catch (MalformedURLException e) {
// skip bad URLs
}
}
Object[] result = new Object[2];
result[0] = urls.toArray(new URL[urls.size()]);
result[1] = cfs.toArray(new URLContentFilter[cfs.size()]);
return result;
}
/**
* @see BootLoader
*/
/*
* This method is retained for R1.0 compatibility because it is defined as API.
* It's function matches the API description (returns <code>null</code> when
* argument URL is <code>null</code> or cannot be read).
*/
public static URL[] getPluginPath(URL pluginPathLocation/*R1.0 compatibility*/) {
InputStream input = null;
// first try and see if the given plugin path location exists.
if (pluginPathLocation == null)
return null;
try {
input = pluginPathLocation.openStream();
} catch (IOException e) {
//fall through
}
// if the given path was null or did not exist, look for a plugin path
// definition in the install location.
if (input == null)
try {
URL url = new URL(PlatformURLBaseConnection.PLATFORM_URL_STRING + PLUGIN_PATH);
input = url.openStream();
} catch (MalformedURLException e) {
//fall through
} catch (IOException e) {
//fall through
}
// nothing was found at the supplied location or in the install location
if (input == null)
return null;
// if we found a plugin path definition somewhere so read it and close the location.
URL[] result = null;
try {
try {
result = readPluginPath(input);
} finally {
input.close();
}
} catch (IOException e) {
//let it return null on failure to read
}
return result;
}
/**
* @see BootLoader
*/
public static IPlatformRunnable getRunnable(String applicationName) throws Exception {
assertRunning();
Class platform = loader.loadClass(PLATFORM_ENTRYPOINT);
Method method = platform.getDeclaredMethod("loaderGetRunnable", new Class[] {String.class}); //$NON-NLS-1$
try {
return (IPlatformRunnable) method.invoke(platform, new Object[] {applicationName});
} catch (InvocationTargetException e) {
if (e.getTargetException() instanceof Error)
throw (Error) e.getTargetException();
else
throw e;
}
}
/**
* @see BootLoader
*/
public static IPlatformRunnable getRunnable(String pluginId, String className, Object args) throws Exception {
assertRunning();
Class platform = loader.loadClass(PLATFORM_ENTRYPOINT);
Method method = platform.getDeclaredMethod("loaderGetRunnable", new Class[] {String.class, String.class, Object.class}); //$NON-NLS-1$
try {
return (IPlatformRunnable) method.invoke(platform, new Object[] {pluginId, className, args});
} catch (InvocationTargetException e) {
if (e.getTargetException() instanceof Error)
throw (Error) e.getTargetException();
else
throw e;
}
}
/**
* @see BootLoader
*/
public static String getWS() {
return ws;
}
/**
* Converts an ASCII character representing a hexadecimal
* value into its integer equivalent.
*/
private static int hexToByte(byte b) {
switch (b) {
case '0':return 0;
case '1':return 1;
case '2':return 2;
case '3':return 3;
case '4':return 4;
case '5':return 5;
case '6':return 6;
case '7':return 7;
case '8':return 8;
case '9':return 9;
case 'A':
case 'a':return 10;
case 'B':
case 'b':return 11;
case 'C':
case 'c':return 12;
case 'D':
case 'd':return 13;
case 'E':
case 'e':return 14;
case 'F':
case 'f':return 15;
default:
throw new IllegalArgumentException("Switch error decoding URL"); //$NON-NLS-1$
}
}
/**
* @see BootLoader
*/
public static boolean inDebugMode() {
return debugRequested;
}
/**
* @see BootLoader
*/
public static boolean inDevelopmentMode() {
return inDevelopmentMode;
}
private static String[] initialize(URL pluginPathLocation/*R1.0 compatibility*/, String location, String[] args) throws Exception {
if (running)
throw new RuntimeException(Policy.bind("platform.running")); //$NON-NLS-1$
baseLocation = location;
String[] appArgs = processCommandLine(args);
// Do setupSystemContext() ASAP after processCommandLine
setupSystemContext();
// call before referencing DelegatingURLClassLoader
initializeBootDir();
// setup the devClassPath if any
DelegatingURLClassLoader.devClassPath = devClassPath;
// if a platform location was not found in the arguments, compute one.
if (baseLocation == null) {
// Default location for the workspace is <user.dir>/workspace/
baseLocation = System.getProperty("user.dir"); //$NON-NLS-1$
if (!baseLocation.endsWith(File.separator))
baseLocation += File.separator;
baseLocation += WORKSPACE;
}
if (debugRequested)
System.out.println("Workspace location:\n " + baseLocation); //$NON-NLS-1$
// load any debug options
loadOptions();
// initialize eclipse URL handling
String metaPath = baseLocation.replace(File.separatorChar, '/');
if (!metaPath.endsWith("/")) //$NON-NLS-1$
metaPath += "/"; //$NON-NLS-1$
metaPath += META_AREA;
PlatformURLHandlerFactory.startup(metaPath);
PlatformURLBaseConnection.startup(getInstallURL()); // past this point we can use eclipse:/platform/ URLs
// load platform configuration and consume configuration-related arguments (must call after URL handler initialization)
appArgs = PlatformConfiguration.startup(appArgs, pluginPathLocation/*R1.0 compatibility*/, applicationR10/*R1.0 compatibility*/, metaPath);
// create and configure platform class loader
loader = configurePlatformLoader();
return appArgs;
}
/**
* @see BootLoader
*/
public static boolean isRunning() {
return running;
}
public static boolean isStarting() {
return starting;
}
/**
* Return a boolean value indicating whether or not the user requested
* to read the classloader properties file for performance enhancement. */
static boolean useClassLoaderProperties() {
return useClassLoaderProperties;
}
/**
* Return the name of the file to be used for the class loader properties. */
static String getClassLoaderPropertiesFilename() {
return classLoaderPropertiesFilename;
}
/**
* Return the default name for the class loader properties file.
*/
static String getDefaultClassLoaderPropertiesFilename() {
return BOOTDIR + "classloader.properties"; //$NON-NLS-1$
}
private static void loadOptions() {
// if no debug option was specified, don't even bother to try.
// Must ensure that the options slot is null as this is the signal to the
// platform that debugging is not enabled.
if (!debugRequested) {
options = null;
return;
}
options = new Properties();
URL optionsFile;
if (debugOptionsFilename == null) {
// default options location is user.dir (install location may be r/o so
// is not a good candidate for a trace options that need to be updatable by
// by the user)
String userDir = System.getProperty("user.dir").replace(File.separatorChar,'/'); //$NON-NLS-1$
if (!userDir.endsWith("/")) //$NON-NLS-1$
userDir += "/"; //$NON-NLS-1$
debugOptionsFilename = "file:" + userDir + OPTIONS; //$NON-NLS-1$
}
try {
optionsFile = new URL(debugOptionsFilename);
} catch (MalformedURLException e) {
System.out.println("Unable to construct URL for options file: " + debugOptionsFilename); //$NON-NLS-1$
e.printStackTrace(System.out);
return;
}
System.out.println("Debug-Options:\n " + debugOptionsFilename); //$NON-NLS-1$
try {
InputStream input = optionsFile.openStream();
try {
options.load(input);
} finally {
input.close();
}
} catch (FileNotFoundException e) {
// Its not an error to not find the options file
} catch (IOException e) {
System.out.println("Could not parse the options file: " + optionsFile); //$NON-NLS-1$
e.printStackTrace(System.out);
}
// trim off all the blanks since properties files don't do that.
for (Iterator i = options.keySet().iterator(); i.hasNext();) {
Object key = i.next();
options.put(key, ((String) options.get(key)).trim());
}
InternalBootLoader.setupOptions();
}
private static 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 this is the last arg or there is a following arg (i.e., arg+1 has a leading -),
// simply enable debug. Otherwise, assume that that the following arg is
// actually the filename of an options file. This will be processed below.
if (args[i].equalsIgnoreCase(DEBUG) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$
found = true;
debugRequested = true;
}
// check to see if we should be using a the classloader package prefix file.
// If this is the last arg or there is a following arg (i.e., arg+1 has a leading -),
// simply enable the option. Otherwise, assume that that the following arg is
// actually the filename of the file. This will be processed below.
if (args[i].equalsIgnoreCase(CLASSLOADER_PROPERTIES) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$
useClassLoaderProperties = true;
found = true;
}
// 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("-"))))) { //$NON-NLS-1$
inDevelopmentMode = true;
found = true;
continue;
}
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("-")) { //$NON-NLS-1$
continue;
}
String arg = args[++i];
// look for the debug options file location.
if (args[i - 1].equalsIgnoreCase(DEBUG)) {
found = true;
debugRequested = true;
debugOptionsFilename = arg;
}
// look for the classloader package prefix file location.
if (args[i - 1].equalsIgnoreCase(CLASSLOADER_PROPERTIES)) {
found = true;
useClassLoaderProperties = true;
classLoaderPropertiesFilename = arg;
}
// look for the development mode and class path entries.
if (args[i - 1].equalsIgnoreCase(DEV)) {
inDevelopmentMode = true;
devClassPath = arg;
found = true;
continue;
}
// look for the install location.
if (args[i - 1].equalsIgnoreCase(INSTALL)) {
found = true;
installLocation = arg;
}
// look for the platform location. Only set it if not already set. This
// preserves the value set in the startup() parameter. Be sure however
// to consume the command-line argument.
if (args[i - 1].equalsIgnoreCase(DATA)) {
found = true;
if (baseLocation == null)
baseLocation = arg;
}
// look for the window system.
if (args[i - 1].equalsIgnoreCase(WS)) {
found = true;
ws = arg;
}
// look for the operating system
if (args[i - 1].equalsIgnoreCase(OS)) {
found = true;
os = arg;
}
// look for the system architecture
if (args[i - 1].equalsIgnoreCase(ARCH)) {
found = true;
arch = arg;
}
// look for the nationality/language
if (args[i - 1].equalsIgnoreCase(NL)) {
found = true;
nl = arg;
}
// 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;
}
private static URL[] readPluginPath(InputStream input) {
Properties ini = new Properties();
try {
ini.load(input);
} catch (IOException e) {
return null;
}
Vector result = new Vector(5);
for (Enumeration groups = ini.propertyNames(); groups.hasMoreElements();) {
String group = (String) groups.nextElement();
for (StringTokenizer entries = new StringTokenizer(ini.getProperty(group), ";"); entries.hasMoreElements();) { //$NON-NLS-1$
String entry = (String) entries.nextElement();
if (!entry.equals("")) //$NON-NLS-1$
try {
result.addElement(new URL(entry));
} catch (MalformedURLException e) {
//intentionally ignore bad URLs
System.err.println(Policy.bind("ignore.plugin", entry)); //$NON-NLS-1$
}
}
}
return (URL[]) result.toArray(new URL[result.size()]);
}
public static URL resolve(URL url) throws IOException {
if (!url.getProtocol().equals(PlatformURLHandler.PROTOCOL))
return url;
URLConnection connection = url.openConnection();
if (connection instanceof PlatformURLConnection)
return ((PlatformURLConnection) connection).getResolvedURL();
else
return url;
}
/**
* @see BootLoader
* Retained for compatibility with R1.0 launchers
*/
public static Object run(String applicationName/*R1.0 compatibility*/, URL pluginPathLocation/*R1.0 compatibility*/, String location, String[] args) throws Exception {
return run(applicationName, pluginPathLocation, location, args, null);
}
/**
* @see BootLoader
*/
public static Object run(String applicationName/*R1.0 compatibility*/, URL pluginPathLocation/*R1.0 compatibility*/, String location, String[] args, Runnable handler) throws Exception {
Object result = null;
applicationR10 = applicationName; // for R1.0 compatibility
String[] applicationArgs = startup(pluginPathLocation, location, args, handler);
String application = getCurrentPlatformConfiguration().getApplicationIdentifier();
IPlatformRunnable runnable = getRunnable(application);
if (runnable == null)
throw new IllegalArgumentException(Policy.bind("application.notFound", application)); //$NON-NLS-1$
try {
result = runnable.run(applicationArgs);
} catch (Throwable e) {
e.printStackTrace();
throw new InvocationTargetException(e);
} finally {
shutdown();
return result;
}
}
/**
* Setup the debug flags for the given debug options. This method will likely
* be called twice. Once when loading the options file from the command
* line or install dir and then again when we have loaded options from the
* specific platform metaarea.
*/
public static void setupOptions() {
// if no debug option was specified, don't even bother to try.
// Must ensure that the options slot is null as this is the signal to the
// platform that debugging is not enabled.
if (!debugRequested)
return;
options.put(OPTION_STARTTIME, Long.toString(System.currentTimeMillis()));
DelegatingURLClassLoader.DEBUG = getBooleanOption(OPTION_LOADER_DEBUG, false);
DelegatingURLClassLoader.DEBUG_SHOW_CREATE = getBooleanOption(OPTION_LOADER_SHOW_CREATE, true);
DelegatingURLClassLoader.DEBUG_SHOW_ACTIVATE = getBooleanOption(OPTION_LOADER_SHOW_ACTIVATE, true);
DelegatingURLClassLoader.DEBUG_SHOW_ACTIONS = getBooleanOption(OPTION_LOADER_SHOW_ACTIONS, true);
DelegatingURLClassLoader.DEBUG_SHOW_SUCCESS = getBooleanOption(OPTION_LOADER_SHOW_SUCCESS, true);
DelegatingURLClassLoader.DEBUG_SHOW_FAILURE = getBooleanOption(OPTION_LOADER_SHOW_FAILURE, true);
DelegatingURLClassLoader.DEBUG_FILTER_CLASS = getListOption(OPTION_LOADER_FILTER_CLASS);
DelegatingURLClassLoader.DEBUG_FILTER_LOADER = getListOption(OPTION_LOADER_FILTER_LOADER);
DelegatingURLClassLoader.DEBUG_FILTER_RESOURCE = getListOption(OPTION_LOADER_FILTER_RESOURCE);
DelegatingURLClassLoader.DEBUG_FILTER_NATIVE = getListOption(OPTION_LOADER_FILTER_NATIVE);
PlatformURLConnection.DEBUG = getBooleanOption(OPTION_URL_DEBUG, false);
PlatformURLConnection.DEBUG_CONNECT = getBooleanOption(OPTION_URL_DEBUG_CONNECT, true);
PlatformURLConnection.DEBUG_CACHE_LOOKUP = getBooleanOption(OPTION_URL_DEBUG_CACHE_LOOKUP, true);
PlatformURLConnection.DEBUG_CACHE_COPY = getBooleanOption(OPTION_URL_DEBUG_CACHE_COPY, true);
PlatformConfiguration.DEBUG = getBooleanOption(OPTION_CONFIGURATION_DEBUG,false);
}
/**
* Initializes the execution context for this run of the platform. The context
* includes information about the locale, operating system and window system.
*
* NOTE: The OS, WS, and ARCH values should never be null. The executable should
* be setting these values and therefore this code path is obsolete for Eclipse
* when run from the executable.
*/
private static void setupSystemContext() {
// if the user didn't set the locale with a command line argument then
// use the default.
if (nl == null)
nl = Locale.getDefault().toString();
// if the user didn't set the operating system with a command line
// argument then use the default.
if (os == null) {
String name = System.getProperty("os.name");//$NON-NLS-1$
// check to see if the VM returned "Windows 98" or some other
// flavour which should be converted to win32.
if (name.regionMatches(true, 0, BootLoader.OS_WIN32, 0, 3))
os = BootLoader.OS_WIN32;
// EXCEPTION: All mappings of SunOS convert to Solaris
if (os == null)
os = name.equalsIgnoreCase(INTERNAL_OS_SUNOS) ? BootLoader.OS_SOLARIS : BootLoader.OS_UNKNOWN;
}
// if the user didn't set the window system with a command line
// argument then use the default.
if (ws == null) {
// setup default values for known OSes if nothing was specified
if (os.equals(BootLoader.OS_WIN32))
ws = BootLoader.WS_WIN32;
else if (os.equals(BootLoader.OS_LINUX))
ws = BootLoader.WS_MOTIF;
else if (os.equals(BootLoader.OS_MACOSX))
ws = BootLoader.WS_CARBON;
else if (os.equals(BootLoader.OS_HPUX))
ws = BootLoader.WS_MOTIF;
else if (os.equals(BootLoader.OS_AIX))
ws = BootLoader.WS_MOTIF;
else if (os.equals(BootLoader.OS_SOLARIS))
ws = BootLoader.WS_MOTIF;
else
ws = BootLoader.WS_UNKNOWN;
}
// if the user didn't set the system architecture with a command line
// argument then use the default.
if (arch == null) {
String name = System.getProperty("os.arch");//$NON-NLS-1$
// Map i386 architecture to x86
arch = name.equalsIgnoreCase(INTERNAL_ARCH_I386) ? BootLoader.ARCH_X86 : name;
}
}
/**
* @see BootLoader
*/
public static void shutdown() throws Exception {
assertRunning();
// no matter what happens, record that its no longer running
running = false;
Class platform = loader.loadClass(PLATFORM_ENTRYPOINT);
Method method = platform.getDeclaredMethod("loaderShutdown", new Class[0]); //$NON-NLS-1$
try {
method.invoke(platform, new Object[0]);
} catch (InvocationTargetException e) {
if (e.getTargetException() instanceof Error)
throw (Error) e.getTargetException();
else
throw e;
} finally {
PlatformURLHandlerFactory.shutdown();
PlatformConfiguration.shutdown();
loader = null;
}
}
/**
* @see BootLoader
* Retained for compatibility with R1.0 launchers
*/
public static String[] startup(URL pluginPathLocation/*R1.0 compatibility*/, String location, String[] args) throws Exception {
return startup(pluginPathLocation, location, args, null);
}
/**
* @see BootLoader
*/
public static String[] startup(URL pluginPathLocation/*R1.0 compatibility*/, String location, String[] args, Runnable handler) throws Exception {
assertNotRunning();
starting = true;
commandLine = args;
String[] applicationArgs = initialize(pluginPathLocation, location, args);
Class platform = loader.loadClass(PLATFORM_ENTRYPOINT);
Method method = platform.getDeclaredMethod("loaderStartup", new Class[] { URL[].class, String.class, Properties.class, String[].class, Runnable.class }); //$NON-NLS-1$
try {
URL[] pluginPath = getCurrentPlatformConfiguration().getPluginPath();
method.invoke(platform, new Object[] { pluginPath, baseLocation, options, args, handler });
} catch (InvocationTargetException e) {
if (e.getTargetException() instanceof Error)
throw (Error) e.getTargetException();
else
throw e;
}
// only record the platform as running if everything went swimmingly
running = true;
starting = false;
return applicationArgs;
}
}