KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > osgi > framework > internal > core > Framework


1 /*******************************************************************************
2  * Copyright (c) 2003, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.osgi.framework.internal.core;
12
13 import java.io.*;
14 import java.lang.reflect.*;
15 import java.net.*;
16 import java.security.*;
17 import java.util.*;
18 import org.eclipse.core.runtime.internal.adaptor.ContextFinder;
19 import org.eclipse.osgi.framework.adaptor.*;
20 import org.eclipse.osgi.framework.debug.Debug;
21 import org.eclipse.osgi.framework.eventmgr.*;
22 import org.eclipse.osgi.framework.internal.protocol.ContentHandlerFactory;
23 import org.eclipse.osgi.framework.internal.protocol.StreamHandlerFactory;
24 import org.eclipse.osgi.framework.log.FrameworkLog;
25 import org.eclipse.osgi.framework.log.FrameworkLogEntry;
26 import org.eclipse.osgi.framework.util.SecureAction;
27 import org.eclipse.osgi.internal.profile.Profile;
28 import org.eclipse.osgi.util.ManifestElement;
29 import org.eclipse.osgi.util.NLS;
30 import org.osgi.framework.*;
31
32 /**
33  * Core OSGi Framework class.
34  */

35 public class Framework implements EventDispatcher, EventPublisher {
36     // System property used to set the context classloader parent classloader type (ccl is the default)
37
private static final String JavaDoc PROP_CONTEXTCLASSLOADER_PARENT = "osgi.contextClassLoaderParent"; //$NON-NLS-1$
38
private static final String JavaDoc CONTEXTCLASSLOADER_PARENT_APP = "app"; //$NON-NLS-1$
39
private static final String JavaDoc CONTEXTCLASSLOADER_PARENT_EXT = "ext"; //$NON-NLS-1$
40
private static final String JavaDoc CONTEXTCLASSLOADER_PARENT_BOOT = "boot"; //$NON-NLS-1$
41
private static final String JavaDoc CONTEXTCLASSLOADER_PARENT_FWK = "fwk"; //$NON-NLS-1$
42

43     private static String JavaDoc J2SE = "J2SE-"; //$NON-NLS-1$
44
private static String JavaDoc JAVASE = "JavaSE-"; //$NON-NLS-1$
45
private static String JavaDoc PROFILE_EXT = ".profile"; //$NON-NLS-1$
46
/** FrameworkAdaptor specific functions. */
47     protected FrameworkAdaptor adaptor;
48     /** Framework properties object. A reference to the
49      * System.getProperies() object. The properties from
50      * the adaptor will be merged into these properties.
51      */

52     protected Properties properties;
53     /** Has the service space been started */
54     protected boolean active;
55     /** The bundles installed in the framework */
56     protected BundleRepository bundles;
57     /** Package Admin object. This object manages the exported packages. */
58     protected PackageAdminImpl packageAdmin;
59     /** Package Admin object. This object manages the exported packages. */
60     protected PermissionAdminImpl permissionAdmin;
61     /**
62      * Startlevel object. This object manages the framework and bundle
63      * startlevels
64      */

65     protected StartLevelManager startLevelManager;
66     /** The ServiceRegistry */
67     protected ServiceRegistry serviceRegistry; //TODO This is duplicated from the adaptor, do we really gain ?
68
/** next free service id. */
69     protected long serviceid;
70
71     /*
72      * The following EventListeners objects keep track of event listeners
73      * by BundleContext. Each element is a EventListeners that is the list
74      * of event listeners for a particular BundleContext. The max number of
75      * elements each of the following lists will have is the number of bundles
76      * installed in the Framework.
77      */

78     /** List of BundleContexts for bundle's BundleListeners. */
79     protected EventListeners bundleEvent;
80     protected static final int BUNDLEEVENT = 1;
81     /** List of BundleContexts for bundle's SynchronousBundleListeners. */
82     protected EventListeners bundleEventSync;
83     protected static final int BUNDLEEVENTSYNC = 2;
84     /** List of BundleContexts for bundle's ServiceListeners. */
85     protected EventListeners serviceEvent;
86     protected static final int SERVICEEVENT = 3;
87     /** List of BundleContexts for bundle's FrameworkListeners. */
88     protected EventListeners frameworkEvent;
89     protected static final int FRAMEWORKEVENT = 4;
90     protected static final int BATCHEVENT_BEGIN = Integer.MIN_VALUE + 1;
91     protected static final int BATCHEVENT_END = Integer.MIN_VALUE;
92     /** EventManager for event delivery. */
93     protected EventManager eventManager;
94     /* Reservation object for install synchronization */
95     protected Hashtable installLock;
96     /** System Bundle object */
97     protected SystemBundle systemBundle;
98     String JavaDoc[] bootDelegation;
99     String JavaDoc[] bootDelegationStems;
100     boolean bootDelegateAll = false;
101     boolean contextBootDelegation = "true".equals(FrameworkProperties.getProperty("osgi.context.bootdelegation", "true")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
102
boolean compatibiltyBootDelegation = false;
103
104     /**
105      * The AliasMapper used to alias OS Names.
106      */

107     protected static AliasMapper aliasMapper = new AliasMapper();
108     protected ConditionalPermissionAdminImpl condPermAdmin;
109     SecureAction secureAction = (SecureAction) AccessController.doPrivileged(SecureAction.createSecureAction());
110     // cache of AdminPermissions keyed by Bundle ID
111
private HashMap adminPermissions = new HashMap();
112     
113     // we need to hold these so that we can unregister them at shutdown
114
private StreamHandlerFactory streamHandlerFactory;
115     private ContentHandlerFactory contentHandlerFactory;
116
117     /*
118      * We need to make sure that the GetDataFileAction class loads early to prevent a ClassCircularityError when checking permissions.
119      * see bug 161561
120      */

121     static {
122         Class JavaDoc c;
123         c = GetDataFileAction.class;
124         c.getName(); // to prevent compiler warnings
125
}
126
127     static class GetDataFileAction implements PrivilegedAction {
128         private AbstractBundle bundle;
129         private String JavaDoc filename;
130
131         public GetDataFileAction(AbstractBundle bundle, String JavaDoc filename) {
132             this.bundle = bundle;
133             this.filename= filename;
134         }
135
136         public Object JavaDoc run() {
137             return bundle.getBundleData().getDataFile(filename);
138         }
139     }
140     
141     /**
142      * Constructor for the Framework instance. This method initializes the
143      * framework to an unlaunched state.
144      *
145      */

146     public Framework(FrameworkAdaptor adaptor) {
147         initialize(adaptor);
148     }
149
150     /**
151      * Initialize the framework to an unlaunched state. This method is called
152      * by the Framework constructor.
153      *
154      */

155     protected void initialize(FrameworkAdaptor adaptor) {
156         if (Profile.PROFILE && Profile.STARTUP)
157             Profile.logEnter("Framework.initialze()", null); //$NON-NLS-1$
158
long start = System.currentTimeMillis();
159         this.adaptor = adaptor;
160         active = false;
161         installSecurityManager();
162         if (Debug.DEBUG && Debug.DEBUG_SECURITY) {
163             Debug.println("SecurityManager: " + System.getSecurityManager()); //$NON-NLS-1$
164
Debug.println("ProtectionDomain of Framework.class: \n" + this.getClass().getProtectionDomain()); //$NON-NLS-1$
165
}
166         setNLSFrameworkLog();
167         // initialize ContextFinder
168
initializeContextFinder();
169         /* initialize the adaptor */
170         adaptor.initialize(this);
171         if (Profile.PROFILE && Profile.STARTUP)
172             Profile.logTime("Framework.initialze()", "adapter initialized"); //$NON-NLS-1$//$NON-NLS-2$
173
try {
174             adaptor.initializeStorage();
175         } catch (IOException e) /* fatal error */{
176             e.printStackTrace();
177             throw new RuntimeException JavaDoc(e.getMessage());
178         }
179         if (Profile.PROFILE && Profile.STARTUP)
180             Profile.logTime("Framework.initialze()", "adapter storage initialized"); //$NON-NLS-1$//$NON-NLS-2$
181
/*
182          * This must be done before calling any of the framework getProperty
183          * methods.
184          */

185         initializeProperties(adaptor.getProperties());
186         /* initialize admin objects */
187         packageAdmin = new PackageAdminImpl(this);
188         SecurityManager JavaDoc sm = System.getSecurityManager();
189         if (sm != null) {
190             try {
191                 permissionAdmin = new PermissionAdminImpl(this, adaptor.getPermissionStorage());
192             } catch (IOException e) /* fatal error */{
193                 e.printStackTrace();
194                 throw new RuntimeException JavaDoc(e.getMessage());
195             }
196             try {
197                 condPermAdmin = new ConditionalPermissionAdminImpl(this, adaptor.getPermissionStorage());
198             } catch (IOException e) /* fatal error */{
199                 e.printStackTrace();
200                 throw new RuntimeException JavaDoc(e.getMessage());
201             }
202         }
203         if (Profile.PROFILE && Profile.STARTUP)
204             Profile.logTime("Framework.initialze()", "done init props & new PermissionAdminImpl"); //$NON-NLS-1$//$NON-NLS-2$
205
startLevelManager = new StartLevelManager(this);
206         /* create the event manager and top level event dispatchers */
207         eventManager = new EventManager("Framework Event Dispatcher"); //$NON-NLS-1$
208
bundleEvent = new EventListeners();
209         bundleEventSync = new EventListeners();
210         serviceEvent = new EventListeners();
211         frameworkEvent = new EventListeners();
212         if (Profile.PROFILE && Profile.STARTUP)
213             Profile.logTime("Framework.initialze()", "done new EventManager"); //$NON-NLS-1$ //$NON-NLS-2$
214
/* create the service registry */
215         serviceid = 1;
216         serviceRegistry = adaptor.getServiceRegistry();
217         // Initialize the installLock; there is no way of knowing
218
// what the initial size should be, at most it will be the number
219
// of threads trying to install a bundle (probably a very low number).
220
installLock = new Hashtable(10);
221         /* create the system bundle */
222         createSystemBundle();
223         loadVMProfile(); // load VM profile after the system bundle has been created
224
setBootDelegation(); //set boot delegation property after system exports have been set
225
if (Profile.PROFILE && Profile.STARTUP)
226             Profile.logTime("Framework.initialze()", "done createSystemBundle"); //$NON-NLS-1$ //$NON-NLS-2$
227
/* install URLStreamHandlerFactory */
228         installURLStreamHandlerFactory(systemBundle.context, adaptor);
229         /* install ContentHandlerFactory for OSGi URLStreamHandler support */
230         installContentHandlerFactory(systemBundle.context, adaptor);
231         if (Profile.PROFILE && Profile.STARTUP)
232             Profile.logTime("Framework.initialze()", "done new URLStream/Content HandlerFactory"); //$NON-NLS-1$//$NON-NLS-2$
233
/* create bundle objects for all installed bundles. */
234         BundleData[] bundleDatas = adaptor.getInstalledBundles();
235         bundles = new BundleRepository(bundleDatas == null ? 10 : bundleDatas.length + 1);
236         /* add the system bundle to the Bundle Repository */
237         bundles.add(systemBundle);
238         if (bundleDatas != null) {
239             for (int i = 0; i < bundleDatas.length; i++) {
240                 try {
241                     AbstractBundle bundle = AbstractBundle.createBundle(bundleDatas[i], this);
242                     bundles.add(bundle);
243                 } catch (BundleException be) {
244                     // This is not a fatal error. Publish the framework event.
245
publishFrameworkEvent(FrameworkEvent.ERROR, systemBundle, be);
246                 }
247             }
248         }
249         if (Debug.DEBUG && Debug.DEBUG_GENERAL)
250             System.out.println("Initialize the framework: " + (System.currentTimeMillis() - start)); //$NON-NLS-1$
251
if (Profile.PROFILE && Profile.STARTUP)
252             Profile.logExit("Framework.initialize()"); //$NON-NLS-1$
253
}
254
255     private void setNLSFrameworkLog() {
256         try {
257             Field frameworkLogField = NLS.class.getDeclaredField("frameworkLog"); //$NON-NLS-1$
258
frameworkLogField.setAccessible(true);
259             frameworkLogField.set(null, adaptor.getFrameworkLog());
260         } catch (Exception JavaDoc e) {
261             adaptor.getFrameworkLog().log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, e.getMessage(), 0, e, null));
262         }
263     }
264
265     private void createSystemBundle() {
266         try {
267             systemBundle = new SystemBundle(this);
268         } catch (BundleException e) { // fatal error
269
e.printStackTrace();
270             throw new RuntimeException JavaDoc(NLS.bind(Msg.OSGI_SYSTEMBUNDLE_CREATE_EXCEPTION, e.getMessage()));
271         }
272     }
273
274     /**
275      * Initialize the System properties by copying properties from the adaptor
276      * properties object. This method is called by the initialize method.
277      *
278      */

279     protected void initializeProperties(Properties adaptorProperties) {
280         properties = FrameworkProperties.getProperties();
281         Enumeration enumKeys = adaptorProperties.propertyNames();
282         while (enumKeys.hasMoreElements()) {
283             String JavaDoc key = (String JavaDoc) enumKeys.nextElement();
284             if (properties.getProperty(key) == null) {
285                 properties.put(key, adaptorProperties.getProperty(key));
286             }
287         }
288         properties.put(Constants.FRAMEWORK_VENDOR, Constants.OSGI_FRAMEWORK_VENDOR);
289         properties.put(Constants.FRAMEWORK_VERSION, Constants.OSGI_FRAMEWORK_VERSION);
290         String JavaDoc value = properties.getProperty(Constants.FRAMEWORK_PROCESSOR);
291         if (value == null) {
292             value = properties.getProperty(Constants.JVM_OS_ARCH);
293             if (value != null) {
294                 properties.put(Constants.FRAMEWORK_PROCESSOR, value);
295             }
296         }
297         value = properties.getProperty(Constants.FRAMEWORK_OS_NAME);
298         if (value == null) {
299             value = properties.getProperty(Constants.JVM_OS_NAME);
300             try {
301                 String JavaDoc canonicalValue = (String JavaDoc) aliasMapper.aliasOSName(value);
302                 if (canonicalValue != null) {
303                     value = canonicalValue;
304                 }
305             } catch (ClassCastException JavaDoc ex) {
306                 //A vector was returned from the alias mapper.
307
//The alias mapped to more than one canonical value
308
//such as "win32" for example
309
}
310             if (value != null) {
311                 properties.put(Constants.FRAMEWORK_OS_NAME, value);
312             }
313         }
314         value = properties.getProperty(Constants.FRAMEWORK_OS_VERSION);
315         if (value == null) {
316             value = properties.getProperty(Constants.JVM_OS_VERSION);
317             if (value != null) {
318                 int space = value.indexOf(' ');
319                 if (space > 0) {
320                     value = value.substring(0, space);
321                 }
322                 properties.put(Constants.FRAMEWORK_OS_VERSION, value);
323             }
324         }
325         value = properties.getProperty(Constants.FRAMEWORK_LANGUAGE);
326         if (value == null)
327             // set the value of the framework language property
328
properties.put(Constants.FRAMEWORK_LANGUAGE, Locale.getDefault().getLanguage());
329         // set the support properties for fragments and require-bundle (bug 173090)
330
properties.put(Constants.SUPPORTS_FRAMEWORK_FRAGMENT, "true");
331         properties.put(Constants.SUPPORTS_FRAMEWORK_REQUIREBUNDLE, "true");
332     }
333
334     private void setBootDelegation() {
335         // set the compatibility boot delegation flag
336
compatibiltyBootDelegation = "true".equals(FrameworkProperties.getProperty(Constants.OSGI_COMPATIBILITY_BOOTDELEGATION)); //$NON-NLS-1$
337
// set the boot delegation according to the osgi boot delegation property
338
String JavaDoc bootDelegationProp = properties.getProperty(Constants.OSGI_BOOTDELEGATION);
339         if (bootDelegationProp == null)
340             return;
341         if (bootDelegationProp.trim().length() == 0)
342             return;
343         String JavaDoc[] bootPackages = ManifestElement.getArrayFromList(bootDelegationProp);
344         ArrayList exactMatch = new ArrayList(bootPackages.length);
345         ArrayList stemMatch = new ArrayList(bootPackages.length);
346         for (int i = 0; i < bootPackages.length; i++) {
347             if (bootPackages[i].equals("*")) { //$NON-NLS-1$
348
bootDelegateAll = true;
349                 return;
350             } else if (bootPackages[i].endsWith("*")) { //$NON-NLS-1$
351
if (bootPackages[i].length() > 2 && bootPackages[i].endsWith(".*")) //$NON-NLS-1$
352
stemMatch.add(bootPackages[i].substring(0, bootPackages[i].length() - 1));
353             } else {
354                 exactMatch.add(bootPackages[i]);
355             }
356         }
357         if (exactMatch.size() > 0)
358             bootDelegation = (String JavaDoc[]) exactMatch.toArray(new String JavaDoc[exactMatch.size()]);
359         if (stemMatch.size() > 0)
360             bootDelegationStems = (String JavaDoc[]) stemMatch.toArray(new String JavaDoc[stemMatch.size()]);
361     }
362
363     private void loadVMProfile() {
364         Properties profileProps = findVMProfile();
365         String JavaDoc systemExports = properties.getProperty(Constants.OSGI_FRAMEWORK_SYSTEM_PACKAGES);
366         // set the system exports property using the vm profile; only if the property is not already set
367
if (systemExports == null) {
368             systemExports = profileProps.getProperty(Constants.OSGI_FRAMEWORK_SYSTEM_PACKAGES);
369             if (systemExports != null)
370                 properties.put(Constants.OSGI_FRAMEWORK_SYSTEM_PACKAGES, systemExports);
371         }
372         // set the org.osgi.framework.bootdelegation property according to the java profile
373
String JavaDoc type = properties.getProperty(Constants.OSGI_JAVA_PROFILE_BOOTDELEGATION); // a null value means ignore
374
String JavaDoc profileBootDelegation = profileProps.getProperty(Constants.OSGI_BOOTDELEGATION);
375         if (Constants.OSGI_BOOTDELEGATION_OVERRIDE.equals(type)) {
376             if (profileBootDelegation == null)
377                 properties.remove(Constants.OSGI_BOOTDELEGATION); // override with a null value
378
else
379                 properties.put(Constants.OSGI_BOOTDELEGATION, profileBootDelegation); // override with the profile value
380
} else if (Constants.OSGI_BOOTDELEGATION_NONE.equals(type))
381             properties.remove(Constants.OSGI_BOOTDELEGATION); // remove the bootdelegation property in case it was set
382
// set the org.osgi.framework.executionenvironment property according to the java profile
383
if (properties.getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT) == null) {
384             // get the ee from the java profile; if no ee is defined then try the java profile name
385
String JavaDoc ee = profileProps.getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT, profileProps.getProperty(Constants.OSGI_JAVA_PROFILE_NAME));
386             if (ee != null)
387                 properties.put(Constants.FRAMEWORK_EXECUTIONENVIRONMENT, ee);
388         }
389     }
390
391     private Properties findVMProfile() {
392         Properties result = new Properties();
393         // Find the VM profile name using J2ME properties
394
String JavaDoc j2meConfig = properties.getProperty(Constants.J2ME_MICROEDITION_CONFIGURATION);
395         String JavaDoc j2meProfiles = properties.getProperty(Constants.J2ME_MICROEDITION_PROFILES);
396         String JavaDoc vmProfile = null;
397         String JavaDoc javaEdition = null;
398         Version javaVersion = null;
399         if (j2meConfig != null && j2meConfig.length() > 0 && j2meProfiles != null && j2meProfiles.length() > 0) {
400             // save the vmProfile based off of the config and profile
401
// use the last profile; assuming that is the highest one
402
String JavaDoc[] j2meProfileList = ManifestElement.getArrayFromList(j2meProfiles, " "); //$NON-NLS-1$
403
if (j2meProfileList != null && j2meProfileList.length > 0)
404                 vmProfile = j2meConfig + '_' + j2meProfileList[j2meProfileList.length - 1];
405         } else {
406             // No J2ME properties; use J2SE properties
407
// Note that the CDC spec appears not to require VM implementations to set the
408
// javax.microedition properties!! So we will try to fall back to the
409
// java.specification.name property, but this is pretty ridiculous!!
410
String JavaDoc javaSpecVersion = properties.getProperty("java.specification.version"); //$NON-NLS-1$
411
// set the profile and EE based off of the java.specification.version
412
// TODO We assume J2ME Foundation and J2SE here. need to support other profiles J2EE ...
413
if (javaSpecVersion != null) {
414                 StringTokenizer st = new StringTokenizer(javaSpecVersion, " _-"); //$NON-NLS-1$
415
javaSpecVersion = st.nextToken();
416                 String JavaDoc javaSpecName = properties.getProperty("java.specification.name"); //$NON-NLS-1$
417
if ("J2ME Foundation Specification".equals(javaSpecName)) //$NON-NLS-1$
418
vmProfile = "CDC-" + javaSpecVersion + "_Foundation-" + javaSpecVersion; //$NON-NLS-1$ //$NON-NLS-2$
419
else {
420                     // look for JavaSE if 1.6 or greater; otherwise look for J2SE
421
Version v16 = new Version("1.6"); //$NON-NLS-1$
422
javaEdition = J2SE;
423                     try {
424                         javaVersion = new Version(javaSpecVersion);
425                         if (v16.compareTo(javaVersion) <= 0)
426                             javaEdition = JAVASE;
427                     } catch (IllegalArgumentException JavaDoc e) {
428                         // do nothing
429
}
430                     vmProfile = javaEdition + javaSpecVersion;
431                 }
432             }
433         }
434         URL url = null;
435         // check for the java profile property for a url
436
String JavaDoc propJavaProfile = FrameworkProperties.getProperty(Constants.OSGI_JAVA_PROFILE);
437         if (propJavaProfile != null)
438             try {
439                 // we assume a URL
440
url = new URL(propJavaProfile);
441             } catch (MalformedURLException e1) {
442                 // try using a relative path in the system bundle
443
url = findInSystemBundle(propJavaProfile);
444             }
445         if (url == null && vmProfile != null) {
446             // look for a profile in the system bundle based on the vm profile
447
String JavaDoc javaProfile = vmProfile + PROFILE_EXT;
448             url = findInSystemBundle(javaProfile);
449             if (url == null)
450                 url = getNextBestProfile(javaEdition, javaVersion);
451         }
452         if (url == null)
453             // the profile url is still null then use the osgi min profile in OSGi by default
454
url = findInSystemBundle("OSGi_Minimum-1.1.profile"); //$NON-NLS-1$
455
if (url != null) {
456             InputStream in = null;
457             try {
458                 in = url.openStream();
459                 result.load(new BufferedInputStream(in));
460             } catch (IOException e) {
461                 // TODO consider logging ...
462
} finally {
463                 if (in != null)
464                     try {
465                         in.close();
466                     } catch (IOException ee) {
467                         // do nothing
468
}
469             }
470         }
471         // set the profile name if it does not provide one
472
if (result.getProperty(Constants.OSGI_JAVA_PROFILE_NAME) == null)
473             if (vmProfile != null)
474                 result.put(Constants.OSGI_JAVA_PROFILE_NAME, vmProfile.replace('_', '/'));
475             else
476                 // last resort; default to the absolute minimum profile name for the framework
477
result.put(Constants.OSGI_JAVA_PROFILE_NAME, "OSGi/Minimum-1.1"); //$NON-NLS-1$
478
return result;
479     }
480
481     private URL getNextBestProfile(String JavaDoc javaEdition, Version javaVersion) {
482         if (javaVersion == null || (javaEdition != J2SE && javaEdition != JAVASE))
483             return null; // we cannot automatically choose the next best profile unless this is a J2SE or JavaSE vm
484
URL bestProfile = findNextBestProfile(javaEdition, javaVersion);
485         if (bestProfile == null && javaEdition == JAVASE)
486             // if this is a JavaSE VM then search for a lower J2SE profile
487
bestProfile = findNextBestProfile(J2SE, javaVersion);
488         return bestProfile;
489     }
490
491     private URL findNextBestProfile(String JavaDoc javaEdition, Version javaVersion) {
492         URL result = null;
493         int minor = javaVersion.getMinor();
494         do {
495             result = findInSystemBundle(javaEdition + javaVersion.getMajor() + "." + minor + PROFILE_EXT); //$NON-NLS-1$
496
minor = minor - 1;
497         } while (result == null && minor > 0);
498         return result;
499     }
500
501     private URL findInSystemBundle(String JavaDoc entry) {
502         URL result = systemBundle.getEntry(entry);
503         if (result == null) {
504             // Check the ClassLoader in case we're launched off the Java boot classpath
505
ClassLoader JavaDoc loader=getClass().getClassLoader();
506             result = loader==null ? ClassLoader.getSystemResource(entry) : loader.getResource(entry);
507         }
508         return result;
509     }
510
511     /**
512      * This method return the state of the framework.
513      *
514      */

515     protected boolean isActive() {
516         return (active);
517     }
518
519     /**
520      * This method is called to destory the framework instance.
521      *
522      */

523     public synchronized void close() {
524         if (active) {
525             shutdown();
526         }
527         synchronized (bundles) {
528             List allBundles = bundles.getBundles();
529             int size = allBundles.size();
530             for (int i = 0; i < size; i++) {
531                 AbstractBundle bundle = (AbstractBundle) allBundles.get(i);
532                 bundle.close();
533             }
534             bundles.removeAllBundles();
535         }
536         serviceRegistry = null;
537         if (bundleEvent != null) {
538             bundleEvent.removeAllListeners();
539             bundleEvent = null;
540         }
541         if (bundleEventSync != null) {
542             bundleEventSync.removeAllListeners();
543             bundleEventSync = null;
544         }
545         if (serviceEvent != null) {
546             serviceEvent.removeAllListeners();
547             serviceEvent = null;
548         }
549         if (frameworkEvent != null) {
550             frameworkEvent.removeAllListeners();
551             frameworkEvent = null;
552         }
553         if (eventManager != null) {
554             eventManager.close();
555             eventManager = null;
556         }
557         permissionAdmin = null;
558         condPermAdmin = null;
559         packageAdmin = null;
560         adaptor = null;
561         uninstallURLStreamHandlerFactory();
562         uninstallContentHandlerFactory();
563     }
564
565     /**
566      * Start the framework.
567      *
568      * When the framework is started. The following actions occur: 1. Event
569      * handling is enabled. Events can now be delivered to listeners. 2. All
570      * bundles which are recorded as started are started as described in the
571      * Bundle.start() method. These bundles are the bundles that were started
572      * when the framework was last stopped. Reports any exceptions that occur
573      * during startup using FrameworkEvents. 3. A FrameworkEvent of type
574      * FrameworkEvent.STARTED is broadcast.
575      *
576      */

577     public synchronized void launch() {
578         /* Return if framework already started */
579         if (active) {
580             return;
581         }
582         /* mark framework as started */
583         active = true;
584         /* Resume systembundle */
585         if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
586             Debug.println("Trying to launch framework"); //$NON-NLS-1$
587
}
588         systemBundle.resume();
589     }
590
591     /**
592      * Stop the framework.
593      *
594      * When the framework is stopped. The following actions occur: 1. Suspend
595      * all started bundles as described in the Bundle.stop method except that
596      * the bundle is recorded as started. These bundles will be restarted when
597      * the framework is next started. Reports any exceptions that occur during
598      * stopping using FrameworkEvents. 2. Event handling is disabled.
599      *
600      */

601     public synchronized void shutdown() {
602         /* Return if framework already stopped */
603         if (!active) {
604             return;
605         }
606         /*
607          * set the state of the System Bundle to STOPPING.
608          * this must be done first according to section 4.19.2 from the OSGi R3 spec.
609          */

610         systemBundle.state = AbstractBundle.STOPPING;
611         publishBundleEvent(BundleEvent.STOPPING, systemBundle); // need to send system bundle stopping event
612
/* call the FrameworkAdaptor.frameworkStopping method first */
613         try {
614             adaptor.frameworkStopping(systemBundle.getContext());
615         } catch (Throwable JavaDoc t) {
616             publishFrameworkEvent(FrameworkEvent.ERROR, systemBundle, t);
617         }
618         /* Suspend systembundle */
619         if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
620             Debug.println("Trying to shutdown Framework"); //$NON-NLS-1$
621
}
622         systemBundle.suspend();
623         try {
624             adaptor.compactStorage();
625         } catch (IOException e) {
626             publishFrameworkEvent(FrameworkEvent.ERROR, systemBundle, e);
627         }
628         /* mark framework as stopped */
629         active = false;
630     }
631
632     /**
633      * Create a new Bundle object.
634      *
635      * @param bundledata the BundleData of the Bundle to create
636      */

637     AbstractBundle createAndVerifyBundle(BundleData bundledata) throws BundleException {
638         // Check for a bundle already installed with the same symbolic name and version.
639
if (bundledata.getSymbolicName() != null) {
640             AbstractBundle installedBundle = getBundleBySymbolicName(bundledata.getSymbolicName(), bundledata.getVersion());
641             if (installedBundle != null && installedBundle.getBundleId() != bundledata.getBundleID()) {
642                 throw new BundleException(NLS.bind(Msg.BUNDLE_INSTALL_SAME_UNIQUEID, new Object JavaDoc[] {installedBundle.getSymbolicName(), installedBundle.getVersion().toString(), installedBundle.getLocation()}));
643             }
644         }
645         verifyExecutionEnvironment(bundledata.getManifest());
646         return AbstractBundle.createBundle(bundledata, this);
647     }
648
649     /**
650      * Verifies that the framework supports one of the required Execution
651      * Environments
652      *
653      * @param manifest
654      * BundleManifest of the bundle to verify the Execution
655      * Enviroment for
656      * @return boolean true if the required Execution Enviroment is available.
657      * @throws BundleException
658      * if the framework does not support the required Execution
659      * Environment.
660      */

661     protected boolean verifyExecutionEnvironment(Dictionary manifest) throws BundleException {
662         if (!Boolean.valueOf(FrameworkProperties.getProperty(Constants.ECLIPSE_EE_INSTALL_VERIFY, Boolean.TRUE.toString())).booleanValue()) //$NON-NLS-1$
663
return true;
664         String JavaDoc headerValue = (String JavaDoc) manifest.get(Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT);
665         /* If no required EE is in the manifest return true */
666         if (headerValue == null) {
667             return true;
668         }
669         ManifestElement[] bundleRequiredEE = ManifestElement.parseHeader(Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT, headerValue);
670         if (bundleRequiredEE.length == 0) {
671             return true;
672         }
673         String JavaDoc systemEE = FrameworkProperties.getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT);
674         if (systemEE != null && !systemEE.equals("")) { //$NON-NLS-1$
675
ManifestElement[] systemEEs = ManifestElement.parseHeader(Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT, systemEE);
676             for (int i = 0; i < systemEEs.length; i++) {
677                 for (int j = 0; j < bundleRequiredEE.length; j++) {
678                     if (systemEEs[i].getValue().equals(bundleRequiredEE[j].getValue())) {
679                         return true;
680                     }
681                 }
682             }
683         }
684         /* If we got here then no matching EE is available, throw exception. */
685         StringBuffer JavaDoc bundleEE = new StringBuffer JavaDoc(25);
686         for (int i = 0; i < bundleRequiredEE.length; i++) {
687             if (i > 0) {
688                 bundleEE.append(","); //$NON-NLS-1$
689
}
690             bundleEE.append(bundleRequiredEE[i].getValue());
691         }
692         throw new BundleException(NLS.bind(Msg.BUNDLE_INSTALL_REQUIRED_EE_EXCEPTION, bundleEE.toString()));
693     }
694
695     /**
696      * Retrieve the value of the named environment property. Values are
697      * provided for the following properties:
698      * <dl>
699      * <dt><code>org.osgi.framework.version</code>
700      * <dd>The version of the framework.
701      * <dt><code>org.osgi.framework.vendor</code>
702      * <dd>The vendor of this framework implementation.
703      * <dt><code>org.osgi.framework.language</code>
704      * <dd>The language being used. See ISO 639 for possible values.
705      * <dt><code>org.osgi.framework.os.name</code>
706      * <dd>The name of the operating system of the hosting computer.
707      * <dt><code>org.osgi.framework.os.version</code>
708      * <dd>The version number of the operating system of the hosting computer.
709      * <dt><code>org.osgi.framework.processor</code>
710      * <dd>The name of the processor of the hosting computer.
711      * </dl>
712      *
713      * <p>
714      * Note: These last four properties are used by the <code>Bundle-NativeCode</code>
715      * manifest header's matching algorithm for selecting native code.
716      *
717      * @param key
718      * The name of the requested property.
719      * @return The value of the requested property, or <code>null</code> if
720      * the property is undefined.
721      */

722     public String JavaDoc getProperty(String JavaDoc key) {
723         return properties.getProperty(key);
724     }
725
726     /**
727      * Retrieve the value of the named environment property. Values are
728      * provided for the following properties:
729      * <dl>
730      * <dt><code>org.osgi.framework.version</code>
731      * <dd>The version of the framework.
732      * <dt><code>org.osgi.framework.vendor</code>
733      * <dd>The vendor of this framework implementation.
734      * <dt><code>org.osgi.framework.language</code>
735      * <dd>The language being used. See ISO 639 for possible values.
736      * <dt><code>org.osgi.framework.os.name</code>
737      * <dd>The name of the operating system of the hosting computer.
738      * <dt><code>org.osgi.framework.os.version</code>
739      * <dd>The version number of the operating system of the hosting computer.
740      * <dt><code>org.osgi.framework.processor</code>
741      * <dd>The name of the processor of the hosting computer.
742      * </dl>
743      *
744      * <p>
745      * Note: These last four properties are used by the <code>Bundle-NativeCode</code>
746      * manifest header's matching algorithm for selecting native code.
747      *
748      * @param key
749      * The name