Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 5783d5a9e10c600b53f6775fbd3a96f91bd0f553 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
/*******************************************************************************
 * Copyright (c) 2003, 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Alex Blewitt (bug 172969)
 *******************************************************************************/
package org.eclipse.core.runtime.adaptor;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.*;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.*;
import org.eclipse.core.runtime.internal.adaptor.*;
import org.eclipse.osgi.framework.adaptor.*;
import org.eclipse.osgi.framework.internal.core.*;
import org.eclipse.osgi.framework.internal.core.Constants;
import org.eclipse.osgi.framework.log.FrameworkLog;
import org.eclipse.osgi.framework.log.FrameworkLogEntry;
import org.eclipse.osgi.internal.baseadaptor.BaseStorageHook;
import org.eclipse.osgi.internal.profile.Profile;
import org.eclipse.osgi.service.datalocation.Location;
import org.eclipse.osgi.service.resolver.*;
import org.eclipse.osgi.service.runnable.ApplicationLauncher;
import org.eclipse.osgi.service.runnable.StartupMonitor;
import org.eclipse.osgi.util.ManifestElement;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.*;
import org.osgi.service.packageadmin.PackageAdmin;
import org.osgi.service.startlevel.StartLevel;
import org.osgi.util.tracker.ServiceTracker;

/**
 * Special startup class for the Eclipse Platform. This class cannot be 
 * instantiated; all functionality is provided by static methods. 
 * <p>
 * The Eclipse Platform makes heavy use of Java class loaders for loading 
 * plug-ins. Even the Eclipse Runtime itself and the OSGi framework need
 * to be loaded by special class loaders. The upshot is that a 
 * client program (such as a Java main program, a servlet) cannot  
 * reference any part of Eclipse directly. Instead, a client must use this 
 * loader class to start the platform, invoking functionality defined 
 * in plug-ins, and shutting down the platform when done. 
 * </p>
 * <p>Note that the fields on this class are not API. </p>
 * @since 3.0
 * @noextend This class is not intended to be subclassed by clients.
 */
public class EclipseStarter {
	private static FrameworkAdaptor adaptor;
	private static BundleContext context;
	private static boolean initialize = false;
	public static boolean debug = false;
	private static boolean running = false;
	private static Framework framework = null;
	private static ServiceRegistration<?> defaultMonitorRegistration = null;
	private static ServiceRegistration<?> appLauncherRegistration = null;
	private static ServiceRegistration<?> splashStreamRegistration = null;

	// command line arguments
	private static final String CLEAN = "-clean"; //$NON-NLS-1$
	private static final String CONSOLE = "-console"; //$NON-NLS-1$
	private static final String CONSOLE_LOG = "-consoleLog"; //$NON-NLS-1$
	private static final String DEBUG = "-debug"; //$NON-NLS-1$
	private static final String INITIALIZE = "-initialize"; //$NON-NLS-1$
	private static final String DEV = "-dev"; //$NON-NLS-1$
	private static final String WS = "-ws"; //$NON-NLS-1$
	private static final String OS = "-os"; //$NON-NLS-1$
	private static final String ARCH = "-arch"; //$NON-NLS-1$
	private static final String NL = "-nl"; //$NON-NLS-1$
	private static final String NL_EXTENSIONS = "-nlExtensions"; //$NON-NLS-1$
	private static final String CONFIGURATION = "-configuration"; //$NON-NLS-1$	
	private static final String USER = "-user"; //$NON-NLS-1$
	private static final String NOEXIT = "-noExit"; //$NON-NLS-1$
	private static final String LAUNCHER = "-launcher"; //$NON-NLS-1$

	// this is more of an Eclipse argument but this OSGi implementation stores its 
	// metadata alongside Eclipse's.
	private static final String DATA = "-data"; //$NON-NLS-1$

	// System properties
	public static final String PROP_BUNDLES = "osgi.bundles"; //$NON-NLS-1$
	public static final String PROP_BUNDLES_STARTLEVEL = "osgi.bundles.defaultStartLevel"; //$NON-NLS-1$ //The start level used to install the bundles
	public static final String PROP_EXTENSIONS = "osgi.framework.extensions"; //$NON-NLS-1$
	public static final String PROP_INITIAL_STARTLEVEL = "osgi.startLevel"; //$NON-NLS-1$ //The start level when the fwl start
	public static final String PROP_DEBUG = "osgi.debug"; //$NON-NLS-1$
	public static final String PROP_DEV = "osgi.dev"; //$NON-NLS-1$
	public static final String PROP_CLEAN = "osgi.clean"; //$NON-NLS-1$
	public static final String PROP_CONSOLE = "osgi.console"; //$NON-NLS-1$
	public static final String PROP_CONSOLE_CLASS = "osgi.consoleClass"; //$NON-NLS-1$
	public static final String PROP_CHECK_CONFIG = "osgi.checkConfiguration"; //$NON-NLS-1$
	public static final String PROP_OS = "osgi.os"; //$NON-NLS-1$
	public static final String PROP_WS = "osgi.ws"; //$NON-NLS-1$
	public static final String PROP_NL = "osgi.nl"; //$NON-NLS-1$
	private static final String PROP_NL_EXTENSIONS = "osgi.nl.extensions"; //$NON-NLS-1$
	public static final String PROP_ARCH = "osgi.arch"; //$NON-NLS-1$
	public static final String PROP_ADAPTOR = "osgi.adaptor"; //$NON-NLS-1$
	public static final String PROP_SYSPATH = "osgi.syspath"; //$NON-NLS-1$
	public static final String PROP_LOGFILE = "osgi.logfile"; //$NON-NLS-1$
	public static final String PROP_FRAMEWORK = "osgi.framework"; //$NON-NLS-1$
	public static final String PROP_INSTALL_AREA = "osgi.install.area"; //$NON-NLS-1$
	public static final String PROP_FRAMEWORK_SHAPE = "osgi.framework.shape"; //$NON-NLS-1$ //the shape of the fwk (jar, or folder)
	public static final String PROP_NOSHUTDOWN = "osgi.noShutdown"; //$NON-NLS-1$
	private static final String PROP_FORCED_RESTART = "osgi.forcedRestart"; //$NON-NLS-1$

	public static final String PROP_EXITCODE = "eclipse.exitcode"; //$NON-NLS-1$
	public static final String PROP_EXITDATA = "eclipse.exitdata"; //$NON-NLS-1$
	public static final String PROP_CONSOLE_LOG = "eclipse.consoleLog"; //$NON-NLS-1$
	public static final String PROP_IGNOREAPP = "eclipse.ignoreApp"; //$NON-NLS-1$
	public static final String PROP_REFRESH_BUNDLES = "eclipse.refreshBundles"; //$NON-NLS-1$
	private static final String PROP_ALLOW_APPRELAUNCH = "eclipse.allowAppRelaunch"; //$NON-NLS-1$
	private static final String PROP_APPLICATION_LAUNCHDEFAULT = "eclipse.application.launchDefault"; //$NON-NLS-1$

	private static final String FILE_SCHEME = "file:"; //$NON-NLS-1$
	private static final String REFERENCE_SCHEME = "reference:"; //$NON-NLS-1$
	private static final String REFERENCE_PROTOCOL = "reference"; //$NON-NLS-1$
	private static final String INITIAL_LOCATION = "initial@"; //$NON-NLS-1$
	/** string containing the classname of the adaptor to be used in this framework instance */
	protected static final String DEFAULT_ADAPTOR_CLASS = "org.eclipse.osgi.baseadaptor.BaseAdaptor"; //$NON-NLS-1$

	private static final int DEFAULT_INITIAL_STARTLEVEL = 6; // default value for legacy purposes
	private static final String DEFAULT_BUNDLES_STARTLEVEL = "4"; //$NON-NLS-1$

	private static FrameworkLog log;
	// directory of serch candidates keyed by directory abs path -> directory listing (bug 122024)
	private static Map<String, String[]> searchCandidates = new HashMap<String, String[]>(4);
	private static EclipseAppLauncher appLauncher;
	private static List<Runnable> shutdownHandlers;

	private static ConsoleManager consoleMgr = null;

	/**
	 * This is the main to start osgi.
	 * It only works when the framework is being jared as a single jar
	 */
	public static void main(String[] args) throws Exception {
		if (FrameworkProperties.getProperty("eclipse.startTime") == null) //$NON-NLS-1$
			FrameworkProperties.setProperty("eclipse.startTime", Long.toString(System.currentTimeMillis())); //$NON-NLS-1$
		if (FrameworkProperties.getProperty(PROP_NOSHUTDOWN) == null)
			FrameworkProperties.setProperty(PROP_NOSHUTDOWN, "true"); //$NON-NLS-1$
		// set the compatibility boot delegation flag to false to get "standard" OSGi behavior WRT boot delegation (bug 178477)
		if (FrameworkProperties.getProperty(Constants.OSGI_COMPATIBILITY_BOOTDELEGATION) == null)
			FrameworkProperties.setProperty(Constants.OSGI_COMPATIBILITY_BOOTDELEGATION, "false"); //$NON-NLS-1$
		Object result = run(args, null);
		if (result instanceof Integer && !Boolean.valueOf(FrameworkProperties.getProperty(PROP_NOSHUTDOWN)).booleanValue())
			System.exit(((Integer) result).intValue());
	}

	/**
	 * Launches the platform and runs a single application. The application is either identified
	 * in the given arguments (e.g., -application &lt;app id&gt;) or in the <code>eclipse.application</code> 
	 * System property.  This convenience method starts 
	 * up the platform, runs the indicated application, and then shuts down the 
	 * platform. The platform must not be running already. 
	 * 
	 * @param args the command line-style arguments used to configure the platform
	 * @param endSplashHandler the block of code to run to tear down the splash 
	 * 	screen or <code>null</code> if no tear down is required
	 * @return the result of running the application
	 * @throws Exception if anything goes wrong
	 */
	public static Object run(String[] args, Runnable endSplashHandler) throws Exception {
		if (Profile.PROFILE && Profile.STARTUP)
			Profile.logEnter("EclipseStarter.run()", null); //$NON-NLS-1$
		if (running)
			throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING);
		boolean startupFailed = true;
		try {
			startup(args, endSplashHandler);
			startupFailed = false;
			if (Boolean.valueOf(FrameworkProperties.getProperty(PROP_IGNOREAPP)).booleanValue() || isForcedRestart())
				return null;
			return run(null);
		} catch (Throwable e) {
			// ensure the splash screen is down
			if (endSplashHandler != null)
				endSplashHandler.run();
			// may use startupFailed to understand where the error happened
			FrameworkLogEntry logEntry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, startupFailed ? EclipseAdaptorMsg.ECLIPSE_STARTUP_STARTUP_ERROR : EclipseAdaptorMsg.ECLIPSE_STARTUP_APP_ERROR, 1, e, null);
			if (log != null)
				log.log(logEntry);
			else
				// TODO desperate measure - ideally, we should write this to disk (a la Main.log)
				e.printStackTrace();
		} finally {
			try {
				// The application typically sets the exit code however the framework can request that
				// it be re-started. We need to check for this and potentially override the exit code.
				if (isForcedRestart())
					FrameworkProperties.setProperty(PROP_EXITCODE, "23"); //$NON-NLS-1$
				if (!Boolean.valueOf(FrameworkProperties.getProperty(PROP_NOSHUTDOWN)).booleanValue())
					shutdown();
			} catch (Throwable e) {
				FrameworkLogEntry logEntry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, EclipseAdaptorMsg.ECLIPSE_STARTUP_SHUTDOWN_ERROR, 1, e, null);
				if (log != null)
					log.log(logEntry);
				else
					// TODO desperate measure - ideally, we should write this to disk (a la Main.log)
					e.printStackTrace();
			}
			if (Profile.PROFILE && Profile.STARTUP)
				Profile.logExit("EclipseStarter.run()"); //$NON-NLS-1$
			if (Profile.PROFILE) {
				String report = Profile.getProfileLog();
				// avoiding writing to the console if there is nothing to print
				if (report != null && report.length() > 0)
					System.out.println(report);
			}
		}
		// we only get here if an error happened
		if (FrameworkProperties.getProperty(PROP_EXITCODE) == null) {
			FrameworkProperties.setProperty(PROP_EXITCODE, "13"); //$NON-NLS-1$
			FrameworkProperties.setProperty(PROP_EXITDATA, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_CHECK_LOG, log == null ? null : log.getFile().getPath()));
		}
		return null;
	}

	/**
	 * Returns true if the platform is already running, false otherwise.
	 * @return whether or not the platform is already running
	 */
	public static boolean isRunning() {
		return running;
	}

	/**
	 * Starts the platform and sets it up to run a single application. The application is either identified
	 * in the given arguments (e.g., -application &lt;app id&gt;) or in the <code>eclipse.application</code>
	 * System property.  The platform must not be running already. 
	 * <p>
	 * The given runnable (if not <code>null</code>) is used to tear down the splash screen if required.
	 * </p>
	 * @param args the arguments passed to the application
	 * @return BundleContext the context of the system bundle
	 * @throws Exception if anything goes wrong
	 */
	public static BundleContext startup(String[] args, Runnable endSplashHandler) throws Exception {
		if (Profile.PROFILE && Profile.STARTUP)
			Profile.logEnter("EclipseStarter.startup()", null); //$NON-NLS-1$
		if (running)
			throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING);
		FrameworkProperties.initializeProperties();
		processCommandLine(args);
		LocationManager.initializeLocations();
		loadConfigurationInfo();
		finalizeProperties();
		if (Profile.PROFILE)
			Profile.initProps(); // catch any Profile properties set in eclipse.properties...
		if (Profile.PROFILE && Profile.STARTUP)
			Profile.logTime("EclipseStarter.startup()", "props inited"); //$NON-NLS-1$ //$NON-NLS-2$
		adaptor = createAdaptor();
		log = adaptor.getFrameworkLog();
		if (Profile.PROFILE && Profile.STARTUP)
			Profile.logTime("EclipseStarter.startup()", "adapter created"); //$NON-NLS-1$ //$NON-NLS-2$
		framework = new Framework(adaptor);
		if (Profile.PROFILE && Profile.STARTUP)
			Profile.logTime("EclipseStarter.startup()", "OSGi created"); //$NON-NLS-1$ //$NON-NLS-2$
		context = framework.getBundle(0).getBundleContext();
		registerFrameworkShutdownHandlers();
		publishSplashScreen(endSplashHandler);
		if (Profile.PROFILE && Profile.STARTUP)
			Profile.logTime("EclipseStarter.startup()", "osgi launched"); //$NON-NLS-1$ //$NON-NLS-2$
		consoleMgr = ConsoleManager.startConsole(framework);
		if (Profile.PROFILE && Profile.STARTUP) {
			Profile.logTime("EclipseStarter.startup()", "console started"); //$NON-NLS-1$ //$NON-NLS-2$
		}
		framework.launch();
		// save the cached timestamp before loading basic bundles; this is needed so we can do a proper timestamp check when logging resolver errors
		long stateStamp = adaptor.getState().getTimeStamp();
		Bundle[] startBundles = loadBasicBundles();

		if (startBundles == null || ("true".equals(FrameworkProperties.getProperty(PROP_REFRESH_BUNDLES)) && refreshPackages(getCurrentBundles(false)))) { //$NON-NLS-1$
			waitForShutdown();
			return context; // cannot continue; loadBasicBundles caused refreshPackages to shutdown the framework
		}

		if (Profile.PROFILE && Profile.STARTUP)
			Profile.logTime("EclipseStarter.startup()", "loading basic bundles"); //$NON-NLS-1$ //$NON-NLS-2$

		// set the framework start level to the ultimate value.  This will actually start things
		// running if they are persistently active.
		setStartLevel(getStartLevel());
		if (Profile.PROFILE && Profile.STARTUP)
			Profile.logTime("EclipseStarter.startup()", "StartLevel set"); //$NON-NLS-1$ //$NON-NLS-2$
		// they should all be active by this time
		ensureBundlesActive(startBundles);

		// in the case where the built-in console is disabled we should try to start the console bundle
		try {
			consoleMgr.checkForConsoleBundle();
		} catch (BundleException e) {
			FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, e.getMessage(), 0, e, null);
			log.log(entry);
		}
		if (debug || FrameworkProperties.getProperty(PROP_DEV) != null)
			// only spend time showing unresolved bundles in dev/debug mode and the state has changed
			if (stateStamp != adaptor.getState().getTimeStamp())
				logUnresolvedBundles(context.getBundles());
		running = true;
		if (Profile.PROFILE && Profile.STARTUP)
			Profile.logExit("EclipseStarter.startup()"); //$NON-NLS-1$
		return context;
	}

	private static int getStartLevel() {
		String level = FrameworkProperties.getProperty(PROP_INITIAL_STARTLEVEL);
		if (level != null)
			try {
				return Integer.parseInt(level);
			} catch (NumberFormatException e) {
				if (debug)
					System.out.println("Start level = " + level + "  parsed. Using hardcoded default: 6"); //$NON-NLS-1$ //$NON-NLS-2$
			}
		return DEFAULT_INITIAL_STARTLEVEL;
	}

	/**
	 * Runs the application for which the platform was started. The platform 
	 * must be running. 
	 * <p>
	 * The given argument is passed to the application being run.  If it is <code>null</code>
	 * then the command line arguments used in starting the platform, and not consumed
	 * by the platform code, are passed to the application as a <code>String[]</code>.
	 * </p>
	 * @param argument the argument passed to the application. May be <code>null</code>
	 * @return the result of running the application
	 * @throws Exception if anything goes wrong
	 */
	public static Object run(Object argument) throws Exception {
		if (Profile.PROFILE && Profile.STARTUP)
			Profile.logEnter("EclipseStarter.run(Object)()", null); //$NON-NLS-1$
		if (!running)
			throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_NOT_RUNNING);
		// if we are just initializing, do not run the application just return.
		if (initialize)
			return new Integer(0);
		try {
			if (appLauncher == null) {
				boolean launchDefault = Boolean.valueOf(FrameworkProperties.getProperty(PROP_APPLICATION_LAUNCHDEFAULT, "true")).booleanValue(); //$NON-NLS-1$
				// create the ApplicationLauncher and register it as a service
				appLauncher = new EclipseAppLauncher(context, Boolean.valueOf(FrameworkProperties.getProperty(PROP_ALLOW_APPRELAUNCH)).booleanValue(), launchDefault, log);
				appLauncherRegistration = context.registerService(ApplicationLauncher.class.getName(), appLauncher, null);
				// must start the launcher AFTER service restration because this method 
				// blocks and runs the application on the current thread.  This method 
				// will return only after the application has stopped.
				return appLauncher.start(argument);
			}
			return appLauncher.reStart(argument);
		} catch (Exception e) {
			if (log != null && context != null) // context can be null if OSGi failed to launch (bug 151413)
				logUnresolvedBundles(context.getBundles());
			throw e;
		}
	}

	/**
	 * Shuts down the Platform. The state of the Platform is not automatically 
	 * saved before shutting down. 
	 * <p>
	 * On return, the Platform will no longer be running (but could be re-launched 
	 * with another call to startup). If relaunching, care must be taken to reinitialize
	 * any System properties which the platform uses (e.g., osgi.instance.area) as
	 * some policies in the platform do not allow resetting of such properties on 
	 * subsequent runs.
	 * </p><p>
	 * Any objects handed out by running Platform, 
	 * including Platform runnables obtained via getRunnable, will be 
	 * permanently invalid. The effects of attempting to invoke methods 
	 * on invalid objects is undefined. 
	 * </p>
	 * @throws Exception if anything goes wrong
	 */
	public static void shutdown() throws Exception {
		if (!running || framework == null)
			return;
		if (appLauncherRegistration != null)
			appLauncherRegistration.unregister();
		if (splashStreamRegistration != null)
			splashStreamRegistration.unregister();
		if (defaultMonitorRegistration != null)
			defaultMonitorRegistration.unregister();
		if (appLauncher != null)
			appLauncher.shutdown();
		appLauncherRegistration = null;
		appLauncher = null;
		splashStreamRegistration = null;
		defaultMonitorRegistration = null;
		if (consoleMgr != null) {
			consoleMgr.stopConsole();
			consoleMgr = null;
		}
		framework.close();
		framework = null;
		context = null;
		running = false;
	}

	private static void ensureBundlesActive(Bundle[] bundles) {
		ServiceTracker<StartLevel, StartLevel> tracker = null;
		try {
			for (int i = 0; i < bundles.length; i++) {
				if (bundles[i].getState() != Bundle.ACTIVE) {
					if (bundles[i].getState() == Bundle.INSTALLED) {
						// Log that the bundle is not resolved
						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));
						continue;
					}
					// check that the startlevel allows the bundle to be active (111550)
					if (tracker == null) {
						tracker = new ServiceTracker<StartLevel, StartLevel>(context, StartLevel.class.getName(), null);
						tracker.open();
					}
					StartLevel sl = tracker.getService();
					if (sl != null && (sl.getBundleStartLevel(bundles[i]) <= sl.getStartLevel())) {
						log.log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_BUNDLE_NOT_ACTIVE, bundles[i]), 0, null, null));
					}
				}
			}
		} finally {
			if (tracker != null)
				tracker.close();
		}
	}

	private static void logUnresolvedBundles(Bundle[] bundles) {
		State state = adaptor.getState();
		FrameworkLog logService = adaptor.getFrameworkLog();
		StateHelper stateHelper = adaptor.getPlatformAdmin().getStateHelper();

		// first lets look for missing leaf constraints (bug 114120)
		VersionConstraint[] leafConstraints = stateHelper.getUnsatisfiedLeaves(state.getBundles());
		// hash the missing leaf constraints by the declaring bundles
		Map<BundleDescription, List<VersionConstraint>> missing = new HashMap<BundleDescription, List<VersionConstraint>>();
		for (int i = 0; i < leafConstraints.length; i++) {
			// only include non-optional and non-dynamic constraint leafs
			if (leafConstraints[i] instanceof BundleSpecification && ((BundleSpecification) leafConstraints[i]).isOptional())
				continue;
			if (leafConstraints[i] instanceof ImportPackageSpecification) {
				if (ImportPackageSpecification.RESOLUTION_OPTIONAL.equals(((ImportPackageSpecification) leafConstraints[i]).getDirective(Constants.RESOLUTION_DIRECTIVE)))
					continue;
				if (ImportPackageSpecification.RESOLUTION_DYNAMIC.equals(((ImportPackageSpecification) leafConstraints[i]).getDirective(Constants.RESOLUTION_DIRECTIVE)))
					continue;
			}
			BundleDescription bundle = leafConstraints[i].getBundle();
			List<VersionConstraint> constraints = missing.get(bundle);
			if (constraints == null) {
				constraints = new ArrayList<VersionConstraint>();
				missing.put(bundle, constraints);
			}
			constraints.add(leafConstraints[i]);
		}

		// found some bundles with missing leaf constraints; log them first 
		if (missing.size() > 0) {
			FrameworkLogEntry[] rootChildren = new FrameworkLogEntry[missing.size()];
			int rootIndex = 0;
			for (Iterator<BundleDescription> iter = missing.keySet().iterator(); iter.hasNext(); rootIndex++) {
				BundleDescription description = iter.next();
				String symbolicName = description.getSymbolicName() == null ? FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME : description.getSymbolicName();
				String generalMessage = NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_BUNDLE_NOT_RESOLVED, description.getLocation());
				List<VersionConstraint> constraints = missing.get(description);
				FrameworkLogEntry[] logChildren = new FrameworkLogEntry[constraints.size()];
				for (int i = 0; i < logChildren.length; i++)
					logChildren[i] = new FrameworkLogEntry(symbolicName, FrameworkLogEntry.WARNING, 0, MessageHelper.getResolutionFailureMessage(constraints.get(i)), 0, null, null);
				rootChildren[rootIndex] = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, generalMessage, 0, null, logChildren);
			}
			logService.log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, EclipseAdaptorMsg.ECLIPSE_STARTUP_ROOTS_NOT_RESOLVED, 0, null, rootChildren));
		}

		// There may be some bundles unresolved for other reasons, causing the system to be unresolved
		// log all unresolved constraints now
		List<FrameworkLogEntry> allChildren = new ArrayList<FrameworkLogEntry>();
		for (int i = 0; i < bundles.length; i++)
			if (bundles[i].getState() == Bundle.INSTALLED) {
				String symbolicName = bundles[i].getSymbolicName() == null ? FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME : bundles[i].getSymbolicName();
				String generalMessage = NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_BUNDLE_NOT_RESOLVED, bundles[i]);
				BundleDescription description = state.getBundle(bundles[i].getBundleId());
				// for some reason, the state does not know about that bundle
				if (description == null)
					continue;
				FrameworkLogEntry[] logChildren = null;
				VersionConstraint[] unsatisfied = stateHelper.getUnsatisfiedConstraints(description);
				if (unsatisfied.length > 0) {
					// the bundle wasn't resolved due to some of its constraints were unsatisfiable
					logChildren = new FrameworkLogEntry[unsatisfied.length];
					for (int j = 0; j < unsatisfied.length; j++)
						logChildren[j] = new FrameworkLogEntry(symbolicName, FrameworkLogEntry.WARNING, 0, MessageHelper.getResolutionFailureMessage(unsatisfied[j]), 0, null, null);
				} else {
					ResolverError[] resolverErrors = state.getResolverErrors(description);
					if (resolverErrors.length > 0) {
						logChildren = new FrameworkLogEntry[resolverErrors.length];
						for (int j = 0; j < resolverErrors.length; j++)
							logChildren[j] = new FrameworkLogEntry(symbolicName, FrameworkLogEntry.WARNING, 0, resolverErrors[j].toString(), 0, null, null);
					}
				}

				allChildren.add(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, generalMessage, 0, null, logChildren));
			}
		if (allChildren.size() > 0)
			logService.log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, EclipseAdaptorMsg.ECLIPSE_STARTUP_ALL_NOT_RESOLVED, 0, null, allChildren.toArray(new FrameworkLogEntry[allChildren.size()])));
	}

	private static void publishSplashScreen(final Runnable endSplashHandler) {
		if (endSplashHandler == null)
			return;
		// register the output stream to the launcher if it exists
		try {
			Method method = endSplashHandler.getClass().getMethod("getOutputStream", new Class[0]); //$NON-NLS-1$
			Object outputStream = method.invoke(endSplashHandler, new Object[0]);
			if (outputStream instanceof OutputStream) {
				Dictionary<String, Object> osProperties = new Hashtable<String, Object>();
				osProperties.put("name", "splashstream"); //$NON-NLS-1$//$NON-NLS-2$
				splashStreamRegistration = context.registerService(OutputStream.class.getName(), outputStream, osProperties);
			}
		} catch (Exception ex) {
			// ignore
		}
		// keep this splash handler as the default startup monitor
		try {
			Dictionary<String, Object> monitorProps = new Hashtable<String, Object>();
			monitorProps.put(Constants.SERVICE_RANKING, new Integer(Integer.MIN_VALUE));
			defaultMonitorRegistration = context.registerService(StartupMonitor.class.getName(), new DefaultStartupMonitor(endSplashHandler), monitorProps);
		} catch (IllegalStateException e) {
			//splash handler did not provide the necessary methods, ignore it
		}
	}

	@SuppressWarnings("deprecation")
	private static URL searchForBundle(String name, String parent) throws MalformedURLException {
		URL url = null;
		File fileLocation = null;
		boolean reference = false;
		try {
			new URL(name); // quick check to see if the name is a valid URL
			url = new URL(new File(parent).toURL(), name);
		} catch (MalformedURLException e) {
			// TODO this is legacy support for non-URL names.  It should be removed eventually.
			// if name was not a URL then construct one.  
			// Assume it should be a reference and that it is relative.  This support need not 
			// be robust as it is temporary..
			File child = new File(name);
			fileLocation = child.isAbsolute() ? child : new File(parent, name);
			url = new URL(REFERENCE_PROTOCOL, null, fileLocation.toURL().toExternalForm());
			reference = true;
		}
		// if the name was a URL then see if it is relative.  If so, insert syspath.
		if (!reference) {
			URL baseURL = url;
			// if it is a reference URL then strip off the reference: and set base to the file:...
			if (url.getProtocol().equals(REFERENCE_PROTOCOL)) {
				reference = true;
				String baseSpec = url.getFile();
				if (baseSpec.startsWith(FILE_SCHEME)) {
					File child = new File(baseSpec.substring(5));
					baseURL = child.isAbsolute() ? child.toURL() : new File(parent, child.getPath()).toURL();
				} else
					baseURL = new URL(baseSpec);
			}

			fileLocation = new File(baseURL.getFile());
			// if the location is relative, prefix it with the parent
			if (!fileLocation.isAbsolute())
				fileLocation = new File(parent, fileLocation.toString());
		}
		// If the result is a reference then search for the real result and 
		// reconstruct the answer.
		if (reference) {
			String result = searchFor(fileLocation.getName(), new File(fileLocation.getParent()).getAbsolutePath());
			if (result != null)
				url = new URL(REFERENCE_PROTOCOL, null, FILE_SCHEME + result);
			else
				return null;
		}

		// finally we have something worth trying	
		try {
			URLConnection result = url.openConnection();
			result.connect();
			return url;
		} catch (IOException e) {
			//			int i = location.lastIndexOf('_');
			//			return i == -1? location : location.substring(0, i);
			return null;
		}
	}

	/*
	 * Ensure all basic bundles are installed, resolved and scheduled to start. Returns an array containing
	 * all basic bundles that are marked to start. 
	 * Returns null if the framework has been shutdown as a result of refreshPackages
	 */
	private static Bundle[] loadBasicBundles() {
		long startTime = System.currentTimeMillis();
		String osgiBundles = FrameworkProperties.getProperty(PROP_BUNDLES);
		String osgiExtensions = FrameworkProperties.getProperty(PROP_EXTENSIONS);
		if (osgiExtensions != null && osgiExtensions.length() > 0) {
			osgiBundles = osgiExtensions + ',' + osgiBundles;
			FrameworkProperties.setProperty(PROP_BUNDLES, osgiBundles);
		}
		String[] installEntries = getArrayFromList(osgiBundles, ","); //$NON-NLS-1$
		// get the initial bundle list from the installEntries
		InitialBundle[] initialBundles = getInitialBundles(installEntries);
		// get the list of currently installed initial bundles from the framework
		Bundle[] curInitBundles = getCurrentBundles(true);

		// list of bundles to be refreshed
		List<Bundle> toRefresh = new ArrayList<Bundle>(curInitBundles.length);
		// uninstall any of the currently installed bundles that do not exist in the 
		// initial bundle list from installEntries.
		uninstallBundles(curInitBundles, initialBundles, toRefresh);

		// install the initialBundles that are not already installed.
		List<Bundle> startBundles = new ArrayList<Bundle>(installEntries.length);
		List<Bundle> lazyActivationBundles = new ArrayList<Bundle>(installEntries.length);
		installBundles(initialBundles, curInitBundles, startBundles, lazyActivationBundles, toRefresh);

		// If we installed/uninstalled something, force a refresh of all installed/uninstalled bundles
		if (!toRefresh.isEmpty() && refreshPackages(toRefresh.toArray(new Bundle[toRefresh.size()])))
			return null; // cannot continue; refreshPackages shutdown the framework

		// schedule all basic bundles to be started
		Bundle[] startInitBundles = startBundles.toArray(new Bundle[startBundles.size()]);
		Bundle[] lazyInitBundles = lazyActivationBundles.toArray(new Bundle[lazyActivationBundles.size()]);
		startBundles(startInitBundles, lazyInitBundles);

		if (debug)
			System.out.println("Time to load bundles: " + (System.currentTimeMillis() - startTime)); //$NON-NLS-1$
		return startInitBundles;
	}

	private static InitialBundle[] getInitialBundles(String[] installEntries) {
		searchCandidates.clear();
		List<InitialBundle> result = new ArrayList<InitialBundle>(installEntries.length);
		int defaultStartLevel = Integer.parseInt(FrameworkProperties.getProperty(PROP_BUNDLES_STARTLEVEL, DEFAULT_BUNDLES_STARTLEVEL));
		String syspath = getSysPath();
		// should canonicalize the syspath.
		try {
			syspath = new File(syspath).getCanonicalPath();
		} catch (IOException ioe) {
			// do nothing
		}
		for (int i = 0; i < installEntries.length; i++) {
			String name = installEntries[i];
			int level = defaultStartLevel;
			boolean start = false;
			int index = name.lastIndexOf('@');
			if (index >= 0) {
				String[] attributes = getArrayFromList(name.substring(index + 1, name.length()), ":"); //$NON-NLS-1$
				for (int j = 0; j < attributes.length; j++) {
					String attribute = attributes[j];
					if (attribute.equals("start")) //$NON-NLS-1$
						start = true;
					else {
						try {
							level = Integer.parseInt(attribute);
						} catch (NumberFormatException e) { // bug 188089
							index = name.length();
							continue;
						}
					}
				}
				name = name.substring(0, index);
			}
			try {
				URL location = searchForBundle(name, syspath);
				if (location == null) {
					FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_BUNDLE_NOT_FOUND, installEntries[i]), 0, null, null);
					log.log(entry);
					// skip this entry
					continue;
				}
				location = makeRelative(LocationManager.getInstallLocation().getURL(), location);
				String locationString = INITIAL_LOCATION + location.toExternalForm();
				result.add(new InitialBundle(locationString, location, level, start));
			} catch (IOException e) {
				log.log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, e.getMessage(), 0, e, null));
			}
		}
		return result.toArray(new InitialBundle[result.size()]);
	}

	// returns true if the refreshPackages operation caused the framework to shutdown
	private static boolean refreshPackages(Bundle[] bundles) {
		ServiceReference<?> packageAdminRef = context.getServiceReference(PackageAdmin.class.getName());
		PackageAdmin packageAdmin = null;
		if (packageAdminRef != null)
			packageAdmin = (PackageAdmin) context.getService(packageAdminRef);
		if (packageAdmin == null)
			return false;
		// TODO this is such a hack it is silly.  There are still cases for race conditions etc
		// but this should allow for some progress...
		final Semaphore semaphore = new Semaphore(0);
		StartupEventListener listener = new StartupEventListener(semaphore, FrameworkEvent.PACKAGES_REFRESHED);
		context.addFrameworkListener(listener);
		context.addBundleListener(listener);
		packageAdmin.refreshPackages(bundles);
		context.ungetService(packageAdminRef);
		updateSplash(semaphore, listener);
		if (isForcedRestart())
			return true;
		return false;
	}

	private static void waitForShutdown() {
		if (!isForcedRestart())
			return;
		// wait for the system bundle to stop
		Bundle systemBundle = framework.getBundle(0);
		int i = 0;
		while (i < 5000 && (systemBundle.getState() & (Bundle.STARTING | Bundle.ACTIVE | Bundle.STOPPING)) != 0) {
			i += 200;
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				break;
			}
		}
	}

	/**
	 *  Creates and returns the adaptor
	 *
	 *  @return a FrameworkAdaptor object
	 */
	private static FrameworkAdaptor createAdaptor() throws Exception {
		String adaptorClassName = FrameworkProperties.getProperty(PROP_ADAPTOR, DEFAULT_ADAPTOR_CLASS);
		Class<?> adaptorClass = Class.forName(adaptorClassName);
		Class<?>[] constructorArgs = new Class[] {String[].class};
		Constructor<?> constructor = adaptorClass.getConstructor(constructorArgs);
		return (FrameworkAdaptor) constructor.newInstance(new Object[] {new String[0]});
	}

	private static String[] processCommandLine(String[] args) throws Exception {
		EclipseEnvironmentInfo.setAllArgs(args);
		if (args.length == 0) {
			EclipseEnvironmentInfo.setFrameworkArgs(args);
			EclipseEnvironmentInfo.setAllArgs(args);
			return args;
		}
		int[] configArgs = new int[args.length];
		configArgs[0] = -1; // need to initialize the first element to something that could not be an index.
		int configArgIndex = 0;
		for (int i = 0; i < args.length; i++) {
			boolean found = false;
			// check for args without parameters (i.e., a flag arg)

			// check if debug should be enabled for the entire platform
			// If this is the last arg or there is a following arg (i.e., arg+1 has a leading -), 
			// simply enable debug.  Otherwise, assume that that the following arg is
			// actually the filename of an options file.  This will be processed below.
			if (args[i].equalsIgnoreCase(DEBUG) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$
				FrameworkProperties.setProperty(PROP_DEBUG, ""); //$NON-NLS-1$
				debug = true;
				found = true;
			}

			// check if development mode should be enabled for the entire platform
			// If this is the last arg or there is a following arg (i.e., arg+1 has a leading -), 
			// simply enable development mode.  Otherwise, assume that that the following arg is
			// actually some additional development time class path entries.  This will be processed below.
			if (args[i].equalsIgnoreCase(DEV) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$
				FrameworkProperties.setProperty(PROP_DEV, ""); //$NON-NLS-1$
				found = true;
			}

			// look for the initialization arg
			if (args[i].equalsIgnoreCase(INITIALIZE)) {
				initialize = true;
				found = true;
			}

			// look for the clean flag.
			if (args[i].equalsIgnoreCase(CLEAN)) {
				FrameworkProperties.setProperty(PROP_CLEAN, "true"); //$NON-NLS-1$
				found = true;
			}

			// look for the consoleLog flag
			if (args[i].equalsIgnoreCase(CONSOLE_LOG)) {
				FrameworkProperties.setProperty(PROP_CONSOLE_LOG, "true"); //$NON-NLS-1$
				found = true;
			}

			// look for the console with no port.  
			if (args[i].equalsIgnoreCase(CONSOLE) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$
				FrameworkProperties.setProperty(PROP_CONSOLE, ""); //$NON-NLS-1$
				found = true;
			}

			if (args[i].equalsIgnoreCase(NOEXIT)) {
				FrameworkProperties.setProperty(PROP_NOSHUTDOWN, "true"); //$NON-NLS-1$
				found = true;
			}

			if (found) {
				configArgs[configArgIndex++] = i;
				continue;
			}
			// check for args with parameters. If we are at the last argument or if the next one
			// has a '-' as the first character, then we can't have an arg with a parm so continue.
			if (i == args.length - 1 || args[i + 1].startsWith("-")) { //$NON-NLS-1$
				continue;
			}
			String arg = args[++i];

			// look for the console and port.  
			if (args[i - 1].equalsIgnoreCase(CONSOLE)) {
				FrameworkProperties.setProperty(PROP_CONSOLE, arg);
				found = true;
			}

			// look for the configuration location .  
			if (args[i - 1].equalsIgnoreCase(CONFIGURATION)) {
				FrameworkProperties.setProperty(LocationManager.PROP_CONFIG_AREA, arg);
				found = true;
			}

			// look for the data location for this instance.  
			if (args[i - 1].equalsIgnoreCase(DATA)) {
				FrameworkProperties.setProperty(LocationManager.PROP_INSTANCE_AREA, arg);
				found = true;
			}

			// look for the user location for this instance.  
			if (args[i - 1].equalsIgnoreCase(USER)) {
				FrameworkProperties.setProperty(LocationManager.PROP_USER_AREA, arg);
				found = true;
			}

			// look for the launcher location
			if (args[i - 1].equalsIgnoreCase(LAUNCHER)) {
				FrameworkProperties.setProperty(LocationManager.PROP_LAUNCHER, arg);
				found = true;
			}
			// look for the development mode and class path entries.  
			if (args[i - 1].equalsIgnoreCase(DEV)) {
				FrameworkProperties.setProperty(PROP_DEV, arg);
				found = true;
			}

			// look for the debug mode and option file location.  
			if (args[i - 1].equalsIgnoreCase(DEBUG)) {
				FrameworkProperties.setProperty(PROP_DEBUG, arg);
				debug = true;
				found = true;
			}

			// look for the window system.  
			if (args[i - 1].equalsIgnoreCase(WS)) {
				FrameworkProperties.setProperty(PROP_WS, arg);
				found = true;
			}

			// look for the operating system
			if (args[i - 1].equalsIgnoreCase(OS)) {
				FrameworkProperties.setProperty(PROP_OS, arg);
				found = true;
			}

			// look for the system architecture
			if (args[i - 1].equalsIgnoreCase(ARCH)) {
				FrameworkProperties.setProperty(PROP_ARCH, arg);
				found = true;
			}

			// look for the nationality/language
			if (args[i - 1].equalsIgnoreCase(NL)) {
				FrameworkProperties.setProperty(PROP_NL, arg);
				found = true;
			}

			// look for the locale extensions
			if (args[i - 1].equalsIgnoreCase(NL_EXTENSIONS)) {
				FrameworkProperties.setProperty(PROP_NL_EXTENSIONS, arg);
				found = true;
			}

			// done checking for args.  Remember where an arg was found 
			if (found) {
				configArgs[configArgIndex++] = i - 1;
				configArgs[configArgIndex++] = i;
			}
		}

		// remove all the arguments consumed by this argument parsing
		if (configArgIndex == 0) {
			EclipseEnvironmentInfo.setFrameworkArgs(new String[0]);
			EclipseEnvironmentInfo.setAppArgs(args);
			return args;
		}
		String[] appArgs = new String[args.length - configArgIndex];
		String[] frameworkArgs = new String[configArgIndex];
		configArgIndex = 0;
		int j = 0;
		int k = 0;
		for (int i = 0; i < args.length; i++) {
			if (i == configArgs[configArgIndex]) {
				frameworkArgs[k++] = args[i];
				configArgIndex++;
			} else
				appArgs[j++] = args[i];
		}
		EclipseEnvironmentInfo.setFrameworkArgs(frameworkArgs);
		EclipseEnvironmentInfo.setAppArgs(appArgs);
		return appArgs;
	}

	/**
	 * Returns the result of converting a list of comma-separated tokens into an array
	 * 
	 * @return the array of string tokens
	 * @param prop the initial comma-separated string
	 */
	private static String[] getArrayFromList(String prop, String separator) {
		return ManifestElement.getArrayFromList(prop, separator);
	}

	protected static String getSysPath() {
		String result = FrameworkProperties.getProperty(PROP_SYSPATH);
		if (result != null)
			return result;
		result = getSysPathFromURL(FrameworkProperties.getProperty(PROP_FRAMEWORK));
		if (result == null)
			result = getSysPathFromCodeSource();
		if (result == null)
			throw new IllegalStateException("Can not find the system path."); //$NON-NLS-1$
		if (Character.isUpperCase(result.charAt(0))) {
			char[] chars = result.toCharArray();
			chars[0] = Character.toLowerCase(chars[0]);
			result = new String(chars);
		}
		FrameworkProperties.setProperty(PROP_SYSPATH, result);
		return result;
	}

	private static String getSysPathFromURL(String urlSpec) {
		if (urlSpec == null)
			return null;
		URL url = LocationHelper.buildURL(urlSpec, false);
		if (url == null)
			return null;
		File fwkFile = new File(url.getFile());
		fwkFile = new File(fwkFile.getAbsolutePath());
		fwkFile = new File(fwkFile.getParent());
		return fwkFile.getAbsolutePath();
	}

	private static String getSysPathFromCodeSource() {
		ProtectionDomain pd = EclipseStarter.class.getProtectionDomain();
		if (pd == null)
			return null;
		CodeSource cs = pd.getCodeSource();
		if (cs == null)
			return null;
		URL url = cs.getLocation();
		if (url == null)
			return null;
		String result = url.getFile();
		if (result.endsWith(".jar")) { //$NON-NLS-1$
			result = result.substring(0, result.lastIndexOf('/'));
			if ("folder".equals(FrameworkProperties.getProperty(PROP_FRAMEWORK_SHAPE))) //$NON-NLS-1$
				result = result.substring(0, result.lastIndexOf('/'));
		} else {
			if (result.endsWith("/")) //$NON-NLS-1$
				result = result.substring(0, result.length() - 1);
			result = result.substring(0, result.lastIndexOf('/'));
			result = result.substring(0, result.lastIndexOf('/'));
		}
		return result;
	}

	private static Bundle[] getCurrentBundles(boolean includeInitial) {
		Bundle[] installed = context.getBundles();
		List<Bundle> initial = new ArrayList<Bundle>();
		for (int i = 0; i < installed.length; i++) {
			Bundle bundle = installed[i];
			if (bundle.getLocation().startsWith(INITIAL_LOCATION)) {
				if (includeInitial)
					initial.add(bundle);
			} else if (!includeInitial && bundle.getBundleId() != 0)
				initial.add(bundle);
		}
		return initial.toArray(new Bundle[initial.size()]);
	}

	private static Bundle getBundleByLocation(String location, Bundle[] bundles) {
		for (int i = 0; i < bundles.length; i++) {
			Bundle bundle = bundles[i];
			if (location.equalsIgnoreCase(bundle.getLocation()))
				return bundle;
		}
		return null;
	}

	private static void uninstallBundles(Bundle[] curInitBundles, InitialBundle[] newInitBundles, List<Bundle> toRefresh) {
		for (int i = 0; i < curInitBundles.length; i++) {
			boolean found = false;
			for (int j = 0; j < newInitBundles.length; j++) {
				if (curInitBundles[i].getLocation().equalsIgnoreCase(newInitBundles[j].locationString)) {
					found = true;
					break;
				}
			}
			if (!found)
				try {
					curInitBundles[i].uninstall();
					toRefresh.add(curInitBundles[i]);
				} catch (BundleException e) {
					FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FAILED_UNINSTALL, curInitBundles[i].getLocation()), 0, e, null);
					log.log(entry);
				}
		}
	}

	private static void installBundles(InitialBundle[] initialBundles, Bundle[] curInitBundles, List<Bundle> startBundles, List<Bundle> lazyActivationBundles, List<Bundle> toRefresh) {
		ServiceReference<?> reference = context.getServiceReference(StartLevel.class.getName());
		StartLevel startService = null;
		if (reference != null)
			startService = (StartLevel) context.getService(reference);
		try {
			for (int i = 0; i < initialBundles.length; i++) {
				Bundle osgiBundle = getBundleByLocation(initialBundles[i].locationString, curInitBundles);
				try {
					// don't need to install if it is already installed
					if (osgiBundle == null) {
						InputStream in = initialBundles[i].location.openStream();
						try {
							osgiBundle = context.installBundle(initialBundles[i].locationString, in);
						} catch (BundleException e) {
							StatusException status = e instanceof StatusException ? (StatusException) e : null;
							if (status != null && status.getStatusCode() == StatusException.CODE_OK && status.getStatus() instanceof Bundle) {
								osgiBundle = (Bundle) status.getStatus();
							} else
								throw e;
						}
						// only check for lazy activation header if this is a newly installed bundle and is not marked for persistent start
						if (!initialBundles[i].start && hasLazyActivationPolicy(osgiBundle))
							lazyActivationBundles.add(osgiBundle);
					}
					// always set the startlevel incase it has changed (bug 111549)
					// this is a no-op if the level is the same as previous launch.
					if ((osgiBundle.getState() & Bundle.UNINSTALLED) == 0 && initialBundles[i].level >= 0 && startService != null)
						startService.setBundleStartLevel(osgiBundle, initialBundles[i].level);
					// if this bundle is supposed to be started then add it to the start list
					if (initialBundles[i].start)
						startBundles.add(osgiBundle);
					// include basic bundles in case they were not resolved before
					if ((osgiBundle.getState() & Bundle.INSTALLED) != 0)
						toRefresh.add(osgiBundle);
				} catch (BundleException e) {
					FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FAILED_INSTALL, initialBundles[i].location), 0, e, null);
					log.log(entry);
				} catch (IOException e) {
					FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FAILED_INSTALL, initialBundles[i].location), 0, e, null);
					log.log(entry);
				}
			}
		} finally {
			if (reference != null)
				context.ungetService(reference);
		}
	}

	@SuppressWarnings("deprecation")
	private static boolean hasLazyActivationPolicy(Bundle target) {
		// check the bundle manifest to see if it defines a lazy activation policy
		Dictionary<String, String> headers = target.getHeaders(""); //$NON-NLS-1$
		// first check to see if this is a fragment bundle
		String fragmentHost = headers.get(Constants.FRAGMENT_HOST);
		if (fragmentHost != null)
			return false; // do not activate fragment bundles
		// look for the OSGi defined Bundle-ActivationPolicy header
		String activationPolicy = headers.get(Constants.BUNDLE_ACTIVATIONPOLICY);
		try {
			if (activationPolicy != null) {
				ManifestElement[] elements = ManifestElement.parseHeader(Constants.BUNDLE_ACTIVATIONPOLICY, activationPolicy);
				if (elements != null && elements.length > 0) {
					// if the value is "lazy" then it has a lazy activation poliyc
					if (Constants.ACTIVATION_LAZY.equals(elements[0].getValue()))
						return true;
				}
			} else {
				// check for Eclipse specific lazy start headers "Eclipse-LazyStart" and "Eclipse-AutoStart"
				String eclipseLazyStart = headers.get(Constants.ECLIPSE_LAZYSTART);
				if (eclipseLazyStart == null)
					eclipseLazyStart = headers.get(Constants.ECLIPSE_AUTOSTART);
				ManifestElement[] elements = ManifestElement.parseHeader(Constants.ECLIPSE_LAZYSTART, eclipseLazyStart);
				if (elements != null && elements.length > 0) {
					// if the value is true then it is lazy activated
					if ("true".equals(elements[0].getValue())) //$NON-NLS-1$
						return true;
					// otherwise it is only lazy activated if it defines an exceptions directive.
					else if (elements[0].getDirective("exceptions") != null) //$NON-NLS-1$
						return true;
				}
			}
		} catch (BundleException be) {
			// ignore this
		}
		return false;
	}

	private static void startBundles(Bundle[] startBundles, Bundle[] lazyBundles) {
		for (int i = 0; i < startBundles.length; i++)
			startBundle(startBundles[i], 0);
		for (int i = 0; i < lazyBundles.length; i++)
			startBundle(lazyBundles[i], Bundle.START_ACTIVATION_POLICY);
	}

	private static void startBundle(Bundle bundle, int options) {
		try {
			bundle.start(options);
		} catch (BundleException e) {
			if ((bundle.getState() & Bundle.RESOLVED) != 0) {
				// only log errors if the bundle is resolved
				FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FAILED_START, bundle.getLocation()), 0, e, null);
				log.log(entry);
			}
		}
	}

	private static void loadConfigurationInfo() {
		Location configArea = LocationManager.getConfigurationLocation();
		if (configArea == null)
			return;

		URL location = null;
		try {
			location = new URL(configArea.getURL().toExternalForm() + LocationManager.CONFIG_FILE);
		} catch (MalformedURLException e) {
			// its ok.  This should never happen
		}
		mergeProperties(FrameworkProperties.getProperties(), loadProperties(location));
	}

	private static Properties loadProperties(URL location) {
		Properties result = new Properties();
		if (location == null)
			return result;
		try {
			InputStream in = location.openStream();
			try {
				result.load(in);
			} finally {
				in.close();
			}
		} catch (IOException e) {
			// its ok if there is no file.  We'll just use the defaults for everything
			// TODO but it might be nice to log something with gentle wording (i.e., it is not an error)
		}
		return substituteVars(result);
	}

	private static Properties substituteVars(Properties result) {
		if (result == null) {
			//nothing todo.
			return null;
		}
		for (Enumeration<Object> eKeys = result.keys(); eKeys.hasMoreElements();) {
			Object key = eKeys.nextElement();
			if (key instanceof String) {
				String value = result.getProperty((String) key);
				if (value != null)
					result.put(key, BaseStorageHook.substituteVars(value));
			}
		}
		return result;
	}

	/**
	 * Returns a URL which is equivalent to the given URL relative to the
	 * specified base URL. Works only for file: URLs
	 * @throws MalformedURLException 
	 */
	private static URL makeRelative(URL base, URL location) throws MalformedURLException {
		if (base == null)
			return location;
		if (!"file".equals(base.getProtocol())) //$NON-NLS-1$
			return location;
		if (!location.getProtocol().equals(REFERENCE_PROTOCOL))
			return location; // we can only make reference urls relative
		URL nonReferenceLocation = new URL(location.getPath());
		// if some URL component does not match, return the original location
		if (!base.getProtocol().equals(nonReferenceLocation.getProtocol()))
			return location;
		File locationPath = new File(nonReferenceLocation.getPath());
		// if location is not absolute, return original location 
		if (!locationPath.isAbsolute())
			return location;
		File relativePath = makeRelative(new File(base.getPath()), locationPath);
		String urlPath = relativePath.getPath();
		if (File.separatorChar != '/')
			urlPath = urlPath.replace(File.separatorChar, '/');
		if (nonReferenceLocation.getPath().endsWith("/")) //$NON-NLS-1$
			// restore original trailing slash 
			urlPath += '/';
		// couldn't use File to create URL here because it prepends the path with user.dir 
		URL relativeURL = new URL(base.getProtocol(), base.getHost(), base.getPort(), urlPath);
		// now make it back to a reference URL
		relativeURL = new URL(REFERENCE_SCHEME + relativeURL.toExternalForm());
		return relativeURL;
	}

	private static File makeRelative(File base, File location) {
		if (!location.isAbsolute())
			return location;
		File relative = new File(new FilePath(base).makeRelative(new FilePath(location)));
		return relative;
	}

	private static void mergeProperties(Properties destination, Properties source) {
		for (Enumeration<?> e = source.keys(); e.hasMoreElements();) {
			String key = (String) e.nextElement();
			String value = source.getProperty(key);
			if (destination.getProperty(key) == null)
				destination.setProperty(key, value);
		}
	}

	private static void setStartLevel(final int value) {
		ServiceReference<?> reference = context.getServiceReference(StartLevel.class.getName());
		final StartLevel startLevel = reference != null ? (StartLevel) context.getService(reference) : null;
		if (startLevel == null)
			return;
		final Semaphore semaphore = new Semaphore(0);
		StartupEventListener listener = new StartupEventListener(semaphore, FrameworkEvent.STARTLEVEL_CHANGED);
		context.addFrameworkListener(listener);
		context.addBundleListener(listener);
		startLevel.setStartLevel(value);
		context.ungetService(reference);
		updateSplash(semaphore, listener);
	}

	static class StartupEventListener implements SynchronousBundleListener, FrameworkListener {
		private final Semaphore semaphore;
		private final int frameworkEventType;

		public StartupEventListener(Semaphore semaphore, int frameworkEventType) {
			this.semaphore = semaphore;
			this.frameworkEventType = frameworkEventType;
		}

		public void bundleChanged(BundleEvent event) {
			if (event.getBundle().getBundleId() == 0 && event.getType() == BundleEvent.STOPPING)
				semaphore.release();
		}

		public void frameworkEvent(FrameworkEvent event) {
			if (event.getType() == frameworkEventType)
				semaphore.release();
		}

	}

	private static void updateSplash(Semaphore semaphore, StartupEventListener listener) {
		ServiceTracker<StartupMonitor, StartupMonitor> monitorTracker = new ServiceTracker<StartupMonitor, StartupMonitor>(context, StartupMonitor.class.getName(), null);
		monitorTracker.open();
		try {
			while (true) {
				StartupMonitor monitor = monitorTracker.getService();
				if (monitor != null) {
					try {
						monitor.update();
					} catch (Throwable e) {
						// ignore exceptions thrown by the monitor
					}
				}
				// can we acquire the semaphore yet?
				if (semaphore.acquire(50))
					break; //done
				//else still working, spin another update
			}
		} finally {
			if (listener != null) {
				context.removeFrameworkListener(listener);
				context.removeBundleListener(listener);
			}
			monitorTracker.close();
		}
	}

	/**
	 * Searches for the given target directory immediately under
	 * the given start location.  If one is found then this location is returned; 
	 * otherwise an exception is thrown.
	 * 
	 * @return the location where target directory was found
	 * @param start the location to begin searching
	 */
	private static String searchFor(final String target, String start) {
		String[] candidates = searchCandidates.get(start);
		if (candidates == null) {
			File startFile = new File(start);
			// Pre-check if file exists, if not, and it contains escape characters,
			// try decoding the path
			if (!startFile.exists() && start.indexOf('%') >= 0) {
				String decodePath = FrameworkProperties.decode(start);
				File f = new File(decodePath);
				if (f.exists())
					startFile = f;
			}
			candidates = startFile.list();
			if (candidates != null)
				searchCandidates.put(start, candidates);
		}
		if (candidates == null)
			return null;
		String result = null;
		Object[] maxVersion = null;
		boolean resultIsFile = false;
		for (int i = 0; i < candidates.length; i++) {
			String candidateName = candidates[i];
			if (!candidateName.startsWith(target))
				continue;
			boolean simpleJar = false;
			final char versionSep = candidateName.length() > target.length() ? candidateName.charAt(target.length()) : 0;
			if (candidateName.length() > target.length() && versionSep != '_' && versionSep != '-') {
				// make sure this is not just a jar with no (_|-)version tacked on the end
				if (candidateName.length() == 4 + target.length() && candidateName.endsWith(".jar")) //$NON-NLS-1$
					simpleJar = true;
				else
					// name does not match the target properly with an (_|-) version at the end
					continue;
			}
			// Note: directory with version suffix is always > than directory without version suffix
			String version = candidateName.length() > target.length() + 1 && (versionSep == '_' || versionSep == '-') ? candidateName.substring(target.length() + 1) : ""; //$NON-NLS-1$ 
			Object[] currentVersion = getVersionElements(version);
			if (currentVersion != null && compareVersion(maxVersion, currentVersion) < 0) {
				File candidate = new File(start, candidateName);
				boolean candidateIsFile = candidate.isFile();
				// if simple jar; make sure it is really a file before accepting it
				if (!simpleJar || candidateIsFile) {
					result = candidate.getAbsolutePath();
					resultIsFile = candidateIsFile;
					maxVersion = currentVersion;
				}
			}
		}
		if (result == null)
			return null;
		return result.replace(File.separatorChar, '/') + (resultIsFile ? "" : "/"); //$NON-NLS-1$ //$NON-NLS-2$
	}

	/**
	 * Do a quick parse of version identifier so its elements can be correctly compared.
	 * If we are unable to parse the full version, remaining elements are initialized
	 * with suitable defaults.
	 * @return an array of size 4; first three elements are of type Integer (representing
	 * major, minor and service) and the fourth element is of type String (representing
	 * qualifier).  A value of null is returned if there are no valid Integers.  Note, that 
	 * returning anything else will cause exceptions in the caller.
	 */
	private static Object[] getVersionElements(String version) {
		Object[] result = {new Integer(-1), new Integer(-1), new Integer(-1), ""}; //$NON-NLS-1$
		StringTokenizer t = new StringTokenizer(version, "."); //$NON-NLS-1$
		String token;
		for (int i = 0; t.hasMoreTokens() && i < 4; i++) {
			token = t.nextToken();
			if (i < 3) {
				// major, minor or service ... numeric values
				try {
					result[i] = new Integer(token);
				} catch (Exception e) {
					if (i == 0)
						return null; // return null if no valid numbers are present
					// invalid number format - use default numbers (-1) for the rest
					break;
				}
			} else {
				// qualifier ... string value
				result[i] = token;
			}
		}
		return result;
	}

	/**
	 * Compares version strings. 
	 * @return result of comparison, as integer;
	 * <code><0</code> if left < right;
	 * <code>0</code> if left == right;
	 * <code>>0</code> if left > right;
	 */
	private static int compareVersion(Object[] left, Object[] right) {
		if (left == null)
			return -1;
		int result = ((Integer) left[0]).compareTo((Integer) right[0]); // compare major
		if (result != 0)
			return result;

		result = ((Integer) left[1]).compareTo((Integer) right[1]); // compare minor
		if (result != 0)
			return result;

		result = ((Integer) left[2]).compareTo((Integer) right[2]); // compare service
		if (result != 0)
			return result;

		return ((String) left[3]).compareTo((String) right[3]); // compare qualifier
	}

	private static void finalizeProperties() {
		// if check config is unknown and we are in dev mode, 
		if (FrameworkProperties.getProperty(PROP_DEV) != null && FrameworkProperties.getProperty(PROP_CHECK_CONFIG) == null)
			FrameworkProperties.setProperty(PROP_CHECK_CONFIG, "true"); //$NON-NLS-1$
	}

	private static class InitialBundle {
		public final String locationString;
		public final URL location;
		public final int level;
		public final boolean start;

		InitialBundle(String locationString, URL location, int level, boolean start) {
			this.locationString = locationString;
			this.location = location;
			this.level = level;
			this.start = start;
		}
	}

	/**
	 * Sets the initial properties for the platform.  
	 * This method must be called before calling the {@link  #run(String[], Runnable)} or 
	 * {@link #startup(String[], Runnable)} methods for the properties to be used in 
	 * a launched instance of the platform.  
	 * <p>
	 * If the specified properties contains a null value then the key for that value 
	 * will be cleared from the properties of the platform.
	 * </p>
	 * @param initialProperties the initial properties to set for the platform.
	 * @since 3.2
	 */
	public static void setInitialProperties(Map<String, String> initialProperties) {
		if (initialProperties == null || initialProperties.isEmpty())
			return;
		for (Map.Entry<String, String> entry : initialProperties.entrySet()) {
			if (entry.getValue() != null)
				FrameworkProperties.setProperty(entry.getKey(), entry.getValue());
			else
				FrameworkProperties.clearProperty(entry.getKey());
		}
	}

	/**
	 * Returns the context of the system bundle.  A value of 
	 * <code>null</code> is returned if the platform is not running.
	 * @return the context of the system bundle
	 * @throws java.lang.SecurityException If the caller does not have the
	 *         appropriate <code>AdminPermission[system.bundle,CONTEXT]</code>, and
	 *         the Java Runtime Environment supports permissions.
	 */
	public static BundleContext getSystemBundleContext() {
		if (context == null || !running)
			return null;
		return context.getBundle().getBundleContext();
	}

	private static boolean isForcedRestart() {
		return Boolean.valueOf(FrameworkProperties.getProperty(PROP_FORCED_RESTART)).booleanValue();
	}

	/*
	 * NOTE: This is an internal/experimental method used by launchers that need to react when the framework
	 * is shutdown internally.
	 * 
	 * Adds a framework shutdown handler. <p>
	 * A handler implements the {@link Runnable} interface.  When the framework is shutdown
	 * the {@link Runnable#run()} method is called for each registered handler.  Handlers should 
	 * make no assumptions on the thread it is being called from.  If a handler object is 
	 * registered multiple times it will be called once for each registration.
	 * <p>
	 * At the time a handler is called the framework is shutdown.  Handlers must not depend on 
	 * a running framework to execute or attempt to load additional classes from bundles 
	 * installed in the framework.
	 * @param handler the framework shutdown handler
	 * @throws IllegalStateException if the platform is already running
	 */
	static void internalAddFrameworkShutdownHandler(Runnable handler) {
		if (running)
			throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING);

		if (shutdownHandlers == null)
			shutdownHandlers = new ArrayList<Runnable>();

		shutdownHandlers.add(handler);
	}

	/*
	 * NOTE: This is an internal/experimental method used by launchers that need to react when the framework
	 * is shutdown internally.
	 * 
	 * Removes a framework shutdown handler. <p>
	 * @param handler the framework shutdown handler
	 * @throws IllegalStateException if the platform is already running
	 */
	static void internalRemoveFrameworkShutdownHandler(Runnable handler) {
		if (running)
			throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING);

		if (shutdownHandlers != null)
			shutdownHandlers.remove(handler);
	}

	private static void registerFrameworkShutdownHandlers() {
		if (shutdownHandlers == null)
			return;

		final Bundle systemBundle = context.getBundle();
		for (Iterator<Runnable> it = shutdownHandlers.iterator(); it.hasNext();) {
			final Runnable handler = it.next();
			BundleListener listener = new BundleListener() {
				public void bundleChanged(BundleEvent event) {
					if (event.getBundle() == systemBundle && event.getType() == BundleEvent.STOPPED) {
						handler.run();
					}
				}
			};
			context.addBundleListener(listener);
		}
	}
}

Back to the top