Eclipse Startup
- First of all, we take a look at class EclipseStarter
-
1 /******************************************************************************* 2 * Copyright (c) 2003, 2012 IBM Corporation and others. 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * IBM Corporation - initial API and implementation 10 * Alex Blewitt (bug 172969) 11 *******************************************************************************/ 12 package org.eclipse.core.runtime.adaptor; 13 14 import java.io.*; 15 import java.lang.reflect.Constructor; 16 import java.lang.reflect.Method; 17 import java.net.*; 18 import java.security.CodeSource; 19 import java.security.ProtectionDomain; 20 import java.util.*; 21 import org.eclipse.core.runtime.internal.adaptor.*; 22 import org.eclipse.osgi.framework.adaptor.*; 23 import org.eclipse.osgi.framework.internal.core.*; 24 import org.eclipse.osgi.framework.internal.core.Constants; 25 import org.eclipse.osgi.framework.log.FrameworkLog; 26 import org.eclipse.osgi.framework.log.FrameworkLogEntry; 27 import org.eclipse.osgi.internal.baseadaptor.BaseStorageHook; 28 import org.eclipse.osgi.internal.profile.Profile; 29 import org.eclipse.osgi.service.datalocation.Location; 30 import org.eclipse.osgi.service.resolver.*; 31 import org.eclipse.osgi.service.runnable.ApplicationLauncher; 32 import org.eclipse.osgi.service.runnable.StartupMonitor; 33 import org.eclipse.osgi.util.ManifestElement; 34 import org.eclipse.osgi.util.NLS; 35 import org.osgi.framework.*; 36 import org.osgi.service.packageadmin.PackageAdmin; 37 import org.osgi.service.startlevel.StartLevel; 38 import org.osgi.util.tracker.ServiceTracker; 39 40 /** 41 * Special startup class for the Eclipse Platform. This class cannot be 42 * instantiated; all functionality is provided by static methods. 43 * <p> 44 * The Eclipse Platform makes heavy use of Java class loaders for loading 45 * plug-ins. Even the Eclipse Runtime itself and the OSGi framework need 46 * to be loaded by special class loaders. The upshot is that a 47 * client program (such as a Java main program, a servlet) cannot 48 * reference any part of Eclipse directly. Instead, a client must use this 49 * loader class to start the platform, invoking functionality defined 50 * in plug-ins, and shutting down the platform when done. 51 * </p> 52 * <p>Note that the fields on this class are not API. </p> 53 * @since 3.0 54 * @noextend This class is not intended to be subclassed by clients. 55 */ 56 public class EclipseStarter { 57 private static FrameworkAdaptor adaptor; 58 private static BundleContext context; 59 private static boolean initialize = false; 60 public static boolean debug = false; 61 private static boolean running = false; 62 private static Framework framework = null; 63 private static ServiceRegistration<?> defaultMonitorRegistration = null; 64 private static ServiceRegistration<?> appLauncherRegistration = null; 65 private static ServiceRegistration<?> splashStreamRegistration = null; 66 67 // command line arguments 68 private static final String CLEAN = "-clean"; //$NON-NLS-1$ 69 private static final String CONSOLE = "-console"; //$NON-NLS-1$ 70 private static final String CONSOLE_LOG = "-consoleLog"; //$NON-NLS-1$ 71 private static final String DEBUG = "-debug"; //$NON-NLS-1$ 72 private static final String INITIALIZE = "-initialize"; //$NON-NLS-1$ 73 private static final String DEV = "-dev"; //$NON-NLS-1$ 74 private static final String WS = "-ws"; //$NON-NLS-1$ 75 private static final String OS = "-os"; //$NON-NLS-1$ 76 private static final String ARCH = "-arch"; //$NON-NLS-1$ 77 private static final String NL = "-nl"; //$NON-NLS-1$ 78 private static final String NL_EXTENSIONS = "-nlExtensions"; //$NON-NLS-1$ 79 private static final String CONFIGURATION = "-configuration"; //$NON-NLS-1$ 80 private static final String USER = "-user"; //$NON-NLS-1$ 81 private static final String NOEXIT = "-noExit"; //$NON-NLS-1$ 82 private static final String LAUNCHER = "-launcher"; //$NON-NLS-1$ 83 84 // this is more of an Eclipse argument but this OSGi implementation stores its 85 // metadata alongside Eclipse's. 86 private static final String DATA = "-data"; //$NON-NLS-1$ 87 88 // System properties 89 public static final String PROP_BUNDLES = "osgi.bundles"; //$NON-NLS-1$ 90 public static final String PROP_BUNDLES_STARTLEVEL = "osgi.bundles.defaultStartLevel"; //$NON-NLS-1$ //The start level used to install the bundles 91 public static final String PROP_EXTENSIONS = "osgi.framework.extensions"; //$NON-NLS-1$ 92 public static final String PROP_INITIAL_STARTLEVEL = "osgi.startLevel"; //$NON-NLS-1$ //The start level when the fwl start 93 public static final String PROP_DEBUG = "osgi.debug"; //$NON-NLS-1$ 94 public static final String PROP_DEV = "osgi.dev"; //$NON-NLS-1$ 95 public static final String PROP_CLEAN = "osgi.clean"; //$NON-NLS-1$ 96 public static final String PROP_CONSOLE = "osgi.console"; //$NON-NLS-1$ 97 public static final String PROP_CONSOLE_CLASS = "osgi.consoleClass"; //$NON-NLS-1$ 98 public static final String PROP_CHECK_CONFIG = "osgi.checkConfiguration"; //$NON-NLS-1$ 99 public static final String PROP_OS = "osgi.os"; //$NON-NLS-1$ 100 public static final String PROP_WS = "osgi.ws"; //$NON-NLS-1$ 101 public static final String PROP_NL = "osgi.nl"; //$NON-NLS-1$ 102 private static final String PROP_NL_EXTENSIONS = "osgi.nl.extensions"; //$NON-NLS-1$ 103 public static final String PROP_ARCH = "osgi.arch"; //$NON-NLS-1$ 104 public static final String PROP_ADAPTOR = "osgi.adaptor"; //$NON-NLS-1$ 105 public static final String PROP_SYSPATH = "osgi.syspath"; //$NON-NLS-1$ 106 public static final String PROP_LOGFILE = "osgi.logfile"; //$NON-NLS-1$ 107 public static final String PROP_FRAMEWORK = "osgi.framework"; //$NON-NLS-1$ 108 public static final String PROP_INSTALL_AREA = "osgi.install.area"; //$NON-NLS-1$ 109 public static final String PROP_FRAMEWORK_SHAPE = "osgi.framework.shape"; //$NON-NLS-1$ //the shape of the fwk (jar, or folder) 110 public static final String PROP_NOSHUTDOWN = "osgi.noShutdown"; //$NON-NLS-1$ 111 private static final String PROP_FORCED_RESTART = "osgi.forcedRestart"; //$NON-NLS-1$ 112 113 public static final String PROP_EXITCODE = "eclipse.exitcode"; //$NON-NLS-1$ 114 public static final String PROP_EXITDATA = "eclipse.exitdata"; //$NON-NLS-1$ 115 public static final String PROP_CONSOLE_LOG = "eclipse.consoleLog"; //$NON-NLS-1$ 116 public static final String PROP_IGNOREAPP = "eclipse.ignoreApp"; //$NON-NLS-1$ 117 public static final String PROP_REFRESH_BUNDLES = "eclipse.refreshBundles"; //$NON-NLS-1$ 118 private static final String PROP_ALLOW_APPRELAUNCH = "eclipse.allowAppRelaunch"; //$NON-NLS-1$ 119 private static final String PROP_APPLICATION_LAUNCHDEFAULT = "eclipse.application.launchDefault"; //$NON-NLS-1$ 120 121 private static final String FILE_SCHEME = "file:"; //$NON-NLS-1$ 122 private static final String REFERENCE_SCHEME = "reference:"; //$NON-NLS-1$ 123 private static final String REFERENCE_PROTOCOL = "reference"; //$NON-NLS-1$ 124 private static final String INITIAL_LOCATION = "initial@"; //$NON-NLS-1$ 125 /** string containing the classname of the adaptor to be used in this framework instance */ 126 protected static final String DEFAULT_ADAPTOR_CLASS = "org.eclipse.osgi.baseadaptor.BaseAdaptor"; //$NON-NLS-1$ 127 128 private static final int DEFAULT_INITIAL_STARTLEVEL = 6; // default value for legacy purposes 129 private static final String DEFAULT_BUNDLES_STARTLEVEL = "4"; //$NON-NLS-1$ 130 131 private static FrameworkLog log; 132 // directory of serch candidates keyed by directory abs path -> directory listing (bug 122024) 133 private static Map<String, String[]> searchCandidates = new HashMap<String, String[]>(4); 134 private static EclipseAppLauncher appLauncher; 135 private static List<Runnable> shutdownHandlers; 136 137 private static ConsoleManager consoleMgr = null; 138 139 /** 140 * This is the main to start osgi. 141 * It only works when the framework is being jared as a single jar 142 */ 143 public static void main(String[] args) throws Exception { 144 if (FrameworkProperties.getProperty("eclipse.startTime") == null) //$NON-NLS-1$ 145 FrameworkProperties.setProperty("eclipse.startTime", Long.toString(System.currentTimeMillis())); //$NON-NLS-1$ 146 if (FrameworkProperties.getProperty(PROP_NOSHUTDOWN) == null) 147 FrameworkProperties.setProperty(PROP_NOSHUTDOWN, "true"); //$NON-NLS-1$ 148 // set the compatibility boot delegation flag to false to get "standard" OSGi behavior WRT boot delegation (bug 178477) 149 if (FrameworkProperties.getProperty(Constants.OSGI_COMPATIBILITY_BOOTDELEGATION) == null) 150 FrameworkProperties.setProperty(Constants.OSGI_COMPATIBILITY_BOOTDELEGATION, "false"); //$NON-NLS-1$ 151 Object result = run(args, null); 152 if (result instanceof Integer && !Boolean.valueOf(FrameworkProperties.getProperty(PROP_NOSHUTDOWN)).booleanValue()) 153 System.exit(((Integer) result).intValue()); 154 } 155 156 /** 157 * Launches the platform and runs a single application. The application is either identified 158 * in the given arguments (e.g., -application <app id>) or in the <code>eclipse.application</code> 159 * System property. This convenience method starts 160 * up the platform, runs the indicated application, and then shuts down the 161 * platform. The platform must not be running already. 162 * 163 * @param args the command line-style arguments used to configure the platform 164 * @param endSplashHandler the block of code to run to tear down the splash 165 * screen or <code>null</code> if no tear down is required 166 * @return the result of running the application 167 * @throws Exception if anything goes wrong 168 */ 169 public static Object run(String[] args, Runnable endSplashHandler) throws Exception { 170 if (Profile.PROFILE && Profile.STARTUP) 171 Profile.logEnter("EclipseStarter.run()", null); //$NON-NLS-1$ 172 if (running) 173 throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING); 174 boolean startupFailed = true; 175 try { 176 startup(args, endSplashHandler); 177 startupFailed = false; 178 if (Boolean.valueOf(FrameworkProperties.getProperty(PROP_IGNOREAPP)).booleanValue() || isForcedRestart()) 179 return null; 180 return run(null); 181 } catch (Throwable e) { 182 // ensure the splash screen is down 183 if (endSplashHandler != null) 184 endSplashHandler.run(); 185 // may use startupFailed to understand where the error happened 186 FrameworkLogEntry logEntry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, startupFailed ? EclipseAdaptorMsg.ECLIPSE_STARTUP_STARTUP_ERROR : EclipseAdaptorMsg.ECLIPSE_STARTUP_APP_ERROR, 1, e, null); 187 if (log != null) 188 log.log(logEntry); 189 else 190 // TODO desperate measure - ideally, we should write this to disk (a la Main.log) 191 e.printStackTrace(); 192 } finally { 193 try { 194 // The application typically sets the exit code however the framework can request that 195 // it be re-started. We need to check for this and potentially override the exit code. 196 if (isForcedRestart()) 197 FrameworkProperties.setProperty(PROP_EXITCODE, "23"); //$NON-NLS-1$ 198 if (!Boolean.valueOf(FrameworkProperties.getProperty(PROP_NOSHUTDOWN)).booleanValue()) 199 shutdown(); 200 } catch (Throwable e) { 201 FrameworkLogEntry logEntry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, EclipseAdaptorMsg.ECLIPSE_STARTUP_SHUTDOWN_ERROR, 1, e, null); 202 if (log != null) 203 log.log(logEntry); 204 else 205 // TODO desperate measure - ideally, we should write this to disk (a la Main.log) 206 e.printStackTrace(); 207 } 208 if (Profile.PROFILE && Profile.STARTUP) 209 Profile.logExit("EclipseStarter.run()"); //$NON-NLS-1$ 210 if (Profile.PROFILE) { 211 String report = Profile.getProfileLog(); 212 // avoiding writing to the console if there is nothing to print 213 if (report != null && report.length() > 0) 214 System.out.println(report); 215 } 216 } 217 // we only get here if an error happened 218 if (FrameworkProperties.getProperty(PROP_EXITCODE) == null) { 219 FrameworkProperties.setProperty(PROP_EXITCODE, "13"); //$NON-NLS-1$ 220 FrameworkProperties.setProperty(PROP_EXITDATA, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_CHECK_LOG, log == null ? null : log.getFile().getPath())); 221 } 222 return null; 223 } 224 225 /** 226 * Returns true if the platform is already running, false otherwise. 227 * @return whether or not the platform is already running 228 */ 229 public static boolean isRunning() { 230 return running; 231 } 232 233 /** 234 * Starts the platform and sets it up to run a single application. The application is either identified 235 * in the given arguments (e.g., -application <app id>) or in the <code>eclipse.application</code> 236 * System property. The platform must not be running already. 237 * <p> 238 * The given runnable (if not <code>null</code>) is used to tear down the splash screen if required. 239 * </p> 240 * @param args the arguments passed to the application 241 * @return BundleContext the context of the system bundle 242 * @throws Exception if anything goes wrong 243 */ 244 public static BundleContext startup(String[] args, Runnable endSplashHandler) throws Exception { 245 if (Profile.PROFILE && Profile.STARTUP) 246 Profile.logEnter("EclipseStarter.startup()", null); //$NON-NLS-1$ 247 if (running) 248 throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING); 249 FrameworkProperties.initializeProperties(); 250 processCommandLine(args); 251 LocationManager.initializeLocations(); 252 loadConfigurationInfo(); 253 finalizeProperties(); 254 if (Profile.PROFILE) 255 Profile.initProps(); // catch any Profile properties set in eclipse.properties... 256 if (Profile.PROFILE && Profile.STARTUP) 257 Profile.logTime("EclipseStarter.startup()", "props inited"); //$NON-NLS-1$ //$NON-NLS-2$ 258 adaptor = createAdaptor(); 259 log = adaptor.getFrameworkLog(); 260 if (Profile.PROFILE && Profile.STARTUP) 261 Profile.logTime("EclipseStarter.startup()", "adapter created"); //$NON-NLS-1$ //$NON-NLS-2$ 262 framework = new Framework(adaptor); 263 if (Profile.PROFILE && Profile.STARTUP) 264 Profile.logTime("EclipseStarter.startup()", "OSGi created"); //$NON-NLS-1$ //$NON-NLS-2$ 265 context = framework.getBundle(0).getBundleContext(); 266 registerFrameworkShutdownHandlers(); 267 publishSplashScreen(endSplashHandler); 268 if (Profile.PROFILE && Profile.STARTUP) 269 Profile.logTime("EclipseStarter.startup()", "osgi launched"); //$NON-NLS-1$ //$NON-NLS-2$ 270 consoleMgr = ConsoleManager.startConsole(framework); 271 if (Profile.PROFILE && Profile.STARTUP) { 272 Profile.logTime("EclipseStarter.startup()", "console started"); //$NON-NLS-1$ //$NON-NLS-2$ 273 } 274 framework.launch(); 275 // save the cached timestamp before loading basic bundles; this is needed so we can do a proper timestamp check when logging resolver errors 276 long stateStamp = adaptor.getState().getTimeStamp(); 277 Bundle[] startBundles = loadBasicBundles(); 278 279 if (startBundles == null || ("true".equals(FrameworkProperties.getProperty(PROP_REFRESH_BUNDLES)) && refreshPackages(getCurrentBundles(false)))) { //$NON-NLS-1$ 280 waitForShutdown(); 281 return context; // cannot continue; loadBasicBundles caused refreshPackages to shutdown the framework 282 } 283 284 if (Profile.PROFILE && Profile.STARTUP) 285 Profile.logTime("EclipseStarter.startup()", "loading basic bundles"); //$NON-NLS-1$ //$NON-NLS-2$ 286 287 // set the framework start level to the ultimate value. This will actually start things 288 // running if they are persistently active. 289 setStartLevel(getStartLevel()); 290 if (Profile.PROFILE && Profile.STARTUP) 291 Profile.logTime("EclipseStarter.startup()", "StartLevel set"); //$NON-NLS-1$ //$NON-NLS-2$ 292 // they should all be active by this time 293 ensureBundlesActive(startBundles); 294 295 // in the case where the built-in console is disabled we should try to start the console bundle 296 try { 297 consoleMgr.checkForConsoleBundle(); 298 } catch (BundleException e) { 299 FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, e.getMessage(), 0, e, null); 300 log.log(entry); 301 } 302 if (debug || FrameworkProperties.getProperty(PROP_DEV) != null) 303 // only spend time showing unresolved bundles in dev/debug mode and the state has changed 304 if (stateStamp != adaptor.getState().getTimeStamp()) 305 logUnresolvedBundles(context.getBundles()); 306 running = true; 307 if (Profile.PROFILE && Profile.STARTUP) 308 Profile.logExit("EclipseStarter.startup()"); //$NON-NLS-1$ 309 return context; 310 } 311 312 private static int getStartLevel() { 313 String level = FrameworkProperties.getProperty(PROP_INITIAL_STARTLEVEL); 314 if (level != null) 315 try { 316 return Integer.parseInt(level); 317 } catch (NumberFormatException e) { 318 if (debug) 319 System.out.println("Start level = " + level + " parsed. Using hardcoded default: 6"); //$NON-NLS-1$ //$NON-NLS-2$ 320 } 321 return DEFAULT_INITIAL_STARTLEVEL; 322 } 323 324 /** 325 * Runs the application for which the platform was started. The platform 326 * must be running. 327 * <p> 328 * The given argument is passed to the application being run. If it is <code>null</code> 329 * then the command line arguments used in starting the platform, and not consumed 330 * by the platform code, are passed to the application as a <code>String[]</code>. 331 * </p> 332 * @param argument the argument passed to the application. May be <code>null</code> 333 * @return the result of running the application 334 * @throws Exception if anything goes wrong 335 */ 336 public static Object run(Object argument) throws Exception { 337 if (Profile.PROFILE && Profile.STARTUP) 338 Profile.logEnter("EclipseStarter.run(Object)()", null); //$NON-NLS-1$ 339 if (!running) 340 throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_NOT_RUNNING); 341 // if we are just initializing, do not run the application just return. 342 if (initialize) 343 return new Integer(0); 344 try { 345 if (appLauncher == null) { 346 boolean launchDefault = Boolean.valueOf(FrameworkProperties.getProperty(PROP_APPLICATION_LAUNCHDEFAULT, "true")).booleanValue(); //$NON-NLS-1$ 347 // create the ApplicationLauncher and register it as a service 348 appLauncher = new EclipseAppLauncher(context, Boolean.valueOf(FrameworkProperties.getProperty(PROP_ALLOW_APPRELAUNCH)).booleanValue(), launchDefault, log); 349 appLauncherRegistration = context.registerService(ApplicationLauncher.class.getName(), appLauncher, null); 350 // must start the launcher AFTER service restration because this method 351 // blocks and runs the application on the current thread. This method 352 // will return only after the application has stopped. 353 return appLauncher.start(argument); 354 } 355 return appLauncher.reStart(argument); 356 } catch (Exception e) { 357 if (log != null && context != null) // context can be null if OSGi failed to launch (bug 151413) 358 logUnresolvedBundles(context.getBundles()); 359 throw e; 360 } 361 } 362 363 /** 364 * Shuts down the Platform. The state of the Platform is not automatically 365 * saved before shutting down. 366 * <p> 367 * On return, the Platform will no longer be running (but could be re-launched 368 * with another call to startup). If relaunching, care must be taken to reinitialize 369 * any System properties which the platform uses (e.g., osgi.instance.area) as 370 * some policies in the platform do not allow resetting of such properties on 371 * subsequent runs. 372 * </p><p> 373 * Any objects handed out by running Platform, 374 * including Platform runnables obtained via getRunnable, will be 375 * permanently invalid. The effects of attempting to invoke methods 376 * on invalid objects is undefined. 377 * </p> 378 * @throws Exception if anything goes wrong 379 */ 380 public static void shutdown() throws Exception { 381 if (!running || framework == null) 382 return; 383 if (appLauncherRegistration != null) 384 appLauncherRegistration.unregister(); 385 if (splashStreamRegistration != null) 386 splashStreamRegistration.unregister(); 387 if (defaultMonitorRegistration != null) 388 defaultMonitorRegistration.unregister(); 389 if (appLauncher != null) 390 appLauncher.shutdown(); 391 appLauncherRegistration = null; 392 appLauncher = null; 393 splashStreamRegistration = null; 394 defaultMonitorRegistration = null; 395 if (consoleMgr != null) { 396 consoleMgr.stopConsole(); 397 consoleMgr = null; 398 } 399 framework.close(); 400 framework = null; 401 context = null; 402 running = false; 403 } 404 405 private static void ensureBundlesActive(Bundle[] bundles) { 406 ServiceTracker<StartLevel, StartLevel> tracker = null; 407 try { 408 for (int i = 0; i < bundles.length; i++) { 409 if (bundles[i].getState() != Bundle.ACTIVE) { 410 if (bundles[i].getState() == Bundle.INSTALLED) { 411 // Log that the bundle is not resolved 412 log.log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_BUNDLE_NOT_RESOLVED, bundles[i].getLocation()), 0, null, null)); 413 continue; 414 } 415 // check that the startlevel allows the bundle to be active (111550) 416 if (tracker == null) { 417 tracker = new ServiceTracker<StartLevel, StartLevel>(context, StartLevel.class.getName(), null); 418 tracker.open(); 419 } 420 StartLevel sl = tracker.getService(); 421 if (sl != null && (sl.getBundleStartLevel(bundles[i]) <= sl.getStartLevel())) { 422 log.log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_BUNDLE_NOT_ACTIVE, bundles[i]), 0, null, null)); 423 } 424 } 425 } 426 } finally { 427 if (tracker != null) 428 tracker.close(); 429 } 430 } 431 432 private static void logUnresolvedBundles(Bundle[] bundles) { 433 State state = adaptor.getState(); 434 FrameworkLog logService = adaptor.getFrameworkLog(); 435 StateHelper stateHelper = adaptor.getPlatformAdmin().getStateHelper(); 436 437 // first lets look for missing leaf constraints (bug 114120) 438 VersionConstraint[] leafConstraints = stateHelper.getUnsatisfiedLeaves(state.getBundles()); 439 // hash the missing leaf constraints by the declaring bundles 440 Map<BundleDescription, List<VersionConstraint>> missing = new HashMap<BundleDescription, List<VersionConstraint>>(); 441 for (int i = 0; i < leafConstraints.length; i++) { 442 // only include non-optional and non-dynamic constraint leafs 443 if (leafConstraints[i] instanceof BundleSpecification && ((BundleSpecification) leafConstraints[i]).isOptional()) 444 continue; 445 if (leafConstraints[i] instanceof ImportPackageSpecification) { 446 if (ImportPackageSpecification.RESOLUTION_OPTIONAL.equals(((ImportPackageSpecification) leafConstraints[i]).getDirective(Constants.RESOLUTION_DIRECTIVE))) 447 continue; 448 if (ImportPackageSpecification.RESOLUTION_DYNAMIC.equals(((ImportPackageSpecification) leafConstraints[i]).getDirective(Constants.RESOLUTION_DIRECTIVE))) 449 continue; 450 } 451 BundleDescription bundle = leafConstraints[i].getBundle(); 452 List<VersionConstraint> constraints = missing.get(bundle); 453 if (constraints == null) { 454 constraints = new ArrayList<VersionConstraint>(); 455 missing.put(bundle, constraints); 456 } 457 constraints.add(leafConstraints[i]); 458 } 459 460 // found some bundles with missing leaf constraints; log them first 461 if (missing.size() > 0) { 462 FrameworkLogEntry[] rootChildren = new FrameworkLogEntry[missing.size()]; 463 int rootIndex = 0; 464 for (Iterator<BundleDescription> iter = missing.keySet().iterator(); iter.hasNext(); rootIndex++) { 465 BundleDescription description = iter.next(); 466 String symbolicName = description.getSymbolicName() == null ? FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME : description.getSymbolicName(); 467 String generalMessage = NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_BUNDLE_NOT_RESOLVED, description.getLocation()); 468 List<VersionConstraint> constraints = missing.get(description); 469 FrameworkLogEntry[] logChildren = new FrameworkLogEntry[constraints.size()]; 470 for (int i = 0; i < logChildren.length; i++) 471 logChildren[i] = new FrameworkLogEntry(symbolicName, FrameworkLogEntry.WARNING, 0, MessageHelper.getResolutionFailureMessage(constraints.get(i)), 0, null, null); 472 rootChildren[rootIndex] = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, generalMessage, 0, null, logChildren); 473 } 474 logService.log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, EclipseAdaptorMsg.ECLIPSE_STARTUP_ROOTS_NOT_RESOLVED, 0, null, rootChildren)); 475 } 476 477 // There may be some bundles unresolved for other reasons, causing the system to be unresolved 478 // log all unresolved constraints now 479 List<FrameworkLogEntry> allChildren = new ArrayList<FrameworkLogEntry>(); 480 for (int i = 0; i < bundles.length; i++) 481 if (bundles[i].getState() == Bundle.INSTALLED) { 482 String symbolicName = bundles[i].getSymbolicName() == null ? FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME : bundles[i].getSymbolicName(); 483 String generalMessage = NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_BUNDLE_NOT_RESOLVED, bundles[i]); 484 BundleDescription description = state.getBundle(bundles[i].getBundleId()); 485 // for some reason, the state does not know about that bundle 486 if (description == null) 487 continue; 488 FrameworkLogEntry[] logChildren = null; 489 VersionConstraint[] unsatisfied = stateHelper.getUnsatisfiedConstraints(description); 490 if (unsatisfied.length > 0) { 491 // the bundle wasn't resolved due to some of its constraints were unsatisfiable 492 logChildren = new FrameworkLogEntry[unsatisfied.length]; 493 for (int j = 0; j < unsatisfied.length; j++) 494 logChildren[j] = new FrameworkLogEntry(symbolicName, FrameworkLogEntry.WARNING, 0, MessageHelper.getResolutionFailureMessage(unsatisfied[j]), 0, null, null); 495 } else { 496 ResolverError[] resolverErrors = state.getResolverErrors(description); 497 if (resolverErrors.length > 0) { 498 logChildren = new FrameworkLogEntry[resolverErrors.length]; 499 for (int j = 0; j < resolverErrors.length; j++) 500 logChildren[j] = new FrameworkLogEntry(symbolicName, FrameworkLogEntry.WARNING, 0, resolverErrors[j].toString(), 0, null, null); 501 } 502 } 503 504 allChildren.add(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, generalMessage, 0, null, logChildren)); 505 } 506 if (allChildren.size() > 0) 507 logService.log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, EclipseAdaptorMsg.ECLIPSE_STARTUP_ALL_NOT_RESOLVED, 0, null, allChildren.toArray(new FrameworkLogEntry[allChildren.size()]))); 508 } 509 510 private static void publishSplashScreen(final Runnable endSplashHandler) { 511 if (endSplashHandler == null) 512 return; 513 // register the output stream to the launcher if it exists 514 try { 515 Method method = endSplashHandler.getClass().getMethod("getOutputStream", new Class[0]); //$NON-NLS-1$ 516 Object outputStream = method.invoke(endSplashHandler, new Object[0]); 517 if (outputStream instanceof OutputStream) { 518 Dictionary<String, Object> osProperties = new Hashtable<String, Object>(); 519 osProperties.put("name", "splashstream"); //$NON-NLS-1$//$NON-NLS-2$ 520 splashStreamRegistration = context.registerService(OutputStream.class.getName(), outputStream, osProperties); 521 } 522 } catch (Exception ex) { 523 // ignore 524 } 525 // keep this splash handler as the default startup monitor 526 try { 527 Dictionary<String, Object> monitorProps = new Hashtable<String, Object>(); 528 monitorProps.put(Constants.SERVICE_RANKING, new Integer(Integer.MIN_VALUE)); 529 defaultMonitorRegistration = context.registerService(StartupMonitor.class.getName(), new DefaultStartupMonitor(endSplashHandler), monitorProps); 530 } catch (IllegalStateException e) { 531 //splash handler did not provide the necessary methods, ignore it 532 } 533 } 534 535 @SuppressWarnings("deprecation") 536 private static URL searchForBundle(String name, String parent) throws MalformedURLException { 537 URL url = null; 538 File fileLocation = null; 539 boolean reference = false; 540 try { 541 new URL(name); // quick check to see if the name is a valid URL 542 url = new URL(new File(parent).toURL(), name); 543 } catch (MalformedURLException e) { 544 // TODO this is legacy support for non-URL names. It should be removed eventually. 545 // if name was not a URL then construct one. 546 // Assume it should be a reference and that it is relative. This support need not 547 // be robust as it is temporary.. 548 File child = new File(name); 549 fileLocation = child.isAbsolute() ? child : new File(parent, name); 550 url = new URL(REFERENCE_PROTOCOL, null, fileLocation.toURL().toExternalForm()); 551 reference = true; 552 } 553 // if the name was a URL then see if it is relative. If so, insert syspath. 554 if (!reference) { 555 URL baseURL = url; 556 // if it is a reference URL then strip off the reference: and set base to the file:... 557 if (url.getProtocol().equals(REFERENCE_PROTOCOL)) { 558 reference = true; 559 String baseSpec = url.getFile(); 560 if (baseSpec.startsWith(FILE_SCHEME)) { 561 File child = new File(baseSpec.substring(5)); 562 baseURL = child.isAbsolute() ? child.toURL() : new File(parent, child.getPath()).toURL(); 563 } else 564 baseURL = new URL(baseSpec); 565 } 566 567 fileLocation = new File(baseURL.getFile()); 568 // if the location is relative, prefix it with the parent 569 if (!fileLocation.isAbsolute()) 570 fileLocation = new File(parent, fileLocation.toString()); 571 } 572 // If the result is a reference then search for the real result and 573 // reconstruct the answer. 574 if (reference) { 575 String result = searchFor(fileLocation.getName(), new File(fileLocation.getParent()).getAbsolutePath()); 576 if (result != null) 577 url = new URL(REFERENCE_PROTOCOL, null, FILE_SCHEME + result); 578 else 579 return null; 580 } 581 582 // finally we have something worth trying 583 try { 584 URLConnection result = url.openConnection(); 585 result.connect(); 586 return url; 587 } catch (IOException e) { 588 // int i = location.lastIndexOf('_'); 589 // return i == -1? location : location.substring(0, i); 590 return null; 591 } 592 } 593 594 /* 595 * Ensure all basic bundles are installed, resolved and scheduled to start. Returns an array containing 596 * all basic bundles that are marked to start. 597 * Returns null if the framework has been shutdown as a result of refreshPackages 598 */ 599 private static Bundle[] loadBasicBundles() { 600 long startTime = System.currentTimeMillis(); 601 String osgiBundles = FrameworkProperties.getProperty(PROP_BUNDLES); 602 String osgiExtensions = FrameworkProperties.getProperty(PROP_EXTENSIONS); 603 if (osgiExtensions != null && osgiExtensions.length() > 0) { 604 osgiBundles = osgiExtensions + ',' + osgiBundles; 605 FrameworkProperties.setProperty(PROP_BUNDLES, osgiBundles); 606 } 607 String[] installEntries = getArrayFromList(osgiBundles, ","); //$NON-NLS-1$ 608 // get the initial bundle list from the installEntries 609 InitialBundle[] initialBundles = getInitialBundles(installEntries); 610 // get the list of currently installed initial bundles from the framework 611 Bundle[] curInitBundles = getCurrentBundles(true); 612 613 // list of bundles to be refreshed 614 List<Bundle> toRefresh = new ArrayList<Bundle>(curInitBundles.length); 615 // uninstall any of the currently installed bundles that do not exist in the 616 // initial bundle list from installEntries. 617 uninstallBundles(curInitBundles, initialBundles, toRefresh); 618 619 // install the initialBundles that are not already installed. 620 List<Bundle> startBundles = new ArrayList<Bundle>(installEntries.length); 621 List<Bundle> lazyActivationBundles = new ArrayList<Bundle>(installEntries.length); 622 installBundles(initialBundles, curInitBundles, startBundles, lazyActivationBundles, toRefresh); 623 624 // If we installed/uninstalled something, force a refresh of all installed/uninstalled bundles 625 if (!toRefresh.isEmpty() && refreshPackages(toRefresh.toArray(new Bundle[toRefresh.size()]))) 626 return null; // cannot continue; refreshPackages shutdown the framework 627 628 // schedule all basic bundles to be started 629 Bundle[] startInitBundles = startBundles.toArray(new Bundle[startBundles.size()]); 630 Bundle[] lazyInitBundles = lazyActivationBundles.toArray(new Bundle[lazyActivationBundles.size()]); 631 startBundles(startInitBundles, lazyInitBundles); 632 633 if (debug) 634 System.out.println("Time to load bundles: " + (System.currentTimeMillis() - startTime)); //$NON-NLS-1$ 635 return startInitBundles; 636 } 637 638 private static InitialBundle[] getInitialBundles(String[] installEntries) { 639 searchCandidates.clear(); 640 List<InitialBundle> result = new ArrayList<InitialBundle>(installEntries.length); 641 int defaultStartLevel = Integer.parseInt(FrameworkProperties.getProperty(PROP_BUNDLES_STARTLEVEL, DEFAULT_BUNDLES_STARTLEVEL)); 642 String syspath = getSysPath(); 643 // should canonicalize the syspath. 644 try { 645 syspath = new File(syspath).getCanonicalPath(); 646 } catch (IOException ioe) { 647 // do nothing 648 } 649 for (int i = 0; i < installEntries.length; i++) { 650 String name = installEntries[i]; 651 int level = defaultStartLevel; 652 boolean start = false; 653 int index = name.lastIndexOf('@'); 654 if (index >= 0) { 655 String[] attributes = getArrayFromList(name.substring(index + 1, name.length()), ":"); //$NON-NLS-1$ 656 for (int j = 0; j < attributes.length; j++) { 657 String attribute = attributes[j]; 658 if (attribute.equals("start")) //$NON-NLS-1$ 659 start = true; 660 else { 661 try { 662 level = Integer.parseInt(attribute); 663 } catch (NumberFormatException e) { // bug 188089 664 index = name.length(); 665 continue; 666 } 667 } 668 } 669 name = name.substring(0, index); 670 } 671 try { 672 URL location = searchForBundle(name, syspath); 673 if (location == null) { 674 FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_BUNDLE_NOT_FOUND, installEntries[i]), 0, null, null); 675 log.log(entry); 676 // skip this entry 677 continue; 678 } 679 location = makeRelative(LocationManager.getInstallLocation().getURL(), location); 680 String locationString = INITIAL_LOCATION + location.toExternalForm(); 681 result.add(new InitialBundle(locationString, location, level, start)); 682 } catch (IOException e) { 683 log.log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, e.getMessage(), 0, e, null)); 684 } 685 } 686 return result.toArray(new InitialBundle[result.size()]); 687 } 688 689 // returns true if the refreshPackages operation caused the framework to shutdown 690 private static boolean refreshPackages(Bundle[] bundles) { 691 ServiceReference<?> packageAdminRef = context.getServiceReference(PackageAdmin.class.getName()); 692 PackageAdmin packageAdmin = null; 693 if (packageAdminRef != null) 694 packageAdmin = (PackageAdmin) context.getService(packageAdminRef); 695 if (packageAdmin == null) 696 return false; 697 // TODO this is such a hack it is silly. There are still cases for race conditions etc 698 // but this should allow for some progress... 699 final Semaphore semaphore = new Semaphore(0); 700 StartupEventListener listener = new StartupEventListener(semaphore, FrameworkEvent.PACKAGES_REFRESHED); 701 context.addFrameworkListener(listener); 702 context.addBundleListener(listener); 703 packageAdmin.refreshPackages(bundles); 704 context.ungetService(packageAdminRef); 705 updateSplash(semaphore, listener); 706 if (isForcedRestart()) 707 return true; 708 return false; 709 } 710 711 private static void waitForShutdown() { 712 if (!isForcedRestart()) 713 return; 714 // wait for the system bundle to stop 715 Bundle systemBundle = framework.getBundle(0); 716 int i = 0; 717 while (i < 5000 && (systemBundle.getState() & (Bundle.STARTING | Bundle.ACTIVE | Bundle.STOPPING)) != 0) { 718 i += 200; 719 try { 720 Thread.sleep(200); 721 } catch (InterruptedException e) { 722 break; 723 } 724 } 725 } 726 727 /** 728 * Creates and returns the adaptor 729 * 730 * @return a FrameworkAdaptor object 731 */ 732 private static FrameworkAdaptor createAdaptor() throws Exception { 733 String adaptorClassName = FrameworkProperties.getProperty(PROP_ADAPTOR, DEFAULT_ADAPTOR_CLASS); 734 Class<?> adaptorClass = Class.forName(adaptorClassName); 735 Class<?>[] constructorArgs = new Class[] {String[].class}; 736 Constructor<?> constructor = adaptorClass.getConstructor(constructorArgs); 737 return (FrameworkAdaptor) constructor.newInstance(new Object[] {new String[0]}); 738 } 739 740 private static String[] processCommandLine(String[] args) throws Exception { 741 EclipseEnvironmentInfo.setAllArgs(args); 742 if (args.length == 0) { 743 EclipseEnvironmentInfo.setFrameworkArgs(args); 744 EclipseEnvironmentInfo.setAllArgs(args); 745 return args; 746 } 747 int[] configArgs = new int[args.length]; 748 configArgs[0] = -1; // need to initialize the first element to something that could not be an index. 749 int configArgIndex = 0; 750 for (int i = 0; i < args.length; i++) { 751 boolean found = false; 752 // check for args without parameters (i.e., a flag arg) 753 754 // check if debug should be enabled for the entire platform 755 // If this is the last arg or there is a following arg (i.e., arg+1 has a leading -), 756 // simply enable debug. Otherwise, assume that that the following arg is 757 // actually the filename of an options file. This will be processed below. 758 if (args[i].equalsIgnoreCase(DEBUG) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$ 759 FrameworkProperties.setProperty(PROP_DEBUG, ""); //$NON-NLS-1$ 760 debug = true; 761 found = true; 762 } 763 764 // check if development mode should be enabled for the entire platform 765 // If this is the last arg or there is a following arg (i.e., arg+1 has a leading -), 766 // simply enable development mode. Otherwise, assume that that the following arg is 767 // actually some additional development time class path entries. This will be processed below. 768 if (args[i].equalsIgnoreCase(DEV) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$ 769 FrameworkProperties.setProperty(PROP_DEV, ""); //$NON-NLS-1$ 770 found = true; 771 } 772 773 // look for the initialization arg 774 if (args[i].equalsIgnoreCase(INITIALIZE)) { 775 initialize = true; 776 found = true; 777 } 778 779 // look for the clean flag. 780 if (args[i].equalsIgnoreCase(CLEAN)) { 781 FrameworkProperties.setProperty(PROP_CLEAN, "true"); //$NON-NLS-1$ 782 found = true; 783 } 784 785 // look for the consoleLog flag 786 if (args[i].equalsIgnoreCase(CONSOLE_LOG)) { 787 FrameworkProperties.setProperty(PROP_CONSOLE_LOG, "true"); //$NON-NLS-1$ 788 found = true; 789 } 790 791 // look for the console with no port. 792 if (args[i].equalsIgnoreCase(CONSOLE) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$ 793 FrameworkProperties.setProperty(PROP_CONSOLE, ""); //$NON-NLS-1$ 794 found = true; 795 } 796 797 if (args[i].equalsIgnoreCase(NOEXIT)) { 798 FrameworkProperties.setProperty(PROP_NOSHUTDOWN, "true"); //$NON-NLS-1$ 799 found = true; 800 } 801 802 if (found) { 803 configArgs[configArgIndex++] = i; 804 continue; 805 } 806 // check for args with parameters. If we are at the last argument or if the next one 807 // has a '-' as the first character, then we can't have an arg with a parm so continue. 808 if (i == args.length - 1 || args[i + 1].startsWith("-")) { //$NON-NLS-1$ 809 continue; 810 } 811 String arg = args[++i]; 812 813 // look for the console and port. 814 if (args[i - 1].equalsIgnoreCase(CONSOLE)) { 815 FrameworkProperties.setProperty(PROP_CONSOLE, arg); 816 found = true; 817 } 818 819 // look for the configuration location . 820 if (args[i - 1].equalsIgnoreCase(CONFIGURATION)) { 821 FrameworkProperties.setProperty(LocationManager.PROP_CONFIG_AREA, arg); 822 found = true; 823 } 824 825 // look for the data location for this instance. 826 if (args[i - 1].equalsIgnoreCase(DATA)) { 827 FrameworkProperties.setProperty(LocationManager.PROP_INSTANCE_AREA, arg); 828 found = true; 829 } 830 831 // look for the user location for this instance. 832 if (args[i - 1].equalsIgnoreCase(USER)) { 833 FrameworkProperties.setProperty(LocationManager.PROP_USER_AREA, arg); 834 found = true; 835 } 836 837 // look for the launcher location 838 if (args[i - 1].equalsIgnoreCase(LAUNCHER)) { 839 FrameworkProperties.setProperty(LocationManager.PROP_LAUNCHER, arg); 840 found = true; 841 } 842 // look for the development mode and class path entries. 843 if (args[i - 1].equalsIgnoreCase(DEV)) { 844 FrameworkProperties.setProperty(PROP_DEV, arg); 845 found = true; 846 } 847 848 // look for the debug mode and option file location. 849 if (args[i - 1].equalsIgnoreCase(DEBUG)) { 850 FrameworkProperties.setProperty(PROP_DEBUG, arg); 851 debug = true; 852 found = true; 853 } 854 855 // look for the window system. 856 if (args[i - 1].equalsIgnoreCase(WS)) { 857 FrameworkProperties.setProperty(PROP_WS, arg); 858 found = true; 859 } 860 861 // look for the operating system 862 if (args[i - 1].equalsIgnoreCase(OS)) { 863 FrameworkProperties.setProperty(PROP_OS, arg); 864 found = true; 865 } 866 867 // look for the system architecture 868 if (args[i - 1].equalsIgnoreCase(ARCH)) { 869 FrameworkProperties.setProperty(PROP_ARCH, arg); 870 found = true; 871 } 872 873 // look for the nationality/language 874 if (args[i - 1].equalsIgnoreCase(NL)) { 875 FrameworkProperties.setProperty(PROP_NL, arg); 876 found = true; 877 } 878 879 // look for the locale extensions 880 if (args[i - 1].equalsIgnoreCase(NL_EXTENSIONS)) { 881 FrameworkProperties.setProperty(PROP_NL_EXTENSIONS, arg); 882 found = true; 883 } 884 885 // done checking for args. Remember where an arg was found 886 if (found) { 887 configArgs[configArgIndex++] = i - 1; 888 configArgs[configArgIndex++] = i; 889 } 890 } 891 892 // remove all the arguments consumed by this argument parsing 893 if (configArgIndex == 0) { 894 EclipseEnvironmentInfo.setFrameworkArgs(new String[0]); 895 EclipseEnvironmentInfo.setAppArgs(args); 896 return args; 897 } 898 String[] appArgs = new String[args.length - configArgIndex]; 899 String[] frameworkArgs = new String[configArgIndex]; 900 configArgIndex = 0; 901 int j = 0; 902 int k = 0; 903 for (int i = 0; i < args.length; i++) { 904 if (i == configArgs[configArgIndex]) { 905 frameworkArgs[k++] = args[i]; 906 configArgIndex++; 907 } else 908 appArgs[j++] = args[i]; 909 } 910 EclipseEnvironmentInfo.setFrameworkArgs(frameworkArgs); 911 EclipseEnvironmentInfo.setAppArgs(appArgs); 912 return appArgs; 913 } 914 915 /** 916 * Returns the result of converting a list of comma-separated tokens into an array 917 * 918 * @return the array of string tokens 919 * @param prop the initial comma-separated string 920 */ 921 private static String[] getArrayFromList(String prop, String separator) { 922 return ManifestElement.getArrayFromList(prop, separator); 923 } 924 925 protected static String getSysPath() { 926 String result = FrameworkProperties.getProperty(PROP_SYSPATH); 927 if (result != null) 928 return result; 929 result = getSysPathFromURL(FrameworkProperties.getProperty(PROP_FRAMEWORK)); 930 if (result == null) 931 result = getSysPathFromCodeSource(); 932 if (result == null) 933 throw new IllegalStateException("Can not find the system path."); //$NON-NLS-1$ 934 if (Character.isUpperCase(result.charAt(0))) { 935 char[] chars = result.toCharArray(); 936 chars[0] = Character.toLowerCase(chars[0]); 937 result = new String(chars); 938 } 939 FrameworkProperties.setProperty(PROP_SYSPATH, result); 940 return result; 941 } 942 943 private static String getSysPathFromURL(String urlSpec) { 944 if (urlSpec == null) 945 return null; 946 URL url = LocationHelper.buildURL(urlSpec, false); 947 if (url == null) 948 return null; 949 File fwkFile = new File(url.getFile()); 950 fwkFile = new File(fwkFile.getAbsolutePath()); 951 fwkFile = new File(fwkFile.getParent()); 952 return fwkFile.getAbsolutePath(); 953 } 954 955 private static String getSysPathFromCodeSource() { 956 ProtectionDomain pd = EclipseStarter.class.getProtectionDomain(); 957 if (pd == null) 958 return null; 959 CodeSource cs = pd.getCodeSource(); 960 if (cs == null) 961 return null; 962 URL url = cs.getLocation(); 963 if (url == null) 964 return null; 965 String result = url.getFile(); 966 if (result.endsWith(".jar")) { //$NON-NLS-1$ 967 result = result.substring(0, result.lastIndexOf('/')); 968 if ("folder".equals(FrameworkProperties.getProperty(PROP_FRAMEWORK_SHAPE))) //$NON-NLS-1$ 969 result = result.substring(0, result.lastIndexOf('/')); 970 } else { 971 if (result.endsWith("/")) //$NON-NLS-1$ 972 result = result.substring(0, result.length() - 1); 973 result = result.substring(0, result.lastIndexOf('/')); 974 result = result.substring(0, result.lastIndexOf('/')); 975 } 976 return result; 977 } 978 979 private static Bundle[] getCurrentBundles(boolean includeInitial) { 980 Bundle[] installed = context.getBundles(); 981 List<Bundle> initial = new ArrayList<Bundle>(); 982 for (int i = 0; i < installed.length; i++) { 983 Bundle bundle = installed[i]; 984 if (bundle.getLocation().startsWith(INITIAL_LOCATION)) { 985 if (includeInitial) 986 initial.add(bundle); 987 } else if (!includeInitial && bundle.getBundleId() != 0) 988 initial.add(bundle); 989 } 990 return initial.toArray(new Bundle[initial.size()]); 991 } 992 993 private static Bundle getBundleByLocation(String location, Bundle[] bundles) { 994 for (int i = 0; i < bundles.length; i++) { 995 Bundle bundle = bundles[i]; 996 if (location.equalsIgnoreCase(bundle.getLocation())) 997 return bundle; 998 } 999 return null; 1000 } 1001 1002 private static void uninstallBundles(Bundle[] curInitBundles, InitialBundle[] newInitBundles, List<Bundle> toRefresh) { 1003 for (int i = 0; i < curInitBundles.length; i++) { 1004 boolean found = false; 1005 for (int j = 0; j < newInitBundles.length; j++) { 1006 if (curInitBundles[i].getLocation().equalsIgnoreCase(newInitBundles[j].locationString)) { 1007 found = true; 1008 break; 1009 } 1010 } 1011 if (!found) 1012 try { 1013 curInitBundles[i].uninstall(); 1014 toRefresh.add(curInitBundles[i]); 1015 } catch (BundleException e) { 1016 FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FAILED_UNINSTALL, curInitBundles[i].getLocation()), 0, e, null); 1017 log.log(entry); 1018 } 1019 } 1020 } 1021 1022 private static void installBundles(InitialBundle[] initialBundles, Bundle[] curInitBundles, List<Bundle> startBundles, List<Bundle> lazyActivationBundles, List<Bundle> toRefresh) { 1023 ServiceReference<?> reference = context.getServiceReference(StartLevel.class.getName()); 1024 StartLevel startService = null; 1025 if (reference != null) 1026 startService = (StartLevel) context.getService(reference); 1027 try { 1028 for (int i = 0; i < initialBundles.length; i++) { 1029 Bundle osgiBundle = getBundleByLocation(initialBundles[i].locationString, curInitBundles); 1030 try { 1031 // don't need to install if it is already installed 1032 if (osgiBundle == null) { 1033 InputStream in = initialBundles[i].location.openStream(); 1034 try { 1035 osgiBundle = context.installBundle(initialBundles[i].locationString, in); 1036 } catch (BundleException e) { 1037 StatusException status = e instanceof StatusException ? (StatusException) e : null; 1038 if (status != null && status.getStatusCode() == StatusException.CODE_OK && status.getStatus() instanceof Bundle) { 1039 osgiBundle = (Bundle) status.getStatus(); 1040 } else 1041 throw e; 1042 } 1043 // only check for lazy activation header if this is a newly installed bundle and is not marked for persistent start 1044 if (!initialBundles[i].start && hasLazyActivationPolicy(osgiBundle)) 1045 lazyActivationBundles.add(osgiBundle); 1046 } 1047 // always set the startlevel incase it has changed (bug 111549) 1048 // this is a no-op if the level is the same as previous launch. 1049 if ((osgiBundle.getState() & Bundle.UNINSTALLED) == 0 && initialBundles[i].level >= 0 && startService != null) 1050 startService.setBundleStartLevel(osgiBundle, initialBundles[i].level); 1051 // if this bundle is supposed to be started then add it to the start list 1052 if (initialBundles[i].start) 1053 startBundles.add(osgiBundle); 1054 // include basic bundles in case they were not resolved before 1055 if ((osgiBundle.getState() & Bundle.INSTALLED) != 0) 1056 toRefresh.add(osgiBundle); 1057 } catch (BundleException e) { 1058 FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FAILED_INSTALL, initialBundles[i].location), 0, e, null); 1059 log.log(entry); 1060 } catch (IOException e) { 1061 FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FAILED_INSTALL, initialBundles[i].location), 0, e, null); 1062 log.log(entry); 1063 } 1064 } 1065 } finally { 1066 if (reference != null) 1067 context.ungetService(reference); 1068 } 1069 } 1070 1071 @SuppressWarnings("deprecation") 1072 private static boolean hasLazyActivationPolicy(Bundle target) { 1073 // check the bundle manifest to see if it defines a lazy activation policy 1074 Dictionary<String, String> headers = target.getHeaders(""); //$NON-NLS-1$ 1075 // first check to see if this is a fragment bundle 1076 String fragmentHost = headers.get(Constants.FRAGMENT_HOST); 1077 if (fragmentHost != null) 1078 return false; // do not activate fragment bundles 1079 // look for the OSGi defined Bundle-ActivationPolicy header 1080 String activationPolicy = headers.get(Constants.BUNDLE_ACTIVATIONPOLICY); 1081 try { 1082 if (activationPolicy != null) { 1083 ManifestElement[] elements = ManifestElement.parseHeader(Constants.BUNDLE_ACTIVATIONPOLICY, activationPolicy); 1084 if (elements != null && elements.length > 0) { 1085 // if the value is "lazy" then it has a lazy activation poliyc 1086 if (Constants.ACTIVATION_LAZY.equals(elements[0].getValue())) 1087 return true; 1088 } 1089 } else { 1090 // check for Eclipse specific lazy start headers "Eclipse-LazyStart" and "Eclipse-AutoStart" 1091 String eclipseLazyStart = headers.get(Constants.ECLIPSE_LAZYSTART); 1092 if (eclipseLazyStart == null) 1093 eclipseLazyStart = headers.get(Constants.ECLIPSE_AUTOSTART); 1094 ManifestElement[] elements = ManifestElement.parseHeader(Constants.ECLIPSE_LAZYSTART, eclipseLazyStart); 1095 if (elements != null && elements.length > 0) { 1096 // if the value is true then it is lazy activated 1097 if ("true".equals(elements[0].getValue())) //$NON-NLS-1$ 1098 return true; 1099 // otherwise it is only lazy activated if it defines an exceptions directive. 1100 else if (elements[0].getDirective("exceptions") != null) //$NON-NLS-1$ 1101 return true; 1102 } 1103 } 1104 } catch (BundleException be) { 1105 // ignore this 1106 } 1107 return false; 1108 } 1109 1110 private static void startBundles(Bundle[] startBundles, Bundle[] lazyBundles) { 1111 for (int i = 0; i < startBundles.length; i++) 1112 startBundle(startBundles[i], 0); 1113 for (int i = 0; i < lazyBundles.length; i++) 1114 startBundle(lazyBundles[i], Bundle.START_ACTIVATION_POLICY); 1115 } 1116 1117 private static void startBundle(Bundle bundle, int options) { 1118 try { 1119 bundle.start(options); 1120 } catch (BundleException e) { 1121 if ((bundle.getState() & Bundle.RESOLVED) != 0) { 1122 // only log errors if the bundle is resolved 1123 FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FAILED_START, bundle.getLocation()), 0, e, null); 1124 log.log(entry); 1125 } 1126 } 1127 } 1128 1129 private static void loadConfigurationInfo() { 1130 Location configArea = LocationManager.getConfigurationLocation(); 1131 if (configArea == null) 1132 return; 1133 1134 URL location = null; 1135 try { 1136 location = new URL(configArea.getURL().toExternalForm() + LocationManager.CONFIG_FILE); 1137 } catch (MalformedURLException e) { 1138 // its ok. This should never happen 1139 } 1140 mergeProperties(FrameworkProperties.getProperties(), loadProperties(location)); 1141 } 1142 1143 private static Properties loadProperties(URL location) { 1144 Properties result = new Properties(); 1145 if (location == null) 1146 return result; 1147 try { 1148 InputStream in = location.openStream(); 1149 try { 1150 result.load(in); 1151 } finally { 1152 in.close(); 1153 } 1154 } catch (IOException e) { 1155 // its ok if there is no file. We'll just use the defaults for everything 1156 // TODO but it might be nice to log something with gentle wording (i.e., it is not an error) 1157 } 1158 return substituteVars(result); 1159 } 1160 1161 private static Properties substituteVars(Properties result) { 1162 if (result == null) { 1163 //nothing todo. 1164 return null; 1165 } 1166 for (Enumeration<Object> eKeys = result.keys(); eKeys.hasMoreElements();) { 1167 Object key = eKeys.nextElement(); 1168 if (key instanceof String) { 1169 String value = result.getProperty((String) key); 1170 if (value != null) 1171 result.put(key, BaseStorageHook.substituteVars(value)); 1172 } 1173 } 1174 return result; 1175 } 1176 1177 /** 1178 * Returns a URL which is equivalent to the given URL relative to the 1179 * specified base URL. Works only for file: URLs 1180 * @throws MalformedURLException 1181 */ 1182 private static URL makeRelative(URL base, URL location) throws MalformedURLException { 1183 if (base == null) 1184 return location; 1185 if (!"file".equals(base.getProtocol())) //$NON-NLS-1$ 1186 return location; 1187 if (!location.getProtocol().equals(REFERENCE_PROTOCOL)) 1188 return location; // we can only make reference urls relative 1189 URL nonReferenceLocation = new URL(location.getPath()); 1190 // if some URL component does not match, return the original location 1191 if (!base.getProtocol().equals(nonReferenceLocation.getProtocol())) 1192 return location; 1193 File locationPath = new File(nonReferenceLocation.getPath()); 1194 // if location is not absolute, return original location 1195 if (!locationPath.isAbsolute()) 1196 return location; 1197 File relativePath = makeRelative(new File(base.getPath()), locationPath); 1198 String urlPath = relativePath.getPath(); 1199 if (File.separatorChar != '/') 1200 urlPath = urlPath.replace(File.separatorChar, '/'); 1201 if (nonReferenceLocation.getPath().endsWith("/")) //$NON-NLS-1$ 1202 // restore original trailing slash 1203 urlPath += '/'; 1204 // couldn't use File to create URL here because it prepends the path with user.dir 1205 URL relativeURL = new URL(base.getProtocol(), base.getHost(), base.getPort(), urlPath); 1206 // now make it back to a reference URL 1207 relativeURL = new URL(REFERENCE_SCHEME + relativeURL.toExternalForm()); 1208 return relativeURL; 1209 } 1210 1211 private static File makeRelative(File base, File location) { 1212 if (!location.isAbsolute()) 1213 return location; 1214 File relative = new File(new FilePath(base).makeRelative(new FilePath(location))); 1215 return relative; 1216 } 1217 1218 private static void mergeProperties(Properties destination, Properties source) { 1219 for (Enumeration<?> e = source.keys(); e.hasMoreElements();) { 1220 String key = (String) e.nextElement(); 1221 String value = source.getProperty(key); 1222 if (destination.getProperty(key) == null) 1223 destination.setProperty(key, value); 1224 } 1225 } 1226 1227 private static void setStartLevel(final int value) { 1228 ServiceReference<?> reference = context.getServiceReference(StartLevel.class.getName()); 1229 final StartLevel startLevel = reference != null ? (StartLevel) context.getService(reference) : null; 1230 if (startLevel == null) 1231 return; 1232 final Semaphore semaphore = new Semaphore(0); 1233 StartupEventListener listener = new StartupEventListener(semaphore, FrameworkEvent.STARTLEVEL_CHANGED); 1234 context.addFrameworkListener(listener); 1235 context.addBundleListener(listener); 1236 startLevel.setStartLevel(value); 1237 context.ungetService(reference); 1238 updateSplash(semaphore, listener); 1239 } 1240 1241 static class StartupEventListener implements SynchronousBundleListener, FrameworkListener { 1242 private final Semaphore semaphore; 1243 private final int frameworkEventType; 1244 1245 public StartupEventListener(Semaphore semaphore, int frameworkEventType) { 1246 this.semaphore = semaphore; 1247 this.frameworkEventType = frameworkEventType; 1248 } 1249 1250 public void bundleChanged(BundleEvent event) { 1251 if (event.getBundle().getBundleId() == 0 && event.getType() == BundleEvent.STOPPING) 1252 semaphore.release(); 1253 } 1254 1255 public void frameworkEvent(FrameworkEvent event) { 1256 if (event.getType() == frameworkEventType) 1257 semaphore.release(); 1258 } 1259 1260 } 1261 1262 private static void updateSplash(Semaphore semaphore, StartupEventListener listener) { 1263 ServiceTracker<StartupMonitor, StartupMonitor> monitorTracker = new ServiceTracker<StartupMonitor, StartupMonitor>(context, StartupMonitor.class.getName(), null); 1264 monitorTracker.open(); 1265 try { 1266 while (true) { 1267 StartupMonitor monitor = monitorTracker.getService(); 1268 if (monitor != null) { 1269 try { 1270 monitor.update(); 1271 } catch (Throwable e) { 1272 // ignore exceptions thrown by the monitor 1273 } 1274 } 1275 // can we acquire the semaphore yet? 1276 if (semaphore.acquire(50)) 1277 break; //done 1278 //else still working, spin another update 1279 } 1280 } finally { 1281 if (listener != null) { 1282 context.removeFrameworkListener(listener); 1283 context.removeBundleListener(listener); 1284 } 1285 monitorTracker.close(); 1286 } 1287 } 1288 1289 /** 1290 * Searches for the given target directory immediately under 1291 * the given start location. If one is found then this location is returned; 1292 * otherwise an exception is thrown. 1293 * 1294 * @return the location where target directory was found 1295 * @param start the location to begin searching 1296 */ 1297 private static String searchFor(final String target, String start) { 1298 String[] candidates = searchCandidates.get(start); 1299 if (candidates == null) { 1300 File startFile = new File(start); 1301 // Pre-check if file exists, if not, and it contains escape characters, 1302 // try decoding the path 1303 if (!startFile.exists() && start.indexOf('%') >= 0) { 1304 String decodePath = FrameworkProperties.decode(start); 1305 File f = new File(decodePath); 1306 if (f.exists()) 1307 startFile = f; 1308 } 1309 candidates = startFile.list(); 1310 if (candidates != null) 1311 searchCandidates.put(start, candidates); 1312 } 1313 if (candidates == null) 1314 return null; 1315 String result = null; 1316 Object[] maxVersion = null; 1317 boolean resultIsFile = false; 1318 for (int i = 0; i < candidates.length; i++) { 1319 String candidateName = candidates[i]; 1320 if (!candidateName.startsWith(target)) 1321 continue; 1322 boolean simpleJar = false; 1323 final char versionSep = candidateName.length() > target.length() ? candidateName.charAt(target.length()) : 0; 1324 if (candidateName.length() > target.length() && versionSep != '_' && versionSep != '-') { 1325 // make sure this is not just a jar with no (_|-)version tacked on the end 1326 if (candidateName.length() == 4 + target.length() && candidateName.endsWith(".jar")) //$NON-NLS-1$ 1327 simpleJar = true; 1328 else 1329 // name does not match the target properly with an (_|-) version at the end 1330 continue; 1331 } 1332 // Note: directory with version suffix is always > than directory without version suffix 1333 String version = candidateName.length() > target.length() + 1 && (versionSep == '_' || versionSep == '-') ? candidateName.substring(target.length() + 1) : ""; //$NON-NLS-1$ 1334 Object[] currentVersion = getVersionElements(version); 1335 if (currentVersion != null && compareVersion(maxVersion, currentVersion) < 0) { 1336 File candidate = new File(start, candidateName); 1337 boolean candidateIsFile = candidate.isFile(); 1338 // if simple jar; make sure it is really a file before accepting it 1339 if (!simpleJar || candidateIsFile) { 1340 result = candidate.getAbsolutePath(); 1341 resultIsFile = candidateIsFile; 1342 maxVersion = currentVersion; 1343 } 1344 } 1345 } 1346 if (result == null) 1347 return null; 1348 return result.replace(File.separatorChar, '/') + (resultIsFile ? "" : "/"); //$NON-NLS-1$ //$NON-NLS-2$ 1349 } 1350 1351 /** 1352 * Do a quick parse of version identifier so its elements can be correctly compared. 1353 * If we are unable to parse the full version, remaining elements are initialized 1354 * with suitable defaults. 1355 * @return an array of size 4; first three elements are of type Integer (representing 1356 * major, minor and service) and the fourth element is of type String (representing 1357 * qualifier). A value of null is returned if there are no valid Integers. Note, that 1358 * returning anything else will cause exceptions in the caller. 1359 */ 1360 private static Object[] getVersionElements(String version) { 1361 Object[] result = {new Integer(-1), new Integer(-1), new Integer(-1), ""}; //$NON-NLS-1$ 1362 StringTokenizer t = new StringTokenizer(version, "."); //$NON-NLS-1$ 1363 String token; 1364 for (int i = 0; t.hasMoreTokens() && i < 4; i++) { 1365 token = t.nextToken(); 1366 if (i < 3) { 1367 // major, minor or service ... numeric values 1368 try { 1369 result[i] = new Integer(token); 1370 } catch (Exception e) { 1371 if (i == 0) 1372 return null; // return null if no valid numbers are present 1373 // invalid number format - use default numbers (-1) for the rest 1374 break; 1375 } 1376 } else { 1377 // qualifier ... string value 1378 result[i] = token; 1379 } 1380 } 1381 return result; 1382 } 1383 1384 /** 1385 * Compares version strings. 1386 * @return result of comparison, as integer; 1387 * <code><0</code> if left < right; 1388 * <code>0</code> if left == right; 1389 * <code>>0</code> if left > right; 1390 */ 1391 private static int compareVersion(Object[] left, Object[] right) { 1392 if (left == null) 1393 return -1; 1394 int result = ((Integer) left[0]).compareTo((Integer) right[0]); // compare major 1395 if (result != 0) 1396 return result; 1397 1398 result = ((Integer) left[1]).compareTo((Integer) right[1]); // compare minor 1399 if (result != 0) 1400 return result; 1401 1402 result = ((Integer) left[2]).compareTo((Integer) right[2]); // compare service 1403 if (result != 0) 1404 return result; 1405 1406 return ((String) left[3]).compareTo((String) right[3]); // compare qualifier 1407 } 1408 1409 private static void finalizeProperties() { 1410 // if check config is unknown and we are in dev mode, 1411 if (FrameworkProperties.getProperty(PROP_DEV) != null && FrameworkProperties.getProperty(PROP_CHECK_CONFIG) == null) 1412 FrameworkProperties.setProperty(PROP_CHECK_CONFIG, "true"); //$NON-NLS-1$ 1413 } 1414 1415 private static class InitialBundle { 1416 public final String locationString; 1417 public final URL location; 1418 public final int level; 1419 public final boolean start; 1420 1421 InitialBundle(String locationString, URL location, int level, boolean start) { 1422 this.locationString = locationString; 1423 this.location = location; 1424 this.level = level; 1425 this.start = start; 1426 } 1427 } 1428 1429 /** 1430 * Sets the initial properties for the platform. 1431 * This method must be called before calling the {@link #run(String[], Runnable)} or 1432 * {@link #startup(String[], Runnable)} methods for the properties to be used in 1433 * a launched instance of the platform. 1434 * <p> 1435 * If the specified properties contains a null value then the key for that value 1436 * will be cleared from the properties of the platform. 1437 * </p> 1438 * @param initialProperties the initial properties to set for the platform. 1439 * @since 3.2 1440 */ 1441 public static void setInitialProperties(Map<String, String> initialProperties) { 1442 if (initialProperties == null || initialProperties.isEmpty()) 1443 return; 1444 for (Map.Entry<String, String> entry : initialProperties.entrySet()) { 1445 if (entry.getValue() != null) 1446 FrameworkProperties.setProperty(entry.getKey(), entry.getValue()); 1447 else 1448 FrameworkProperties.clearProperty(entry.getKey()); 1449 } 1450 } 1451 1452 /** 1453 * Returns the context of the system bundle. A value of 1454 * <code>null</code> is returned if the platform is not running. 1455 * @return the context of the system bundle 1456 * @throws java.lang.SecurityException If the caller does not have the 1457 * appropriate <code>AdminPermission[system.bundle,CONTEXT]</code>, and 1458 * the Java Runtime Environment supports permissions. 1459 */ 1460 public static BundleContext getSystemBundleContext() { 1461 if (context == null || !running) 1462 return null; 1463 return context.getBundle().getBundleContext(); 1464 } 1465 1466 private static boolean isForcedRestart() { 1467 return Boolean.valueOf(FrameworkProperties.getProperty(PROP_FORCED_RESTART)).booleanValue(); 1468 } 1469 1470 /* 1471 * NOTE: This is an internal/experimental method used by launchers that need to react when the framework 1472 * is shutdown internally. 1473 * 1474 * Adds a framework shutdown handler. <p> 1475 * A handler implements the {@link Runnable} interface. When the framework is shutdown 1476 * the {@link Runnable#run()} method is called for each registered handler. Handlers should 1477 * make no assumptions on the thread it is being called from. If a handler object is 1478 * registered multiple times it will be called once for each registration. 1479 * <p> 1480 * At the time a handler is called the framework is shutdown. Handlers must not depend on 1481 * a running framework to execute or attempt to load additional classes from bundles 1482 * installed in the framework. 1483 * @param handler the framework shutdown handler 1484 * @throws IllegalStateException if the platform is already running 1485 */ 1486 static void internalAddFrameworkShutdownHandler(Runnable handler) { 1487 if (running) 1488 throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING); 1489 1490 if (shutdownHandlers == null) 1491 shutdownHandlers = new ArrayList<Runnable>(); 1492 1493 shutdownHandlers.add(handler); 1494 } 1495 1496 /* 1497 * NOTE: This is an internal/experimental method used by launchers that need to react when the framework 1498 * is shutdown internally. 1499 * 1500 * Removes a framework shutdown handler. <p> 1501 * @param handler the framework shutdown handler 1502 * @throws IllegalStateException if the platform is already running 1503 */ 1504 static void internalRemoveFrameworkShutdownHandler(Runnable handler) { 1505 if (running) 1506 throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING); 1507 1508 if (shutdownHandlers != null) 1509 shutdownHandlers.remove(handler); 1510 } 1511 1512 private static void registerFrameworkShutdownHandlers() { 1513 if (shutdownHandlers == null) 1514 return; 1515 1516 final Bundle systemBundle = context.getBundle(); 1517 for (Iterator<Runnable> it = shutdownHandlers.iterator(); it.hasNext();) { 1518 final Runnable handler = it.next(); 1519 BundleListener listener = new BundleListener() { 1520 public void bundleChanged(BundleEvent event) { 1521 if (event.getBundle() == systemBundle && event.getType() == BundleEvent.STOPPED) { 1522 handler.run(); 1523 } 1524 } 1525 }; 1526 context.addBundleListener(listener); 1527 } 1528 } 1529 }
- main() in class EclipseStarter
-
1 /** 2 * This is the main to start osgi. 3 * It only works when the framework is being jared as a single jar 4 */ 5 public static void main(String[] args) throws Exception { 6 if (FrameworkProperties.getProperty("eclipse.startTime") == null) //$NON-NLS-1$ 7 FrameworkProperties.setProperty("eclipse.startTime", Long.toString(System.currentTimeMillis())); //$NON-NLS-1$ 8 if (FrameworkProperties.getProperty(PROP_NOSHUTDOWN) == null) 9 FrameworkProperties.setProperty(PROP_NOSHUTDOWN, "true"); //$NON-NLS-1$ 10 // set the compatibility boot delegation flag to false to get "standard" OSGi behavior WRT boot delegation (bug 178477) 11 if (FrameworkProperties.getProperty(Constants.OSGI_COMPATIBILITY_BOOTDELEGATION) == null) 12 FrameworkProperties.setProperty(Constants.OSGI_COMPATIBILITY_BOOTDELEGATION, "false"); //$NON-NLS-1$ 13 Object result = run(args, null); 14 if (result instanceof Integer && !Boolean.valueOf(FrameworkProperties.getProperty(PROP_NOSHUTDOWN)).booleanValue()) 15 System.exit(((Integer) result).intValue()); 16 }
- run() in class ElipseStarter
-
1 /** 2 * Launches the platform and runs a single application. The application is either identified 3 * in the given arguments (e.g., -application <app id>) or in the <code>eclipse.application</code> 4 * System property. This convenience method starts 5 * up the platform, runs the indicated application, and then shuts down the 6 * platform. The platform must not be running already. 7 * 8 * @param args the command line-style arguments used to configure the platform 9 * @param endSplashHandler the block of code to run to tear down the splash 10 * screen or <code>null</code> if no tear down is required 11 * @return the result of running the application 12 * @throws Exception if anything goes wrong 13 */ 14 public static Object run(String[] args, Runnable endSplashHandler) throws Exception { 15 if (Profile.PROFILE && Profile.STARTUP) 16 Profile.logEnter("EclipseStarter.run()", null); //$NON-NLS-1$ 17 if (running) 18 throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING); 19 boolean startupFailed = true; 20 try { 21 startup(args, endSplashHandler);//endSplashHandler == null 22 startupFailed = false; 23 if (Boolean.valueOf(FrameworkProperties.getProperty(PROP_IGNOREAPP)).booleanValue() || isForcedRestart()) 24 return null; 25 return run(null);//make EclipseAppLauncher run to starup platform 26 } catch (Throwable e) { 27 // ensure the splash screen is down 28 if (endSplashHandler != null) 29 endSplashHandler.run(); 30 // may use startupFailed to understand where the error happened 31 FrameworkLogEntry logEntry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, startupFailed ? EclipseAdaptorMsg.ECLIPSE_STARTUP_STARTUP_ERROR : EclipseAdaptorMsg.ECLIPSE_STARTUP_APP_ERROR, 1, e, null); 32 if (log != null) 33 log.log(logEntry); 34 else 35 // TODO desperate measure - ideally, we should write this to disk (a la Main.log) 36 e.printStackTrace(); 37 } finally { 38 try { 39 // The application typically sets the exit code however the framework can request that 40 // it be re-started. We need to check for this and potentially override the exit code. 41 if (isForcedRestart()) 42 FrameworkProperties.setProperty(PROP_EXITCODE, "23"); //$NON-NLS-1$ 43 if (!Boolean.valueOf(FrameworkProperties.getProperty(PROP_NOSHUTDOWN)).booleanValue()) 44 shutdown(); 45 } catch (Throwable e) { 46 FrameworkLogEntry logEntry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, EclipseAdaptorMsg.ECLIPSE_STARTUP_SHUTDOWN_ERROR, 1, e, null); 47 if (log != null) 48 log.log(logEntry); 49 else 50 // TODO desperate measure - ideally, we should write this to disk (a la Main.log) 51 e.printStackTrace(); 52 } 53 if (Profile.PROFILE && Profile.STARTUP) 54 Profile.logExit("EclipseStarter.run()"); //$NON-NLS-1$ 55 if (Profile.PROFILE) { 56 String report = Profile.getProfileLog(); 57 // avoiding writing to the console if there is nothing to print 58 if (report != null && report.length() > 0) 59 System.out.println(report); 60 } 61 } 62 // we only get here if an error happened 63 if (FrameworkProperties.getProperty(PROP_EXITCODE) == null) { 64 FrameworkProperties.setProperty(PROP_EXITCODE, "13"); //$NON-NLS-1$ 65 FrameworkProperties.setProperty(PROP_EXITDATA, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_CHECK_LOG, log == null ? null : log.getFile().getPath())); 66 } 67 return null; 68 }
- startup in class ElicpseStartup
-
1 /** 2 * Starts the platform and sets it up to run a single application. The application is either identified 3 * in the given arguments (e.g., -application <app id>) or in the <code>eclipse.application</code> 4 * System property. The platform must not be running already. 5 * <p> 6 * The given runnable (if not <code>null</code>) is used to tear down the splash screen if required. 7 * </p> 8 * @param args the arguments passed to the application 9 * @return BundleContext the context of the system bundle 10 * @throws Exception if anything goes wrong 11 */ 12 public static BundleContext startup(String[] args, Runnable endSplashHandler) throws Exception { 13 if (Profile.PROFILE && Profile.STARTUP) 14 Profile.logEnter("EclipseStarter.startup()", null); //$NON-NLS-1$ 15 if (running) 16 throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING); 17 FrameworkProperties.initializeProperties(); // initialize some framework properties that must always be set 18 processCommandLine(args); 19 LocationManager.initializeLocations(); 20 loadConfigurationInfo(); 21 finalizeProperties(); 22 if (Profile.PROFILE) 23 Profile.initProps(); // catch any Profile properties set in eclipse.properties... 24 if (Profile.PROFILE && Profile.STARTUP) 25 Profile.logTime("EclipseStarter.startup()", "props inited"); //$NON-NLS-1$ //$NON-NLS-2$ 26 adaptor = createAdaptor(); 27 log = adaptor.getFrameworkLog(); 28 if (Profile.PROFILE && Profile.STARTUP) 29 Profile.logTime("EclipseStarter.startup()", "adapter created"); //$NON-NLS-1$ //$NON-NLS-2$ 30 framework = new Framework(adaptor); 31 if (Profile.PROFILE && Profile.STARTUP) 32 Profile.logTime("EclipseStarter.startup()", "OSGi created"); //$NON-NLS-1$ //$NON-NLS-2$ 33 context = framework.getBundle(0).getBundleContext(); 34 registerFrameworkShutdownHandlers(); 35 publishSplashScreen(endSplashHandler); 36 if (Profile.PROFILE && Profile.STARTUP) 37 Profile.logTime("EclipseStarter.startup()", "osgi launched"); //$NON-NLS-1$ //$NON-NLS-2$ 38 consoleMgr = ConsoleManager.startConsole(framework); 39 if (Profile.PROFILE && Profile.STARTUP) { 40 Profile.logTime("EclipseStarter.startup()", "console started"); //$NON-NLS-1$ //$NON-NLS-2$ 41 } 42 framework.launch(); 43 // save the cached timestamp before loading basic bundles; this is needed so we can do a proper timestamp check when logging resolver errors 44 long stateStamp = adaptor.getState().getTimeStamp(); 45 Bundle[] startBundles = loadBasicBundles(); 46 47 if (startBundles == null || ("true".equals(FrameworkProperties.getProperty(PROP_REFRESH_BUNDLES)) && refreshPackages(getCurrentBundles(false)))) { //$NON-NLS-1$ 48 waitForShutdown(); 49 return context; // cannot continue; loadBasicBundles caused refreshPackages to shutdown the framework 50 } 51 52 if (Profile.PROFILE && Profile.STARTUP) 53 Profile.logTime("EclipseStarter.startup()", "loading basic bundles"); //$NON-NLS-1$ //$NON-NLS-2$ 54 55 // set the framework start level to the ultimate value. This will actually start things 56 // running if they are persistently active. 57 setStartLevel(getStartLevel()); 58 if (Profile.PROFILE && Profile.STARTUP) 59 Profile.logTime("EclipseStarter.startup()", "StartLevel set"); //$NON-NLS-1$ //$NON-NLS-2$ 60 // they should all be active by this time 61 ensureBundlesActive(startBundles); 62 63 // in the case where the built-in console is disabled we should try to start the console bundle 64 try { 65 consoleMgr.checkForConsoleBundle(); 66 } catch (BundleException e) { 67 FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, e.getMessage(), 0, e, null); 68 log.log(entry); 69 } 70 if (debug || FrameworkProperties.getProperty(PROP_DEV) != null) 71 // only spend time showing unresolved bundles in dev/debug mode and the state has changed 72 if (stateStamp != adaptor.getState().getTimeStamp()) 73 logUnresolvedBundles(context.getBundles()); 74 running = true; 75 if (Profile.PROFILE && Profile.STARTUP) 76 Profile.logExit("EclipseStarter.startup()"); //$NON-NLS-1$ 77 return context; 78 }
- processCommandLine() in class ElicpseStartup
-
1 private static String[] processCommandLine(String[] args) throws Exception { 2 EclipseEnvironmentInfo.setAllArgs(args);//set environment information for use by application runing on Elicpse 3 if (args.length == 0) { 4 EclipseEnvironmentInfo.setFrameworkArgs(args); 5 EclipseEnvironmentInfo.setAllArgs(args); 6 return args; 7 } 8 int[] configArgs = new int[args.length]; 9 configArgs[0] = -1; // need to initialize the first element to something that could not be an index. 10 int configArgIndex = 0; 11 for (int i = 0; i < args.length; i++) { 12 boolean found = false; 13 // check for args without parameters (i.e., a flag arg) 14 15 // check if debug should be enabled for the entire platform 16 // If this is the last arg or there is a following arg (i.e., arg+1 has a leading -), 17 // simply enable debug. Otherwise, assume that that the following arg is 18 // actually the filename of an options file. This will be processed below. 19 if (args[i].equalsIgnoreCase(DEBUG) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$ 20 FrameworkProperties.setProperty(PROP_DEBUG, ""); //$NON-NLS-1$ 21 debug = true; 22 found = true; 23 } 24 25 // check if development mode should be enabled for the entire platform 26 // If this is the last arg or there is a following arg (i.e., arg+1 has a leading -), 27 // simply enable development mode. Otherwise, assume that that the following arg is 28 // actually some additional development time class path entries. This will be processed below. 29 if (args[i].equalsIgnoreCase(DEV) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$ 30 FrameworkProperties.setProperty(PROP_DEV, ""); //$NON-NLS-1$ 31 found = true; 32 } 33 34 // look for the initialization arg 35 if (args[i].equalsIgnoreCase(INITIALIZE)) { 36 initialize = true; 37 found = true; 38 } 39 40 // look for the clean flag. 41 if (args[i].equalsIgnoreCase(CLEAN)) { 42 FrameworkProperties.setProperty(PROP_CLEAN, "true"); //$NON-NLS-1$ 43 found = true; 44 } 45 46 // look for the consoleLog flag 47 if (args[i].equalsIgnoreCase(CONSOLE_LOG)) { 48 FrameworkProperties.setProperty(PROP_CONSOLE_LOG, "true"); //$NON-NLS-1$ 49 found = true; 50 } 51 52 // look for the console with no port. 53 if (args[i].equalsIgnoreCase(CONSOLE) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$ 54 FrameworkProperties.setProperty(PROP_CONSOLE, ""); //$NON-NLS-1$ 55 found = true; 56 } 57 58 if (args[i].equalsIgnoreCase(NOEXIT)) { 59 FrameworkProperties.setProperty(PROP_NOSHUTDOWN, "true"); //$NON-NLS-1$ 60 found = true; 61 } 62 63 if (found) { 64 configArgs[configArgIndex++] = i; 65 continue; 66 } 67 // check for args with parameters. If we are at the last argument or if the next one 68 // has a '-' as the first character, then we can't have an arg with a parm so continue. 69 if (i == args.length - 1 || args[i + 1].startsWith("-")) { //$NON-NLS-1$ 70 continue; 71 } 72 String arg = args[++i]; 73 74 // look for the console and port. 75 if (args[i - 1].equalsIgnoreCase(CONSOLE)) { 76 FrameworkProperties.setProperty(PROP_CONSOLE, arg); 77 found = true; 78 } 79 80 // look for the configuration location . 81 if (args[i - 1].equalsIgnoreCase(CONFIGURATION)) { 82 FrameworkProperties.setProperty(LocationManager.PROP_CONFIG_AREA, arg); 83 found = true; 84 } 85 86 // look for the data location for this instance. 87 if (args[i - 1].equalsIgnoreCase(DATA)) { 88 FrameworkProperties.setProperty(LocationManager.PROP_INSTANCE_AREA, arg); 89 found = true; 90 } 91 92 // look for the user location for this instance. 93 if (args[i - 1].equalsIgnoreCase(USER)) { 94 FrameworkProperties.setProperty(LocationManager.PROP_USER_AREA, arg); 95 found = true; 96 } 97 98 // look for the launcher location 99 if (args[i - 1].equalsIgnoreCase(LAUNCHER)) { 100 FrameworkProperties.setProperty(LocationManager.PROP_LAUNCHER, arg); 101 found = true; 102 } 103 // look for the development mode and class path entries. 104 if (args[i - 1].equalsIgnoreCase(DEV)) { 105 FrameworkProperties.setProperty(PROP_DEV, arg); 106 found = true; 107 } 108 109 // look for the debug mode and option file location. 110 if (args[i - 1].equalsIgnoreCase(DEBUG)) { 111 FrameworkProperties.setProperty(PROP_DEBUG, arg); 112 debug = true; 113 found = true; 114 } 115 116 // look for the window system. 117 if (args[i - 1].equalsIgnoreCase(WS)) { 118 FrameworkProperties.setProperty(PROP_WS, arg); 119 found = true; 120 } 121 122 // look for the operating system 123 if (args[i - 1].equalsIgnoreCase(OS)) { 124 FrameworkProperties.setProperty(PROP_OS, arg); 125 found = true; 126 } 127 128 // look for the system architecture 129 if (args[i - 1].equalsIgnoreCase(ARCH)) { 130 FrameworkProperties.setProperty(PROP_ARCH, arg); 131 found = true; 132 } 133 134 // look for the nationality/language 135 if (args[i - 1].equalsIgnoreCase(NL)) { 136 FrameworkProperties.setProperty(PROP_NL, arg); 137 found = true; 138 } 139 140 // look for the locale extensions 141 if (args[i - 1].equalsIgnoreCase(NL_EXTENSIONS)) { 142 FrameworkProperties.setProperty(PROP_NL_EXTENSIONS, arg); 143 found = true; 144 } 145 146 // done checking for args. Remember where an arg was found 147 if (found) { 148 configArgs[configArgIndex++] = i - 1; 149 configArgs[configArgIndex++] = i; 150 } 151 } 152 153 // remove all the arguments consumed by this argument parsing 154 if (configArgIndex == 0) { 155 EclipseEnvironmentInfo.setFrameworkArgs(new String[0]); 156 EclipseEnvironmentInfo.setAppArgs(args); 157 return args; 158 } 159 String[] appArgs = new String[args.length - configArgIndex]; 160 String[] frameworkArgs = new String[configArgIndex]; 161 configArgIndex = 0; 162 int j = 0; 163 int k = 0; 164 for (int i = 0; i < args.length; i++) { 165 if (i == configArgs[configArgIndex]) { 166 frameworkArgs[k++] = args[i]; 167 configArgIndex++; 168 } else 169 appArgs[j++] = args[i]; 170 } 171 EclipseEnvironmentInfo.setFrameworkArgs(frameworkArgs); 172 EclipseEnvironmentInfo.setAppArgs(appArgs); 173 return appArgs; 174 }
- LocationManager
-
1 /******************************************************************************* 2 * Copyright (c) 2004, 2011 IBM Corporation and others. 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * IBM Corporation - initial API and implementation 10 *******************************************************************************/ 11 package org.eclipse.core.runtime.adaptor; 12 13 import java.io.*; 14 import java.net.MalformedURLException; 15 import java.net.URL; 16 import java.util.Properties; 17 import org.eclipse.core.runtime.internal.adaptor.*; 18 import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; 19 import org.eclipse.osgi.framework.internal.core.Constants; 20 import org.eclipse.osgi.framework.internal.core.FrameworkProperties; 21 import org.eclipse.osgi.internal.baseadaptor.AdaptorUtil; 22 import org.eclipse.osgi.service.datalocation.Location; 23 24 /** 25 * This class is used to manage the various Locations for Eclipse. 26 * <p> 27 * Clients may not extend this class. 28 * </p> 29 * @since 3.1 30 * @noextend This class is not intended to be subclassed by clients. 31 */ 32 public class LocationManager { 33 private static Location installLocation = null; 34 private static Location configurationLocation = null; 35 private static Location userLocation = null; 36 private static Location instanceLocation = null; 37 private static Location eclipseHomeLocation = null; 38 39 public static final String READ_ONLY_AREA_SUFFIX = ".readOnly"; //$NON-NLS-1$ 40 public static final String PROP_INSTALL_AREA = "osgi.install.area"; //$NON-NLS-1$ 41 public static final String PROP_CONFIG_AREA = "osgi.configuration.area"; //$NON-NLS-1$ 42 public static final String PROP_CONFIG_AREA_DEFAULT = "osgi.configuration.area.default"; //$NON-NLS-1$ 43 public static final String PROP_SHARED_CONFIG_AREA = "osgi.sharedConfiguration.area"; //$NON-NLS-1$ 44 public static final String PROP_INSTANCE_AREA = "osgi.instance.area"; //$NON-NLS-1$ 45 public static final String PROP_INSTANCE_AREA_DEFAULT = "osgi.instance.area.default"; //$NON-NLS-1$ 46 public static final String PROP_USER_AREA = "osgi.user.area"; //$NON-NLS-1$ 47 public static final String PROP_USER_AREA_DEFAULT = "osgi.user.area.default"; //$NON-NLS-1$ 48 public static final String PROP_MANIFEST_CACHE = "osgi.manifest.cache"; //$NON-NLS-1$ 49 public static final String PROP_USER_HOME = "user.home"; //$NON-NLS-1$ 50 public static final String PROP_USER_DIR = "user.dir"; //$NON-NLS-1$ 51 public static final String PROP_HOME_LOCATION_AREA = "eclipse.home.location"; //$NON-NLS-1$ 52 static final String PROP_LAUNCHER = "eclipse.launcher"; //$NON-NLS-1$ 53 54 // configuration area file/dir names 55 public static final String BUNDLES_DIR = "bundles"; //$NON-NLS-1$ 56 public static final String STATE_FILE = ".state"; //$NON-NLS-1$ 57 public static final String LAZY_FILE = ".lazy"; //$NON-NLS-1$ 58 public static final String BUNDLE_DATA_FILE = ".bundledata"; //$NON-NLS-1$ 59 public static final String MANIFESTS_DIR = "manifests"; //$NON-NLS-1$ 60 public static final String CONFIG_FILE = "config.ini"; //$NON-NLS-1$ 61 public static final String ECLIPSE_PROPERTIES = "eclipse.properties"; //$NON-NLS-1$ 62 63 // Constants for configuration location discovery 64 private static final String ECLIPSE = "eclipse"; //$NON-NLS-1$ 65 private static final String PRODUCT_SITE_MARKER = ".eclipseproduct"; //$NON-NLS-1$ 66 private static final String PRODUCT_SITE_ID = "id"; //$NON-NLS-1$ 67 private static final String PRODUCT_SITE_VERSION = "version"; //$NON-NLS-1$ 68 69 private static final String CONFIG_DIR = "configuration"; //$NON-NLS-1$ 70 71 // Data mode constants for user, configuration and data locations. 72 private static final String NONE = "@none"; //$NON-NLS-1$ 73 private static final String NO_DEFAULT = "@noDefault"; //$NON-NLS-1$ 74 private static final String USER_HOME = "@user.home"; //$NON-NLS-1$ 75 private static final String USER_DIR = "@user.dir"; //$NON-NLS-1$ 76 // Placeholder for hashcode of installation directory 77 private static final String INSTALL_HASH_PLACEHOLDER = "@install.hash"; //$NON-NLS-1$ 78 79 private static final String INSTANCE_DATA_AREA_PREFIX = ".metadata/.plugins/"; //$NON-NLS-1$ 80 81 /** 82 * Builds a URL with the given specification 83 * @param spec the URL specification 84 * @param trailingSlash flag to indicate a trailing slash on the spec 85 * @return a URL 86 */ 87 public static URL buildURL(String spec, boolean trailingSlash) { 88 return LocationHelper.buildURL(spec, trailingSlash); 89 } 90 91 private static void mungeConfigurationLocation() { 92 // if the config property was set, munge it for backwards compatibility. 93 String location = FrameworkProperties.getProperty(PROP_CONFIG_AREA); 94 if (location != null) { 95 if (location.endsWith(".cfg")) { //$NON-NLS-1$ 96 int index = location.lastIndexOf('/'); 97 if (index < 0) 98 index = location.lastIndexOf('\\'); 99 location = location.substring(0, index + 1); 100 FrameworkProperties.setProperty(PROP_CONFIG_AREA, location); 101 } 102 } 103 } 104 105 /** 106 * Initializes the Location objects for the LocationManager. 107 */ 108 public static void initializeLocations() { 109 // set the osgi storage area if it exists 110 String osgiStorage = FrameworkProperties.getProperty(Constants.FRAMEWORK_STORAGE); 111 if (osgiStorage != null) 112 FrameworkProperties.setProperty(PROP_CONFIG_AREA, osgiStorage); 113 // do install location initialization first since others may depend on it 114 // assumes that the property is already set 115 installLocation = buildLocation(PROP_INSTALL_AREA, null, "", true, false, null); //$NON-NLS-1$ 116 117 // TODO not sure what the data area prefix should be here for the user area 118 Location temp = buildLocation(PROP_USER_AREA_DEFAULT, null, "", false, false, null); //$NON-NLS-1$ 119 URL defaultLocation = temp == null ? null : temp.getURL(); 120 if (defaultLocation == null) 121 defaultLocation = buildURL(new File(FrameworkProperties.getProperty(PROP_USER_HOME), "user").getAbsolutePath(), true); //$NON-NLS-1$ 122 userLocation = buildLocation(PROP_USER_AREA, defaultLocation, "", false, false, null); //$NON-NLS-1$ 123 124 temp = buildLocation(PROP_INSTANCE_AREA_DEFAULT, null, "", false, false, INSTANCE_DATA_AREA_PREFIX); //$NON-NLS-1$ 125 defaultLocation = temp == null ? null : temp.getURL(); 126 if (defaultLocation == null) 127 defaultLocation = buildURL(new File(FrameworkProperties.getProperty(PROP_USER_DIR), "workspace").getAbsolutePath(), true); //$NON-NLS-1$ 128 instanceLocation = buildLocation(PROP_INSTANCE_AREA, defaultLocation, "", false, false, INSTANCE_DATA_AREA_PREFIX); //$NON-NLS-1$ 129 130 mungeConfigurationLocation(); 131 // compute a default but it is very unlikely to be used since main will have computed everything 132 temp = buildLocation(PROP_CONFIG_AREA_DEFAULT, null, "", false, false, null); //$NON-NLS-1$ 133 defaultLocation = temp == null ? null : temp.getURL(); 134 if (defaultLocation == null && FrameworkProperties.getProperty(PROP_CONFIG_AREA) == null) 135 // only compute the default if the configuration area property is not set 136 defaultLocation = buildURL(computeDefaultConfigurationLocation(), true); 137 configurationLocation = buildLocation(PROP_CONFIG_AREA, defaultLocation, "", false, false, null); //$NON-NLS-1$ 138 // get the parent location based on the system property. This will have been set on the 139 // way in either by the caller/user or by main. There will be no parent location if we are not 140 // cascaded. 141 URL parentLocation = computeSharedConfigurationLocation(); 142 if (parentLocation != null && !parentLocation.equals(configurationLocation.getURL())) { 143 Location parent = new BasicLocation(null, parentLocation, true, null); 144 ((BasicLocation) configurationLocation).setParent(parent); 145 } 146 initializeDerivedConfigurationLocations(); 147 148 if (FrameworkProperties.getProperty(PROP_HOME_LOCATION_AREA) == null) { 149 String eclipseLauncher = FrameworkProperties.getProperty(PROP_LAUNCHER); 150 String eclipseHomeLocationPath = getEclipseHomeLocation(eclipseLauncher); 151 if (eclipseHomeLocationPath != null) 152 FrameworkProperties.setProperty(PROP_HOME_LOCATION_AREA, eclipseHomeLocationPath); 153 } 154 // if eclipse.home.location is not set then default to osgi.install.area 155 if (FrameworkProperties.getProperty(PROP_HOME_LOCATION_AREA) == null && FrameworkProperties.getProperty(PROP_INSTALL_AREA) != null) 156 FrameworkProperties.setProperty(PROP_HOME_LOCATION_AREA, FrameworkProperties.getProperty(PROP_INSTALL_AREA)); 157 eclipseHomeLocation = buildLocation(PROP_HOME_LOCATION_AREA, null, "", true, true, null); //$NON-NLS-1$ 158 } 159 160 private static String getEclipseHomeLocation(String launcher) { 161 if (launcher == null) 162 return null; 163 File launcherFile = new File(launcher); 164 if (launcherFile.getParent() == null) 165 return null; 166 File launcherDir = new File(launcherFile.getParent()); 167 // check for mac os; the os check is copied from EclipseEnvironmentInfo. 168 String macosx = org.eclipse.osgi.service.environment.Constants.OS_MACOSX; 169 if (macosx.equals(EclipseEnvironmentInfo.getDefault().getOS())) 170 launcherDir = getMacOSEclipsoeHomeLocation(launcherDir); 171 return (launcherDir.exists() && launcherDir.isDirectory()) ? launcherDir.getAbsolutePath() : null; 172 } 173 174 private static File getMacOSEclipsoeHomeLocation(File launcherDir) { 175 // TODO for now we go up three directories from the launcher dir as long as the parent dir is named MacOS; is this always the case? 176 // TODO not sure if case is important 177 if (!launcherDir.getName().equalsIgnoreCase("macos")) //$NON-NLS-1$ 178 return launcherDir; // don't do the up three stuff if not in macos directory 179 String launcherParent = launcherDir.getParent(); 180 if (launcherParent != null) 181 launcherParent = new File(launcherParent).getParent(); 182 if (launcherParent != null) 183 launcherParent = new File(launcherParent).getParent(); 184 return launcherParent == null ? null : new File(launcherParent); 185 } 186 187 @SuppressWarnings("deprecation") 188 private static Location buildLocation(String property, URL defaultLocation, String userDefaultAppendage, boolean readOnlyDefault, boolean computeReadOnly, String dataAreaPrefix) { 189 String location = FrameworkProperties.clearProperty(property); 190 // the user/product may specify a non-default readOnly setting 191 String userReadOnlySetting = FrameworkProperties.getProperty(property + READ_ONLY_AREA_SUFFIX); 192 boolean readOnly = (userReadOnlySetting == null ? readOnlyDefault : Boolean.valueOf(userReadOnlySetting).booleanValue()); 193 // if the instance location is not set, predict where the workspace will be and 194 // put the instance area inside the workspace meta area. 195 if (location == null) 196 return new BasicLocation(property, defaultLocation, userReadOnlySetting != null || !computeReadOnly ? readOnly : !canWrite(defaultLocation), dataAreaPrefix); 197 String trimmedLocation = location.trim(); 198 if (trimmedLocation.equalsIgnoreCase(NONE)) 199 return null; 200 if (trimmedLocation.equalsIgnoreCase(NO_DEFAULT)) 201 return new BasicLocation(property, null, readOnly, dataAreaPrefix); 202 if (trimmedLocation.startsWith(USER_HOME)) { 203 String base = substituteVar(location, USER_HOME, PROP_USER_HOME); 204 location = new File(base, userDefaultAppendage).getAbsolutePath(); 205 } else if (trimmedLocation.startsWith(USER_DIR)) { 206 String base = substituteVar(location, USER_DIR, PROP_USER_DIR); 207 location = new File(base, userDefaultAppendage).getAbsolutePath(); 208 } 209 int idx = location.indexOf(INSTALL_HASH_PLACEHOLDER); 210 if (idx == 0) { 211 throw new RuntimeException("The location cannot start with '" + INSTALL_HASH_PLACEHOLDER + "': " + location); //$NON-NLS-1$ //$NON-NLS-2$ 212 } else if (idx > 0) { 213 location = location.substring(0, idx) + getInstallDirHash() + location.substring(idx + INSTALL_HASH_PLACEHOLDER.length()); 214 } 215 URL url = buildURL(location, true); 216 BasicLocation result = null; 217 if (url != null) { 218 result = new BasicLocation(property, null, userReadOnlySetting != null || !computeReadOnly ? readOnly : !canWrite(url), dataAreaPrefix); 219 result.setURL(url, false); 220 } 221 return result; 222 } 223 224 private static String substituteVar(String source, String var, String prop) { 225 String value = FrameworkProperties.getProperty(prop, ""); //$NON-NLS-1$ 226 return value + source.substring(var.length()); 227 } 228 229 private static void initializeDerivedConfigurationLocations() { 230 if (FrameworkProperties.getProperty(PROP_MANIFEST_CACHE) == null) 231 FrameworkProperties.setProperty(PROP_MANIFEST_CACHE, getConfigurationFile(MANIFESTS_DIR).getAbsolutePath()); 232 } 233 234 private static URL computeInstallConfigurationLocation() { 235 String property = FrameworkProperties.getProperty(PROP_INSTALL_AREA); 236 if (property != null) 237 return LocationHelper.buildURL(property, true); 238 return null; 239 } 240 241 private static URL computeSharedConfigurationLocation() { 242 String property = FrameworkProperties.getProperty(PROP_SHARED_CONFIG_AREA); 243 if (property == null) 244 return null; 245 try { 246 URL sharedConfigurationURL = LocationHelper.buildURL(property, true); 247 if (sharedConfigurationURL == null) 248 return null; 249 if (sharedConfigurationURL.getPath().startsWith("/")) //$NON-NLS-1$ 250 // absolute 251 return sharedConfigurationURL; 252 URL installURL = installLocation.getURL(); 253 if (!sharedConfigurationURL.getProtocol().equals(installURL.getProtocol())) 254 // different protocol 255 return sharedConfigurationURL; 256 sharedConfigurationURL = new URL(installURL, sharedConfigurationURL.getPath()); 257 FrameworkProperties.setProperty(PROP_SHARED_CONFIG_AREA, sharedConfigurationURL.toExternalForm()); 258 } catch (MalformedURLException e) { 259 // do nothing here since it is basically impossible to get a bogus url 260 } 261 return null; 262 } 263 264 private static String computeDefaultConfigurationLocation() { 265 // 1) We store the config state relative to the 'eclipse' directory if possible 266 // 2) If this directory is read-only 267 // we store the state in <user.home>/.eclipse/<application-id>_<version> where <user.home> 268 // is unique for each local user, and <application-id> is the one 269 // defined in .eclipseproduct marker file. If .eclipseproduct does not 270 // exist, use "eclipse" as the application-id. 271 272 URL installURL = computeInstallConfigurationLocation(); 273 if (installURL != null && "file".equals(installURL.getProtocol())) { //$NON-NLS-1$ 274 File installDir = new File(installURL.getFile()); 275 File defaultConfigDir = new File(installDir, CONFIG_DIR); 276 if (!defaultConfigDir.exists()) 277 defaultConfigDir.mkdirs(); 278 if (defaultConfigDir.exists() && AdaptorUtil.canWrite(defaultConfigDir)) 279 return defaultConfigDir.getAbsolutePath(); 280 } 281 // We can't write in the eclipse install dir so try for some place in the user's home dir 282 return computeDefaultUserAreaLocation(CONFIG_DIR); 283 } 284 285 private static boolean canWrite(URL location) { 286 if (location != null && "file".equals(location.getProtocol())) { //$NON-NLS-1$ 287 File locationDir = new File(location.getFile()); 288 if (!locationDir.exists()) 289 locationDir.mkdirs(); 290 if (locationDir.exists() && AdaptorUtil.canWrite(locationDir)) 291 return true; 292 } 293 return false; 294 } 295 296 private static String computeDefaultUserAreaLocation(String pathAppendage) { 297 // we store the state in <user.home>/.eclipse/<application-id>_<version> where <user.home> 298 // is unique for each local user, and <application-id> is the one 299 // defined in .eclipseproduct marker file. If .eclipseproduct does not 300 // exist, use "eclipse" as the application-id. 301 String installProperty = FrameworkProperties.getProperty(PROP_INSTALL_AREA); 302 URL installURL = buildURL(installProperty, true); 303 if (installURL == null) 304 return null; 305 File installDir = new File(installURL.getFile()); 306 String installDirHash = getInstallDirHash(); 307 308 String appName = "." + ECLIPSE; //$NON-NLS-1$ 309 File eclipseProduct = new File(installDir, PRODUCT_SITE_MARKER); 310 if (eclipseProduct.exists()) { 311 Properties props = new Properties(); 312 try { 313 props.load(new FileInputStream(eclipseProduct)); 314 String appId = props.getProperty(PRODUCT_SITE_ID); 315 if (appId == null || appId.trim().length() == 0) 316 appId = ECLIPSE; 317 String appVersion = props.getProperty(PRODUCT_SITE_VERSION); 318 if (appVersion == null || appVersion.trim().length() == 0) 319 appVersion = ""; //$NON-NLS-1$ 320 appName += File.separator + appId + "_" + appVersion + "_" + installDirHash; //$NON-NLS-1$ //$NON-NLS-2$ 321 } catch (IOException e) { 322 // Do nothing if we get an exception. We will default to a standard location 323 // in the user's home dir. 324 // add the hash to help prevent collisions 325 appName += File.separator + installDirHash; 326 } 327 } else { 328 // add the hash to help prevent collisions 329 appName += File.separator + installDirHash; 330 } 331 String userHome = FrameworkProperties.getProperty(PROP_USER_HOME); 332 return new File(userHome, appName + "/" + pathAppendage).getAbsolutePath(); //$NON-NLS-1$ 333 } 334 335 /** 336 * Return hash code identifying an absolute installation path 337 * @return hash code as String 338 */ 339 private static String getInstallDirHash() { 340 // compute an install dir hash to prevent configuration area collisions with other eclipse installs 341 String installProperty = FrameworkProperties.getProperty(PROP_INSTALL_AREA); 342 URL installURL = buildURL(installProperty, true); 343 if (installURL == null) 344 return ""; //$NON-NLS-1$ 345 File installDir = new File(installURL.getFile()); 346 int hashCode; 347 try { 348 hashCode = installDir.getCanonicalPath().hashCode(); 349 } catch (IOException ioe) { 350 // fall back to absolute path 351 hashCode = installDir.getAbsolutePath().hashCode(); 352 } 353 if (hashCode < 0) 354 hashCode = -(hashCode); 355 String installDirHash = String.valueOf(hashCode); 356 return installDirHash; 357 } 358 359 /** 360 * Returns the user Location object 361 * @return the user Location object 362 */ 363 public static Location getUserLocation() { 364 return userLocation; 365 } 366 367 /** 368 * Returns the configuration Location object 369 * @return the configuration Location object 370 */ 371 public static Location getConfigurationLocation() { 372 return configurationLocation; 373 } 374 375 /** 376 * Returns the install Location object 377 * @return the install Location object 378 */ 379 public static Location getInstallLocation() { 380 return installLocation; 381 } 382 383 /** 384 * Returns the instance Location object 385 * @return the instance Location object 386 */ 387 public static Location getInstanceLocation() { 388 return instanceLocation; 389 } 390 391 public static Location getEclipseHomeLocation() { 392 return eclipseHomeLocation; 393 } 394 395 /** 396 * Returns the File object under the configuration location used for the OSGi configuration 397 * @return the OSGi configuration directory 398 */ 399 public static File getOSGiConfigurationDir() { 400 // TODO assumes the URL is a file: url 401 return new File(configurationLocation.getURL().getFile(), FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME); 402 } 403 404 /** 405 * Returns a file from the configuration area that can be used by the framework 406 * @param filename the filename 407 * @return a file from the configuration area 408 */ 409 public static File getConfigurationFile(String filename) { 410 File dir = getOSGiConfigurationDir(); 411 if (!dir.exists()) 412 dir.mkdirs(); 413 return new File(dir, filename); 414 } 415 }
- createAdaptor
DEFAULT_ADAPTER_CLASS = org.eclipse.osgi.baseadaptor.BaseAdaptor

1 /******************************************************************************* 2 * Copyright (c) 2005, 2011 IBM Corporation and others. 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * IBM Corporation - initial API and implementation 10 *******************************************************************************/ 11 12 package org.eclipse.osgi.baseadaptor; 13 14 import java.io.*; 15 import java.net.URL; 16 import java.net.URLConnection; 17 import java.util.*; 18 import org.eclipse.core.runtime.adaptor.LocationManager; 19 import org.eclipse.osgi.baseadaptor.bundlefile.BundleFile; 20 import org.eclipse.osgi.baseadaptor.hooks.*; 21 import org.eclipse.osgi.framework.adaptor.*; 22 import org.eclipse.osgi.framework.debug.Debug; 23 import org.eclipse.osgi.framework.internal.core.*; 24 import org.eclipse.osgi.framework.internal.core.Constants; 25 import org.eclipse.osgi.framework.log.FrameworkLog; 26 import org.eclipse.osgi.framework.log.FrameworkLogEntry; 27 import org.eclipse.osgi.internal.baseadaptor.*; 28 import org.eclipse.osgi.service.resolver.PlatformAdmin; 29 import org.eclipse.osgi.service.resolver.State; 30 import org.eclipse.osgi.util.NLS; 31 import org.osgi.framework.*; 32 import org.osgi.framework.wiring.BundleWiring; 33 34 /** 35 * A Framework adaptor implementation that allows additional functionality to be 36 * hooked in. Hooks are configured using {@link HookConfigurator} 37 * objects. A framework extension may add hook configurators which can be used 38 * to add hooks to the {@link HookRegistry}. 39 * @see HookConfigurator 40 * @see HookRegistry 41 * @see AdaptorHook 42 * @since 3.2 43 */ 44 public class BaseAdaptor implements FrameworkAdaptor { 45 // System property used to set the parent classloader type (boot is the default) 46 private static final String PROP_PARENT_CLASSLOADER = "osgi.parentClassloader"; //$NON-NLS-1$ 47 // A parent classloader type that specifies the application classloader 48 private static final String PARENT_CLASSLOADER_APP = "app"; //$NON-NLS-1$ 49 // A parent classloader type that specifies the extension classlaoder 50 private static final String PARENT_CLASSLOADER_EXT = "ext"; //$NON-NLS-1$ 51 // A parent classloader type that specifies the boot classlaoder 52 private static final String PARENT_CLASSLOADER_BOOT = "boot"; //$NON-NLS-1$ 53 // A parent classloader type that specifies the framework classlaoder 54 private static final String PARENT_CLASSLOADER_FWK = "fwk"; //$NON-NLS-1$ 55 // The BundleClassLoader parent to use when creating BundleClassLoaders. 56 private static ClassLoader bundleClassLoaderParent; 57 static { 58 // check property for specified parent 59 // check the osgi defined property first 60 String type = FrameworkProperties.getProperty(Constants.FRAMEWORK_BUNDLE_PARENT); 61 if (type != null) { 62 if (Constants.FRAMEWORK_BUNDLE_PARENT_FRAMEWORK.equals(type)) 63 type = PARENT_CLASSLOADER_FWK; 64 } else { 65 type = FrameworkProperties.getProperty(BaseAdaptor.PROP_PARENT_CLASSLOADER, BaseAdaptor.PARENT_CLASSLOADER_BOOT); 66 } 67 68 if (BaseAdaptor.PARENT_CLASSLOADER_FWK.equalsIgnoreCase(type)) 69 bundleClassLoaderParent = FrameworkAdaptor.class.getClassLoader(); 70 else if (BaseAdaptor.PARENT_CLASSLOADER_APP.equalsIgnoreCase(type)) 71 bundleClassLoaderParent = ClassLoader.getSystemClassLoader(); 72 else if (BaseAdaptor.PARENT_CLASSLOADER_EXT.equalsIgnoreCase(type)) { 73 ClassLoader appCL = ClassLoader.getSystemClassLoader(); 74 if (appCL != null) 75 bundleClassLoaderParent = appCL.getParent(); 76 } 77 // default to boot classloader 78 if (bundleClassLoaderParent == null) 79 bundleClassLoaderParent = new ClassLoader(Object.class.getClassLoader()) {/* boot class loader*/}; 80 } 81 82 private Framework eventPublisher; 83 private boolean stopping; 84 private HookRegistry hookRegistry; 85 private FrameworkLog log; 86 private BundleContext context; 87 private BaseStorage storage; 88 private BundleWatcher bundleWatcher; 89 90 /** 91 * Constructs a BaseAdaptor. 92 * @param args arguments passed to the adaptor by the framework. 93 */ 94 public BaseAdaptor(String[] args) { 95 if (LocationManager.getConfigurationLocation() == null) 96 LocationManager.initializeLocations(); 97 hookRegistry = new HookRegistry(this); 98 FrameworkLogEntry[] errors = hookRegistry.initialize(); 99 if (errors.length > 0) 100 for (int i = 0; i < errors.length; i++) 101 getFrameworkLog().log(errors[i]); 102 // get the storage after the registry has been initialized 103 storage = getStorage(); 104 // TODO consider passing args to BaseAdaptorHooks 105 } 106 107 /** 108 * This method will call all configured adaptor hooks {@link AdaptorHook#initialize(BaseAdaptor)} method. 109 * @see FrameworkAdaptor#initialize(EventPublisher) 110 */ 111 public void initialize(EventPublisher publisher) { 112 this.eventPublisher = (Framework) publisher; 113 // set the adaptor for the adaptor hooks 114 AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks(); 115 for (int i = 0; i < adaptorHooks.length; i++) 116 adaptorHooks[i].initialize(this); 117 } 118 119 /** 120 * @see FrameworkAdaptor#initializeStorage() 121 */ 122 public void initializeStorage() throws IOException { 123 storage.initialize(this); 124 } 125 126 /** 127 * @throws IOException 128 * @see FrameworkAdaptor#compactStorage() 129 */ 130 public void compactStorage() throws IOException { 131 storage.compact(); 132 } 133 134 /** 135 * This method will call all the configured adaptor hook {@link AdaptorHook#addProperties(Properties)} methods. 136 * @see FrameworkAdaptor#getProperties() 137 */ 138 public Properties getProperties() { 139 Properties props = new Properties(); 140 String resource = FrameworkProperties.getProperty(Constants.OSGI_PROPERTIES, Constants.DEFAULT_OSGI_PROPERTIES); 141 try { 142 InputStream in = null; 143 File file = new File(resource); 144 if (file.exists()) 145 in = new FileInputStream(file); 146 if (in == null) 147 in = getClass().getResourceAsStream(resource); 148 if (in != null) { 149 try { 150 props.load(new BufferedInputStream(in)); 151 } finally { 152 try { 153 in.close(); 154 } catch (IOException ee) { 155 // nothing to do 156 } 157 } 158 } else { 159 if (Debug.DEBUG_GENERAL) 160 Debug.println("Skipping osgi.properties: " + resource); //$NON-NLS-1$ 161 } 162 } catch (IOException e) { 163 if (Debug.DEBUG_GENERAL) 164 Debug.println("Unable to load osgi.properties: " + e.getMessage()); //$NON-NLS-1$ 165 } 166 // add the storage properties 167 storage.addProperties(props); 168 // add the properties from each adaptor hook 169 AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks(); 170 for (int i = 0; i < adaptorHooks.length; i++) 171 adaptorHooks[i].addProperties(props); 172 return props; 173 } 174 175 /** 176 * @see FrameworkAdaptor#getInstalledBundles() 177 */ 178 public BundleData[] getInstalledBundles() { 179 return storage.getInstalledBundles(); 180 } 181 182 /** 183 * This method will call each configured adaptor hook {@link AdaptorHook#mapLocationToURLConnection(String)} method 184 * until one returns a non-null value. If none of the adaptor hooks return a non-null value then the 185 * string is used to construct a new URL object to open a new url connection. 186 * 187 * @see FrameworkAdaptor#mapLocationToURLConnection(String) 188 */ 189 public URLConnection mapLocationToURLConnection(String location) throws BundleException { 190 try { 191 URLConnection result = null; 192 // try the adaptor hooks first; 193 AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks(); 194 for (int i = 0; i < adaptorHooks.length; i++) { 195 result = adaptorHooks[i].mapLocationToURLConnection(location); 196 if (result != null) 197 return result; 198 } 199 // just do the default 200 return (new URL(location).openConnection()); 201 } catch (IOException e) { 202 throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_URL_CREATE_EXCEPTION, location), e); 203 } 204 } 205 206 /** 207 * @see FrameworkAdaptor#installBundle(String, URLConnection) 208 */ 209 public BundleOperation installBundle(String location, URLConnection source) { 210 return storage.installBundle(location, source); 211 } 212 213 /** 214 * @see FrameworkAdaptor#updateBundle(BundleData, URLConnection) 215 */ 216 public BundleOperation updateBundle(BundleData bundledata, URLConnection source) { 217 return storage.updateBundle((BaseData) bundledata, source); 218 } 219 220 /** 221 * @see FrameworkAdaptor#uninstallBundle(BundleData) 222 */ 223 public BundleOperation uninstallBundle(BundleData bundledata) { 224 return storage.uninstallBundle((BaseData) bundledata); 225 } 226 227 /** 228 * @see FrameworkAdaptor#getTotalFreeSpace() 229 */ 230 public long getTotalFreeSpace() throws IOException { 231 return storage.getFreeSpace(); 232 } 233 234 /** 235 * @throws IOException 236 * @see FrameworkAdaptor#getPermissionStorage() 237 */ 238 public PermissionStorage getPermissionStorage() throws IOException { 239 return storage.getPermissionStorage(); 240 } 241 242 /** 243 * This method calls all the configured adaptor hook {@link AdaptorHook#frameworkStart(BundleContext)} methods. 244 * @see FrameworkAdaptor#frameworkStart(BundleContext) 245 */ 246 public void frameworkStart(BundleContext fwContext) throws BundleException { 247 this.context = fwContext; 248 stopping = false; 249 // always start the storage first 250 storage.frameworkStart(fwContext); 251 AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks(); 252 for (int i = 0; i < adaptorHooks.length; i++) 253 adaptorHooks[i].frameworkStart(fwContext); 254 } 255 256 /** 257 * This method calls all the configured adaptor hook {@link AdaptorHook#frameworkStop(BundleContext)} methods. 258 * @see FrameworkAdaptor#frameworkStop(BundleContext) 259 */ 260 public void frameworkStop(BundleContext fwContext) throws BundleException { 261 // first inform all configured adaptor hooks 262 AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks(); 263 for (int i = 0; i < adaptorHooks.length; i++) 264 adaptorHooks[i].frameworkStop(fwContext); 265 // stop the storage last 266 storage.frameworkStop(fwContext); 267 } 268 269 /** 270 * This method calls all the configured adaptor hook {@link AdaptorHook#frameworkStopping(BundleContext)} methods. 271 * @see FrameworkAdaptor#frameworkStopping(BundleContext) 272 */ 273 public void frameworkStopping(BundleContext fwContext) { 274 stopping = true; 275 // always tell storage of stopping first 276 storage.frameworkStopping(fwContext); 277 // inform all configured adaptor hooks last 278 AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks(); 279 for (int i = 0; i < adaptorHooks.length; i++) 280 adaptorHooks[i].frameworkStopping(fwContext); 281 } 282 283 /** 284 * @see FrameworkAdaptor#getInitialBundleStartLevel() 285 */ 286 public int getInitialBundleStartLevel() { 287 return storage.getInitialBundleStartLevel(); 288 } 289 290 /** 291 * @see FrameworkAdaptor#setInitialBundleStartLevel(int) 292 */ 293 public void setInitialBundleStartLevel(int value) { 294 storage.setInitialBundleStartLevel(value); 295 } 296 297 /** 298 * This method calls all configured adaptor hook {@link AdaptorHook#createFrameworkLog()} methods 299 * until the first one returns a non-null value. If none of the adaptor hooks return a non-null 300 * value then a framework log implementation which does nothing is returned. 301 * @see FrameworkAdaptor#getFrameworkLog() 302 */ 303 public FrameworkLog getFrameworkLog() { 304 if (log != null) 305 return log; 306 AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks(); 307 for (int i = 0; i < adaptorHooks.length; i++) { 308 log = adaptorHooks[i].createFrameworkLog(); 309 if (log != null) 310 return log; 311 } 312 log = new FrameworkLog() { 313 public void log(FrameworkEvent frameworkEvent) { 314 log(new FrameworkLogEntry(frameworkEvent.getBundle().getSymbolicName() == null ? frameworkEvent.getBundle().getLocation() : frameworkEvent.getBundle().getSymbolicName(), FrameworkLogEntry.ERROR, 0, "FrameworkEvent.ERROR", 0, frameworkEvent.getThrowable(), null)); //$NON-NLS-1$ 315 } 316 317 public void log(FrameworkLogEntry logEntry) { 318 System.err.print(logEntry.getEntry() + " "); //$NON-NLS-1$ 319 System.err.println(logEntry.getMessage()); 320 if (logEntry.getThrowable() != null) 321 logEntry.getThrowable().printStackTrace(System.err); 322 } 323 324 public void setWriter(Writer newWriter, boolean append) { 325 // do nothing 326 } 327 328 /** 329 * @throws IOException 330 */ 331 public void setFile(File newFile, boolean append) throws IOException { 332 // do nothing 333 } 334 335 public File getFile() { 336 // do nothing 337 return null; 338 } 339 340 public void setConsoleLog(boolean consoleLog) { 341 // do nothing 342 } 343 344 public void close() { 345 // do nothing 346 } 347 }; 348 return log; 349 } 350 351 /** 352 * @see FrameworkAdaptor#createSystemBundleData() 353 */ 354 public BundleData createSystemBundleData() throws BundleException { 355 return new SystemBundleData(this); 356 } 357 358 /** 359 * @see FrameworkAdaptor#getBundleWatcher() 360 */ 361 public BundleWatcher getBundleWatcher() { 362 if (bundleWatcher != null) 363 return bundleWatcher; 364 final BundleWatcher[] watchers = hookRegistry.getWatchers(); 365 if (watchers.length == 0) 366 return null; 367 bundleWatcher = new BundleWatcher() { 368 public void watchBundle(Bundle bundle, int type) { 369 for (int i = 0; i < watchers.length; i++) 370 watchers[i].watchBundle(bundle, type); 371 } 372 }; 373 return bundleWatcher; 374 } 375 376 /** 377 * @see FrameworkAdaptor#getPlatformAdmin() 378 */ 379 public PlatformAdmin getPlatformAdmin() { 380 return storage.getStateManager(); 381 } 382 383 /** 384 * @see FrameworkAdaptor#getState() 385 */ 386 public State getState() { 387 return storage.getStateManager().getSystemState(); 388 } 389 390 /** 391 * This method calls all the configured classloading hooks {@link ClassLoadingHook#getBundleClassLoaderParent()} methods 392 * until one returns a non-null value. 393 * @see FrameworkAdaptor#getBundleClassLoaderParent() 394 */ 395 public ClassLoader getBundleClassLoaderParent() { 396 // ask the configured adaptor hooks first 397 ClassLoader result = null; 398 ClassLoadingHook[] cpManagerHooks = getHookRegistry().getClassLoadingHooks(); 399 for (int i = 0; i < cpManagerHooks.length; i++) { 400 result = cpManagerHooks[i].getBundleClassLoaderParent(); 401 if (result != null) 402 return result; 403 } 404 // none of the configured adaptor hooks gave use a parent loader; use the default 405 return bundleClassLoaderParent; 406 } 407 408 /** 409 * This method calls all the configured adaptor hooks {@link AdaptorHook#handleRuntimeError(Throwable)} methods. 410 * @see FrameworkAdaptor#handleRuntimeError(Throwable) 411 */ 412 public void handleRuntimeError(Throwable error) { 413 AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks(); 414 for (int i = 0; i < adaptorHooks.length; i++) 415 adaptorHooks[i].handleRuntimeError(error); 416 } 417 418 /** 419 * Returns true if the {@link #frameworkStopping(BundleContext)} method has been called 420 * @return true if the framework is stopping 421 */ 422 public boolean isStopping() { 423 return stopping; 424 } 425 426 /** 427 * Returns the event publisher for this BaseAdaptor 428 * @return the event publisher for this BaseAdaptor 429 */ 430 public EventPublisher getEventPublisher() { 431 return eventPublisher; 432 } 433 434 /** 435 * Returns the <code>HookRegistry</code> object for this adaptor. 436 * @return the <code>HookRegistry</code> object for this adaptor. 437 */ 438 public HookRegistry getHookRegistry() { 439 return hookRegistry; 440 } 441 442 /** 443 * Returns the system bundle's context 444 * @return the system bundle's context 445 */ 446 public BundleContext getContext() { 447 return context; 448 } 449 450 /** 451 * Returns the bundle with the specified identifier. This method 452 * does not invoke and bundle find hooks and therefore does not 453 * allow bundle find hooks to hide a bundle from the caller. 454 * 455 * @param id The identifier of the bundle to retrieve. 456 * @return A {@code Bundle} object or {@code null} if the identifier does 457 * not match any installed bundle. 458 */ 459 public Bundle getBundle(long id) { 460 return eventPublisher.getBundle(id); 461 } 462 463 /** 464 * Creates a bundle file object for the given content and base data. 465 * This method must delegate to each configured bundle file factory 466 * {@link BundleFileFactoryHook#createBundleFile(Object, BaseData, boolean)} method until one 467 * factory returns a non-null value. If no bundle file factory returns a non-null value 468 * then the the default behavior will be performed. 469 * <p> 470 * If the specified content is <code>null</code> then the base content of the specified 471 * bundledata must be found before calling any bundle file factories. 472 * </p> 473 * <p> 474 * After the bundle file has been created each configured bundle file wrapper factory 475 * {@link BundleFileWrapperFactoryHook#wrapBundleFile(BundleFile, Object, BaseData, boolean)} 476 * method is called to wrap the bundle file. 477 * </p> 478 * @param content The object which contains the content of a bundle file. A value of 479 * <code>null</code> indicates that the storage must find the base content for the 480 * specified BaseData. 481 * @param data The BaseData associated with the content 482 * @return a BundleFile object. 483 * @throws IOException if an error occured while creating the BundleFile 484 */ 485 public BundleFile createBundleFile(Object content, BaseData data) throws IOException { 486 return storage.createBundleFile(content, data); 487 } 488 489 /** 490 * Returns true if the persistent storage is read-only 491 * @return true if the persistent storage is read-only 492 */ 493 public boolean isReadOnly() { 494 return storage.isReadOnly(); 495 } 496 497 /* 498 * This is an experimental method to allow adaptors to replace the storage implementation by 499 * extending BaseAdaptor and overriding this method. This method is experimental. 500 * @return a base storage object. 501 */ 502 protected BaseStorage getStorage() { 503 if (storage != null) 504 return storage; 505 // this bit of code assumes the registry is initialized with a BaseStorageHook 506 // we want to make sure we are using the same BaseStorage instance as the BaseStorageHook 507 StorageHook[] hooks = hookRegistry.getStorageHooks(); 508 for (int i = 0; i < hooks.length && storage == null; i++) 509 if (hooks[i] instanceof BaseStorageHook) 510 storage = ((BaseStorageHook) hooks[i]).getStorage(); 511 return storage; 512 } 513 514 /** 515 * @see FrameworkAdaptor#findEntries(List, String, String, int) 516 */ 517 public Enumeration<URL> findEntries(List<BundleData> datas, String path, String filePattern, int options) { 518 List<BundleFile> bundleFiles = new ArrayList<BundleFile>(datas.size()); 519 for (BundleData data : datas) 520 bundleFiles.add(((BaseData) data).getBundleFile()); 521 // search all the bundle files 522 List<String> pathList = listEntryPaths(bundleFiles, path, filePattern, options); 523 // return null if no entries found 524 if (pathList.size() == 0) 525 return null; 526 // create an enumeration to enumerate the pathList 527 final String[] pathArray = pathList.toArray(new String[pathList.size()]); 528 final BundleData[] dataArray = datas.toArray(new BundleData[datas.size()]); 529 return new Enumeration<URL>() { 530 private int curPathIndex = 0; 531 private int curDataIndex = 0; 532 private URL nextElement = null; 533 534 public boolean hasMoreElements() { 535 if (nextElement != null) 536 return true; 537 getNextElement(); 538 return nextElement != null; 539 } 540 541 public URL nextElement() { 542 if (!hasMoreElements()) 543 throw new NoSuchElementException(); 544 URL result = nextElement; 545 // force the next element search 546 getNextElement(); 547 return result; 548 } 549 550 private void getNextElement() { 551 nextElement = null; 552 if (curPathIndex >= pathArray.length) 553 // reached the end of the pathArray; no more elements 554 return; 555 while (nextElement == null && curPathIndex < pathArray.length) { 556 String curPath = pathArray[curPathIndex]; 557 // search the datas until we have searched them all 558 while (nextElement == null && curDataIndex < dataArray.length) 559 nextElement = dataArray[curDataIndex++].getEntry(curPath); 560 // we have searched all datas then advance to the next path 561 if (curDataIndex >= dataArray.length) { 562 curPathIndex++; 563 curDataIndex = 0; 564 } 565 } 566 } 567 }; 568 } 569 570 /** 571 * Returns the names of resources available from a list of bundle files. 572 * No duplicate resource names are returned, each name is unique. 573 * @param bundleFiles the list of bundle files to search in 574 * @param path The path name in which to look. 575 * @param filePattern The file name pattern for selecting resource names in 576 * the specified path. 577 * @param options The options for listing resource names. 578 * @return a list of resource names. If no resources are found then 579 * the empty list is returned. 580 * @see BundleWiring#listResources(String, String, int) 581 */ 582 public List<String> listEntryPaths(List<BundleFile> bundleFiles, String path, String filePattern, int options) { 583 // a list used to store the results of the search 584 List<String> pathList = new ArrayList<String>(); 585 Filter patternFilter = null; 586 Hashtable<String, String> patternProps = null; 587 if (filePattern != null) { 588 // Optimization: If the file pattern does not include a wildcard or escape char then it must represent a single file. 589 // Avoid pattern matching and use BundleFile.getEntry() if recursion was not requested. 590 if ((options & BundleWiring.FINDENTRIES_RECURSE) == 0 && filePattern.indexOf('*') == -1 && filePattern.indexOf('\\') == -1) { 591 if (path.length() == 0) 592 path = filePattern; 593 else 594 path += path.charAt(path.length() - 1) == '/' ? filePattern : '/' + filePattern; 595 for (BundleFile bundleFile : bundleFiles) { 596 if (bundleFile.getEntry(path) != null && !pathList.contains(path)) 597 pathList.add(path); 598 } 599 return pathList; 600 } 601 // For when the file pattern includes a wildcard. 602 try { 603 // create a file pattern filter with 'filename' as the key 604 patternFilter = FilterImpl.newInstance("(filename=" + sanitizeFilterInput(filePattern) + ")"); //$NON-NLS-1$ //$NON-NLS-2$ 605 // create a single hashtable to be shared during the recursive search 606 patternProps = new Hashtable<String, String>(2); 607 } catch (InvalidSyntaxException e) { 608 // something unexpected happened; log error and return nothing 609 Bundle b = context == null ? null : context.getBundle(); 610 eventPublisher.publishFrameworkEvent(FrameworkEvent.ERROR, b, e); 611 return pathList; 612 } 613 } 614 // find the entry paths for the datas 615 for (BundleFile bundleFile : bundleFiles) { 616 listEntryPaths(bundleFile, path, patternFilter, patternProps, options, pathList); 617 } 618 return pathList; 619 } 620 621 private String sanitizeFilterInput(String filePattern) throws InvalidSyntaxException { 622 StringBuffer buffer = null; 623 boolean foundEscape = false; 624 for (int i = 0; i < filePattern.length(); i++) { 625 char c = filePattern.charAt(i); 626 switch (c) { 627 case '\\' : 628 // we either used the escape found or found a new escape. 629 foundEscape = foundEscape ? false : true; 630 if (buffer != null) 631 buffer.append(c); 632 break; 633 case '(' : 634 case ')' : 635 if (!foundEscape) { 636 if (buffer == null) { 637 buffer = new StringBuffer(filePattern.length() + 16); 638 buffer.append(filePattern.substring(0, i)); 639 } 640 // must escape with '\' 641 buffer.append('\\'); 642 } else { 643 foundEscape = false; // used the escape found 644 } 645 if (buffer != null) 646 buffer.append(c); 647 break; 648 default : 649 // if we found an escape it has been used 650 foundEscape = false; 651 if (buffer != null) 652 buffer.append(c); 653 break; 654 } 655 } 656 if (foundEscape) 657 throw new InvalidSyntaxException("Trailing escape characters must be escaped.", filePattern); //$NON-NLS-1$ 658 return buffer == null ? filePattern : buffer.toString(); 659 } 660 661 private List<String> listEntryPaths(BundleFile bundleFile, String path, Filter patternFilter, Hashtable<String, String> patternProps, int options, List<String> pathList) { 662 if (pathList == null) 663 pathList = new ArrayList<String>(); 664 Enumeration<String> entryPaths = bundleFile.getEntryPaths(path); 665 if (entryPaths == null) 666 return pathList; 667 while (entryPaths.hasMoreElements()) { 668 String entry = entryPaths.nextElement(); 669 int lastSlash = entry.lastIndexOf('/'); 670 if (patternProps != null) { 671 int secondToLastSlash = entry.lastIndexOf('/', lastSlash - 1); 672 int fileStart; 673 int fileEnd = entry.length(); 674 if (lastSlash < 0) 675 fileStart = 0; 676 else if (lastSlash != entry.length() - 1) 677 fileStart = lastSlash + 1; 678 else { 679 fileEnd = lastSlash; // leave the lastSlash out 680 if (secondToLastSlash < 0) 681 fileStart = 0; 682 else 683 fileStart = secondToLastSlash + 1; 684 } 685 String fileName = entry.substring(fileStart, fileEnd); 686 // set the filename to the current entry 687 patternProps.put("filename", fileName); //$NON-NLS-1$ 688 } 689 // prevent duplicates and match on the patternFilter 690 if (!pathList.contains(entry) && (patternFilter == null || patternFilter.matchCase(patternProps))) 691 pathList.add(entry); 692 // recurse only into entries that are directories 693 if (((options & BundleWiring.FINDENTRIES_RECURSE) != 0) && !entry.equals(path) && entry.length() > 0 && lastSlash == (entry.length() - 1)) 694 listEntryPaths(bundleFile, entry, patternFilter, patternProps, options, pathList); 695 } 696 return pathList; 697 } 698 699 }
-
1 private static FrameworkAdaptor createAdaptor() throws Exception { 2 String adaptorClassName = FrameworkProperties.getProperty(PROP_ADAPTOR, DEFAULT_ADAPTOR_CLASS); 3 Class<?> adaptorClass = Class.forName(adaptorClassName); 4 Class<?>[] constructorArgs = new Class[] {String[].class}; 5 Constructor<?> constructor = adaptorClass.getConstructor(constructorArgs); 6 return (FrameworkAdaptor) constructor.newInstance(new Object[] {new String[0]}); 7 }
- Create a new Framework
-
1 framework = new Framework(adaptor);
1 /******************************************************************************* 2 * Copyright (c) 2003, 2012 IBM Corporation and others. 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * IBM Corporation - initial API and implementation 10 *******************************************************************************/ 11 package org.eclipse.osgi.framework.internal.core; 12 13 import java.io.*; 14 import java.lang.reflect.*; 15 import java.net.*; 16 import java.security.*; 17 import java.util.*; 18 import org.eclipse.core.runtime.internal.adaptor.ContextFinder; 19 import org.eclipse.osgi.baseadaptor.BaseAdaptor; 20 import org.eclipse.osgi.framework.adaptor.*; 21 import org.eclipse.osgi.framework.debug.Debug; 22 import org.eclipse.osgi.framework.eventmgr.*; 23 import org.eclipse.osgi.framework.internal.protocol.ContentHandlerFactory; 24 import org.eclipse.osgi.framework.internal.protocol.StreamHandlerFactory; 25 import org.eclipse.osgi.framework.log.FrameworkLogEntry; 26 import org.eclipse.osgi.framework.util.SecureAction; 27 import org.eclipse.osgi.internal.loader.*; 28 import org.eclipse.osgi.internal.permadmin.EquinoxSecurityManager; 29 import org.eclipse.osgi.internal.permadmin.SecurityAdmin; 30 import org.eclipse.osgi.internal.profile.Profile; 31 import org.eclipse.osgi.internal.serviceregistry.*; 32 import org.eclipse.osgi.signedcontent.SignedContentFactory; 33 import org.eclipse.osgi.util.ManifestElement; 34 import org.eclipse.osgi.util.NLS; 35 import org.osgi.framework.*; 36 import org.osgi.framework.hooks.bundle.*; 37 import org.osgi.util.tracker.ServiceTracker; 38 39 /** 40 * Core OSGi Framework class. 41 */ 42 public class Framework implements EventPublisher, Runnable { 43 // System property used to set the context classloader parent classloader type (ccl is the default) 44 private static final String PROP_CONTEXTCLASSLOADER_PARENT = "osgi.contextClassLoaderParent"; //$NON-NLS-1$ 45 private static final String CONTEXTCLASSLOADER_PARENT_APP = "app"; //$NON-NLS-1$ 46 private static final String CONTEXTCLASSLOADER_PARENT_EXT = "ext"; //$NON-NLS-1$ 47 private static final String CONTEXTCLASSLOADER_PARENT_BOOT = "boot"; //$NON-NLS-1$ 48 private static final String CONTEXTCLASSLOADER_PARENT_FWK = "fwk"; //$NON-NLS-1$ 49 50 public static final String PROP_FRAMEWORK_THREAD = "osgi.framework.activeThreadType"; //$NON-NLS-1$ 51 public static final String THREAD_NORMAL = "normal"; //$NON-NLS-1$ 52 public static final String PROP_EQUINOX_SECURITY = "eclipse.security"; //$NON-NLS-1$ 53 public static final String SECURITY_OSGI = "osgi"; //$NON-NLS-1$ 54 55 private static String J2SE = "J2SE-"; //$NON-NLS-1$ 56 private static String JAVASE = "JavaSE-"; //$NON-NLS-1$ 57 private static String PROFILE_EXT = ".profile"; //$NON-NLS-1$ 58 /** FrameworkAdaptor specific functions. */ 59 protected FrameworkAdaptor adaptor; 60 /** Framework properties object. A reference to the 61 * System.getProperies() object. The properties from 62 * the adaptor will be merged into these properties. 63 */ 64 protected Properties properties; 65 /** Has the framework been started */ 66 protected boolean active; 67 /** Event indicating the reason for shutdown*/ 68 private FrameworkEvent[] shutdownEvent; 69 /** The bundles installed in the framework */ 70 protected BundleRepository bundles; 71 /** Package Admin object. This object manages the exported packages. */ 72 protected PackageAdminImpl packageAdmin; 73 /** PermissionAdmin and ConditionalPermissionAdmin impl. This object manages the bundle permissions. */ 74 protected SecurityAdmin securityAdmin; 75 /** Startlevel object. This object manages the framework and bundle startlevels */ 76 protected StartLevelManager startLevelManager; 77 /** The ServiceRegistry */ 78 private ServiceRegistry serviceRegistry; 79 private final int BSN_VERSION; 80 private static final int BSN_VERSION_SINGLE = 1; 81 private static final int BSN_VERSION_MULTIPLE = 2; 82 private static final int BSN_VERSION_MANAGED = 3; 83 84 /* 85 * The following maps objects keep track of event listeners 86 * by BundleContext. Each element is a Map that is the set 87 * of event listeners for a particular BundleContext. The max number of 88 * elements each of the following maps will have is the number of bundles 89 * installed in the Framework. 90 */ 91 // Map of BundleContexts for bundle's BundleListeners. 92 private final Map<BundleContextImpl, CopyOnWriteIdentityMap<BundleListener, BundleListener>> allBundleListeners = new HashMap<BundleContextImpl, CopyOnWriteIdentityMap<BundleListener, BundleListener>>(); 93 protected static final int BUNDLEEVENT = 1; 94 // Map of BundleContexts for bundle's SynchronousBundleListeners. 95 private final Map<BundleContextImpl, CopyOnWriteIdentityMap<SynchronousBundleListener, SynchronousBundleListener>> allSyncBundleListeners = new HashMap<BundleContextImpl, CopyOnWriteIdentityMap<SynchronousBundleListener, SynchronousBundleListener>>(); 96 protected static final int BUNDLEEVENTSYNC = 2; 97 /* SERVICEEVENT(3) is now handled by ServiceRegistry */ 98 // Map of BundleContexts for bundle's FrameworkListeners. 99 private final Map<BundleContextImpl, CopyOnWriteIdentityMap<FrameworkListener, FrameworkListener>> allFrameworkListeners = new HashMap<BundleContextImpl, CopyOnWriteIdentityMap<FrameworkListener, FrameworkListener>>(); 100 protected static final int FRAMEWORKEVENT = 4; 101 protected static final int BATCHEVENT_BEGIN = Integer.MIN_VALUE + 1; 102 protected static final int BATCHEVENT_END = Integer.MIN_VALUE; 103 static final String eventHookName = EventHook.class.getName(); 104 static final String findHookName = FindHook.class.getName(); 105 static final String collisionHookName = CollisionHook.class.getName(); 106 /** EventManager for event delivery. */ 107 protected EventManager eventManager; 108 /* Reservation object for install synchronization */ 109 private Map<String, Thread> installLock; 110 /** System Bundle object */ 111 protected InternalSystemBundle systemBundle; 112 private String[] bootDelegation; 113 private String[] bootDelegationStems; 114 private boolean bootDelegateAll = false; 115 public final boolean contextBootDelegation = "true".equals(FrameworkProperties.getProperty("osgi.context.bootdelegation", "true")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 116 public final boolean compatibiltyBootDelegation = "true".equals(FrameworkProperties.getProperty(Constants.OSGI_COMPATIBILITY_BOOTDELEGATION, "true")); //$NON-NLS-1$ //$NON-NLS-2$ 117 private final boolean allowRefreshDuplicateBSN = Boolean.TRUE.toString().equals(FrameworkProperties.getProperty(Constants.REFRESH_DUPLICATE_BSN, "true")); //$NON-NLS-1$ 118 ClassLoaderDelegateHook[] delegateHooks; 119 private volatile boolean forcedRestart = false; 120 /** 121 * The AliasMapper used to alias OS Names. 122 */ 123 protected static AliasMapper aliasMapper = new AliasMapper(); 124 SecureAction secureAction = AccessController.doPrivileged(SecureAction.createSecureAction()); 125 // cache of AdminPermissions keyed by Bundle ID 126 private final Map<Long, Map<String, AdminPermission>> adminPermissions = new HashMap<Long, Map<String, AdminPermission>>(); 127 128 // we need to hold these so that we can unregister them at shutdown 129 private StreamHandlerFactory streamHandlerFactory; 130 private ContentHandlerFactory contentHandlerFactory; 131 132 private volatile ServiceTracker<SignedContentFactory, SignedContentFactory> signedContentFactory; 133 private volatile ContextFinder contextFinder; 134 135 /* 136 * We need to make sure that the GetDataFileAction class loads early to prevent a ClassCircularityError when checking permissions. 137 * see bug 161561 138 */ 139 static { 140 Class<?> c; 141 c = GetDataFileAction.class; 142 c.getName(); // to prevent compiler warnings 143 } 144 145 static class GetDataFileAction implements PrivilegedAction<File> { 146 private AbstractBundle bundle; 147 private String filename; 148 149 public GetDataFileAction(AbstractBundle bundle, String filename) { 150 this.bundle = bundle; 151 this.filename = filename; 152 } 153 154 public File run() { 155 return bundle.getBundleData().getDataFile(filename); 156 } 157 } 158 159 /** 160 * Constructor for the Framework instance. This method initializes the 161 * framework to an unlaunched state. 162 * 163 */ 164 public Framework(FrameworkAdaptor adaptor) { 165 if (Profile.PROFILE && Profile.STARTUP) 166 Profile.logEnter("Framework.initialze()", null); //$NON-NLS-1$ 167 String bsnVersion = FrameworkProperties.getProperty(Constants.FRAMEWORK_BSNVERSION); 168 if (Constants.FRAMEWORK_BSNVERSION_SINGLE.equals(bsnVersion)) { 169 BSN_VERSION = BSN_VERSION_SINGLE; 170 } else if (Constants.FRAMEWORK_BSNVERSION_MULTIPLE.equals(bsnVersion)) { 171 BSN_VERSION = BSN_VERSION_MULTIPLE; 172 } else { 173 BSN_VERSION = BSN_VERSION_MANAGED; 174 } 175 long start = System.currentTimeMillis(); 176 this.adaptor = adaptor; 177 delegateHooks = adaptor instanceof BaseAdaptor ? ((BaseAdaptor) adaptor).getHookRegistry().getClassLoaderDelegateHooks() : null; 178 active = false; 179 installSecurityManager(); 180 if (Debug.DEBUG_SECURITY) { 181 Debug.println("SecurityManager: " + System.getSecurityManager()); //$NON-NLS-1$ 182 Debug.println("ProtectionDomain of Framework.class: \n" + this.getClass().getProtectionDomain()); //$NON-NLS-1$ 183 } 184 setNLSFrameworkLog(); 185 // initialize ContextFinder 186 initializeContextFinder(); 187 /* initialize the adaptor */ 188 adaptor.initialize(this); 189 if (Profile.PROFILE && Profile.STARTUP) 190 Profile.logTime("Framework.initialze()", "adapter initialized"); //$NON-NLS-1$//$NON-NLS-2$ 191 try { 192 adaptor.initializeStorage(); 193 } catch (IOException e) /* fatal error */{ 194 throw new RuntimeException(e.getMessage(), e); 195 } 196 if (Profile.PROFILE && Profile.STARTUP) 197 Profile.logTime("Framework.initialze()", "adapter storage initialized"); //$NON-NLS-1$//$NON-NLS-2$ 198 /* 199 * This must be done before calling any of the framework getProperty 200 * methods. 201 */ 202 initializeProperties(adaptor.getProperties()); 203 /* initialize admin objects */ 204 packageAdmin = new PackageAdminImpl(this); 205 try { 206 // always create security admin even with security off 207 securityAdmin = new SecurityAdmin(null, this, adaptor.getPermissionStorage()); 208 } catch (IOException e) /* fatal error */{ 209 e.printStackTrace(); 210 throw new RuntimeException(e.getMessage(), e); 211 } 212 if (Profile.PROFILE && Profile.STARTUP) 213 Profile.logTime("Framework.initialze()", "done init props & new PermissionAdminImpl"); //$NON-NLS-1$//$NON-NLS-2$ 214 startLevelManager = new StartLevelManager(this); 215 /* create the event manager and top level event dispatchers */ 216 eventManager = new EventManager("Framework Event Dispatcher"); //$NON-NLS-1$ 217 if (Profile.PROFILE && Profile.STARTUP) 218 Profile.logTime("Framework.initialze()", "done new EventManager"); //$NON-NLS-1$ //$NON-NLS-2$ 219 /* create the service registry */ 220 serviceRegistry = new ServiceRegistry(this); 221 // Initialize the installLock; there is no way of knowing 222 // what the initial size should be, at most it will be the number 223 // of threads trying to install a bundle (probably a very low number). 224 installLock = new HashMap<String, Thread>(10); 225 /* create the system bundle */ 226 createSystemBundle(); 227 loadVMProfile(); // load VM profile after the system bundle has been created 228 setBootDelegation(); //set boot delegation property after system exports have been set 229 if (Profile.PROFILE && Profile.STARTUP) 230 Profile.logTime("Framework.initialze()", "done createSystemBundle"); //$NON-NLS-1$ //$NON-NLS-2$ 231 /* install URLStreamHandlerFactory */ 232 installURLStreamHandlerFactory(systemBundle.context, adaptor); 233 /* install ContentHandlerFactory for OSGi URLStreamHandler support */ 234 installContentHandlerFactory(systemBundle.context, adaptor); 235 if (Profile.PROFILE && Profile.STARTUP) 236 Profile.logTime("Framework.initialze()", "done new URLStream/Content HandlerFactory"); //$NON-NLS-1$//$NON-NLS-2$ 237 /* create bundle objects for all installed bundles. */ 238 BundleData[] bundleDatas = adaptor.getInstalledBundles(); 239 bundles = new BundleRepository(bundleDatas == null ? 10 : bundleDatas.length + 1); 240 /* add the system bundle to the Bundle Repository */ 241 bundles.add(systemBundle); 242 if (bundleDatas != null) { 243 for (int i = 0; i < bundleDatas.length; i++) { 244 try { 245 AbstractBundle bundle = AbstractBundle.createBundle(bundleDatas[i], this, true); 246 bundles.add(bundle); 247 } catch (BundleException be) { 248 // This is not a fatal error. Publish the framework event. 249 publishFrameworkEvent(FrameworkEvent.ERROR, systemBundle, be); 250 } 251 } 252 } 253 if (Debug.DEBUG_GENERAL) 254 System.out.println("Initialize the framework: " + (System.currentTimeMillis() - start)); //$NON-NLS-1$ 255 if (Profile.PROFILE && Profile.STARTUP) 256 Profile.logExit("Framework.initialize()"); //$NON-NLS-1$ 257 } 258 259 public FrameworkAdaptor getAdaptor() { 260 return adaptor; 261 } 262 263 public ClassLoaderDelegateHook[] getDelegateHooks() { 264 return delegateHooks; 265 } 266 267 public ServiceRegistry getServiceRegistry() { 268 return serviceRegistry; 269 } 270 271 private void setNLSFrameworkLog() { 272 try { 273 Field frameworkLogField = NLS.class.getDeclaredField("frameworkLog"); //$NON-NLS-1$ 274 frameworkLogField.setAccessible(true); 275 frameworkLogField.set(null, adaptor.getFrameworkLog()); 276 } catch (Exception e) { 277 adaptor.getFrameworkLog().log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, e.getMessage(), 0, e, null)); 278 } 279 } 280 281 private void createSystemBundle() { 282 try { 283 systemBundle = new InternalSystemBundle(this); 284 systemBundle.getBundleData().setBundle(systemBundle); 285 } catch (BundleException e) { // fatal error 286 e.printStackTrace(); 287 throw new RuntimeException(NLS.bind(Msg.OSGI_SYSTEMBUNDLE_CREATE_EXCEPTION, e.getMessage()), e); 288 } 289 } 290 291 /** 292 * Initialize the System properties by copying properties from the adaptor 293 * properties object. This method is called by the initialize method. 294 * 295 */ 296 protected void initializeProperties(Properties adaptorProperties) { 297 properties = FrameworkProperties.getProperties(); 298 Enumeration<?> enumKeys = adaptorProperties.propertyNames(); 299 while (enumKeys.hasMoreElements()) { 300 String key = (String) enumKeys.nextElement(); 301 if (properties.getProperty(key) == null) { 302 properties.put(key, adaptorProperties.getProperty(key)); 303 } 304 } 305 properties.put(Constants.FRAMEWORK_VENDOR, Constants.OSGI_FRAMEWORK_VENDOR); 306 properties.put(Constants.FRAMEWORK_VERSION, Constants.OSGI_FRAMEWORK_VERSION); 307 String value = properties.getProperty(Constants.FRAMEWORK_PROCESSOR); 308 if (value == null) { 309 value = properties.getProperty(Constants.JVM_OS_ARCH); 310 if (value != null) { 311 properties.put(Constants.FRAMEWORK_PROCESSOR, aliasMapper.aliasProcessor(value)); 312 } 313 } 314 value = properties.getProperty(Constants.FRAMEWORK_OS_NAME); 315 if (value == null) { 316 value = properties.getProperty(Constants.JVM_OS_NAME); 317 try { 318 String canonicalValue = (String) aliasMapper.aliasOSName(value); 319 if (canonicalValue != null) { 320 value = canonicalValue; 321 } 322 } catch (ClassCastException ex) { 323 //A vector was returned from the alias mapper. 324 //The alias mapped to more than one canonical value 325 //such as "win32" for example 326 } 327 if (value != null) { 328 properties.put(Constants.FRAMEWORK_OS_NAME, value); 329 } 330 } 331 value = properties.getProperty(Constants.FRAMEWORK_OS_VERSION); 332 if (value == null) { 333 value = properties.getProperty(Constants.JVM_OS_VERSION); 334 if (value != null) { 335 // only use the value upto the first space 336 int space = value.indexOf(' '); 337 if (space > 0) { 338 value = value.substring(0, space); 339 } 340 // fix up cases where the os version does not make a valid Version string. 341 int major = 0, minor = 0, micro = 0; 342 String qualifier = ""; //$NON-NLS-1$ 343 try { 344 StringTokenizer st = new StringTokenizer(value, ".", true); //$NON-NLS-1$ 345 major = parseVersionInt(st.nextToken()); 346 347 if (st.hasMoreTokens()) { 348 st.nextToken(); // consume delimiter 349 minor = parseVersionInt(st.nextToken()); 350 351 if (st.hasMoreTokens()) { 352 st.nextToken(); // consume delimiter 353 micro = parseVersionInt(st.nextToken()); 354 355 if (st.hasMoreTokens()) { 356 st.nextToken(); // consume delimiter 357 qualifier = st.nextToken(); 358 } 359 } 360 } 361 } catch (NoSuchElementException e) { 362 // ignore, use the values parsed so far 363 } 364 try { 365 value = new Version(major, minor, micro, qualifier).toString(); 366 } catch (IllegalArgumentException e) { 367 // must be an invalid qualifier; just ignore it 368 value = new Version(major, minor, micro).toString(); 369 } 370 properties.put(Constants.FRAMEWORK_OS_VERSION, value); 371 } 372 } 373 value = properties.getProperty(Constants.FRAMEWORK_LANGUAGE); 374 if (value == null) 375 // set the value of the framework language property 376 properties.put(Constants.FRAMEWORK_LANGUAGE, Locale.getDefault().getLanguage()); 377 // set the support properties for fragments and require-bundle (bug 173090) 378 properties.put(Constants.SUPPORTS_FRAMEWORK_FRAGMENT, "true"); //$NON-NLS-1$ 379 properties.put(Constants.SUPPORTS_FRAMEWORK_REQUIREBUNDLE, "true"); //$NON-NLS-1$ 380 properties.put(Constants.FRAMEWORK_UUID, new UniversalUniqueIdentifier().toString()); 381 } 382 383 private int parseVersionInt(String value) { 384 try { 385 return Integer.parseInt(value); 386 } catch (NumberFormatException e) { 387 // try up to the first non-number char 388 StringBuffer sb = new StringBuffer(value.length()); 389 char[] chars = value.toCharArray(); 390 for (int i = 0; i < chars.length; i++) { 391 if (!Character.isDigit(chars[i])) 392 break; 393 sb.append(chars[i]); 394 } 395 if (sb.length() > 0) 396 return Integer.parseInt(sb.toString()); 397 return 0; 398 } 399 } 400 401 private void setBootDelegation() { 402 // set the boot delegation according to the osgi boot delegation property 403 String bootDelegationProp = properties.getProperty(Constants.FRAMEWORK_BOOTDELEGATION); 404 if (bootDelegationProp == null) 405 return; 406 if (bootDelegationProp.trim().length() == 0) 407 return; 408 String[] bootPackages = ManifestElement.getArrayFromList(bootDelegationProp); 409 List<String> exactMatch = new ArrayList<String>(bootPackages.length); 410 List<String> stemMatch = new ArrayList<String>(bootPackages.length); 411 for (int i = 0; i < bootPackages.length; i++) { 412 if (bootPackages[i].equals("*")) { //$NON-NLS-1$ 413 bootDelegateAll = true; 414 return; 415 } else if (bootPackages[i].endsWith("*")) { //$NON-NLS-1$ 416 if (bootPackages[i].length() > 2 && bootPackages[i].endsWith(".*")) //$NON-NLS-1$ 417 stemMatch.add(bootPackages[i].substring(0, bootPackages[i].length() - 1)); 418 } else { 419 exactMatch.add(bootPackages[i]); 420 } 421 } 422 if (!exactMatch.isEmpty()) 423 bootDelegation = exactMatch.toArray(new String[exactMatch.size()]); 424 if (!stemMatch.isEmpty()) 425 bootDelegationStems = stemMatch.toArray(new String[stemMatch.size()]); 426 } 427 428 @SuppressWarnings("deprecation") 429 private void loadVMProfile() { 430 Properties profileProps = findVMProfile(); 431 String systemExports = properties.getProperty(Constants.FRAMEWORK_SYSTEMPACKAGES); 432 // set the system exports property using the vm profile; only if the property is not already set 433 if (systemExports == null) { 434 systemExports = profileProps.getProperty(Constants.FRAMEWORK_SYSTEMPACKAGES); 435 if (systemExports != null) 436 properties.put(Constants.FRAMEWORK_SYSTEMPACKAGES, systemExports); 437 } 438 // set the org.osgi.framework.bootdelegation property according to the java profile 439 String type = properties.getProperty(Constants.OSGI_JAVA_PROFILE_BOOTDELEGATION); // a null value means ignore 440 String profileBootDelegation = profileProps.getProperty(Constants.FRAMEWORK_BOOTDELEGATION); 441 if (Constants.OSGI_BOOTDELEGATION_OVERRIDE.equals(type)) { 442 if (profileBootDelegation == null) 443 properties.remove(Constants.FRAMEWORK_BOOTDELEGATION); // override with a null value 444 else 445 properties.put(Constants.FRAMEWORK_BOOTDELEGATION, profileBootDelegation); // override with the profile value 446 } else if (Constants.OSGI_BOOTDELEGATION_NONE.equals(type)) 447 properties.remove(Constants.FRAMEWORK_BOOTDELEGATION); // remove the bootdelegation property in case it was set 448 // set the org.osgi.framework.executionenvironment property according to the java profile 449 if (properties.getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT) == null) { 450 // get the ee from the java profile; if no ee is defined then try the java profile name 451 String ee = profileProps.getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT, profileProps.getProperty(Constants.OSGI_JAVA_PROFILE_NAME)); 452 if (ee != null) 453 properties.put(Constants.FRAMEWORK_EXECUTIONENVIRONMENT, ee); 454 } 455 // set the org.osgi.framework.system.capabilities property according to the java profile 456 if (properties.getProperty(Constants.FRAMEWORK_SYSTEMCAPABILITIES) == null) { 457 String systemCapabilities = profileProps.getProperty(Constants.FRAMEWORK_SYSTEMCAPABILITIES); 458 if (systemCapabilities != null) 459 properties.put(Constants.FRAMEWORK_SYSTEMCAPABILITIES, systemCapabilities); 460 } 461 } 462 463 private Properties findVMProfile() { 464 Properties result = new Properties(); 465 // Find the VM profile name using J2ME properties 466 String j2meConfig = properties.getProperty(Constants.J2ME_MICROEDITION_CONFIGURATION); 467 String j2meProfiles = properties.getProperty(Constants.J2ME_MICROEDITION_PROFILES); 468 String vmProfile = null; 469 String javaEdition = null; 470 Version javaVersion = null; 471 if (j2meConfig != null && j2meConfig.length() > 0 && j2meProfiles != null && j2meProfiles.length() > 0) { 472 // save the vmProfile based off of the config and profile 473 // use the last profile; assuming that is the highest one 474 String[] j2meProfileList = ManifestElement.getArrayFromList(j2meProfiles, " "); //$NON-NLS-1$ 475 if (j2meProfileList != null && j2meProfileList.length > 0) 476 vmProfile = j2meConfig + '_' + j2meProfileList[j2meProfileList.length - 1]; 477 } else { 478 // No J2ME properties; use J2SE properties 479 // Note that the CDC spec appears not to require VM implementations to set the 480 // javax.microedition properties!! So we will try to fall back to the 481 // java.specification.name property, but this is pretty ridiculous!! 482 String javaSpecVersion = properties.getProperty("java.specification.version"); //$NON-NLS-1$ 483 // set the profile and EE based off of the java.specification.version 484 // TODO We assume J2ME Foundation and J2SE here. need to support other profiles J2EE ... 485 if (javaSpecVersion != null) { 486 StringTokenizer st = new StringTokenizer(javaSpecVersion, " _-"); //$NON-NLS-1$ 487 javaSpecVersion = st.nextToken(); 488 String javaSpecName = properties.getProperty("java.specification.name"); //$NON-NLS-1$ 489 // See bug 291269 we check for Foundation Specification and Foundation Profile Specification 490 if (javaSpecName != null && (javaSpecName.indexOf("Foundation Specification") >= 0 || javaSpecName.indexOf("Foundation Profile Specification") >= 0)) //$NON-NLS-1$ //$NON-NLS-2$ 491 vmProfile = "CDC-" + javaSpecVersion + "_Foundation-" + javaSpecVersion; //$NON-NLS-1$ //$NON-NLS-2$ 492 else { 493 // look for JavaSE if 1.6 or greater; otherwise look for J2SE 494 Version v16 = new Version("1.6"); //$NON-NLS-1$ 495 javaEdition = J2SE; 496 try { 497 javaVersion = new Version(javaSpecVersion); 498 if (v16.compareTo(javaVersion) <= 0) 499 javaEdition = JAVASE; 500 } catch (IllegalArgumentException e) { 501 // do nothing 502 } 503 vmProfile = javaEdition + javaSpecVersion; 504 } 505 } 506 } 507 URL url = null; 508 // check for the java profile property for a url 509 String propJavaProfile = FrameworkProperties.getProperty(Constants.OSGI_JAVA_PROFILE); 510 if (propJavaProfile != null) 511 try { 512 // we assume a URL 513 url = new URL(propJavaProfile); 514 } catch (MalformedURLException e1) { 515 // try using a relative path in the system bundle 516 url = findInSystemBundle(propJavaProfile); 517 } 518 if (url == null && vmProfile != null) { 519 // look for a profile in the system bundle based on the vm profile 520 String javaProfile = vmProfile + PROFILE_EXT; 521 url = findInSystemBundle(javaProfile); 522 if (url == null) 523 url = getNextBestProfile(javaEdition, javaVersion); 524 } 525 if (url == null) 526 // the profile url is still null then use the osgi min profile in OSGi by default 527 url = findInSystemBundle("OSGi_Minimum-1.2.profile"); //$NON-NLS-1$ 528 if (url != null) { 529 InputStream in = null; 530 try { 531 in = url.openStream(); 532 result.load(new BufferedInputStream(in)); 533 } catch (IOException e) { 534 // TODO consider logging ... 535 } finally { 536 if (in != null) 537 try { 538 in.close(); 539 } catch (IOException ee) { 540 // do nothing 541 } 542 } 543 } 544 // set the profile name if it does not provide one 545 if (result.getProperty(Constants.OSGI_JAVA_PROFILE_NAME) == null) 546 if (vmProfile != null) 547 result.put(Constants.OSGI_JAVA_PROFILE_NAME, vmProfile.replace('_', '/')); 548 else 549 // last resort; default to the absolute minimum profile name for the framework 550 result.put(Constants.OSGI_JAVA_PROFILE_NAME, "OSGi/Minimum-1.2"); //$NON-NLS-1$ 551 return result; 552 } 553 554 private URL getNextBestProfile(String javaEdition, Version javaVersion) { 555 if (javaVersion == null || (javaEdition != J2SE && javaEdition != JAVASE)) 556 return null; // we cannot automatically choose the next best profile unless this is a J2SE or JavaSE vm 557 URL bestProfile = findNextBestProfile(javaEdition, javaVersion); 558 if (bestProfile == null && javaEdition == JAVASE) 559 // if this is a JavaSE VM then search for a lower J2SE profile 560 bestProfile = findNextBestProfile(J2SE, javaVersion); 561 return bestProfile; 562 } 563 564 private URL findNextBestProfile(String javaEdition, Version javaVersion) { 565 URL result = null; 566 int minor = javaVersion.getMinor(); 567 do { 568 result = findInSystemBundle(javaEdition + javaVersion.getMajor() + "." + minor + PROFILE_EXT); //$NON-NLS-1$ 569 minor = minor - 1; 570 } while (result == null && minor > 0); 571 return result; 572 } 573 574 private URL findInSystemBundle(String entry) { 575 URL result = systemBundle.getEntry0(entry); 576 if (result == null) { 577 // Check the ClassLoader in case we're launched off the Java boot classpath 578 ClassLoader loader = getClass().getClassLoader(); 579 result = loader == null ? ClassLoader.getSystemResource(entry) : loader.getResource(entry); 580 } 581 return result; 582 } 583 584 /** 585 * This method return the state of the framework. 586 * 587 */ 588 protected boolean isActive() { 589 return (active); 590 } 591 592 /** 593 * This method is called to destory the framework instance. 594 * 595 */ 596 public synchronized void close() { 597 if (adaptor == null) 598 return; 599 if (active) 600 shutdown(FrameworkEvent.STOPPED); 601 602 synchronized (bundles) { 603 List<AbstractBundle> allBundles = bundles.getBundles(); 604 int size = allBundles.size(); 605 for (int i = 0; i < size; i++) { 606 AbstractBundle bundle = allBundles.get(i); 607 bundle.close(); 608 } 609 bundles.removeAllBundles(); 610 } 611 serviceRegistry = null; 612 allBundleListeners.clear(); 613 allSyncBundleListeners.clear(); 614 allFrameworkListeners.clear(); 615 if (eventManager != null) { 616 eventManager.close(); 617 eventManager = null; 618 } 619 secureAction = null; 620 packageAdmin = null; 621 adaptor = null; 622 uninstallURLStreamHandlerFactory(); 623 uninstallContentHandlerFactory(); 624 if (System.getSecurityManager() instanceof EquinoxSecurityManager) 625 System.setSecurityManager(null); 626 } 627 628 /** 629 * Start the framework. 630 * 631 * When the framework is started. The following actions occur: 1. Event 632 * handling is enabled. Events can now be delivered to listeners. 2. All 633 * bundles which are recorded as started are started as described in the 634 * Bundle.start() method. These bundles are the bundles that were started 635 * when the framework was last stopped. Reports any exceptions that occur 636 * during startup using FrameworkEvents. 3. A FrameworkEvent of type 637 * FrameworkEvent.STARTED is broadcast. 638 * 639 */ 640 public synchronized void launch() { 641 /* Return if framework already started */ 642 if (active) { 643 return; 644 } 645 /* mark framework as started */ 646 active = true; 647 shutdownEvent = new FrameworkEvent[1]; 648 if (THREAD_NORMAL.equals(FrameworkProperties.getProperty(PROP_FRAMEWORK_THREAD, THREAD_NORMAL))) { 649 Thread fwkThread = new Thread(this, "Framework Active Thread"); //$NON-NLS-1$ 650 fwkThread.setDaemon(false); 651 fwkThread.start(); 652 } 653 /* Resume systembundle */ 654 if (Debug.DEBUG_GENERAL) { 655 Debug.println("Trying to launch framework"); //$NON-NLS-1$ 656 } 657 systemBundle.resume(); 658 signedContentFactory = new ServiceTracker<SignedContentFactory, SignedContentFactory>(systemBundle.getBundleContext(), SignedContentFactory.class.getName(), null); 659 signedContentFactory.open(); 660 } 661 662 /** 663 * Stop the framework. 664 * 665 * When the framework is stopped. The following actions occur: 1. Suspend 666 * all started bundles as described in the Bundle.stop method except that 667 * the bundle is recorded as started. These bundles will be restarted when 668 * the framework is next started. Reports any exceptions that occur during 669 * stopping using FrameworkEvents. 2. Event handling is disabled. 670 * 671 */ 672 public synchronized void shutdown(int eventType) { 673 /* Return if framework already stopped */ 674 if (!active) 675 return; 676 this.shutdownEvent[0] = new FrameworkEvent(eventType, systemBundle, null); 677 /* 678 * set the state of the System Bundle to STOPPING. 679 * this must be done first according to section 4.19.2 from the OSGi R3 spec. 680 */ 681 systemBundle.state = Bundle.STOPPING; 682 publishBundleEvent(BundleEvent.STOPPING, systemBundle); // need to send system bundle stopping event 683 /* call the FrameworkAdaptor.frameworkStopping method first */ 684 try { 685 adaptor.frameworkStopping(systemBundle.getContext()); 686 } catch (Throwable t) { 687 publishFrameworkEvent(FrameworkEvent.ERROR, systemBundle, t); 688 } 689 /* Suspend systembundle */ 690 if (Debug.DEBUG_GENERAL) { 691 Debug.println("Trying to shutdown Framework"); //$NON-NLS-1$ 692 } 693 systemBundle.suspend(); 694 try { 695 adaptor.compactStorage(); 696 } catch (IOException e) { 697 publishFrameworkEvent(FrameworkEvent.ERROR, systemBundle, e); 698 } 699 if (signedContentFactory != null) 700 signedContentFactory.close(); 701 /* mark framework as stopped */ 702 active = false; 703 notifyAll(); 704 } 705 706 /** 707 * Create a new Bundle object. 708 * @param bundledata the BundleData of the Bundle to create 709 */ 710 AbstractBundle createAndVerifyBundle(int operationType, Bundle target, BundleData bundledata, boolean setBundle) throws BundleException { 711 // Check for a bundle already installed with the same symbolic name and version. 712 if (BSN_VERSION != BSN_VERSION_MULTIPLE && bundledata.getSymbolicName() != null) { 713 List<AbstractBundle> installedBundles = getBundleBySymbolicName(bundledata.getSymbolicName(), bundledata.getVersion()); 714 if (operationType == CollisionHook.UPDATING) { 715 installedBundles.remove(target); 716 } 717 if (BSN_VERSION == BSN_VERSION_MANAGED && !installedBundles.isEmpty()) { 718 notifyCollisionHooks(operationType, target, installedBundles); 719 } 720 if (!installedBundles.isEmpty()) { 721 Bundle installedBundle = installedBundles.iterator().next(); 722 String msg = NLS.bind(Msg.BUNDLE_INSTALL_SAME_UNIQUEID, new Object[] {installedBundle.getSymbolicName(), installedBundle.getVersion().toString(), installedBundle.getLocation()}); 723 throw new DuplicateBundleException(msg, installedBundle); 724 } 725 } 726 return AbstractBundle.createBundle(bundledata, this, setBundle); 727 } 728 729 private class DuplicateBundleException extends BundleException implements StatusException { 730 private static final long serialVersionUID = 135669822846323624L; 731 private transient Bundle duplicate; 732 733 public DuplicateBundleException(String msg, Bundle duplicate) { 734 super(msg, BundleException.DUPLICATE_BUNDLE_ERROR); 735 this.duplicate = duplicate; 736 } 737 738 public Object getStatus() { 739 return duplicate; 740 } 741 742 public int getStatusCode() { 743 return StatusException.CODE_OK; 744 } 745 746 } 747 748 /** 749 * Retrieve the value of the named environment property. Values are 750 * provided for the following properties: 751 * <dl> 752 * <dt><code>org.osgi.framework.version</code> 753 * <dd>The version of the framework. 754 * <dt><code>org.osgi.framework.vendor</code> 755 * <dd>The vendor of this framework implementation. 756 * <dt><code>org.osgi.framework.language</code> 757 * <dd>The language being used. See ISO 639 for possible values. 758 * <dt><code>org.osgi.framework.os.name</code> 759 * <dd>The name of the operating system of the hosting computer. 760 * <dt><code>org.osgi.framework.os.version</code> 761 * <dd>The version number of the operating system of the hosting computer. 762 * <dt><code>org.osgi.framework.processor</code> 763 * <dd>The name of the processor of the hosting computer. 764 * </dl> 765 * 766 * <p> 767 * Note: These last four properties are used by the <code>Bundle-NativeCode</code> 768 * manifest header's matching algorithm for selecting native code. 769 * 770 * @param key 771 * The name of the requested property. 772 * @return The value of the requested property, or <code>null</code> if 773 * the property is undefined. 774 */ 775 public String getProperty(String key) { 776 return properties.getProperty(key); 777 } 778 779 /** 780 * Retrieve the value of the named environment property. Values are 781 * provided for the following properties: 782 * <dl> 783 * <dt><code>org.osgi.framework.version</code> 784 * <dd>The version of the framework. 785 * <dt><code>org.osgi.framework.vendor</code> 786 * <dd>The vendor of this framework implementation. 787 * <dt><code>org.osgi.framework.language</code> 788 * <dd>The language being used. See ISO 639 for possible values. 789 * <dt><code>org.osgi.framework.os.name</code> 790 * <dd>The name of the operating system of the hosting computer. 791 * <dt><code>org.osgi.framework.os.version</code> 792 * <dd>The version number of the operating system of the hosting computer. 793 * <dt><code>org.osgi.framework.processor</code> 794 * <dd>The name of the processor of the hosting computer. 795 * </dl> 796 * 797 * <p> 798 * Note: These last four properties are used by the <code>Bundle-NativeCode</code> 799 * manifest header's matching algorithm for selecting native code. 800 * 801 * @param key 802 * The name of the requested property. 803 * @param def 804 * A default value is the requested property is not present. 805 * @return The value of the requested property, or the default value if the 806 * property is undefined. 807 */ 808 protected String getProperty(String key, String def) { 809 return properties.getProperty(key, def); 810 } 811 812 /** 813 * Set a system property. 814 * 815 * @param key 816 * The name of the property to set. 817 * @param value 818 * The value to set. 819 * @return The previous value of the property or null if the property was 820 * not previously set. 821 */ 822 protected Object setProperty(String key, String value) { 823 return properties.put(key, value); 824 } 825 826 /** 827 * Install a bundle from an InputStream. 828 * 829 * @param location 830 * The location identifier of the bundle to install. 831 * @param in 832 * The InputStream from which the bundle will be read. If null 833 * then the location is used to get the bundle content. 834 * @return The Bundle of the installed bundle. 835 */ 836 AbstractBundle installBundle(final String location, final InputStream in, final BundleContextImpl origin) throws BundleException { 837 if (Debug.DEBUG_GENERAL) { 838 Debug.println("install from inputstream: " + location + ", " + in); //$NON-NLS-1$ //$NON-NLS-2$ 839 } 840 final AccessControlContext callerContext = AccessController.getContext(); 841 return installWorker(location, new PrivilegedExceptionAction<AbstractBundle>() { 842 public AbstractBundle run() throws BundleException { 843 /* Map the InputStream or location to a URLConnection */ 844 URLConnection source = in != null ? new BundleSource(in) : adaptor.mapLocationToURLConnection(location); 845 /* call the worker to install the bundle */ 846 return installWorkerPrivileged(location, source, callerContext, origin); 847 } 848 }, origin); 849 } 850 851 /** 852 * Worker method to install a bundle. It obtains the reservation for the 853 * location and calls the specified action. 854 * 855 * @param location 856 * The location identifier of the bundle to install. 857 * @param action 858 * A PrivilegedExceptionAction which calls the real worker. 859 * @return The {@link AbstractBundle}of the installed bundle. 860 * @exception BundleException 861 * If the action throws an error. 862 */ 863 protected AbstractBundle installWorker(String location, PrivilegedExceptionAction<AbstractBundle> action, BundleContext origin) throws BundleException { 864 synchronized (installLock) { 865 while (true) { 866 /* Check that the bundle is not already installed. */ 867 AbstractBundle bundle = getBundleByLocation(location); 868 /* If already installed, return bundle object */ 869 if (bundle != null) { 870 Bundle visible = origin.getBundle(bundle.getBundleId()); 871 if (visible == null) { 872 BundleData data = bundle.getBundleData(); 873 String msg = NLS.bind(Msg.BUNDLE_INSTALL_SAME_UNIQUEID, new Object[] {data.getSymbolicName(), data.getVersion().toString(), data.getLocation()}); 874 throw new BundleException(msg, BundleException.REJECTED_BY_HOOK); 875 } 876 return bundle; 877 } 878 Thread current = Thread.currentThread(); 879 /* Check for and make reservation */ 880 Thread reservation = installLock.put(location, current); 881 /* if the location is not already reserved */ 882 if (reservation == null) { 883 /* we have made the reservation and can continue */ 884 break; 885 } 886 /* the location was already reserved */ 887 /* 888 * If the reservation is held by the current thread, we have 889 * recursed to install the same bundle! 890 */ 891 if (current.equals(reservation)) { 892 throw new BundleException(Msg.BUNDLE_INSTALL_RECURSION_EXCEPTION, BundleException.STATECHANGE_ERROR); 893 } 894 try { 895 /* wait for the reservation to be released */ 896 installLock.wait(); 897 } catch (InterruptedException e) { 898 Thread.currentThread().interrupt(); 899 throw new BundleException("Thread has been interrupted while waiting for the location lock.", e); //$NON-NLS-1$ 900 } 901 } 902 } 903 /* Don't call adaptor while holding the install lock */ 904 try { 905 AbstractBundle bundle = AccessController.doPrivileged(action); 906 publishBundleEvent(new BundleEvent(BundleEvent.INSTALLED, bundle, origin.getBundle())); 907 return bundle; 908 } catch (PrivilegedActionException e) { 909 if (e.getException() instanceof RuntimeException) 910 throw (RuntimeException) e.getException(); 911 throw (BundleException) e.getException(); 912 } finally { 913 synchronized (installLock) { 914 /* release reservation */ 915 installLock.remove(location); 916 /* wake up all waiters */ 917 installLock.notifyAll(); 918 } 919 } 920 } 921 922 /** 923 * Worker method to install a bundle. It calls the FrameworkAdaptor object 924 * to install the bundle in persistent storage. 925 * 926 * @param location 927 * The location identifier of the bundle to install. 928 * @param source 929 * The URLConnection from which the bundle will be read. 930 * @param callerContext 931 * The caller access control context 932 * @param origin 933 * The origin bundle context that is installing the the bundle 934 * @return The {@link AbstractBundle}of the installed bundle. 935 * @exception BundleException 936 * If the provided stream cannot be read. 937 */ 938 protected AbstractBundle installWorkerPrivileged(String location, URLConnection source, AccessControlContext callerContext, BundleContextImpl origin) throws BundleException { 939 BundleOperation storage = adaptor.installBundle(location, source); 940 final AbstractBundle bundle; 941 try { 942 BundleData bundledata = storage.begin(); 943 bundle = createAndVerifyBundle(CollisionHook.INSTALLING, origin.getBundle(), bundledata, true); 944 945 BundleWatcher bundleStats = adaptor.getBundleWatcher(); 946 if (bundleStats != null) 947 bundleStats.watchBundle(bundle, BundleWatcher.START_INSTALLING); 948 949 try { 950 bundle.load(); 951 if (System.getSecurityManager() != null) { 952 final boolean extension = (bundledata.getType() & (BundleData.TYPE_BOOTCLASSPATH_EXTENSION | BundleData.TYPE_FRAMEWORK_EXTENSION | BundleData.TYPE_EXTCLASSPATH_EXTENSION)) != 0; 953 // must check for AllPermission before allow a bundle extension to be installed 954 if (extension && !bundle.hasPermission(new AllPermission())) 955 throw new BundleException(Msg.BUNDLE_EXTENSION_PERMISSION, BundleException.SECURITY_ERROR, new SecurityException(Msg.BUNDLE_EXTENSION_PERMISSION)); 956 try { 957 AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { 958 public Object run() throws Exception { 959 checkAdminPermission(bundle, AdminPermission.LIFECYCLE); 960 if (extension) // need special permission to install extension bundles 961 checkAdminPermission(bundle, AdminPermission.EXTENSIONLIFECYCLE); 962 return null; 963 } 964 }, callerContext); 965 } catch (PrivilegedActionException e) { 966 throw e.getException(); 967 } 968 } 969 // must add the bundle before committing (bug 330905) 970 bundles.add(bundle); 971 storage.commit(false); 972 } catch (Throwable error) { 973 bundles.remove(bundle); 974 synchronized (bundles) { 975 bundle.unload(); 976 } 977 bundle.close(); 978 throw error; 979 } finally { 980 if (bundleStats != null) 981 bundleStats.watchBundle(bundle, BundleWatcher.END_INSTALLING); 982 } 983 984 } catch (Throwable t) { 985 try { 986 storage.undo(); 987 } catch (BundleException ee) { 988 publishFrameworkEvent(FrameworkEvent.ERROR, systemBundle, ee); 989 } 990 if (t instanceof SecurityException) 991 throw (SecurityException) t; 992 if (t instanceof BundleException) 993 throw (BundleException) t; 994 throw new BundleException(t.getMessage(), t); 995 } 996 return bundle; 997 } 998 999 /** 1000 * Retrieve the bundle that has the given unique identifier. 1001 * 1002 * @param id 1003 * The identifier of the bundle to retrieve. 1004 * @return A {@link AbstractBundle}object, or <code>null</code> if the 1005 * identifier doesn't match any installed bundle. 1006 */ 1007 // changed visibility to gain access through the adaptor 1008 public AbstractBundle getBundle(long id) { 1009 synchronized (bundles) { 1010 return bundles.getBundle(id); 1011 } 1012 } 1013 1014 AbstractBundle getBundle(final BundleContextImpl context, long id) { 1015 AbstractBundle bundle = getBundle(id); 1016 // TODO we make the system bundle special because there are lots of places 1017 // where we assume the system bundle can get all bundles 1018 if (bundle == null || context.getBundle().getBundleId() == 0) 1019 return bundle; 1020 List<AbstractBundle> single = new ArrayList<AbstractBundle>(1); 1021 single.add(bundle); 1022 notifyFindHooks(context, single); 1023 return single.size() == 0 ? null : bundle; 1024 } 1025 1026 public BundleContextImpl getSystemBundleContext() { 1027 if (systemBundle == null) 1028 return null; 1029 return systemBundle.context; 1030 } 1031 1032 public PackageAdminImpl getPackageAdmin() { 1033 return packageAdmin; 1034 } 1035 1036 /** 1037 * Retrieve the bundles that has the given symbolic name and version. 1038 * 1039 * @param symbolicName 1040 * The symbolic name of the bundle to retrieve 1041 * @param version The version of the bundle to retrieve 1042 * @return A collection of {@link AbstractBundle} that match the symbolic name and version 1043 */ 1044 public List<AbstractBundle> getBundleBySymbolicName(String symbolicName, Version version) { 1045 synchronized (bundles) { 1046 return bundles.getBundles(symbolicName, version); 1047 } 1048 } 1049 1050 /** 1051 * Retrieve the BundleRepository of all installed bundles. The list is 1052 * valid at the time of the call to getBundles, but the framework is a very 1053 * dynamic environment and bundles can be installed or uninstalled at 1054 * anytime. 1055 * 1056 * @return The BundleRepository. 1057 */ 1058 protected BundleRepository getBundles() { 1059 return (bundles); 1060 } 1061 1062 /** 1063 * Retrieve a list of all installed bundles. The list is valid at the time 1064 * of the call to getBundleAlls, but the framework is a very dynamic 1065 * environment and bundles can be installed or uninstalled at anytime. 1066 * 1067 * @return An Array of {@link AbstractBundle}objects, one object per installed 1068 * bundle. 1069 */ 1070 protected AbstractBundle[] getAllBundles() { 1071 synchronized (bundles) { 1072 List<AbstractBundle> allBundles = bundles.getBundles(); 1073 int size = allBundles.size(); 1074 if (size == 0) { 1075 return (null); 1076 } 1077 AbstractBundle[] bundlelist = new AbstractBundle[size]; 1078 allBundles.toArray(bundlelist); 1079 return (bundlelist); 1080 } 1081 } 1082 1083 AbstractBundle[] getBundles(final BundleContextImpl context) { 1084 List<AbstractBundle> allBundles; 1085 synchronized (bundles) { 1086 allBundles = new ArrayList<AbstractBundle>(bundles.getBundles()); 1087 } 1088 notifyFindHooks(context, allBundles); 1089 return allBundles.toArray(new AbstractBundle[allBundles.size()]); 1090 } 1091 1092 private void notifyFindHooks(final BundleContextImpl context, List<AbstractBundle> allBundles) { 1093 final Collection<Bundle> shrinkable = new ShrinkableCollection<Bundle>(allBundles); 1094 if (System.getSecurityManager() == null) { 1095 notifyFindHooksPriviledged(context, shrinkable); 1096 } else { 1097 AccessController.doPrivileged(new PrivilegedAction<Object>() { 1098 public Object run() { 1099 notifyFindHooksPriviledged(context, shrinkable); 1100 return null; 1101 } 1102 }); 1103 } 1104 } 1105 1106 void notifyFindHooksPriviledged(final BundleContextImpl context, final Collection<Bundle> allBundles) { 1107 if (Debug.DEBUG_HOOKS) { 1108 Debug.println("notifyBundleFindHooks(" + allBundles + ")"); //$NON-NLS-1$ //$NON-NLS-2$ 1109 } 1110 getServiceRegistry().notifyHooksPrivileged(new HookContext() { 1111 public void call(Object hook, ServiceRegistration<?> hookRegistration) throws Exception { 1112 if (hook instanceof FindHook) { 1113 ((FindHook) hook).find(context, allBundles); 1114 } 1115 } 1116 1117 public String getHookClassName() { 1118 return findHookName; 1119 } 1120 1121 public String getHookMethodName() { 1122 return "find"; //$NON-NLS-1$ 1123 } 1124 }); 1125 } 1126 1127 private void notifyCollisionHooks(final int operationType, final Bundle target, List<AbstractBundle> collisionCandidates) { 1128 final Collection<Bundle> shrinkable = new ShrinkableCollection<Bundle>(collisionCandidates); 1129 if (System.getSecurityManager() == null) { 1130 notifyCollisionHooksPriviledged(operationType, target, shrinkable); 1131 } else { 1132 AccessController.doPrivileged(new PrivilegedAction<Object>() { 1133 public Object run() { 1134 notifyCollisionHooksPriviledged(operationType, target, shrinkable); 1135 return null; 1136 } 1137 }); 1138 } 1139 } 1140 1141 void notifyCollisionHooksPriviledged(final int operationType, final Bundle target, final Collection<Bundle> collisionCandidates) { 1142 if (Debug.DEBUG_HOOKS) { 1143 Debug.println("notifyCollisionHooks(" + operationType + ", " + target + ", " + collisionCandidates + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ 1144 } 1145 getServiceRegistry().notifyHooksPrivileged(new HookContext() { 1146 public void call(Object hook, ServiceRegistration<?> hookRegistration) throws Exception { 1147 if (hook instanceof CollisionHook) { 1148 ((CollisionHook) hook).filterCollisions(operationType, target, collisionCandidates); 1149 } 1150 } 1151 1152 public String getHookClassName() { 1153 return collisionHookName; 1154 } 1155 1156 public String getHookMethodName() { 1157 return "filterCollisions"; //$NON-NLS-1$ 1158 } 1159 }); 1160 } 1161 1162 /** 1163 * Resume a bundle. 1164 * 1165 * @param bundle 1166 * Bundle to resume. 1167 */ 1168 protected void resumeBundle(AbstractBundle bundle) { 1169 if (bundle.isActive()) { 1170 // if bundle is active. 1171 return; 1172 } 1173 try { 1174 if (Debug.DEBUG_GENERAL) { 1175 Debug.println("Trying to resume bundle " + bundle); //$NON-NLS-1$ 1176 } 1177 bundle.resume(); 1178 } catch (BundleException be) { 1179 if (Debug.DEBUG_GENERAL) { 1180 Debug.println("Bundle resume exception: " + be.getMessage()); //$NON-NLS-1$ 1181 Debug.printStackTrace(be.getNestedException() == null ? be : be.getNestedException()); 1182 } 1183 publishFrameworkEvent(FrameworkEvent.ERROR, bundle, be); 1184 } 1185 } 1186 1187 /** 1188 * Suspend a bundle. 1189 * 1190 * @param bundle 1191 * Bundle to suspend. 1192 * @param lock 1193 * true if state change lock should be held when returning from 1194 * this method. 1195 * @return true if bundle was active and is now suspended. 1196 */ 1197 protected boolean suspendBundle(AbstractBundle bundle, boolean lock) { 1198 boolean changed = false; 1199 if (!bundle.isActive() || bundle.isFragment()) { 1200 // if bundle is not active or is a fragment then do nothing. 1201 return changed; 1202 } 1203 try { 1204 if (Debug.DEBUG_GENERAL) { 1205 Debug.println("Trying to suspend bundle " + bundle); //$NON-NLS-1$ 1206 } 1207 bundle.suspend(lock); 1208 } catch (BundleException be) { 1209 if (Debug.DEBUG_GENERAL) { 1210 Debug.println("Bundle suspend exception: " + be.getMessage()); //$NON-NLS-1$ 1211 Debug.printStackTrace(be.getNestedException() == null ? be : be.getNestedException()); 1212 } 1213 publishFrameworkEvent(FrameworkEvent.ERROR, bundle, be); 1214 } 1215 if (!bundle.isActive()) { 1216 changed = true; 1217 } 1218 return (changed); 1219 } 1220 1221 /** 1222 * Locate an installed bundle with a given identity. 1223 * 1224 * @param location 1225 * string for the bundle 1226 * @return Bundle object for bundle with the specified location or null if 1227 * no bundle is installed with the specified location. 1228 */ 1229 protected AbstractBundle getBundleByLocation(String location) { 1230 synchronized (bundles) { 1231 // this is not optimized; do not think it will get called 1232 // that much. 1233 final String finalLocation = location; 1234 1235 //Bundle.getLocation requires AdminPermission (metadata) 1236 return AccessController.doPrivileged(new PrivilegedAction<AbstractBundle>() { 1237 public AbstractBundle run() { 1238 List<AbstractBundle> allBundles = bundles.getBundles(); 1239 int size = allBundles.size(); 1240 for (int i = 0; i < size; i++) { 1241 AbstractBundle bundle = allBundles.get(i); 1242 if (finalLocation.equals(bundle.getLocation())) { 1243 return bundle; 1244 } 1245 } 1246 return null; 1247 } 1248 }); 1249 } 1250 } 1251 1252 /** 1253 * Locate an installed bundle with a given symbolic name 1254 * 1255 * @param symbolicName 1256 * The symbolic name for the bundle 1257 * @return Bundle object for bundle with the specified Unique or null if no 1258 * bundle is installed with the specified symbolicName. 1259 */ 1260 protected AbstractBundle[] getBundleBySymbolicName(String symbolicName) { 1261 synchronized (bundles) { 1262 return bundles.getBundles(symbolicName); 1263 } 1264 } 1265 1266 /** 1267 * Creates a <code>File</code> object for a file in the persistent 1268 * storage area provided for the bundle by the framework. If the adaptor 1269 * does not have file system support, this method will return <code>null</code>. 1270 * 1271 * <p> 1272 * A <code>File</code> object for the base directory of the persistent 1273 * storage area provided for the context bundle by the framework can be 1274 * obtained by calling this method with the empty string ("") as the 1275 * parameter. 1276 */ 1277 protected File getDataFile(final AbstractBundle bundle, final String filename) { 1278 return AccessController.doPrivileged(new GetDataFileAction(bundle, filename)); 1279 } 1280 1281 /** 1282 * Check for specific AdminPermission (RFC 73) 1283 */ 1284 protected void checkAdminPermission(Bundle bundle, String action) { 1285 SecurityManager sm = System.getSecurityManager(); 1286 if (sm != null) 1287 sm.checkPermission(getAdminPermission(bundle, action)); 1288 } 1289 1290 // gets AdminPermission objects from a cache to reduce the number of AdminPermission 1291 // objects that are created. 1292 private AdminPermission getAdminPermission(Bundle bundle, String action) { 1293 synchronized (adminPermissions) { 1294 Long ID = new Long(bundle.getBundleId()); 1295 Map<String, AdminPermission> bundlePermissions = adminPermissions.get(ID); 1296 if (bundlePermissions == null) { 1297 bundlePermissions = new HashMap<String, AdminPermission>(); 1298 adminPermissions.put(ID, bundlePermissions); 1299 } 1300 AdminPermission result = bundlePermissions.get(action); 1301 if (result == null) { 1302 result = new AdminPermission(bundle, action); 1303 bundlePermissions.put(action, result); 1304 } 1305 return result; 1306 } 1307 } 1308 1309 /** 1310 * This is necessary for running from a JXE, otherwise the SecurityManager 1311 * is set much later than we would like! 1312 */ 1313 protected void installSecurityManager() { 1314 String securityManager = FrameworkProperties.getProperty(Constants.FRAMEWORK_SECURITY, FrameworkProperties.getProperty(PROP_EQUINOX_SECURITY, FrameworkProperties.getProperty("java.security.manager"))); 1315 if (securityManager != null) { 1316 SecurityManager sm = System.getSecurityManager(); 1317 if (sm == null) { 1318 if (securityManager.length() == 0) 1319 sm = new SecurityManager(); // use the default one from java 1320 else if (securityManager.equals(SECURITY_OSGI)) 1321 sm = new EquinoxSecurityManager(); // use an OSGi enabled manager that understands postponed conditions 1322 else { 1323 // try to use a specific classloader by classname 1324 try { 1325 Class<?> clazz = Class.forName(securityManager); 1326 sm = (SecurityManager) clazz.newInstance(); 1327 } catch (ClassNotFoundException e) { 1328 // do nothing 1329 } catch (ClassCastException e) { 1330 // do nothing 1331 } catch (InstantiationException e) { 1332 // do nothing 1333 } catch (IllegalAccessException e) { 1334 // do nothing 1335 } 1336 } 1337 if (sm == null) 1338 throw new NoClassDefFoundError(securityManager); 1339 if (Debug.DEBUG_SECURITY) 1340 Debug.println("Setting SecurityManager to: " + sm); //$NON-NLS-1$ 1341 System.setSecurityManager(sm); 1342 return; 1343 } 1344 } 1345 } 1346 1347 void addFrameworkListener(FrameworkListener listener, BundleContextImpl context) { 1348 synchronized (allFrameworkListeners) { 1349 CopyOnWriteIdentityMap<FrameworkListener, FrameworkListener> listeners = allFrameworkListeners.get(context); 1350 if (listeners == null) { 1351 listeners = new CopyOnWriteIdentityMap<FrameworkListener, FrameworkListener>(); 1352 allFrameworkListeners.put(context, listeners); 1353 } 1354 listeners.put(listener, listener); 1355 } 1356 } 1357 1358 void removeFrameworkListener(FrameworkListener listener, BundleContextImpl context) { 1359 synchronized (allFrameworkListeners) { 1360 CopyOnWriteIdentityMap<FrameworkListener, FrameworkListener> listeners = allFrameworkListeners.get(context); 1361 if (listeners != null) 1362 listeners.remove(listener); 1363 } 1364 } 1365 1366 void removeAllListeners(BundleContextImpl context) { 1367 synchronized (allBundleListeners) { 1368 allBundleListeners.remove(context); 1369 } 1370 synchronized (allSyncBundleListeners) { 1371 allSyncBundleListeners.remove(context); 1372 } 1373 synchronized (allFrameworkListeners) { 1374 allFrameworkListeners.remove(context); 1375 } 1376 } 1377 1378 /** 1379 * Deliver a FrameworkEvent. 1380 * 1381 * @param type 1382 * FrameworkEvent type. 1383 * @param bundle 1384 * Affected bundle or null for system bundle. 1385 * @param throwable 1386 * Related exception or null. 1387 */ 1388 public void publishFrameworkEvent(int type, Bundle bundle, Throwable throwable) { 1389 publishFrameworkEvent(type, bundle, throwable, (FrameworkListener[]) null); 1390 } 1391 1392 public void publishFrameworkEvent(int type, Bundle bundle, Throwable throwable, final FrameworkListener... listeners) { 1393 if (bundle == null) 1394 bundle = systemBundle; 1395 final FrameworkEvent event = new FrameworkEvent(type, bundle, throwable); 1396 if (System.getSecurityManager() == null) { 1397 publishFrameworkEventPrivileged(event, listeners); 1398 } else { 1399 AccessController.doPrivileged(new PrivilegedAction<Object>() { 1400 public Object run() { 1401 publishFrameworkEventPrivileged(event, listeners); 1402 return null; 1403 } 1404 }); 1405 } 1406 } 1407 1408 public void publishFrameworkEventPrivileged(FrameworkEvent event, FrameworkListener... callerListeners) { 1409 // Build the listener snapshot 1410 Map<BundleContextImpl, Set<Map.Entry<FrameworkListener, FrameworkListener>>> listenerSnapshot; 1411 synchronized (allFrameworkListeners) { 1412 listenerSnapshot = new HashMap<BundleContextImpl, Set<Map.Entry<FrameworkListener, FrameworkListener>>>(allFrameworkListeners.size()); 1413 for (Map.Entry<BundleContextImpl, CopyOnWriteIdentityMap<FrameworkListener, FrameworkListener>> entry : allFrameworkListeners.entrySet()) { 1414 CopyOnWriteIdentityMap<FrameworkListener, FrameworkListener> listeners = entry.getValue(); 1415 if (!listeners.isEmpty()) { 1416 listenerSnapshot.put(entry.getKey(), listeners.entrySet()); 1417 } 1418 } 1419 } 1420 // If framework event hook were defined they would be called here 1421 1422 // deliver the event to the snapshot 1423 ListenerQueue<FrameworkListener, FrameworkListener, FrameworkEvent> queue = newListenerQueue(); 1424 1425 // add the listeners specified by the caller first 1426 if (callerListeners != null && callerListeners.length > 0) { 1427 Map<FrameworkListener, FrameworkListener> listeners = new HashMap<FrameworkListener, FrameworkListener>(); 1428 for (FrameworkListener listener : callerListeners) { 1429 if (listener != null) 1430 listeners.put(listener, listener); 1431 } 1432 // We use the system bundle context as the dispatcher 1433 if (listeners.size() > 0) { 1434 @SuppressWarnings({"rawtypes", "unchecked"}) 1435 EventDispatcher<FrameworkListener, FrameworkListener, FrameworkEvent> dispatcher = (EventDispatcher) getSystemBundleContext(); 1436 queue.queueListeners(listeners.entrySet(), dispatcher); 1437 } 1438 } 1439 1440 for (Map.Entry<BundleContextImpl, Set<Map.Entry<FrameworkListener, FrameworkListener>>> entry : listenerSnapshot.entrySet()) { 1441 @SuppressWarnings({"rawtypes", "unchecked"}) 1442 EventDispatcher<FrameworkListener, FrameworkListener, FrameworkEvent> dispatcher = (EventDispatcher) entry.getKey(); 1443 Set<Map.Entry<FrameworkListener, FrameworkListener>> listeners = entry.getValue(); 1444 queue.queueListeners(listeners, dispatcher); 1445 } 1446 1447 queue.dispatchEventAsynchronous(FRAMEWORKEVENT, event); 1448 } 1449 1450 void addBundleListener(BundleListener listener, BundleContextImpl context) { 1451 if (listener instanceof SynchronousBundleListener) { 1452 checkAdminPermission(context.getBundle(), AdminPermission.LISTENER); 1453 synchronized (allSyncBundleListeners) { 1454 CopyOnWriteIdentityMap<SynchronousBundleListener, SynchronousBundleListener> listeners = allSyncBundleListeners.get(context); 1455 if (listeners == null) { 1456 listeners = new CopyOnWriteIdentityMap<SynchronousBundleListener, SynchronousBundleListener>(); 1457 allSyncBundleListeners.put(context, listeners); 1458 } 1459 listeners.put((SynchronousBundleListener) listener, (SynchronousBundleListener) listener); 1460 } 1461 } else { 1462 synchronized (allBundleListeners) { 1463 CopyOnWriteIdentityMap<BundleListener, BundleListener> listeners = allBundleListeners.get(context); 1464 if (listeners == null) { 1465 listeners = new CopyOnWriteIdentityMap<BundleListener, BundleListener>(); 1466 allBundleListeners.put(context, listeners); 1467 } 1468 listeners.put(listener, listener); 1469 } 1470 } 1471 } 1472 1473 void removeBundleListener(BundleListener listener, BundleContextImpl context) { 1474 if (listener instanceof SynchronousBundleListener) { 1475 checkAdminPermission(context.getBundle(), AdminPermission.LISTENER); 1476 synchronized (allSyncBundleListeners) { 1477 CopyOnWriteIdentityMap<SynchronousBundleListener, SynchronousBundleListener> listeners = allSyncBundleListeners.get(context); 1478 if (listeners != null) 1479 listeners.remove(listener); 1480 } 1481 } else { 1482 synchronized (allBundleListeners) { 1483 CopyOnWriteIdentityMap<BundleListener, BundleListener> listeners = allBundleListeners.get(context); 1484 if (listeners != null) 1485 listeners.remove(listener); 1486 } 1487 } 1488 } 1489 1490 /** 1491 * Deliver a BundleEvent to SynchronousBundleListeners (synchronous). and 1492 * BundleListeners (asynchronous). 1493 * 1494 * @param type 1495 * BundleEvent type. 1496 * @param bundle 1497 * Affected bundle or null. 1498 */ 1499 public void publishBundleEvent(int type, Bundle bundle) { 1500 publishBundleEvent(new BundleEvent(type, bundle)); 1501 } 1502 1503 private void publishBundleEvent(final BundleEvent event) { 1504 if (System.getSecurityManager() == null) { 1505 publishBundleEventPrivileged(event); 1506 } else { 1507 AccessController.doPrivileged(new PrivilegedAction<Object>() { 1508 public Object run() { 1509 publishBundleEventPrivileged(event); 1510 return null; 1511 } 1512 }); 1513 } 1514 } 1515 1516 public void publishBundleEventPrivileged(BundleEvent event) { 1517 /* 1518 * We must collect the snapshots of the sync and async listeners 1519 * BEFORE we dispatch the event. 1520 */ 1521 /* Collect snapshot of SynchronousBundleListeners */ 1522 /* Build the listener snapshot */ 1523 Map<BundleContextImpl, Set<Map.Entry<SynchronousBundleListener, SynchronousBundleListener>>> listenersSync; 1524 synchronized (allSyncBundleListeners) { 1525 listenersSync = new HashMap<BundleContextImpl, Set<Map.Entry<SynchronousBundleListener, SynchronousBundleListener>>>(allSyncBundleListeners.size()); 1526 for (Map.Entry<BundleContextImpl, CopyOnWriteIdentityMap<SynchronousBundleListener, SynchronousBundleListener>> entry : allSyncBundleListeners.entrySet()) { 1527 CopyOnWriteIdentityMap<SynchronousBundleListener, SynchronousBundleListener> listeners = entry.getValue(); 1528 if (!listeners.isEmpty()) { 1529 listenersSync.put(entry.getKey(), listeners.entrySet()); 1530 } 1531 } 1532 } 1533 /* Collect snapshot of BundleListeners; only if the event is NOT STARTING or STOPPING or LAZY_ACTIVATION */ 1534 Map<BundleContextImpl, Set<Map.Entry<BundleListener, BundleListener>>> listenersAsync = null; 1535 if ((event.getType() & (BundleEvent.STARTING | BundleEvent.STOPPING | BundleEvent.LAZY_ACTIVATION)) == 0) { 1536 synchronized (allBundleListeners) { 1537 listenersAsync = new HashMap<BundleContextImpl, Set<Map.Entry<BundleListener, BundleListener>>>(allBundleListeners.size()); 1538 for (Map.Entry<BundleContextImpl, CopyOnWriteIdentityMap<BundleListener, BundleListener>> entry : allBundleListeners.entrySet()) { 1539 CopyOnWriteIdentityMap<BundleListener, BundleListener> listeners = entry.getValue(); 1540 if (!listeners.isEmpty()) { 1541 listenersAsync.put(entry.getKey(), listeners.entrySet()); 1542 } 1543 } 1544 } 1545 } 1546 1547 /* shrink the snapshot. 1548 * keySet returns a Collection which cannot be added to and 1549 * removals from that collection will result in removals of the 1550 * entry from the snapshot. 1551 */ 1552 Collection<BundleContext> shrinkable; 1553 if (listenersAsync == null) { 1554 shrinkable = asBundleContexts(listenersSync.keySet()); 1555 } else { 1556 shrinkable = new ShrinkableCollection<BundleContext>(asBundleContexts(listenersSync.keySet()), asBundleContexts(listenersAsync.keySet())); 1557 } 1558 notifyEventHooksPrivileged(event, shrinkable); 1559 1560 /* Dispatch the event to the snapshot for sync listeners */ 1561 if (!listenersSync.isEmpty()) { 1562 ListenerQueue<SynchronousBundleListener, SynchronousBundleListener, BundleEvent> queue = newListenerQueue(); 1563 for (Map.Entry<BundleContextImpl, Set<Map.Entry<SynchronousBundleListener, SynchronousBundleListener>>> entry : listenersSync.entrySet()) { 1564 @SuppressWarnings({"rawtypes", "unchecked"}) 1565 EventDispatcher<SynchronousBundleListener, SynchronousBundleListener, BundleEvent> dispatcher = (EventDispatcher) entry.getKey(); 1566 Set<Map.Entry<SynchronousBundleListener, SynchronousBundleListener>> listeners = entry.getValue(); 1567 queue.queueListeners(listeners, dispatcher); 1568 } 1569 queue.dispatchEventSynchronous(BUNDLEEVENTSYNC, event); 1570 } 1571 1572 /* Dispatch the event to the snapshot for async listeners */ 1573 if ((listenersAsync != null) && !listenersAsync.isEmpty()) { 1574 ListenerQueue<BundleListener, BundleListener, BundleEvent> queue = newListenerQueue(); 1575 for (Map.Entry<BundleContextImpl, Set<Map.Entry<BundleListener, BundleListener>>> entry : listenersAsync.entrySet()) { 1576 @SuppressWarnings({"rawtypes", "unchecked"}) 1577 EventDispatcher<BundleListener, BundleListener, BundleEvent> dispatcher = (EventDispatcher) entry.getKey(); 1578 Set<Map.Entry<BundleListener, BundleListener>> listeners = entry.getValue(); 1579 queue.queueListeners(listeners, dispatcher); 1580 } 1581 queue.dispatchEventAsynchronous(BUNDLEEVENT, event); 1582 } 1583 } 1584 1585 /** 1586 * Coerce the generic type of a collection from Collection<BundleContextImpl> 1587 * to Collection<BundleContext> 1588 * @param c Collection to be coerced. 1589 * @return c coerced to Collection<BundleContext> 1590 */ 1591 @SuppressWarnings("unchecked") 1592 public static Collection<BundleContext> asBundleContexts(Collection<? extends BundleContext> c) { 1593 return (Collection<BundleContext>) c; 1594 } 1595 1596 private void notifyEventHooksPrivileged(final BundleEvent event, final Collection<BundleContext> result) { 1597 if (event.getType() == Framework.BATCHEVENT_BEGIN || event.getType() == Framework.BATCHEVENT_END) 1598 return; // we don't need to send this event; it is used to book case special listeners 1599 if (Debug.DEBUG_HOOKS) { 1600 Debug.println("notifyBundleEventHooks(" + event.getType() + ":" + event.getBundle() + ", " + result + " )"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ 1601 } 1602 1603 getServiceRegistry().notifyHooksPrivileged(new HookContext() { 1604 public void call(Object hook, ServiceRegistration<?> hookRegistration) throws Exception { 1605 if (hook instanceof EventHook) { 1606 ((EventHook) hook).event(event, result); 1607 } 1608 } 1609 1610 public String getHookClassName() { 1611 return eventHookName; 1612 } 1613 1614 public String getHookMethodName() { 1615 return "event"; //$NON-NLS-1$ 1616 } 1617 }); 1618 } 1619 1620 public <K, V, E> ListenerQueue<K, V, E> newListenerQueue() { 1621 return new ListenerQueue<K, V, E>(eventManager); 1622 } 1623 1624 private void initializeContextFinder() { 1625 Thread current = Thread.currentThread(); 1626 try { 1627 ClassLoader parent = null; 1628 // check property for specified parent 1629 String type = FrameworkProperties.getProperty(PROP_CONTEXTCLASSLOADER_PARENT); 1630 if (CONTEXTCLASSLOADER_PARENT_APP.equals(type)) 1631 parent = ClassLoader.getSystemClassLoader(); 1632 else if (CONTEXTCLASSLOADER_PARENT_BOOT.equals(type)) 1633 parent = null; 1634 else if (CONTEXTCLASSLOADER_PARENT_FWK.equals(type)) 1635 parent = Framework.class.getClassLoader(); 1636 else if (CONTEXTCLASSLOADER_PARENT_EXT.equals(type)) { 1637 ClassLoader appCL = ClassLoader.getSystemClassLoader(); 1638 if (appCL != null) 1639 parent = appCL.getParent(); 1640 } else { // default is ccl (null or any other value will use ccl) 1641 parent = current.getContextClassLoader(); 1642 } 1643 contextFinder = new ContextFinder(parent); 1644 current.setContextClassLoader(contextFinder); 1645 return; 1646 } catch (Exception e) { 1647 FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.INFO, 0, NLS.bind(Msg.CANNOT_SET_CONTEXTFINDER, null), 0, e, null); 1648 adaptor.getFrameworkLog().log(entry); 1649 } 1650 1651 } 1652 1653 public static Field getField(Class<?> clazz, Class<?> type, boolean instance) { 1654 Field[] fields = clazz.getDeclaredFields(); 1655 for (int i = 0; i < fields.length; i++) { 1656 boolean isStatic = Modifier.isStatic(fields[i].getModifiers()); 1657 if (instance != isStatic && fields[i].getType().equals(type)) { 1658 fields[i].setAccessible(true); 1659 return fields[i]; 1660 } 1661 } 1662 return null; 1663 } 1664 1665 private void installContentHandlerFactory(BundleContext context, FrameworkAdaptor frameworkAdaptor) { 1666 ContentHandlerFactory chf = new ContentHandlerFactory(context, frameworkAdaptor); 1667 try { 1668 // first try the standard way 1669 URLConnection.setContentHandlerFactory(chf); 1670 } catch (Error err) { 1671 // ok we failed now use more drastic means to set the factory 1672 try { 1673 forceContentHandlerFactory(chf); 1674 } catch (Exception ex) { 1675 // this is unexpected, log the exception and throw the original error 1676 adaptor.getFrameworkLog().log(new FrameworkEvent(FrameworkEvent.ERROR, context.getBundle(), ex)); 1677 throw err; 1678 } 1679 } 1680 contentHandlerFactory = chf; 1681 } 1682 1683 private static void forceContentHandlerFactory(ContentHandlerFactory chf) throws Exception { 1684 Field factoryField = getField(URLConnection.class, java.net.ContentHandlerFactory.class, false); 1685 if (factoryField == null) 1686 throw new Exception("Could not find ContentHandlerFactory field"); //$NON-NLS-1$ 1687 synchronized (URLConnection.class) { 1688 java.net.ContentHandlerFactory factory = (java.net.ContentHandlerFactory) factoryField.get(null); 1689 // doing a null check here just in case, but it would be really strange if it was null, 1690 // because we failed to set the factory normally!! 1691 1692 if (factory != null) { 1693 try { 1694 factory.getClass().getMethod("isMultiplexing", (Class[]) null); //$NON-NLS-1$ 1695 Method register = factory.getClass().getMethod("register", new Class[] {Object.class}); //$NON-NLS-1$ 1696 register.invoke(factory, new Object[] {chf}); 1697 } catch (NoSuchMethodException e) { 1698 // current factory does not support multiplexing, ok we'll wrap it 1699 chf.setParentFactory(factory); 1700 factory = chf; 1701 } 1702 } 1703 // null out the field so that we can successfully call setContentHandlerFactory 1704 factoryField.set(null, null); 1705 // always attempt to clear the handlers cache 1706 // This allows an optomization for the single framework use-case 1707 resetContentHandlers(); 1708 URLConnection.setContentHandlerFactory(factory); 1709 } 1710 } 1711 1712 private void uninstallContentHandlerFactory() { 1713 try { 1714 Field factoryField = getField(URLConnection.class, java.net.ContentHandlerFactory.class, false); 1715 if (factoryField == null) 1716 return; // oh well, we tried. 1717 synchronized (URLConnection.class) { 1718 java.net.ContentHandlerFactory factory = (java.net.ContentHandlerFactory) factoryField.get(null); 1719 1720 if (factory == contentHandlerFactory) { 1721 factory = (java.net.ContentHandlerFactory) contentHandlerFactory.designateSuccessor(); 1722 } else { 1723 Method unregister = factory.getClass().getMethod("unregister", new Class[] {Object.class}); //$NON-NLS-1$ 1724 unregister.invoke(factory, new Object[] {contentHandlerFactory}); 1725 } 1726 // null out the field so that we can successfully call setContentHandlerFactory 1727 factoryField.set(null, null); 1728 // always attempt to clear the handlers cache 1729 // This allows an optomization for the single framework use-case 1730 // Note that the call to setContentHandlerFactory below may clear this cache 1731 // but we want to be sure to clear it here just incase the parent is null. 1732 // In this case the call below would not occur. 1733 // Also it appears most java libraries actually do not clear the cache 1734 // when setContentHandlerFactory is called, go figure!! 1735 resetContentHandlers(); 1736 if (factory != null) 1737 URLConnection.setContentHandlerFactory(factory); 1738 } 1739 } catch (Exception e) { 1740 // ignore and continue closing the framework 1741 } 1742 } 1743 1744 private static void resetContentHandlers() throws IllegalAccessException { 1745 Field handlersField = getField(URLConnection.class, Hashtable.class, false); 1746 if (handlersField != null) { 1747 @SuppressWarnings("rawtypes") 1748 Hashtable<?, ?> handlers = (Hashtable) handlersField.get(null); 1749 if (handlers != null) 1750 handlers.clear(); 1751 } 1752 } 1753 1754 private void installURLStreamHandlerFactory(BundleContext context, FrameworkAdaptor frameworkAdaptor) { 1755 StreamHandlerFactory shf = new StreamHandlerFactory(context, frameworkAdaptor); 1756 try { 1757 // first try the standard way 1758 URL.setURLStreamHandlerFactory(shf); 1759 } catch (Error err) { 1760 try { 1761 // ok we failed now use more drastic means to set the factory 1762 forceURLStreamHandlerFactory(shf); 1763 } catch (Exception ex) { 1764 adaptor.getFrameworkLog().log(new FrameworkEvent(FrameworkEvent.ERROR, context.getBundle(), ex)); 1765 throw err; 1766 } 1767 } 1768 streamHandlerFactory = shf; 1769 } 1770 1771 private static void forceURLStreamHandlerFactory(StreamHandlerFactory shf) throws Exception { 1772 Field factoryField = getField(URL.class, URLStreamHandlerFactory.class, false); 1773 if (factoryField == null) 1774 throw new Exception("Could not find URLStreamHandlerFactory field"); //$NON-NLS-1$ 1775 // look for a lock to synchronize on 1776 Object lock = getURLStreamHandlerFactoryLock(); 1777 synchronized (lock) { 1778 URLStreamHandlerFactory factory = (URLStreamHandlerFactory) factoryField.get(null); 1779 // doing a null check here just in case, but it would be really strange if it was null, 1780 // because we failed to set the factory normally!! 1781 if (factory != null) { 1782 try { 1783 factory.getClass().getMethod("isMultiplexing", (Class[]) null); //$NON-NLS-1$ 1784 Method register = factory.getClass().getMethod("register", new Class[] {Object.class}); //$NON-NLS-1$ 1785 register.invoke(factory, new Object[] {shf}); 1786 } catch (NoSuchMethodException e) { 1787 // current factory does not support multiplexing, ok we'll wrap it 1788 shf.setParentFactory(factory); 1789 factory = shf; 1790 } 1791 } 1792 factoryField.set(null, null); 1793 // always attempt to clear the handlers cache 1794 // This allows an optomization for the single framework use-case 1795 resetURLStreamHandlers(); 1796 URL.setURLStreamHandlerFactory(factory); 1797 } 1798 } 1799 1800 private void uninstallURLStreamHandlerFactory() { 1801 try { 1802 Field factoryField = getField(URL.class, URLStreamHandlerFactory.class, false); 1803 if (factoryField == null) 1804 return; // oh well, we tried 1805 Object lock = getURLStreamHandlerFactoryLock(); 1806 synchronized (lock) { 1807 URLStreamHandlerFactory factory = (URLStreamHandlerFactory) factoryField.get(null); 1808 if (factory == streamHandlerFactory) { 1809 factory = (URLStreamHandlerFactory) streamHandlerFactory.designateSuccessor(); 1810 } else { 1811 Method unregister = factory.getClass().getMethod("unregister", new Class[] {Object.class}); //$NON-NLS-1$ 1812 unregister.invoke(factory, new Object[] {streamHandlerFactory}); 1813 } 1814 factoryField.set(null, null); 1815 // always attempt to clear the handlers cache 1816 // This allows an optomization for the single framework use-case 1817 // Note that the call to setURLStreamHandlerFactory below may clear this cache 1818 // but we want to be sure to clear it here just in case the parent is null. 1819 // In this case the call below would not occur. 1820 resetURLStreamHandlers(); 1821 if (factory != null) 1822 URL.setURLStreamHandlerFactory(factory); 1823 } 1824 } catch (Exception e) { 1825 // ignore and continue closing the framework 1826 } 1827 } 1828 1829 private static Object getURLStreamHandlerFactoryLock() throws IllegalAccessException { 1830 Object lock; 1831 try { 1832 Field streamHandlerLockField = URL.class.getDeclaredField("streamHandlerLock"); //$NON-NLS-1$ 1833 streamHandlerLockField.setAccessible(true); 1834 lock = streamHandlerLockField.get(null); 1835 } catch (NoSuchFieldException noField) { 1836 // could not find the lock, lets sync on the class object 1837 lock = URL.class; 1838 } 1839 return lock; 1840 } 1841 1842 private static void resetURLStreamHandlers() throws IllegalAccessException { 1843 Field handlersField = getField(URL.class, Hashtable.class, false); 1844 if (handlersField != null) { 1845 @SuppressWarnings("rawtypes") 1846 Hashtable<?, ?> handlers = (Hashtable) handlersField.get(null); 1847 if (handlers != null) 1848 handlers.clear(); 1849 } 1850 } 1851 1852 /* 1853 * (non-Javadoc) 1854 * @see java.lang.Runnable#run() 1855 * This thread monitors the framework active status and terminates when the framework is 1856 * shutdown. This is needed to ensure the VM does not exist because of the lack of a 1857 * non-daemon thread (bug 215730) 1858 */ 1859 public void run() { 1860 synchronized (this) { 1861 while (active) 1862 try { 1863 this.wait(1000); 1864 } catch (InterruptedException e) { 1865 // do nothing 1866 } 1867 } 1868 } 1869 1870 void setForcedRestart(boolean forcedRestart) { 1871 this.forcedRestart = forcedRestart; 1872 } 1873 1874 boolean isForcedRestart() { 1875 return forcedRestart; 1876 } 1877 1878 public FrameworkEvent waitForStop(long timeout) throws InterruptedException { 1879 boolean waitForEver = timeout == 0; 1880 long start = System.currentTimeMillis(); 1881 long timeLeft = timeout; 1882 synchronized (this) { 1883 FrameworkEvent[] event = shutdownEvent; 1884 while (event != null && event[0] == null) { 1885 this.wait(timeLeft); 1886 if (!waitForEver) { 1887 timeLeft = start + timeout - System.currentTimeMillis(); 1888 // break if we are passed the timeout 1889 if (timeLeft <= 0) 1890 break; 1891 } 1892 } 1893 if (event == null || event[0] == null) 1894 return new FrameworkEvent(FrameworkEvent.WAIT_TIMEDOUT, systemBundle, null); 1895 return event[0]; 1896 } 1897 } 1898 1899 /** 1900 * Used by ServiceReferenceImpl for isAssignableTo 1901 * @param registrant Bundle registering service 1902 * @param client Bundle desiring to use service 1903 * @param className class name to use 1904 * @param serviceClass class of original service object 1905 * @return true if assignable given package wiring 1906 */ 1907 public boolean isServiceAssignableTo(Bundle registrant, Bundle client, String className, Class<?> serviceClass) { 1908 // always return false for fragments 1909 AbstractBundle consumer = (AbstractBundle) client; 1910 if (consumer.isFragment()) 1911 return false; 1912 // 1) if the registrant == consumer always return true 1913 AbstractBundle producer = (AbstractBundle) registrant; 1914 if (consumer == producer) 1915 return true; 1916 // 2) get the package name from the specified className 1917 String pkgName = BundleLoader.getPackageName(className); 1918 if (pkgName.startsWith("java.")) //$NON-NLS-1$ 1919 return true; 1920 BundleLoader producerBL = producer.getBundleLoader(); 1921 if (producerBL == null) 1922 return false; 1923 BundleLoader consumerBL = consumer.getBundleLoader(); 1924 if (consumerBL == null) 1925 return false; 1926 // 3) for the specified bundle, find the wiring for the package. If no wiring is found return true 1927 PackageSource consumerSource = consumerBL.getPackageSource(pkgName); 1928 if (consumerSource == null) 1929 return true; 1930 // work around the issue when the package is in the EE and we delegate to boot for that package 1931 if (isBootDelegationPackage(pkgName)) { 1932 SystemBundleLoader systemLoader = (SystemBundleLoader) systemBundle.getBundleLoader(); 1933 if (systemLoader.isEEPackage(pkgName)) 1934 return true; // in this case we have a common source from the EE 1935 } 1936 // 4) For the registrant bundle, find the wiring for the package. 1937 PackageSource producerSource = producerBL.getPackageSource(pkgName); 1938 if (producerSource == null) { 1939 if (serviceClass != null && ServiceFactory.class.isAssignableFrom(serviceClass)) { 1940 Bundle bundle = packageAdmin.getBundle(serviceClass); 1941 if (bundle != null && bundle != registrant) 1942 // in this case we have a wacky ServiceFactory that is doing something we cannot 1943 // verify if it is correct. Instead of failing we allow the assignment and hope for the best 1944 // bug 326918 1945 return true; 1946 } 1947 // 5) If no wiring is found for the registrant bundle then find the wiring for the classloader of the service object. If no wiring is found return false. 1948 producerSource = getPackageSource(serviceClass, pkgName); 1949 if (producerSource == null) 1950 return false; 1951 } 1952 // 6) If the two wirings found are equal then return true; otherwise return false. 1953 return producerSource.hasCommonSource(consumerSource); 1954 } 1955 1956 private PackageSource getPackageSource(Class<?> serviceClass, String pkgName) { 1957 if (serviceClass == null) 1958 return null; 1959 AbstractBundle serviceBundle = (AbstractBundle) packageAdmin.getBundle(serviceClass); 1960 if (serviceBundle == null) 1961 return null; 1962 BundleLoader producerBL = serviceBundle.getBundleLoader(); 1963 if (producerBL == null) 1964 return null; 1965 PackageSource producerSource = producerBL.getPackageSource(pkgName); 1966 if (producerSource != null) 1967 return producerSource; 1968 // try the interfaces 1969 Class<?>[] interfaces = serviceClass.getInterfaces(); 1970 // note that getInterfaces never returns null 1971 for (int i = 0; i < interfaces.length; i++) { 1972 producerSource = getPackageSource(interfaces[i], pkgName); 1973 if (producerSource != null) 1974 return producerSource; 1975 } 1976 // try super class 1977 return getPackageSource(serviceClass.getSuperclass(), pkgName); 1978 } 1979 1980 public boolean isBootDelegationPackage(String name) { 1981 if (bootDelegateAll) 1982 return true; 1983 if (bootDelegation != null) 1984 for (int i = 0; i < bootDelegation.length; i++) 1985 if (name.equals(bootDelegation[i])) 1986 return true; 1987 if (bootDelegationStems != null) 1988 for (int i = 0; i < bootDelegationStems.length; i++) 1989 if (name.startsWith(bootDelegationStems[i])) 1990 return true; 1991 return false; 1992 } 1993 1994 SignedContentFactory getSignedContentFactory() { 1995 ServiceTracker<SignedContentFactory, SignedContentFactory> currentTracker = signedContentFactory; 1996 return (currentTracker == null ? null : currentTracker.getService()); 1997 } 1998 1999 ContextFinder getContextFinder() { 2000 return contextFinder; 2001 } 2002 2003 public boolean isRefreshDuplicateBSNAllowed() { 2004 return allowRefreshDuplicateBSN; 2005 } 2006 2007 }
1 public Framework(FrameworkAdaptor adaptor) { 2 if (Profile.PROFILE && Profile.STARTUP) 3 Profile.logEnter("Framework.initialze()", null); //$NON-NLS-1$ 4 String bsnVersion = FrameworkProperties.getProperty(Constants.FRAMEWORK_BSNVERSION); 5 if (Constants.FRAMEWORK_BSNVERSION_SINGLE.equals(bsnVersion)) { 6 BSN_VERSION = BSN_VERSION_SINGLE; 7 } else if (Constants.FRAMEWORK_BSNVERSION_MULTIPLE.equals(bsnVersion)) { 8 BSN_VERSION = BSN_VERSION_MULTIPLE; 9 } else { 10 BSN_VERSION = BSN_VERSION_MANAGED; 11 } 12 long start = System.currentTimeMillis(); 13 this.adaptor = adaptor; 14 delegateHooks = adaptor instanceof BaseAdaptor ? ((BaseAdaptor) adaptor).getHookRegistry().getClassLoaderDelegateHooks() : null; 15 active = false; 16 installSecurityManager(); 17 if (Debug.DEBUG_SECURITY) { 18 Debug.println("SecurityManager: " + System.getSecurityManager()); //$NON-NLS-1$ 19 Debug.println("ProtectionDomain of Framework.class: \n" + this.getClass().getProtectionDomain()); //$NON-NLS-1$ 20 } 21 setNLSFrameworkLog(); 22 // initialize ContextFinder 23 initializeContextFinder(); 24 /* initialize the adaptor */ 25 adaptor.initialize(this); 26 if (Profile.PROFILE && Profile.STARTUP) 27 Profile.logTime("Framework.initialze()", "adapter initialized"); //$NON-NLS-1$//$NON-NLS-2$ 28 try { 29 adaptor.initializeStorage(); 30 } catch (IOException e) /* fatal error */{ 31 throw new RuntimeException(e.getMessage(), e); 32 } 33 if (Profile.PROFILE && Profile.STARTUP) 34 Profile.logTime("Framework.initialze()", "adapter storage initialized"); //$NON-NLS-1$//$NON-NLS-2$ 35 /* 36 * This must be done before calling any of the framework getProperty 37 * methods. 38 */ 39 initializeProperties(adaptor.getProperties()); 40 /* initialize admin objects */ 41 packageAdmin = new PackageAdminImpl(this); 42 try { 43 // always create security admin even with security off 44 securityAdmin = new SecurityAdmin(null, this, adaptor.getPermissionStorage()); 45 } catch (IOException e) /* fatal error */{ 46 e.printStackTrace(); 47 throw new RuntimeException(e.getMessage(), e); 48 } 49 if (Profile.PROFILE && Profile.STARTUP) 50 Profile.logTime("Framework.initialze()", "done init props & new PermissionAdminImpl"); //$NON-NLS-1$//$NON-NLS-2$ 51 startLevelManager = new StartLevelManager(this); 52 /* create the event manager and top level event dispatchers */ 53 eventManager = new EventManager("Framework Event Dispatcher"); //$NON-NLS-1$ 54 if (Profile.PROFILE && Profile.STARTUP) 55 Profile.logTime("Framework.initialze()", "done new EventManager"); //$NON-NLS-1$ //$NON-NLS-2$ 56 /* create the service registry */ 57 serviceRegistry = new ServiceRegistry(this); 58 // Initialize the installLock; there is no way of knowing 59 // what the initial size should be, at most it will be the number 60 // of threads trying to install a bundle (probably a very low number). 61 installLock = new HashMap<String, Thread>(10); 62 /* create the system bundle */ 63 createSystemBundle(); 64loadVMProfile(); // load VM profile after the system bundle has been created 65 setBootDelegation(); //set boot delegation property after system exports have been set 66 if (Profile.PROFILE && Profile.STARTUP) 67 Profile.logTime("Framework.initialze()", "done createSystemBundle"); //$NON-NLS-1$ //$NON-NLS-2$ 68 /* install URLStreamHandlerFactory */ 69 installURLStreamHandlerFactory(systemBundle.context, adaptor); 70 /* install ContentHandlerFactory for OSGi URLStreamHandler support */ 71 installContentHandlerFactory(systemBundle.context, adaptor); 72 if (Profile.PROFILE && Profile.STARTUP) 73 Profile.logTime("Framework.initialze()", "done new URLStream/Content HandlerFactory"); //$NON-NLS-1$//$NON-NLS-2$ 74 /* create bundle objects for all installed bundles. */ 75 BundleData[] bundleDatas = adaptor.getInstalledBundles(); 76 bundles = new BundleRepository(bundleDatas == null ? 10 : bundleDatas.length + 1); 77 /* add the system bundle to the Bundle Repository */ 78 bundles.add(systemBundle); 79 if (bundleDatas != null) { 80 for (int i = 0; i < bundleDatas.length; i++) { 81 try { 82 AbstractBundle bundle = AbstractBundle.createBundle(bundleDatas[i], this, true); 83 bundles.add(bundle); 84 } catch (BundleException be) { 85 // This is not a fatal error. Publish the framework event. 86 publishFrameworkEvent(FrameworkEvent.ERROR, systemBundle, be); 87 } 88 } 89 } 90 if (Debug.DEBUG_GENERAL) 91 System.out.println("Initialize the framework: " + (System.currentTimeMillis() - start)); //$NON-NLS-1$ 92 if (Profile.PROFILE && Profile.STARTUP) 93 Profile.logExit("Framework.initialize()"); //$NON-NLS-1$ 94 }
framework.luanch()
1 public synchronized void launch() { 2 /* Return if framework already started */ 3 if (active) { 4 return; 5 } 6 /* mark framework as started */ 7 active = true; 8 shutdownEvent = new FrameworkEvent[1]; 9 if (THREAD_NORMAL.equals(FrameworkProperties.getProperty(PROP_FRAMEWORK_THREAD, THREAD_NORMAL))) { 10 Thread fwkThread = new Thread(this, "Framework Active Thread"); //$NON-NLS-1$ 11 fwkThread.setDaemon(false); 12 fwkThread.start(); 13 } 14 /* Resume systembundle */ 15 if (Debug.DEBUG_GENERAL) { 16 Debug.println("Trying to launch framework"); //$NON-NLS-1$ 17 } 18 systemBundle.resume(); 19 signedContentFactory = new ServiceTracker<SignedContentFactory, SignedContentFactory>(systemBundle.getBundleContext(), SignedContentFactory.class.getName(), null); 20 signedContentFactory.open(); 21 }
1 /* 2 * (non-Javadoc) 3 * @see java.lang.Runnable#run() 4 * This thread monitors the framework active status and terminates when the framework is 5 * shutdown. This is needed to ensure the VM does not exist because of the lack of a 6 * non-daemon thread (bug 215730) 7 */ 8 public void run() { 9 synchronized (this) { 10 while (active) 11 try { 12 this.wait(1000); 13 } catch (InterruptedException e) { 14 // do nothing 15 } 16 } 17 }
- load basic bundles
-
1 Bundle[] startBundles = loadBasicBundles();
-
1 private static Bundle[] loadBasicBundles() { 2 long startTime = System.currentTimeMillis(); 3 String osgiBundles = FrameworkProperties.getProperty(PROP_BUNDLES); 4 String osgiExtensions = FrameworkProperties.getProperty(PROP_EXTENSIONS); 5 if (osgiExtensions != null && osgiExtensions.length() > 0) { 6 osgiBundles = osgiExtensions + ',' + osgiBundles; 7 FrameworkProperties.setProperty(PROP_BUNDLES, osgiBundles); 8 } 9 String[] installEntries = getArrayFromList(osgiBundles, ","); //$NON-NLS-1$ 10 // get the initial bundle list from the installEntries 11 InitialBundle[] initialBundles = getInitialBundles(installEntries); 12 // get the list of currently installed initial bundles from the framework 13 Bundle[] curInitBundles = getCurrentBundles(true); 14 15 // list of bundles to be refreshed 16 List<Bundle> toRefresh = new ArrayList<Bundle>(curInitBundles.length); 17 // uninstall any of the currently installed bundles that do not exist in the 18 // initial bundle list from installEntries. 19 uninstallBundles(curInitBundles, initialBundles, toRefresh); 20 21 // install the initialBundles that are not already installed. 22 List<Bundle> startBundles = new ArrayList<Bundle>(installEntries.length); 23 List<Bundle> lazyActivationBundles = new ArrayList<Bundle>(installEntries.length); 24 installBundles(initialBundles, curInitBundles, startBundles, lazyActivationBundles, toRefresh); 25 26 // If we installed/uninstalled something, force a refresh of all installed/uninstalled bundles 27 if (!toRefresh.isEmpty() && refreshPackages(toRefresh.toArray(new Bundle[toRefresh.size()]))) 28 return null; // cannot continue; refreshPackages shutdown the framework 29 30 // schedule all basic bundles to be started 31 Bundle[] startInitBundles = startBundles.toArray(new Bundle[startBundles.size()]); 32 Bundle[] lazyInitBundles = lazyActivationBundles.toArray(new Bundle[lazyActivationBundles.size()]); 33 startBundles(startInitBundles, lazyInitBundles); 34 35 if (debug) 36 System.out.println("Time to load bundles: " + (System.currentTimeMillis() - startTime)); //$NON-NLS-1$ 37 return startInitBundles; 38 }
startBundles() in which our Activator' s start method will be executed.
-
1 private static void startBundles(Bundle[] startBundles, Bundle[] lazyBundles) { 2 for (int i = 0; i < startBundles.length; i++) 3 startBundle(startBundles[i], 0); 4 for (int i = 0; i < lazyBundles.length; i++) 5 startBundle(lazyBundles[i], Bundle.START_ACTIVATION_POLICY); 6 } 7 8 private static void startBundle(Bundle bundle, int options) { 9 try { 10 bundle.start(options); 11 } catch (BundleException e) { 12 if ((bundle.getState() & Bundle.RESOLVED) != 0) { 13 // only log errors if the bundle is resolved 14 FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FAILED_START, bundle.getLocation()), 0, e, null); 15 log.log(entry); 16 } 17 } 18 }
config.ini
-
1 #This configuration file was written by: org.eclipse.equinox.internal.frameworkadmin.equinox.EquinoxFwConfigFileParser 2 #Thu Sep 05 17:05:01 CST 2013 3 org.eclipse.update.reconcile=false 4 eclipse.p2.profile=SDKProfile 5 osgi.instance.area.default=@user.home/workspace 6 osgi.framework=file\:plugins/org.eclipse.osgi_3.8.0.v20120529-1548.jar 7 equinox.use.ds=true 8 eclipse.buildId=I20120608-1400 9 osgi.bundles=reference\:file\:org.eclipse.equinox.simpleconfigurator_1.0.300.v20110815-1744.jar@1\:start 10 org.eclipse.equinox.simpleconfigurator.configUrl=file\:org.eclipse.equinox.simpleconfigurator/bundles.info 11 eclipse.product=org.eclipse.sdk.ide 12 osgi.splashPath=platform\:/base/plugins/org.eclipse.platform 13 osgi.framework.extensions= 14 osgi.bundles.defaultStartLevel=4 15 eclipse.p2.data.area=@config.dir/../p2/ 16 eclipse.application=org.eclipse.ui.ide.workbench
- When clicking eclipse.exe which is a windows program, it will execute to startup JVM and set some enviroment variables, read elipse.ini
-
Eclipse Launcher Description Eclipse contains a native executable launcher that is used to start Eclipse. There is more to the launcher than just the eclipse executable in the root of the install. The launcher and its shared library The launcher executable comes in 2 pieces: the executable (eclipse.exe), and a shared library (eclipse_1017.dll). The executable lives in the root of the eclipse install. The shared library is in a platform specific fragment, org.eclipse.equinox.launcher.[config], in the plugins directory. Having the majority of the launcher code in a shared library that lives in a fragment means that that portion of the launch code can now be updated from an update site. Also, when starting from java, the shared library can be loaded via JNI in order to display the splash screen. The launcher bundle Previous versions of Eclipse had a startup.jar JAR file in the root of the install. In 3.3, this code has been moved to a plug-in org.eclipse.equinox.launcher in the plugins directory. Eclipse can still be started directly with java using, for example: java -jar plugins/org.eclipse.equinox.launcher_1.0.0.v20070606.jar Launching Eclipse involves 3 main pieces: the native executable, the launcher platform specific fragment and the launcher jar. In the example below, notice that the launcher fragment is in folder form, this is necessary so that the native eclipse.exe can load the shared library: eclipse/ eclipse.exe plugins/ org.eclipse.equinox.launcher_1.0.0.v20070606.jar org.eclipse.equinox.launcher.win32.win32.x86_1.0.0.v20070523/ eclipse_1017a.dll The version numbers above are for illustration purposes only (e.g. 1.0.0.v20070606). The actual version numbers may vary depending on the version of Eclipse you are using. Finding a VM and using the JNI Invocation API The Eclipse launcher is capable of loading the Java VM in the eclipse process using the Java Native Interface Invocation API. The launcher is still capable of starting the Java VM in a separate process the same as previous version of Eclipse did. Which method is used depends on how the VM was found. No -vm specified When no -vm is specified, the launcher looks for a virtual machine first in a jre directory in the root of eclipse and then on the search path. If java is found in either location, then the launcher looks for a jvm shared library (jvm.dll on Windows, libjvm.so on *nix platforms) relative to that java executable. If a jvm shared library is found the launcher loads it and uses the JNI invocation API to start the vm. If no jvm shared library is found, the launcher executes the java launcher to start the vm in a new process. -vm specified on the command line or in eclipse.ini Eclipse can be started with "-vm <location>" to indicate a virtual machine to use. There are several possibilities for the value of <location>: directory: <location> is a directory. We look in that directory for: (1) a java launcher or (2) the jvm shared library. If we find the jvm shared library, we use JNI invocation. If we find a launcher, we attempt to find a jvm library in known locations relative to the launcher. If we find one, we use JNI invocation. If no jvm library is found, we exec java in a new process. java.exe/javaw.exe: <location> is a path to a java launcher. We exec that java launcher to start the vm in a new process. jvm dll or so: <location> is a path to a jvm shared library. We attempt to load that library and use the JNI Invocation API to start the vm in the current process. Exceptions linux.ppc, linux.x86_64, aix.ppc: The launcher is not able to load some older vms using the JNI invocation API. By default on these platforms the launcher will prefer to execute java in a separate process. To force the launcher to load the vm using JNI, specify a -vm option pointing directly to the vm's shared library (libjvm.so). MacOSX: The launcher uses the system JavaVM framework and will always load the vm in-process using the JNI invocation API.
-
1 -startup 2 plugins/org.eclipse.equinox.launcher_1.3.0.v20120522-1813.jar 3 --launcher.library 4 plugins/org.eclipse.equinox.launcher.win32.win32.x86_1.1.200.v20120522-1813 5 -showsplash 6 org.eclipse.platform 7 --launcher.XXMaxPermSize 8 256m 9 --launcher.defaultAction 10 openFile 11 -vmargs 12 -Xms40m 13 -Xmx512m
1 org.eclipse.equinox.launcher.Main.main(Main.java:1414) 2 org.eclipse.equinox.launcher.Main.run(Main.java:1438) 3 org.eclipse.equinox.launcher.Main.basicRun(Main.java:584) 4 org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:629) 5 java.lang.reflect.Method.invoke(Unknown Source) 6 sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) 7 sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) 8 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 9 org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:180) 10 org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:353)
- run()
-
1 public static Object run(Object argument) throws Exception { 2 if (Profile.PROFILE && Profile.STARTUP) 3 Profile.logEnter("EclipseStarter.run(Object)()", null); //$NON-NLS-1$ 4 if (!running) 5 throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_NOT_RUNNING); 6 // if we are just initializing, do not run the application just return. 7 if (initialize) 8 return new Integer(0); 9 try { 10 if (appLauncher == null) { 11 boolean launchDefault = Boolean.valueOf(FrameworkProperties.getProperty(PROP_APPLICATION_LAUNCHDEFAULT, "true")).booleanValue(); //$NON-NLS-1$ 12 // create the ApplicationLauncher and register it as a service 13 appLauncher = new EclipseAppLauncher(context, Boolean.valueOf(FrameworkProperties.getProperty(PROP_ALLOW_APPRELAUNCH)).booleanValue(), launchDefault, log); 14 appLauncherRegistration = context.registerService(ApplicationLauncher.class.getName(), appLauncher, null); 15 // must start the launcher AFTER service restration because this method 16 // blocks and runs the application on the current thread. This method 17 // will return only after the application has stopped. 18 return appLauncher.start(argument); 19 } 20 return appLauncher.reStart(argument); 21 } catch (Exception e) { 22 if (log != null && context != null) // context can be null if OSGi failed to launch (bug 151413) 23 logUnresolvedBundles(context.getBundles()); 24 throw e; 25 } 26 }
- EclipseAppLauncher
-
1 /******************************************************************************* 2 * Copyright (c) 2005, 2010 IBM Corporation and others. 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * IBM Corporation - initial API and implementation 10 *******************************************************************************/ 11 12 package org.eclipse.core.runtime.internal.adaptor; 13 14 import java.lang.reflect.Method; 15 import java.util.Map; 16 import org.eclipse.core.runtime.adaptor.EclipseStarter; 17 import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; 18 import org.eclipse.osgi.framework.internal.core.Constants; 19 import org.eclipse.osgi.framework.internal.core.FrameworkProperties; 20 import org.eclipse.osgi.framework.log.FrameworkLog; 21 import org.eclipse.osgi.framework.log.FrameworkLogEntry; 22 import org.eclipse.osgi.internal.profile.Profile; 23 import org.eclipse.osgi.service.runnable.*; 24 import org.osgi.framework.*; 25 26 public class EclipseAppLauncher implements ApplicationLauncher { 27 volatile private ParameterizedRunnable runnable = null; 28 private Object appContext = null; 29 private Semaphore runningLock = new Semaphore(1); 30 private Semaphore waitForAppLock = new Semaphore(0); 31 private BundleContext context; 32 private boolean relaunch = false; 33 private boolean failOnNoDefault = false; 34 private FrameworkLog log; 35 36 public EclipseAppLauncher(BundleContext context, boolean relaunch, boolean failOnNoDefault, FrameworkLog log) { 37 this.context = context; 38 this.relaunch = relaunch; 39 this.failOnNoDefault = failOnNoDefault; 40 this.log = log; 41 findRunnableService(); 42 } 43 44 /* 45 * Used for backwards compatibility with < 3.2 runtime 46 */ 47 private void findRunnableService() { 48 // look for a ParameterizedRunnable registered as a service by runtimes (3.0, 3.1) 49 String appClass = ParameterizedRunnable.class.getName(); 50 ServiceReference<?>[] runRefs = null; 51 try { 52 runRefs = context.getServiceReferences(ParameterizedRunnable.class.getName(), "(&(objectClass=" + appClass + ")(eclipse.application=*))"); //$NON-NLS-1$//$NON-NLS-2$ 53 } catch (InvalidSyntaxException e) { 54 // ignore this. It should never happen as we have tested the above format. 55 } 56 if (runRefs != null && runRefs.length > 0) { 57 // found the service use it as the application. 58 runnable = (ParameterizedRunnable) context.getService(runRefs[0]); 59 // we will never be able to relaunch with a pre 3.2 runtime 60 relaunch = false; 61 waitForAppLock.release(); 62 } 63 } 64 65 /* 66 * Starts this application launcher on the current thread. This method 67 * should be called by the main thread to ensure that applications are 68 * launched in the main thread. 69 */ 70 public Object start(Object defaultContext) throws Exception { 71 // here we assume that launch has been called by runtime before we started 72 // TODO this may be a bad assumption but it works for now because we register the app launcher as a service and runtime synchronously calls launch on the service 73 if (failOnNoDefault && runnable == null) 74 throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_NO_APPLICATION); 75 Object result = null; 76 boolean doRelaunch; 77 do { 78 try { 79 result = runApplication(defaultContext); 80 } catch (Exception e) { 81 if (!relaunch || (context.getBundle().getState() & Bundle.ACTIVE) == 0) 82 throw e; 83 if (log != null) 84 log.log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, EclipseAdaptorMsg.ECLIPSE_STARTUP_APP_ERROR, 1, e, null)); 85 } 86 doRelaunch = (relaunch && (context.getBundle().getState() & Bundle.ACTIVE) != 0) || FrameworkProperties.getProperty(Constants.PROP_OSGI_RELAUNCH) != null; 87 } while (doRelaunch); 88 return result; 89 } 90 91 /* 92 * Waits for an application to be launched and the runs the application on the 93 * current thread (main). 94 */ 95 private Object runApplication(Object defaultContext) throws Exception { 96 // wait for an application to be launched. 97 waitForAppLock.acquire(); 98 // an application is ready; acquire the running lock. 99 // this must happen after we have acquired an application (by acquiring waitForAppLock above). 100 runningLock.acquire(); 101 if (EclipseStarter.debug) { 102 String timeString = FrameworkProperties.getProperty("eclipse.startTime"); //$NON-NLS-1$ 103 long time = timeString == null ? 0L : Long.parseLong(timeString); 104 System.out.println("Starting application: " + (System.currentTimeMillis() - time)); //$NON-NLS-1$ 105 } 106 if (Profile.PROFILE && (Profile.STARTUP || Profile.BENCHMARK)) 107 Profile.logTime("EclipseStarter.run(Object)()", "framework initialized! starting application..."); //$NON-NLS-1$ //$NON-NLS-2$ 108 try { 109 // run the actual application on the current thread (main). 110 return runnable.run(appContext != null ? appContext : defaultContext); 111 } finally { 112 if (Profile.PROFILE && Profile.STARTUP) 113 Profile.logExit("EclipseStarter.run(Object)()"); //$NON-NLS-1$ 114 // free the runnable application and release the lock to allow another app to be launched. 115 runnable = null; 116 appContext = null; 117 runningLock.release(); 118 } 119 } 120 121 public void launch(ParameterizedRunnable app, Object applicationContext) { 122 waitForAppLock.acquire(-1); // clear out any pending apps notifications 123 if (!runningLock.acquire(-1)) // check to see if an application is currently running 124 throw new IllegalStateException("An application is aready running."); //$NON-NLS-1$ 125 this.runnable = app; 126 this.appContext = applicationContext; 127 waitForAppLock.release(); // notify the main thread to launch an application. 128 runningLock.release(); // release the running lock 129 } 130 131 public void shutdown() { 132 // this method will aquire and keep the runningLock to prevent 133 // all future application launches. 134 if (runningLock.acquire(-1)) 135 return; // no application is currently running. 136 ParameterizedRunnable currentRunnable = runnable; 137 if (currentRunnable instanceof ApplicationRunnable) { 138 ((ApplicationRunnable) currentRunnable).stop(); 139 runningLock.acquire(60000); // timeout after 1 minute. 140 } 141 } 142 143 /* 144 * Similar to the start method this method will restart the default method on current thread. 145 * This method assumes that the default application was launched at least once and that an ApplicationDescriptor 146 * exists that can be used to relaunch the default application. 147 */ 148 public Object reStart(Object argument) throws Exception { 149 ServiceReference<?> ref[] = null; 150 ref = context.getServiceReferences("org.osgi.service.application.ApplicationDescriptor", "(eclipse.application.default=true)"); //$NON-NLS-1$//$NON-NLS-2$ 151 if (ref != null && ref.length > 0) { 152 Object defaultApp = context.getService(ref[0]); 153 Method launch = defaultApp.getClass().getMethod("launch", new Class[] {Map.class}); //$NON-NLS-1$ 154 launch.invoke(defaultApp, new Object[] {null}); 155 return start(argument); 156 } 157 throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_NO_APPLICATION); 158 } 159 }
-
1 at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79) 2 at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110) 3 at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196) 4 at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:124) 5 at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149) 6 at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:540) 7 at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:585) 8 at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:86) 9 at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:916) 10 at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332) 11 at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$9.run(PartRenderingEngine.java:1022) 12 at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3756) 13 at org.eclipse.swt.internal.win32.OS.DispatchMessage(OS.java:2546) 14 at org.eclipse.swt.internal.win32.OS.DispatchMessageW(Native Method) 15 at org.eclipse.swt.widgets.Display.windowProc(Display.java:4976) 16 at org.eclipse.swt.widgets.Control.windowProc(Control.java:4528) 17 at org.eclipse.swt.widgets.Control.WM_CHAR(Control.java:4640) 18 at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1062) 19 at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1077) 20 at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1052) 21 at org.eclipse.swt.widgets.Widget.wmChar(Widget.java:1521) 22 at org.eclipse.swt.widgets.Widget.sendKeyEvent(Widget.java:1100) 23 at org.eclipse.swt.widgets.Widget.sendKeyEvent(Widget.java:1104) 24 at org.eclipse.swt.widgets.Display.filterEvent(Display.java:1262) 25 at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)