blob: 5af97b32c058d4ed6e562c102ca7ac68acebd778 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2004 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 Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.core.internal.runtime;
import java.io.*;
import java.net.*;
import java.util.*;
import org.eclipse.core.internal.boot.*;
import org.eclipse.core.internal.jobs.JobManager;
import org.eclipse.core.internal.registry.BundleModel;
import org.eclipse.core.internal.registry.ExtensionRegistry;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.IJobManager;
import org.eclipse.osgi.service.debug.DebugOptions;
import org.eclipse.osgi.service.environment.EnvironmentInfo;
import org.eclipse.osgi.service.resolver.PlatformAdmin;
import org.eclipse.osgi.service.urlconversion.URLConverter;
import org.osgi.framework.*;
import org.osgi.util.tracker.ServiceTracker;
/**
* Bootstrap class for the platform. It is responsible for setting up the
* platform class loader and passing control to the actual application class
*/
public final class InternalPlatform implements IPlatform {
private BundleContext context;
private IExtensionRegistry registry;
private static IAdapterManager adapterManager;
private Plugin runtimeInstance; //Keep track of the plugin object for runtime in case the backward compatibility is run.
private static final InternalPlatform singleton = new InternalPlatform();
private IPath configMetadataLocation;
static ServiceRegistration platformRegistration;
static EnvironmentInfo infoService;
static URLConverter urlConverter;
// registry index - used to store last modified times for
// registry caching
// ASSUMPTION: Only the plugin registry in 'registry' above will be cached
private static Map regIndex = null;
private static ArrayList logListeners = new ArrayList(5);
private static Map logs = new HashMap(5);
private static PlatformLogWriter platformLog = null;
private static DataArea metaArea;
private static boolean initialized;
private static Runnable endOfInitializationHandler = null;
private static IPath location; //The location as set on the command line - this is just used as a temporary location
private static String password = "";
private static String keyringFile;
private static boolean noData = false;
private static boolean noDefaultData = false;
private ServiceTracker debugTracker;
private DebugOptions options = null;
// Command line args as seen by the Eclipse runtime. allArgs does NOT
// include args consumed by the underlying framework (e.g., OSGi)
private static String[] allArgs = new String[0];
private static String[] appArgs = new String[0];
private static String[] frameworkArgs = new String[0];
// the default workspace directory name
static final String WORKSPACE = "workspace"; //$NON-NLS-1$
private static ILogListener consoleLog = null;
private static boolean splashDown = false;
private static String pluginCustomizationFile = null;
private static URL installLocation = null;
/**
* Whether to write the version.ini file on shutdown.
*/
private static boolean writeVersion = true;
private ArrayList groupProviders = new ArrayList(3);
private IProduct product;
/**
* Name of the plug-in customization file (value "plugin_customization.ini")
* located in the root of the primary feature plug-in and it's
* companion nl-specific file with externalized strings (value
* "plugin_customization.properties"). The companion file can
* be contained in any nl-specific subdirectories of the primary
* feature or any fragment of this feature.
*/
private static final String PLUGIN_CUSTOMIZATION_BASE_NAME = "plugin_customization"; //$NON-NLS-1$
private static final String PLUGIN_CUSTOMIZATION_FILE_NAME = PLUGIN_CUSTOMIZATION_BASE_NAME + ".ini"; //$NON-NLS-1$
// execution options
private static final String OPTION_DEBUG = PI_RUNTIME + "/debug"; //$NON-NLS-1$
private static final String OPTION_DEBUG_SYSTEM_CONTEXT = PI_RUNTIME + "/debug/context"; //$NON-NLS-1$
private static final String OPTION_DEBUG_SHUTDOWN = PI_RUNTIME + "/timing/shutdown"; //$NON-NLS-1$
private static final String OPTION_DEBUG_REGISTRY = PI_RUNTIME + "/registry/debug"; //$NON-NLS-1$
private static final String OPTION_REGISTRY_CACHE_TIMING = IPlatform.PI_RUNTIME + "/registry/cache/timing"; //$NON-NLS-1$
private static final String OPTION_DEBUG_REGISTRY_DUMP = PI_RUNTIME + "/registry/debug/dump"; //$NON-NLS-1$
private static final String OPTION_DEBUG_PREFERENCES = PI_RUNTIME + "/preferences/debug"; //$NON-NLS-1$
// command line options
private static final String NO_DEFAULT_DATA = "-noDefaultData"; //$NON-NLS-1$
private static final String NO_DATA = "-noData"; //$NON-NLS-1$
private static final String PRODUCT = "-product"; //$NON-NLS-1$
private static final String APPLICATION = "-application"; //$NON-NLS-1$
private static final String DATA = "-data"; //$NON-NLS-1$
private static final String LOG = "-consolelog"; //$NON-NLS-1$
private static final String KEYRING = "-keyring"; //$NON-NLS-1$
protected static final String PASSWORD = "-password"; //$NON-NLS-1$
private static final String NOREGISTRYCACHE = "-noregistrycache"; //$NON-NLS-1$
private static final String NO_LAZY_REGISTRY_CACHE_LOADING = "-noLazyRegistryCacheLoading"; //$NON-NLS-1$
private static final String PLUGIN_CUSTOMIZATION = "-plugincustomization"; //$NON-NLS-1$
private static final String NO_PACKAGE_PREFIXES = "-noPackagePrefixes"; //$NON-NLS-1$
private static final String NO_VERSION_CHECK = "-noversioncheck"; //$NON-NLS-1$
private static final String CLASSLOADER_PROPERTIES = "-classloaderProperties"; //$NON-NLS-1$
// debug support: set in loadOptions()
public static boolean DEBUG = false;
public static boolean DEBUG_CONTEXT = false;
public static boolean DEBUG_REGISTRY = false;
public static boolean DEBUG_STARTUP = false;
public static boolean DEBUG_SHUTDOWN = false;
public static String DEBUG_REGISTRY_DUMP = null;
public static boolean DEBUG_PREFERENCES = false;
private static final String KEY_PREFIX = "%"; //$NON-NLS-1$
private static final String KEY_DOUBLE_PREFIX = "%%"; //$NON-NLS-1$
private static final String PLUGIN_PATH = ".plugin-path"; //$NON-NLS-1$
private static final String METADATA_VERSION_KEY = "org.eclipse.core.runtime"; //$NON-NLS-1$
private static final int METADATA_VERSION_VALUE = 1;
// Eclipse System Properties
public static final String PROP_PRODUCT = "eclipse.product"; //$NON-NLS-1$
public static final String PROP_APPLICATION = "eclipse.application"; //$NON-NLS-1$
public static final String PROP_CONSOLE_LOG = "eclipse.consoleLog"; //$NON-NLS-1$
public static final String PROP_NO_VERSION_CHECK = "eclipse.noVersionCheck"; //$NON-NLS-1$
public static final String PROP_NO_DATA = "eclipse.noData"; //$NON-NLS-1$
public static final String PROP_NO_DEFAULT_DATA = "eclipse.noDefaultData"; //$NON-NLS-1$
public static final String PROP_NO_REGISTRY_CACHE = "eclipse.noRegistryCache"; //$NON-NLS-1$
public static final String PROP_NO_LAZY_CACHE_LOADING = "eclipse.noLazyRegistryCacheLoading"; //$NON-NLS-1$
public static final String PROP_EXITCODE = "eclipse.exitcode"; //$NON-NLS-1$
// OSGI system properties. Copied from EclipseStarter
public static final String PROP_INSTALL_LOCATION = "osgi.installLocation"; //$NON-NLS-1$
public static final String PROP_CONFIG_AREA = "osgi.configuration.area"; //$NON-NLS-1$
public static final String PROP_INSTANCE_AREA = "osgi.instance.area"; //$NON-NLS-1$
public static final String PROP_USER_AREA = "osgi.user.area"; //$NON-NLS-1$
public static final String PROP_MANIFEST_CACHE = "osgi.manifest.cache"; //$NON-NLS-1$
public static final String PROP_DEBUG = "osgi.debug"; //$NON-NLS-1$
public static final String PROP_DEV = "osgi.dev"; //$NON-NLS-1$
public static final String PROP_CONSOLE = "osgi.console"; //$NON-NLS-1$
public static final String PROP_CONSOLE_CLASS= "osgi.consoleClass"; //$NON-NLS-1$
public static final String PROP_OS = "osgi.os"; //$NON-NLS-1$
public static final String PROP_WS = "osgi.ws"; //$NON-NLS-1$
public static final String PROP_NL = "osgi.nl"; //$NON-NLS-1$
public static final String PROP_ARCH = "osgi.arch"; //$NON-NLS-1$
public static final String PROP_ADAPTOR = "osgi.adaptor"; //$NON-NLS-1$
public static final String PROP_SYSPATH= "osgi.syspath"; //$NON-NLS-1$
/**
* Private constructor to block instance creation.
*/
private InternalPlatform() {
super();
}
public static InternalPlatform getDefault() {
return singleton;
}
/**
* @see Platform#addLogListener
*/
public void addLogListener(ILogListener listener) {
assertInitialized();
synchronized (logListeners) {
// replace if already exists (Set behaviour but we use an array
// since we want to retain order)
logListeners.remove(listener);
logListeners.add(listener);
}
}
/**
* @see Platform
*/
public URL asLocalURL(URL url) throws IOException {
//TODO: this is bogus - only to satisfy clients that want to resolve bundle2 URLs
if (url.getProtocol().equals("bundle2")) { //$NON-NLS-1$
String bundleName = url.getHost();
Bundle bundle = this.context.getBundle(bundleName.substring(0, bundleName.indexOf('_')));
if (bundle != null) {
URL localURL = bundle.getEntry(url.getPath());
if (localURL != null)
return localURL;
}
return url;
}
URL result = url;
// If this is a platform URL get the local URL from the PlatformURLConnection
if (result.getProtocol().equals(PlatformURLHandler.PROTOCOL)){
result = asActualURL(url);
}
// If the result is a bundleentry or bundleresouce URL then
// convert it to a file URL. This will end up extracting the
// bundle entry to cache if the bundle is packaged as a jar.
if (result.getProtocol().startsWith(PlatformURLHandler.BUNDLE)) {
URLConverter urlConverter = getURLConverter();
if (urlConverter == null) {
throw new IOException("url.noaccess");
}
result = urlConverter.convertToFileURL(result);
}
return result;
}
private URL asActualURL(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;
}
private void assertInitialized() {
//avoid the Policy.bind if assertion is true
if (!initialized)
Assert.isTrue(false, Policy.bind("meta.appNotInit")); //$NON-NLS-1$
}
/**
* @see Platform
*/
public void endSplash() {
if (DEBUG) {
String startString = System.getProperty("eclipse.debug.startupTime"); //$NON-NLS-1$
if (startString != null)
try {
long start = Long.parseLong(startString);
long end = System.currentTimeMillis();
System.out.println("Startup complete: " + (end - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
} catch (NumberFormatException e) {
//this is just debugging code -- ok to swallow exception
}
}
if (splashDown)
return;
splashDown = true;
run(endOfInitializationHandler);
}
/**
* @see Platform#getAdapterManager
*/
public IAdapterManager getAdapterManager() {
assertInitialized();
if (adapterManager == null)
adapterManager = new AdapterManager();
return adapterManager;
}
public boolean getBooleanOption(String option, boolean defaultValue) {
String value = getOption(option);
return (value != null && value.equalsIgnoreCase("true")) || defaultValue; //$NON-NLS-1$
}
public int getIntegerOption(String option, int defaultValue) {
String value = getOption(option);
if (value == null)
return defaultValue;
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
return defaultValue;
}
}
public String[] getAllArgs() {
return allArgs;
}
public String[] getAppArgs() {
return appArgs;
}
public String[] getFrameworkArgs() {
return frameworkArgs;
}
/**
* @see Platform
*/
public String getOption(String option) {
if (options != null)
return options.getOption(option);
return null;
}
public IJobManager getJobManager() {
return JobManager.getInstance();
}
public IPath getLogFileLocation() {
return getMetaArea().getLogLocation();
}
/**
* @see Platform#getLocation
*/
public IPath getLocation() throws IllegalStateException {
return getInstanceLocation();
}
/**
* Returns a log for the given plugin. Creates a new one if needed.
*/
public ILog getLog(Bundle bundle) {
ILog result = (ILog) logs.get(bundle);
if (result != null)
return result;
result = new Log(bundle);
logs.put(bundle, result);
return result;
}
/**
* Returns the object which defines the location and organization
* of the platform's meta area.
*/
public DataArea getMetaArea() {
if (metaArea != null)
return metaArea;
if (noData) {
metaArea = new NoDataArea();
return metaArea;
}
if (noDefaultData) {
metaArea = new NoDefaultDataArea();
} else {
metaArea = new DataArea();
metaArea.setInstanceDataLocation(location);
try {
metaArea.createLockFile();
} catch (CoreException e) {
throw new IllegalStateException(e.getStatus().getMessage());
}
}
metaArea.setKeyringFile(keyringFile);
metaArea.setPasswork(password);
return metaArea;
}
private void handleException(ISafeRunnable code, Throwable e) {
if (!(e instanceof OperationCanceledException)) {
String pluginId = PI_RUNTIME;
String message = Policy.bind("meta.pluginProblems", pluginId); //$NON-NLS-1$
IStatus status;
if (e instanceof CoreException) {
status = new MultiStatus(pluginId, IPlatform.PLUGIN_ERROR, message, e);
((MultiStatus)status).merge(((CoreException)e).getStatus());
} else {
status = new Status(IStatus.ERROR, pluginId, IPlatform.PLUGIN_ERROR, message, e);
}
log(status); //$NON-NLS-1$
}
code.handleException(e);
}
/**
* @return whether platform log writer has already been registered
*/
public boolean hasLogWriter() {
return platformLog != null && logListeners.contains(platformLog);
}
public IExtensionRegistry getRegistry() {
return registry;
}
/**
* Check whether the workspace metadata version matches the expected version.
* If not, prompt the user for whether to proceed, or exit with no changes.
* Side effects:
* <ul>
* <li>remember whether to write the metadata version on exit</li>
* <li>bring down the splash screen if exiting</li>
* </ul>
*
* @return <code>true</code> to proceed, <code>false</code> to exit with no changes
*/
public boolean loaderCheckVersion() {
// if not doing the version check, then proceed with no check or prompt
boolean noVersionCheck = "true".equals(System.getProperty("eclipse.noVersionCheck")); //$NON-NLS-1$
boolean proceed = noVersionCheck || checkVersionPrompt();
// remember whether to write the version on exit;
// don't write it if the user cancelled
writeVersion = proceed;
// bring down the splash screen if the user cancelled,
// since the application won't
if (!proceed)
endSplash();
return proceed;
}
/**
* Internal method for finding and returning a runnable instance of the
* given class as defined in the specified plug-in.
* The returned object is initialized with the supplied arguments.
* <p>
* This method is used by the platform boot loader; is must
* not be called directly by client code.
* </p>
* @see BootLoader
*/
public IPlatformRunnable loaderGetRunnable(String applicationName) {
assertInitialized();
IExtension extension = getRegistry().getExtension(PI_RUNTIME, PT_APPLICATIONS, applicationName);
if (extension == null)
return null;
IConfigurationElement[] configs = extension.getConfigurationElements();
if (configs.length == 0)
return null;
try {
IConfigurationElement config = configs[0];
return (IPlatformRunnable) config.createExecutableExtension("run"); //$NON-NLS-1$
} catch (CoreException e) {
getLog(context.getBundle()).log(e.getStatus());
return null;
} catch (Throwable t) {
t.printStackTrace(System.err);
return null;
}
}
/**
* Internal method for starting up the platform. The platform is started at the
* given location. The plug-ins found at the supplied
* collection of plug-in locations are loaded into the newly started platform.
* <p>
* This method is used by the platform boot loader; is must
* not be called directly by client code.
* </p>
* @param pluginPath the list of places to look for plug-in specifications. This may
* identify individual plug-in files or directories containing directories which contain
* plug-in files.
* @param location the local filesystem location at which the newly started platform
* should be started. If the location does not contain the saved state of a platform,
* the appropriate structures are created on disk (if required).
* @param bootOptions the debug options loaded by the boot loader. If the argument
* is <code>null</code> then debugging enablement was not requested by the
* person starting the platform.
* @see BootLoader
*/
public void start(BundleContext context) {
this.context = context;
// TODO figure out how to do the splash. This really should be something that is in the OSGi implementation
endOfInitializationHandler = getSplashHandler();
processCommandLine(infoService.getAllArgs());
processSystemProperties();
debugTracker = new ServiceTracker(context, DebugOptions.class.getName(), null);
debugTracker.open();
options = (DebugOptions) debugTracker.getService(); //TODO This is not good, but is avoids problems
initializeDebugFlags();
initialized = true;
platformLog = new PlatformLogWriter();
addLogListener(platformLog);
if ("true".equals(System.getProperty("eclipse.consoleLog"))) {
consoleLog = new PlatformLogWriter(System.out);
addLogListener(consoleLog);
}
platformRegistration = context.registerService(IPlatform.class.getName(), this, null);
}
/**
*
*/
private void processSystemProperties() {
noData = "true".equalsIgnoreCase(System.getProperties().getProperty(PROP_NO_DATA));
noDefaultData = "true".equalsIgnoreCase(System.getProperties().getProperty(PROP_NO_DEFAULT_DATA));
}
private Runnable getSplashHandler() {
ServiceReference[] ref;
try {
ref = context.getServiceReferences(Runnable.class.getName(), null);
} catch (InvalidSyntaxException e) {
return null;
}
// assumes the endInitializationHandler is available as a service
// see EclipseStarter.publishSplashScreen
for (int i = 0; i < ref.length; i++) {
String name = (String) ref[i].getProperty("name"); //$NON-NLS-1$
if (name != null && name.equals("splashscreen")) { //$NON-NLS-1$
Runnable result = (Runnable) context.getService(ref[i]);
context.ungetService(ref[i]);
return result;
}
}
return null;
}
/**
* Check whether the workspace metadata version matches the expected version.
* If not, prompt the user for whether to proceed, or exit with no changes.
* Side effects: none
*
* @return <code>true</code> to proceed, <code>false</code> to exit with no changes
*/
private boolean checkVersionPrompt() {
if (checkVersionNoPrompt())
return true;
// run the version check ui class to prompt the user
String appId = "org.eclipse.ui.versioncheck.prompt"; //$NON-NLS-1$
IPlatformRunnable runnable = loaderGetRunnable(appId);
// If there is no UI to confirm the metadata version difference, then just proceed.
if (runnable == null)
return true;
try {
Object result = runnable.run(null);
return Boolean.TRUE.equals(result);
} catch (Exception e) {
// Fail silently since we don't have a UI, but don't proceed if we can't prompt the user.
log(new Status(IStatus.ERROR, PI_RUNTIME, 1, Policy.bind("meta.versionCheckRun", appId), null)); //$NON-NLS-1$
return false;
}
}
//TODO: what else must be done during the platform shutdown? See #loaderShutdown
public void stop(BundleContext bundleContext) {
assertInitialized();
//shutdown all running jobs
JobManager.shutdown();
debugTracker.close();
if (writeVersion)
writeVersion();
if (platformLog != null)
platformLog.shutdown();
initialized = false;
}
/**
* Return whether the workspace metadata version matches the expected version.
*
* @return <code>true</code> if they match, <code>false</code> if not
*/
private boolean checkVersionNoPrompt() {
File pluginsDir = getMetaArea().getMetadataLocation().append(DataArea.F_PLUGIN_DATA).toFile();
if (!pluginsDir.exists())
return true;
int version = -1;
File versionFile = getMetaArea().getVersionPath().toFile();
if (versionFile.exists()) {
try {
// Although the version file is not spec'ed to be a Java properties file,
// it happens to follow the same format currently, so using Properties
// to read it is convenient.
Properties props = new Properties();
FileInputStream is = new FileInputStream(versionFile);
try {
props.load(is);
} finally {
try {
is.close();
} finally {
// ignore
}
}
String prop = props.getProperty(METADATA_VERSION_KEY);
// let any NumberFormatException be caught below
if (prop != null)
version = Integer.parseInt(prop);
} catch (Exception e) {
// Fail silently. Not a catastrophe if we can't read the version file. We don't
// want to fail execution.
log(new Status(IStatus.ERROR, PI_RUNTIME, 1, Policy.bind("meta.checkVersion", versionFile.toString()), e)); //$NON-NLS-1$
}
}
return version == METADATA_VERSION_VALUE;
}
/**
* Write out the version of the metadata into a known file. Overwrite
* any existing file contents.
*/
private void writeVersion() {
File versionFile = getMetaArea().getVersionPath().toFile();
try {
OutputStream output = new BufferedOutputStream(new FileOutputStream(versionFile));
try {
String versionLine = METADATA_VERSION_KEY + "=" + METADATA_VERSION_VALUE; //$NON-NLS-1$
output.write(versionLine.getBytes("UTF-8")); //$NON-NLS-1$
} finally {
output.close();
}
} catch (Exception e) {
// Fail silently. Not a catastrophe if we can't write the version file. We don't
// want to fail execution.
log(new Status(IStatus.ERROR, IPlatform.PI_RUNTIME, 1, Policy.bind("meta.writeVersion", versionFile.toString()), e)); //$NON-NLS-1$
}
}
/*
* Finds and loads the options file
*/
void initializeDebugFlags() {
// load runtime options
DEBUG = getBooleanOption(OPTION_DEBUG, false);
if (DEBUG) {
DEBUG_CONTEXT = getBooleanOption(OPTION_DEBUG_SYSTEM_CONTEXT, false);
DEBUG_SHUTDOWN = getBooleanOption(OPTION_DEBUG_SHUTDOWN, false);
DEBUG_REGISTRY = getBooleanOption(OPTION_DEBUG_REGISTRY, false);
DEBUG_REGISTRY_DUMP = getOption(OPTION_DEBUG_REGISTRY_DUMP);
DEBUG_PREFERENCES = getBooleanOption(OPTION_DEBUG_PREFERENCES, false);
}
}
/**
* Notifies all listeners of the platform log. This includes the console log, if
* used, and the platform log file. All Plugin log messages get funnelled
* through here as well.
*/
public void log(final IStatus status) {
assertInitialized();
// create array to avoid concurrent access
ILogListener[] listeners;
synchronized (logListeners) {
listeners = (ILogListener[]) logListeners.toArray(new ILogListener[logListeners.size()]);
}
for (int i = 0; i < listeners.length; i++) {
final ILogListener listener = listeners[i];
ISafeRunnable code = new ISafeRunnable() {
public void run() throws Exception {
listener.logging(status, PI_RUNTIME);
}
public void handleException(Throwable e) {
}
};
run(code);
}
}
private String[] processCommandLine(String[] args) {
if (args == null)
return args;
allArgs = args;
int[] configArgs = new int[100];
//need to initialize the first element to something that could not be an index.
configArgs[0] = -1;
int configArgIndex = 0;
for (int i = 0; i < args.length; i++) {
boolean found = false;
// check for args without parameters (i.e., a flag arg)
// look for the log flag
if (args[i].equalsIgnoreCase(LOG)) {
System.setProperty(PROP_CONSOLE_LOG, "true"); //$NON-NLS-1$
found = true;
}
// look for the no registry cache flag
if (args[i].equalsIgnoreCase(NOREGISTRYCACHE)) {
System.setProperty(PROP_NO_REGISTRY_CACHE, "true"); //$NON-NLS-1$
found = true;
}
// check to see if we should NOT be lazily loading plug-in definitions from the registry cache file.
// This will be processed below.
if (args[i].equalsIgnoreCase(NO_LAZY_REGISTRY_CACHE_LOADING)) {
System.setProperty(PROP_NO_LAZY_CACHE_LOADING, "true"); //$NON-NLS-1$
found = true;
}
// look for the flag to turn off using package prefixes
if (args[i].equalsIgnoreCase(NO_PACKAGE_PREFIXES)) {
// ignored
// PluginClassLoader.usePackagePrefixes = false;
found = true;
}
// look for the flag to run without workspace
if (args[i].equalsIgnoreCase(NO_DATA)) {
System.setProperty(PROP_NO_DATA, "true");
found = true;
}
// look for the flag to run with a workspace specified programmatically
if (args[i].equalsIgnoreCase(NO_DEFAULT_DATA)) {
System.setProperty(PROP_NO_DEFAULT_DATA, "true");
found = true;
}
// look for the flag to turn off the workspace metadata version check
if (args[i].equalsIgnoreCase(NO_VERSION_CHECK)) {
System.setProperty(PROP_NO_VERSION_CHECK, "true"); //$NON-NLS-1$
found = true;
}
// look for the flag to turn off using package prefixes
if (args[i].equalsIgnoreCase(NO_PACKAGE_PREFIXES))
found = true; // ignored
// this option (may have and argument) comes from InternalBootLoader.processCommandLine
if (args[i].equalsIgnoreCase(CLASSLOADER_PROPERTIES))
found = true; // ignored
// done checking for args. Remember where an arg was found
if (found) {
configArgs[configArgIndex++] = i;
continue;
}
// check for args with parameters
if (i == args.length - 1 || args[i + 1].startsWith("-")) //$NON-NLS-1$
continue;
String arg = args[++i];
// look for the default data location
if (args[i - 1].equalsIgnoreCase(DATA)) {
location = new Path(arg);
found = true;
}
// look for the keyring file
if (args[i - 1].equalsIgnoreCase(KEYRING)) {
keyringFile = arg;
found = true;
}
// look for the user password.
if (args[i - 1].equalsIgnoreCase(PASSWORD)) {
password = arg;
found = true;
}
// look for the product to run
if (args[i - 1].equalsIgnoreCase(PRODUCT)) {
System.setProperty(PROP_PRODUCT, arg); //$NON-NLS-1$
found = true;
}
// look for the application to run.
if (args[i - 1].equalsIgnoreCase(APPLICATION)) {
System.setProperty(PROP_APPLICATION, arg); //$NON-NLS-1$
found = true;
}
// look for the plug-in customization file
if (args[i - 1].equalsIgnoreCase(PLUGIN_CUSTOMIZATION)) {
pluginCustomizationFile = arg;
found = true;
}
if (args[i - 1].equalsIgnoreCase(CLASSLOADER_PROPERTIES)) {
// ignored
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) {
appArgs = args;
return args;
}
appArgs = new String[args.length - configArgIndex];
frameworkArgs = new String[configArgIndex];
configArgIndex = 0;
int j = 0;
int k = 0;
for (int i = 0; i < args.length; i++) {
if (i == configArgs[configArgIndex]) {
frameworkArgs[k++] = args[i];
configArgIndex++;
} else
appArgs[j++] = args[i];
}
return appArgs;
}
/**
* @see Platform#removeLogListener
*/
public void removeLogListener(ILogListener listener) {
assertInitialized();
synchronized (logListeners) {
logListeners.remove(listener);
}
}
/**
* @see Platform
*/
public URL resolve(URL url) throws IOException {
URL result = asActualURL(url);
if (!result.getProtocol().startsWith(PlatformURLHandler.BUNDLE))
return result;
URLConverter urlConverter = getURLConverter();
if (urlConverter == null) {
throw new IOException("url.noaccess");
}
result = urlConverter.convertToLocalURL(result);
return result;
}
public void run(ISafeRunnable code) {
Assert.isNotNull(code);
try {
code.run();
} catch (Exception e) {
handleException(code, e);
} catch (LinkageError e) {
handleException(code, e);
}
}
private void run(Runnable handler) {
// run end-of-initialization handler
if (handler == null)
return;
final Runnable finalHandler = handler;
ISafeRunnable code = new ISafeRunnable() {
public void run() throws Exception {
finalHandler.run();
}
public void handleException(Throwable e) {
// just continue ... the exception has already been logged by
// the platform (see handleException(ISafeRunnable)
}
};
run(code);
}
public void setOption(String option, String value) {
if (options != null)
options.setOption(option, value);
}
public void addLastModifiedTime(String pathKey, long lastModTime) {
if (regIndex == null)
regIndex = new HashMap(30);
regIndex.put(pathKey, new Long(lastModTime));
}
public Map getRegIndex() {
return regIndex;
}
public void clearRegIndex() {
regIndex = null;
}
/**
* Look for the companion preference translation file for a group
* of preferences. This method will attempt to find a companion
* ".properties" file first. This companion file can be in an
* nl-specific directory for this plugin or any of its fragments or
* it can be in the root of this plugin or the root of any of the
* plugin's fragments. This properties file can be used to translate
* preference values.
*
* @param pluginDescriptor the descriptor of the plugin
* who has the preferences
* @param basePrefFileName the base name of the preference file
* This base will be used to construct the name of the
* companion translation file.
* Example: If basePrefFileName is "plugin_customization",
* the preferences are in "plugin_customization.ini" and
* the translations are found in
* "plugin_customization.properties".
* @return the properties file
*
* @since 2.0
*/
public Properties getPreferenceTranslator(String uniqueIdentifier, String basePrefFileName) {
return new Properties();
}
/**
* Takes a preference value and a related resource bundle and
* returns the translated version of this value (if one exists).
*
* @param value the preference value for potential translation
* @param bundle the bundle containing the translated values
*
* @since 2.0
*/
public String translatePreference(String value, Properties props) {
value = value.trim();
if (props == null || value.startsWith(KEY_DOUBLE_PREFIX))
return value;
if (value.startsWith(KEY_PREFIX)) {
int ix = value.indexOf(" "); //$NON-NLS-1$
String key = ix == -1 ? value : value.substring(0, ix);
String dflt = ix == -1 ? value : value.substring(ix + 1);
return props.getProperty(key.substring(1), dflt);
}
return value;
}
/**
* Applies primary feature-specific overrides to default preferences for the
* plug-in with the given id.
* <p>
* Note that by the time this method is called, the default settings
* for the plug-in itself should have already have been filled in.
* </p>
*
* @param id the unique identifier of the plug-in
* @param preferences the preference store for the specified plug-in
*
* @since 2.0
*/
public void applyPrimaryFeaturePluginDefaultOverrides(String id, Preferences preferences) {
}
/**
* Applies command line-supplied overrides to default preferences for the
* plug-in with the given id.
* <p>
* Note that by the time this method is called, the default settings
* for the plug-in itself should have already have been filled in, along
* with any default overrides supplied by the primary feature.
* </p>
*
* @param id the unique identifier of the plug-in
* @param preferences the preference store for the specified plug-in
*
* @since 2.0
*/
public void applyCommandLinePluginDefaultOverrides(String id, Preferences preferences) {
if (pluginCustomizationFile == null) {
// no command line overrides to process
if (DEBUG_PREFERENCES) {
System.out.println("Command line argument -pluginCustomization not used."); //$NON-NLS-1$
}
return;
}
try {
URL pluginCustomizationURL = new File(pluginCustomizationFile).toURL();
if (DEBUG_PREFERENCES) {
System.out.println("Loading preferences from " + pluginCustomizationURL); //$NON-NLS-1$
}
applyPluginDefaultOverrides(pluginCustomizationURL, id, preferences, null);
} catch (MalformedURLException e) {
// fail silently
if (DEBUG_PREFERENCES) {
System.out.println("MalformedURLException creating URL for plugin customization file " //$NON-NLS-1$
+pluginCustomizationFile);
e.printStackTrace();
}
return;
}
}
/**
* Applies overrides to default preferences for the plug-in with the given id.
* The data is contained in the <code>java.io.Properties</code> style file at
* the given URL. The property names consist of "/'-separated plug-in id and
* name of preference; e.g., "com.example.myplugin/mypref".
*
* @param propertiesURL the URL of a <code>java.io.Properties</code> style file
* @param id the unique identifier of the plug-in
* @param preferences the preference store for the specified plug-in
*
* @since 2.0
*/
private void applyPluginDefaultOverrides(URL propertiesURL, String id, Preferences preferences, Properties props) {
// read the java.io.Properties file at the given URL
Properties overrides = new Properties();
SafeFileInputStream in = null;
try {
File inFile = new File(propertiesURL.getFile());
if (!inFile.exists()) {
// We don't have a preferences file to worry about
if (DEBUG_PREFERENCES) {
System.out.println("Preference file " + //$NON-NLS-1$
propertiesURL + " not found."); //$NON-NLS-1$
}
return;
}
in = new SafeFileInputStream(inFile);
if (in == null) {
// fail quietly
if (DEBUG_PREFERENCES) {
System.out.println("Failed to open " + //$NON-NLS-1$
propertiesURL);
}
return;
}
overrides.load(in);
} catch (IOException e) {
// cannot read ini file - fail silently
if (DEBUG_PREFERENCES) {
System.out.println("IOException reading preference file " + //$NON-NLS-1$
propertiesURL);
e.printStackTrace();
}
return;
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
// ignore problems closing file
if (DEBUG_PREFERENCES) {
System.out.println("IOException closing preference file " + //$NON-NLS-1$
propertiesURL);
e.printStackTrace();
}
}
}
for (Iterator it = overrides.entrySet().iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
String qualifiedKey = (String) entry.getKey();
// Keys consist of "/'-separated plug-in id and name of preference
// e.g., "com.example.myplugin/mypref"
int s = qualifiedKey.indexOf('/');
if (s < 0 || s == 0 || s == qualifiedKey.length() - 1) {
// skip mangled entry
continue;
}
// plug-in id is non-empty string before "/"
String pluginId = qualifiedKey.substring(0, s);
if (pluginId.equals(id)) {
// override property in the given plug-in
// plig-in-specified property name is non-empty string after "/"
String propertyName = qualifiedKey.substring(s + 1);
String value = (String) entry.getValue();
value = translatePreference(value, props);
preferences.setDefault(propertyName, value);
}
}
if (DEBUG_PREFERENCES) {
System.out.println("Preferences now set as follows:"); //$NON-NLS-1$
String[] prefNames = preferences.propertyNames();
for (int i = 0; i < prefNames.length; i++) {
String value = preferences.getString(prefNames[i]);
System.out.println("\t" + prefNames[i] + " = " + value); //$NON-NLS-1$ //$NON-NLS-2$
}
prefNames = preferences.defaultPropertyNames();
for (int i = 0; i < prefNames.length; i++) {
String value = preferences.getDefaultString(prefNames[i]);
System.out.println("\tDefault values: " + prefNames[i] + " = " + value); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
public void setExtensionRegistry(IExtensionRegistry value) {
registry = value;
}
public BundleContext getBundleContext() {
return context;
}
public Bundle getBundle(String id) {
return getBundleContext().getBundle(id);
}
public URL getInstallURL() {
if (installLocation == null)
try {
installLocation = new URL(System.getProperty(PROP_INSTALL_LOCATION)); //$NON-NLS-1$
} catch (MalformedURLException e) {
//This can't fail because the location was set coming in
}
return installLocation;
}
public EnvironmentInfo getEnvironmentInfoService() {
return infoService;
}
public URLConverter getURLConverter(){
return urlConverter;
}
public boolean isRunning() {
int state = context.getBundle(PI_RUNTIME).getState();
return state == Bundle.ACTIVE;
}
/*
* 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 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;
}
private 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 IPath getConfigurationLocation() {
if (configMetadataLocation == null)
configMetadataLocation = new Path(System.getProperty("osgi.configuration.area")); //$NON-NLS-1$
return configMetadataLocation;
}
public IPath getConfigurationMetadataLocation() {
return this.getConfigurationLocation();
}
public IPath getStateLocation(Bundle bundle, boolean create) throws IllegalStateException {
assertInitialized();
IPath result = getMetaArea().getStateLocation(bundle);
if (create)
result.toFile().mkdirs();
return result;
}
public URL find(Bundle b, IPath path) {
return FindSupport.find(b, path);
}
public URL find(Bundle bundle, IPath path, Map override) {
return FindSupport.find(bundle, path, override);
}
public InputStream openStream(Bundle bundle, IPath file) throws IOException {
return FindSupport.openStream(bundle, file, false);
}
public InputStream openStream(Bundle bundle, IPath file, boolean localized) throws IOException {
return FindSupport.openStream(bundle, file, localized);
}
public IPath getStateLocation(Bundle bundle) {
return getStateLocation(bundle, true);
}
public ResourceBundle getResourceBundle(Bundle bundle) throws MissingResourceException {
BundleModel model = (BundleModel) ((ExtensionRegistry) getRegistry()).getElement(bundle.getGlobalName());
return model != null ? model.getResourceBundle() : null ;
}
public String getResourceString(Bundle bundle, String value) {
BundleModel model = (BundleModel) ((ExtensionRegistry) getRegistry()).getElement(bundle.getGlobalName());
return model != null ? model.getResourceString(value) : value;
}
public String getResourceString(Bundle bundle, String value, ResourceBundle resourceBundle) {
BundleModel model = (BundleModel) ((ExtensionRegistry) getRegistry()).getElement(bundle.getGlobalName());
return model != null ? model.getResourceString(value, resourceBundle) : value;
}
public String getOSArch() {
return getEnvironmentInfoService().getOSArch();
}
public String getNL() {
return getEnvironmentInfoService().getNL();
}
public String getOS() {
return getEnvironmentInfoService().getOS();
}
public String getWS() {
return getEnvironmentInfoService().getWS();
}
public String[] getApplicationArgs() {
return getEnvironmentInfoService().getApplicationArgs();
}
//Those two methods are only used to register runtime once compatibility has been started.
public void setRuntimeInstance(Plugin runtime) {
runtimeInstance = runtime;
}
public Plugin getRuntimeInstance() {
return runtimeInstance;
}
public long getStateTimeStamp() {
ServiceReference platformAdminReference = context.getServiceReference(PlatformAdmin.class.getName());
if (platformAdminReference == null)
return -1;
else
return ((PlatformAdmin) context.getService(platformAdminReference)).getState(false).getTimeStamp();
}
public PlatformAdmin getPlatformAdmin() {
ServiceReference platformAdminReference = context.getServiceReference(PlatformAdmin.class.getName());
if (platformAdminReference == null)
return null;
return (PlatformAdmin) context.getService(platformAdminReference);
}
public void lockInstanceData() throws CoreException {
getMetaArea().createLockFile();
}
public void unlockInstanceData() {
getMetaArea().clearLockFile();
}
public boolean hasInstanceData() {
return getMetaArea().hasInstanceData();
}
public void addAuthorizationInfo(URL serverUrl, String realm, String authScheme, Map info) throws CoreException {
getMetaArea().addAuthorizationInfo(serverUrl, realm, authScheme, info);
}
public void addProtectionSpace(URL resourceUrl, String realm) throws CoreException {
getMetaArea().addProtectionSpace(resourceUrl, realm);
}
public void flushAuthorizationInfo(URL serverUrl, String realm, String authScheme) throws CoreException {
getMetaArea().flushAuthorizationInfo(serverUrl, realm, authScheme);
}
public Map getAuthorizationInfo(URL serverUrl, String realm, String authScheme) {
return getMetaArea().getAuthorizationInfo(serverUrl, realm, authScheme);
}
public String getProtectionSpace(URL resourceUrl) {
return getMetaArea().getProtectionSpace(resourceUrl);
}
public void setKeyringLocation(String keyringFile) {
getMetaArea().setKeyringFile(keyringFile);
}
public void setInstanceLocation(IPath location) throws IllegalStateException {
getMetaArea().setInstanceDataLocation(location);
}
public IPath getInstanceLocation() throws IllegalStateException {
assertInitialized();
if (! metaArea.isInstanceDataLocationInitiliazed()) {
if (noData)
throw new IllegalStateException(Policy.bind("meta.noDataModeSpecified"));
if (noDefaultData)
throw new IllegalStateException(Policy.bind("meta.instanceDataUnspecified"));
try {
metaArea.initializeLocation();
} catch (CoreException e) {
throw new IllegalStateException(e.getLocalizedMessage());
}
}
return metaArea.getInstanceDataLocation();
}
public IBundleGroupProvider[] getBundleGroupProviders() {
return (IBundleGroupProvider[])groupProviders.toArray(new IBundleGroupProvider[groupProviders.size()]);
}
public IProduct getProduct() {
if (product != null)
return product;
String productId = System.getProperty("eclipse.product");
if (productId == null)
return null;
IConfigurationElement[] entries = getRegistry().getConfigurationElementsFor(PI_RUNTIME, "products", productId);
if (entries == null || entries.length == 0)
return null;
// There should only be one product with the given id so just take the first element
product = new Product(entries[0]);
return product;
}
public void registerBundleGroupProvider(IBundleGroupProvider provider) {
groupProviders.add(provider);
}
public void unregisterBundleGroupProvider(IBundleGroupProvider provider) {
groupProviders.remove(provider);
}
}