1 /*******************************************************************************
2  * Copyright (c) 2000, 2019 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *     Julian Chen - fix for bug #92572, jclRM
14  *     Benjamin Cabe <benjamin.cabe@anyware-tech.com> - fix for bug 265532
15  *     Christoph Läubrich - remove InternalPlatform.getDefault().log (bug 55083)
16  *******************************************************************************/
17 package org.eclipse.core.internal.runtime;
18 
19 import java.io.File;
20 import java.net.URL;
21 import java.util.*;
22 import org.eclipse.core.internal.preferences.exchange.ILegacyPreferences;
23 import org.eclipse.core.internal.preferences.exchange.IProductPreferencesService;
24 import org.eclipse.core.internal.preferences.legacy.InitLegacyPreferences;
25 import org.eclipse.core.internal.preferences.legacy.ProductPreferencesService;
26 import org.eclipse.core.runtime.*;
27 import org.eclipse.core.runtime.content.IContentTypeManager;
28 import org.eclipse.core.runtime.preferences.IPreferencesService;
29 import org.eclipse.equinox.app.IApplicationContext;
30 import org.eclipse.equinox.internal.app.*;
31 import org.eclipse.equinox.internal.app.Activator;
32 import org.eclipse.equinox.log.*;
33 import org.eclipse.osgi.container.ModuleContainer;
34 import org.eclipse.osgi.framework.log.FrameworkLog;
35 import org.eclipse.osgi.service.datalocation.Location;
36 import org.eclipse.osgi.service.debug.DebugOptions;
37 import org.eclipse.osgi.service.environment.EnvironmentInfo;
38 import org.eclipse.osgi.service.resolver.PlatformAdmin;
39 import org.osgi.framework.*;
40 import org.osgi.framework.namespace.HostNamespace;
41 import org.osgi.framework.namespace.IdentityNamespace;
42 import org.osgi.framework.wiring.*;
43 import org.osgi.resource.Namespace;
44 import org.osgi.util.tracker.ServiceTracker;
45 
46 /**
47  * Bootstrap class for the platform. It is responsible for setting up the
48  * platform class loader and passing control to the actual application class
49  */
50 public final class InternalPlatform {
51 
52 	private static final String[] ARCH_LIST = { Platform.ARCH_X86, Platform.ARCH_X86_64 };
53 
54 	// debug support:  set in loadOptions()
55 	public static boolean DEBUG = false;
56 	public static boolean DEBUG_PLUGIN_PREFERENCES = false;
57 
58 	private boolean splashEnded = false;
59 	private boolean initialized;
60 	private static final String KEYRING = "-keyring"; //$NON-NLS-1$
61 	private String keyringFile;
62 
63 	//XXX This is not synchronized
64 	private Map<Bundle,Log> logs = new HashMap<>(5);
65 
66 	private static final String[] OS_LIST = { Platform.OS_FREEBSD, Platform.OS_LINUX, Platform.OS_MACOSX, Platform.OS_WIN32 };
67 	private String password = ""; //$NON-NLS-1$
68 	private static final String PASSWORD = "-password"; //$NON-NLS-1$
69 
70 	public static final String PROP_APPLICATION = "eclipse.application"; //$NON-NLS-1$
71 	public static final String PROP_ARCH = "osgi.arch"; //$NON-NLS-1$
72 	public static final String PROP_CONFIG_AREA = "osgi.configuration.area"; //$NON-NLS-1$
73 	public static final String PROP_CONSOLE_LOG = "eclipse.consoleLog"; //$NON-NLS-1$
74 	public static final String PROP_DEBUG = "osgi.debug"; //$NON-NLS-1$
75 	public static final String PROP_DEV = "osgi.dev"; //$NON-NLS-1$
76 
77 	// OSGI system properties.  Copied from EclipseStarter
78 	public static final String PROP_INSTALL_AREA = "osgi.install.area"; //$NON-NLS-1$
79 	public static final String PROP_NL = "osgi.nl"; //$NON-NLS-1$
80 	public static final String PROP_OS = "osgi.os"; //$NON-NLS-1$
81 
82 	// Eclipse System Properties
83 	public static final String PROP_PRODUCT = "eclipse.product"; //$NON-NLS-1$
84 	public static final String PROP_WS = "osgi.ws"; //$NON-NLS-1$
85 	public static final String PROP_ACTIVATE_PLUGINS = "eclipse.activateRuntimePlugins"; //$NON-NLS-1$
86 
87 	private static final InternalPlatform singleton = new InternalPlatform();
88 
89 	private static final String[] WS_LIST = { Platform.WS_COCOA, Platform.WS_GTK, Platform.WS_WIN32, Platform.WS_WPF };
90 	private Path cachedInstanceLocation; // Cache the path of the instance location
91 	private ServiceTracker<Location,Location> configurationLocation = null;
92 	private BundleContext context;
93 	private FrameworkWiring fwkWiring;
94 
95 	private Map<IBundleGroupProvider,ServiceRegistration<IBundleGroupProvider>> groupProviders = new HashMap<>(3);
96 	private ServiceTracker<Location,Location> installLocation = null;
97 	private ServiceTracker<Location,Location> instanceLocation = null;
98 	private ServiceTracker<Location,Location> userLocation = null;
99 
100 	private Plugin runtimeInstance; // Keep track of the plugin object for runtime in case the backward compatibility is run.
101 
102 	private ServiceRegistration<ILegacyPreferences> legacyPreferencesService = null;
103 	private ServiceRegistration<IProductPreferencesService> customPreferencesService = null;
104 
105 	private ServiceTracker<EnvironmentInfo,EnvironmentInfo> environmentTracker = null;
106 	private ServiceTracker<FrameworkLog,FrameworkLog> logTracker = null;
107 	private ServiceTracker<PlatformAdmin, PlatformAdmin> platformTracker = null;
108 	private ServiceTracker<DebugOptions,DebugOptions> debugTracker = null;
109 	private ServiceTracker<IContentTypeManager,IContentTypeManager> contentTracker = null;
110 	private ServiceTracker<IPreferencesService,IPreferencesService> preferencesTracker = null;
111 	private ServiceTracker<IBundleGroupProvider,IBundleGroupProvider> groupProviderTracker = null;
112 	private ServiceTracker<ExtendedLogReaderService,ExtendedLogReaderService> logReaderTracker = null;
113 	private ServiceTracker<ExtendedLogService,ExtendedLogService> extendedLogTracker = null;
114 
115 	private IProduct product;
116 
getDefault()117 	public static InternalPlatform getDefault() {
118 		return singleton;
119 	}
120 
121 	/**
122 	 * Private constructor to block instance creation.
123 	 */
InternalPlatform()124 	private InternalPlatform() {
125 		super();
126 	}
127 
128 	/**
129 	 * @see Platform#addLogListener(ILogListener)
130 	 */
addLogListener(ILogListener listener)131 	public void addLogListener(ILogListener listener) {
132 		assertInitialized();
133 		RuntimeLog.addLogListener(listener);
134 	}
135 
assertInitialized()136 	private void assertInitialized() {
137 		//avoid the Policy.bind if assertion is true
138 		if (!initialized)
139 			Assert.isTrue(false, Messages.meta_appNotInit);
140 	}
141 
142 	/**
143 	 * @see Platform#endSplash()
144 	 */
endSplash()145 	public void endSplash() {
146 		synchronized (this) {
147 			if (splashEnded)
148 				return; // do not do this more than once
149 			splashEnded = true;
150 		}
151 		IApplicationContext applicationContext = getApplicationContext();
152 		if (applicationContext != null)
153 			applicationContext.applicationRunning();
154 	}
155 
156 	/**
157 	 * @see Platform#getAdapterManager()
158 	 */
getAdapterManager()159 	public IAdapterManager getAdapterManager() {
160 		assertInitialized();
161 		return AdapterManager.getDefault();
162 	}
163 
164 	/**
165 	 * XXX Use the Environment info service. Need to see how to set the value of the app args.
166 	 */
getApplicationArgs()167 	public String[] getApplicationArgs() {
168 		return CommandLineArgs.getApplicationArgs();
169 	}
170 
getBooleanOption(String option, boolean defaultValue)171 	public boolean getBooleanOption(String option, boolean defaultValue) {
172 		String value = getOption(option);
173 		if (value == null)
174 			return defaultValue;
175 		return "true".equalsIgnoreCase(value); //$NON-NLS-1$
176 	}
177 
getBundleContext()178 	public BundleContext getBundleContext() {
179 		return context;
180 	}
181 
182 	/**
183 	 * Returns the bundle id of the bundle that contains the provided object, or
184 	 * <code>null</code> if the bundle could not be determined.
185 	 */
getBundleId(Object object)186 	public String getBundleId(Object object) {
187 		if (object == null)
188 			return null;
189 		Bundle source = FrameworkUtil.getBundle(object.getClass());
190 		if (source != null && source.getSymbolicName() != null)
191 			return source.getSymbolicName();
192 
193 		return null;
194 	}
195 
getBundleGroupProviders()196 	public IBundleGroupProvider[] getBundleGroupProviders() {
197 		return groupProviderTracker.getServices(new IBundleGroupProvider[0]);
198 	}
199 
registerBundleGroupProvider(IBundleGroupProvider provider)200 	public void registerBundleGroupProvider(IBundleGroupProvider provider) {
201 		// get the bundle context and register the provider as a service
202 		ServiceRegistration<IBundleGroupProvider> registration = getBundleContext().registerService(IBundleGroupProvider.class, provider, null);
203 		// store the service registration (map provider -> registration)
204 		synchronized (groupProviders) {
205 			groupProviders.put(provider, registration);
206 		}
207 	}
208 
unregisterBundleGroupProvider(IBundleGroupProvider provider)209 	public void unregisterBundleGroupProvider(IBundleGroupProvider provider) {
210 		// get the service reference (map provider -> reference)
211 		ServiceRegistration<IBundleGroupProvider> registration;
212 		synchronized (groupProviders) {
213 			registration = groupProviders.remove(provider);
214 		}
215 		if (registration == null)
216 			return;
217 		// unregister the provider
218 		registration.unregister();
219 	}
220 
getBundle(String symbolicName)221 	public Bundle getBundle(String symbolicName) {
222 		Bundle[] bundles = getBundles(symbolicName, null);
223 		return bundles != null && bundles.length > 0 ? bundles[0] : null;
224 	}
225 
getBundles(String symbolicName, String versionRange)226 	public Bundle[] getBundles(String symbolicName, String versionRange) {
227 		if (Constants.SYSTEM_BUNDLE_SYMBOLICNAME.equals(symbolicName)) {
228 			symbolicName = context.getBundle(Constants.SYSTEM_BUNDLE_LOCATION).getSymbolicName();
229 		}
230 		Map<String, String> directives = Collections.singletonMap(Namespace.REQUIREMENT_FILTER_DIRECTIVE,
231 				getRequirementFilter(symbolicName, versionRange));
232 		Collection<BundleCapability> matchingBundleCapabilities = fwkWiring.findProviders(ModuleContainer
233 				.createRequirement(IdentityNamespace.IDENTITY_NAMESPACE, directives, Collections.emptyMap()));
234 
235 		if (matchingBundleCapabilities.isEmpty()) {
236 			return null;
237 		}
238 
239 		Bundle[] results = matchingBundleCapabilities.stream().map(c -> c.getRevision().getBundle())
240 				// Remove all the bundles that are installed or uninstalled
241 				.filter(bundle -> (bundle.getState() & (Bundle.INSTALLED | Bundle.UNINSTALLED)) == 0)
242 				.sorted((b1, b2) -> b2.getVersion().compareTo(b1.getVersion())) // highest version first
243 				.toArray(Bundle[]::new);
244 
245 		return results.length > 0 ? results : null;
246 	}
247 
getRequirementFilter(String symbolicName, String versionRange)248 	private String getRequirementFilter(String symbolicName, String versionRange) {
249 		VersionRange range = versionRange == null ? null : new VersionRange(versionRange);
250 		StringBuilder filter = new StringBuilder();
251 		if (range != null) {
252 			filter.append("(&"); //$NON-NLS-1$
253 		}
254 		filter.append('(').append(IdentityNamespace.IDENTITY_NAMESPACE).append('=').append(symbolicName).append(')');
255 
256 		if (range != null) {
257 			filter.append(range.toFilterString(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE)).append(')');
258 		}
259 		return filter.toString();
260 	}
261 
getCommandLineArgs()262 	public String[] getCommandLineArgs() {
263 		return CommandLineArgs.getAllArgs();
264 	}
265 
getConfigurationLocation()266 	public Location getConfigurationLocation() {
267 		assertInitialized();
268 		return configurationLocation.getService();
269 	}
270 
271 	/**
272 	 * Lazy initialize ContentTypeManager - it can only be used after the registry is up and running
273 	 */
getContentTypeManager()274 	public IContentTypeManager getContentTypeManager() {
275 		return contentTracker == null ? null : contentTracker.getService();
276 	}
277 
getEnvironmentInfoService()278 	public EnvironmentInfo getEnvironmentInfoService() {
279 		return environmentTracker == null ? null : environmentTracker.getService();
280 	}
281 
getFrameworkLog()282 	public FrameworkLog getFrameworkLog() {
283 		return logTracker == null ? null : logTracker.getService();
284 	}
285 
getFragments(Bundle bundle)286 	public Bundle[] getFragments(Bundle bundle) {
287 		BundleWiring wiring = bundle.adapt(BundleWiring.class);
288 		if (wiring == null) {
289 			return null;
290 		}
291 		List<BundleWire> hostWires = wiring.getProvidedWires(HostNamespace.HOST_NAMESPACE);
292 		if (hostWires == null) {
293 			// we don't hold locks while checking the graph, just return if no longer valid
294 			return null;
295 		}
296 		Bundle[] result = hostWires.stream().map(wire -> wire.getRequirer().getBundle()).filter(Objects::nonNull)
297 				.toArray(Bundle[]::new);
298 		return result.length > 0 ? result : null;
299 	}
300 
getHosts(Bundle bundle)301 	public Bundle[] getHosts(Bundle bundle) {
302 		BundleWiring wiring = bundle.adapt(BundleWiring.class);
303 		if (wiring == null) {
304 			return null;
305 		}
306 		List<BundleWire> hostWires = wiring.getRequiredWires(HostNamespace.HOST_NAMESPACE);
307 		if (hostWires == null) {
308 			// we don't hold locks while checking the graph, just return if no longer valid
309 			return null;
310 		}
311 		Bundle[] result = hostWires.stream().map(wire -> wire.getProvider().getBundle()).filter(Objects::nonNull)
312 				.toArray(Bundle[]::new);
313 		return result.length > 0 ? result : null;
314 	}
315 
getInstallLocation()316 	public Location getInstallLocation() {
317 		assertInitialized();
318 		return installLocation.getService();
319 	}
320 
getInstallURL()321 	public URL getInstallURL() {
322 		Location location = getInstallLocation();
323 		// it is pretty much impossible for the install location to be null.  If it is, the
324 		// system is in a bad way so throw and exception and get the heck outta here.
325 		if (location == null)
326 			throw new IllegalStateException("The installation location must not be null"); //$NON-NLS-1$
327 		return location.getURL();
328 	}
329 
getInstanceLocation()330 	public Location getInstanceLocation() {
331 		assertInitialized();
332 		return instanceLocation.getService();
333 	}
334 
335 	/**
336 	 * @see Platform#getLocation()
337 	 */
getLocation()338 	public IPath getLocation() throws IllegalStateException {
339 		if (cachedInstanceLocation == null) {
340 			Location location = getInstanceLocation();
341 			if (location == null)
342 				return null;
343 			//	This makes the assumption that the instance location is a file: URL
344 			File file = new File(location.getURL().getFile());
345 			cachedInstanceLocation = new Path(file.toString());
346 		}
347 		return cachedInstanceLocation;
348 	}
349 
350 	/**
351 	 * Returns a log for the given plugin. Creates a new one if needed.
352 	 * XXX change this into a LogMgr service that would keep track of the map. See if it can be a service factory.
353 	 * It would contain all the logging methods that are here.
354 	 * Relate to RuntimeLog if appropriate.
355 	 * The system log listener needs to be optional: turned on or off. What about a system property? :-)
356 	 */
getLog(Bundle bundle)357 	public ILog getLog(Bundle bundle) {
358 		Log result = logs.get(bundle);
359 		if (result != null)
360 			return result;
361 		ExtendedLogService logService = extendedLogTracker.getService();
362 		Logger logger = logService != null ? logService.getLogger(bundle, PlatformLogWriter.EQUINOX_LOGGER_NAME) : null;
363 		result = new Log(bundle, logger);
364 		ExtendedLogReaderService logReader = logReaderTracker.getService();
365 		logReader.addLogListener(result, result);
366 		logs.put(bundle, result);
367 		return result;
368 	}
369 
getNL()370 	public String getNL() {
371 		return getBundleContext().getProperty(PROP_NL);
372 	}
373 
374 	/**
375 	 * Unicode locale extensions are defined using command line parameter -nlExtensions,
376 	 * or the system property "osgi.nl.extensions".
377 	 */
getNLExtensions()378 	public String getNLExtensions() {
379 		String nlExtensions = PlatformActivator.getContext().getProperty("osgi.nl.extensions"); //$NON-NLS-1$
380 		if (nlExtensions == null)
381 			return ""; //$NON-NLS-1$
382 		if (!nlExtensions.startsWith("@")) //$NON-NLS-1$
383 			nlExtensions = '@' + nlExtensions;
384 		return nlExtensions;
385 	}
386 
387 	/**
388 	 * @see Platform
389 	 */
getOption(String option)390 	public String getOption(String option) {
391 		DebugOptions options = getDebugOptions();
392 		if (options != null)
393 			return options.getOption(option);
394 		return null;
395 	}
396 
getOS()397 	public String getOS() {
398 		return getBundleContext().getProperty(PROP_OS);
399 	}
400 
getOSArch()401 	public String getOSArch() {
402 		return getBundleContext().getProperty(PROP_ARCH);
403 	}
404 
getPlatformAdmin()405 	public PlatformAdmin getPlatformAdmin() {
406 		return platformTracker == null ? null : platformTracker.getService();
407 	}
408 
409 
getPreferencesService()410 	public IPreferencesService getPreferencesService() {
411 		return preferencesTracker == null ? null : preferencesTracker.getService();
412 	}
413 
414 	/*
415 	 * XXX move this into the app model.
416 	 */
getProduct()417 	public IProduct getProduct() {
418 		if (product != null)
419 			return product;
420 		EclipseAppContainer container = Activator.getContainer();
421 		IBranding branding = container == null ? null : container.getBranding();
422 		if (branding == null)
423 			return null;
424 		Object brandingProduct = branding.getProduct();
425 		if (!(brandingProduct instanceof IProduct))
426 			brandingProduct = new Product(branding);
427 		product = (IProduct) brandingProduct;
428 		return product;
429 	}
430 
getRegistry()431 	public IExtensionRegistry getRegistry() {
432 		return RegistryFactory.getRegistry();
433 	}
434 
435 	/**
436 	 * XXX deprecate and use NLS or BundleFinder.find()
437 	 */
getResourceBundle(Bundle bundle)438 	public ResourceBundle getResourceBundle(Bundle bundle) {
439 		return ResourceTranslator.getResourceBundle(bundle);
440 	}
441 
442 	/**
443 	 * XXX deprecate and use NLS or BundleFinder.find()
444 	 */
getResourceString(Bundle bundle, String value)445 	public String getResourceString(Bundle bundle, String value) {
446 		return ResourceTranslator.getResourceString(bundle, value);
447 	}
448 
449 	/**
450 	 * XXX deprecate and use NLS or BundleFinder.find()
451 	 */
getResourceString(Bundle bundle, String value, ResourceBundle resourceBundle)452 	public String getResourceString(Bundle bundle, String value, ResourceBundle resourceBundle) {
453 		return ResourceTranslator.getResourceString(bundle, value, resourceBundle);
454 	}
455 
456 	/**
457 	 * This method is only used to register runtime once compatibility has been started.
458 	 */
getRuntimeInstance()459 	public Plugin getRuntimeInstance() {
460 		return runtimeInstance;
461 	}
462 
getApplicationContext()463 	private IApplicationContext getApplicationContext() {
464 		Collection<ServiceReference<IApplicationContext>> references;
465 		try {
466 			references = context.getServiceReferences(IApplicationContext.class, "(eclipse.application.type=main.thread)"); //$NON-NLS-1$
467 		} catch (InvalidSyntaxException e) {
468 			return null;
469 		}
470 		if (references == null || references.isEmpty())
471 			return null;
472 		// assumes the application context is available as a service
473 		ServiceReference<IApplicationContext> firstRef = references.iterator().next();
474 		IApplicationContext result = context.getService(firstRef);
475 		if (result != null) {
476 			context.ungetService(firstRef);
477 			return result;
478 		}
479 		return null;
480 	}
481 
482 	/**
483 	 * XXX Investigate the usage of a service factory
484 	 */
getStateLocation(Bundle bundle)485 	public IPath getStateLocation(Bundle bundle) {
486 		return getStateLocation(bundle, true);
487 	}
488 
getStateLocation(Bundle bundle, boolean create)489 	public IPath getStateLocation(Bundle bundle, boolean create) throws IllegalStateException {
490 		assertInitialized();
491 		IPath result = MetaDataKeeper.getMetaArea().getStateLocation(bundle);
492 		if (create)
493 			result.toFile().mkdirs();
494 		return result;
495 	}
496 
getStateTimeStamp()497 	public long getStateTimeStamp() {
498 		PlatformAdmin admin = getPlatformAdmin();
499 		return admin == null ? -1 : admin.getState(false).getTimeStamp();
500 	}
501 
getUserLocation()502 	public Location getUserLocation() {
503 		assertInitialized();
504 		return userLocation.getService();
505 	}
506 
getWS()507 	public String getWS() {
508 		return getBundleContext().getProperty(PROP_WS);
509 	}
510 
initializeAuthorizationHandler()511 	private void initializeAuthorizationHandler() {
512 		try {
513 			AuthorizationHandler.setKeyringFile(keyringFile);
514 			AuthorizationHandler.setPassword(password);
515 		} catch (NoClassDefFoundError e) {
516 			// The authorization fragment is not available. If someone tries to use that API, an error will be logged
517 		}
518 	}
519 
520 	/*
521 	 * Finds and loads the options file
522 	 */
initializeDebugFlags()523 	void initializeDebugFlags() {
524 		// load runtime options
525 		DEBUG = getBooleanOption(Platform.PI_RUNTIME + "/debug", false); //$NON-NLS-1$
526 		if (DEBUG) {
527 			DEBUG_PLUGIN_PREFERENCES = getBooleanOption(Platform.PI_RUNTIME + "/preferences/plugin", false); //$NON-NLS-1$
528 		}
529 	}
530 
isFragment(Bundle bundle)531 	public boolean isFragment(Bundle bundle) {
532 		BundleRevisions bundleRevisions = bundle.adapt(BundleRevisions.class);
533 		List<BundleRevision> revisions = bundleRevisions.getRevisions();
534 		if (revisions.isEmpty()) {
535 			// bundle is uninstalled and not current users; just return false
536 			return false;
537 		}
538 		return (revisions.get(0).getTypes() & BundleRevision.TYPE_FRAGMENT) != 0;
539 	}
540 
541 	/*
542 	 *XXX do what you want to do. track osgi, track runtime, or whatever.
543 	 */
isRunning()544 	public boolean isRunning() {
545 		try {
546 			return initialized && context != null && context.getBundle().getState() == Bundle.ACTIVE;
547 		} catch (IllegalStateException e) {
548 			return false;
549 		}
550 	}
551 
552 	/**
553 	 * Returns a list of known system architectures.
554 	 *
555 	 * @return the list of system architectures known to the system
556 	 * XXX This is useless
557 	 */
knownOSArchValues()558 	public String[] knownOSArchValues() {
559 		return ARCH_LIST;
560 	}
561 
562 	/**
563 	 * Returns a list of known operating system names.
564 	 *
565 	 * @return the list of operating systems known to the system
566 	 * XXX This is useless
567 	 */
knownOSValues()568 	public String[] knownOSValues() {
569 		return OS_LIST;
570 	}
571 
572 	/**
573 	 * Returns a list of known windowing system names.
574 	 *
575 	 * @return the list of window systems known to the system
576 	 * XXX This is useless
577 	 */
knownWSValues()578 	public String[] knownWSValues() {
579 		return WS_LIST;
580 	}
581 
processCommandLine(String[] args)582 	private void processCommandLine(String[] args) {
583 		if (args == null || args.length == 0)
584 			return;
585 
586 		for (int i = 0; i < args.length; i++) {
587 			// check for args with parameters
588 			if (i == args.length - 1 || args[i + 1].startsWith("-")) //$NON-NLS-1$
589 				continue;
590 			String arg = args[++i];
591 
592 			// look for the keyring file
593 			if (args[i - 1].equalsIgnoreCase(KEYRING))
594 				keyringFile = arg;
595 			// look for the user password.
596 			if (args[i - 1].equalsIgnoreCase(PASSWORD))
597 				password = arg;
598 		}
599 	}
600 
601 	/**
602 	 * @see Platform#removeLogListener(ILogListener)
603 	 */
removeLogListener(ILogListener listener)604 	public void removeLogListener(ILogListener listener) {
605 		assertInitialized();
606 		RuntimeLog.removeLogListener(listener);
607 	}
608 
609 	/**
610 	 * This method is only used to register runtime once compatibility has been started.
611 	 */
setRuntimeInstance(Plugin runtime)612 	public void setRuntimeInstance(Plugin runtime) {
613 		runtimeInstance = runtime;
614 	}
615 
616 	/**
617 	 * Internal method for starting up the platform.  The platform is not started with any location
618 	 * and should not try to access the instance data area.
619 	 *
620 	 * Note: the content type manager must be initialized only after the registry has been created
621 	 */
start(BundleContext runtimeContext)622 	public void start(BundleContext runtimeContext) {
623 		this.context = runtimeContext;
624 		this.fwkWiring = runtimeContext.getBundle(Constants.SYSTEM_BUNDLE_LOCATION).adapt(FrameworkWiring.class);
625 		openOSGiTrackers();
626 		splashEnded = false;
627 		processCommandLine(getEnvironmentInfoService().getNonFrameworkArgs());
628 		initializeDebugFlags();
629 		initialized = true;
630 		initializeAuthorizationHandler();
631 		startServices();
632 	}
633 
634 	/**
635 	 * Shutdown runtime pieces in this order:
636 	 * Content[auto shutdown] -&gt; Preferences[auto shutdown] -&gt; Registry -&gt; Jobs.
637 	 * The "auto" shutdown takes place before this code is executed
638 	 */
stop(BundleContext bundleContext)639 	public void stop(BundleContext bundleContext) {
640 		assertInitialized();
641 		stopServices(); // should be done after preferences shutdown
642 		initialized = false;
643 		closeOSGITrackers();
644 		context = null;
645 	}
646 
openOSGiTrackers()647 	private void openOSGiTrackers() {
648 		Filter filter = null;
649 		try {
650 			filter = context.createFilter(Location.INSTANCE_FILTER);
651 		} catch (InvalidSyntaxException e) {
652 			// ignore this.  It should never happen as we have tested the above format.
653 		}
654 		instanceLocation = new ServiceTracker<>(context, filter, null);
655 		instanceLocation.open();
656 
657 		try {
658 			filter = context.createFilter(Location.USER_FILTER);
659 		} catch (InvalidSyntaxException e) {
660 			// ignore this.  It should never happen as we have tested the above format.
661 		}
662 		userLocation = new ServiceTracker<>(context, filter, null);
663 		userLocation.open();
664 
665 		try {
666 			filter = context.createFilter(Location.CONFIGURATION_FILTER);
667 		} catch (InvalidSyntaxException e) {
668 			// ignore this.  It should never happen as we have tested the above format.
669 		}
670 		configurationLocation = new ServiceTracker<>(context, filter, null);
671 		configurationLocation.open();
672 
673 		try {
674 			filter = context.createFilter(Location.INSTALL_FILTER);
675 		} catch (InvalidSyntaxException e) {
676 			// ignore this.  It should never happen as we have tested the above format.
677 		}
678 		installLocation = new ServiceTracker<>(context, filter, null);
679 		installLocation.open();
680 
681 		if (context != null) {
682 			logTracker = new ServiceTracker<>(context, FrameworkLog.class, null);
683 			logTracker.open();
684 		}
685 
686 		if (context != null) {
687 			platformTracker = new ServiceTracker<>(context, PlatformAdmin.class, null);
688 			platformTracker.open();
689 		}
690 
691 		if (context != null) {
692 			contentTracker = new ServiceTracker<>(context, IContentTypeManager.class, null);
693 			contentTracker.open();
694 		}
695 
696 		if (context != null) {
697 			preferencesTracker = new ServiceTracker<>(context, IPreferencesService.class, null);
698 			preferencesTracker.open();
699 		}
700 
701 		try {
702 			filter = context.createFilter("(objectClass=" + IBundleGroupProvider.class.getName() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
703 		} catch (InvalidSyntaxException e) {
704 			// ignore this, it should never happen
705 		}
706 		groupProviderTracker = new ServiceTracker<>(context, filter, null);
707 		groupProviderTracker.open();
708 
709 		logReaderTracker = new ServiceTracker<>(context, ExtendedLogReaderService.class, null);
710 		logReaderTracker.open();
711 
712 		extendedLogTracker = new ServiceTracker<>(context, ExtendedLogService.class, null);
713 		extendedLogTracker.open();
714 
715 		environmentTracker = new ServiceTracker<>(context, EnvironmentInfo.class, null);
716 		environmentTracker.open();
717 
718 		debugTracker = new ServiceTracker<>(context, DebugOptions.class, null);
719 		debugTracker.open();
720 	}
721 
startServices()722 	private void startServices() {
723 		// The check for getProduct() is relatively expensive (about 3% of the headless startup),
724 		// so we don't want to enforce it here.
725 		customPreferencesService = context.registerService(IProductPreferencesService.class, new ProductPreferencesService(), new Hashtable<>());
726 
727 		legacyPreferencesService = context.registerService(ILegacyPreferences.class, new InitLegacyPreferences(), new Hashtable<>());
728 	}
729 
stopServices()730 	private void stopServices() {
731 		if (legacyPreferencesService != null) {
732 			legacyPreferencesService.unregister();
733 			legacyPreferencesService = null;
734 		}
735 		if (customPreferencesService != null) {
736 			customPreferencesService.unregister();
737 			customPreferencesService = null;
738 		}
739 	}
740 
getDebugOptions()741 	private DebugOptions getDebugOptions() {
742 		return debugTracker == null ? null : debugTracker.getService();
743 	}
744 
closeOSGITrackers()745 	private void closeOSGITrackers() {
746 		if (preferencesTracker != null) {
747 			preferencesTracker.close();
748 		}
749 		if (contentTracker != null) {
750 			contentTracker.close();
751 		}
752 		if (debugTracker != null) {
753 			debugTracker.close();
754 		}
755 		if (platformTracker != null) {
756 			platformTracker.close();
757 		}
758 		if (logTracker != null) {
759 			logTracker.close();
760 		}
761 		if (groupProviderTracker != null) {
762 			groupProviderTracker.close();
763 		}
764 		if (environmentTracker != null) {
765 			environmentTracker.close();
766 		}
767 		if (logReaderTracker != null) {
768 			logReaderTracker.close();
769 		}
770 		if (extendedLogTracker != null) {
771 			extendedLogTracker.close();
772 		}
773 		if (installLocation != null) {
774 			installLocation.close();
775 		}
776 		if (userLocation != null) {
777 			userLocation.close();
778 		}
779 		if (configurationLocation != null) {
780 			configurationLocation.close();
781 		}
782 		if (instanceLocation != null) {
783 			instanceLocation.close();
784 		}
785 	}
786 
787 	/**
788 	 * Print a debug message to the console.
789 	 * Pre-pend the message with the current date and the name of the current thread.
790 	 */
message(String message)791 	public static void message(String message) {
792 		StringBuilder buffer = new StringBuilder();
793 		buffer.append(new Date(System.currentTimeMillis()));
794 		buffer.append(" - ["); //$NON-NLS-1$
795 		buffer.append(Thread.currentThread().getName());
796 		buffer.append("] "); //$NON-NLS-1$
797 		buffer.append(message);
798 		System.out.println(buffer.toString());
799 	}
800 
start(Bundle bundle)801 	public static void start(Bundle bundle) throws BundleException {
802 		int originalState = bundle.getState();
803 		if ((originalState & Bundle.ACTIVE) != 0)
804 			return; // bundle is already active
805 		try {
806 			// attempt to activate the bundle
807 			bundle.start(Bundle.START_TRANSIENT);
808 		} catch (BundleException e) {
809 			if ((originalState & Bundle.STARTING) != 0 && (bundle.getState() & Bundle.STARTING) != 0)
810 				// This can happen if the bundle was in the process of being activated on this thread, just return
811 				return;
812 			throw e;
813 		}
814 	}
815 }
816