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 of the requested property.
750      * @param def
751      * A default value is the requested property is not present.
752      * @return The value of the requested property, or the default value if the
753      * property is undefined.
754      */

755     protected String JavaDoc getProperty(String JavaDoc key, String JavaDoc def) {
756         return properties.getProperty(key, def);
757     }
758
759     /**
760      * Set a system property.
761      *
762      * @param key
763      * The name of the property to set.
764      * @param value
765      * The value to set.
766      * @return The previous value of the property or null if the property was
767      * not previously set.
768      */

769     protected Object JavaDoc setProperty(String JavaDoc key, String JavaDoc value) {
770         return properties.put(key, value);
771     }
772
773     /**
774      * Install a bundle from a location.
775      *
776      * The bundle is obtained from the location parameter as interpreted by the
777      * framework in an implementation dependent way. Typically, location will
778      * most likely be a URL.
779      *
780      * @param location
781      * The location identifier of the bundle to install.
782      * @return The Bundle object of the installed bundle.
783      */

784     public AbstractBundle installBundle(final String JavaDoc location) throws BundleException {
785         if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
786             Debug.println("install from location: " + location); //$NON-NLS-1$
787
}
788         final AccessControlContext callerContext = AccessController.getContext();
789         return installWorker(location, new PrivilegedExceptionAction() {
790             public Object JavaDoc run() throws BundleException {
791                 /* Map the identity to a URLConnection */
792                 URLConnection source = adaptor.mapLocationToURLConnection(location);
793                 /* call the worker to install the bundle */
794                 return installWorkerPrivileged(location, source, callerContext);
795             }
796         });
797     }
798
799     /**
800      * Install a bundle from an InputStream.
801      *
802      * <p>
803      * This method performs all the steps listed in
804      * {@link #installBundle(java.lang.String)}, except the bundle's content
805      * will be read from the InputStream. The location identifier specified
806      * will be used as the identity of the bundle.
807      *
808      * @param location
809      * The location identifier of the bundle to install.
810      * @param in
811      * The InputStream from which the bundle will be read.
812      * @return The Bundle of the installed bundle.
813      */

814     protected AbstractBundle installBundle(final String JavaDoc location, final InputStream in) throws BundleException {
815         if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
816             Debug.println("install from inputstream: " + location + ", " + in); //$NON-NLS-1$ //$NON-NLS-2$
817
}
818         final AccessControlContext callerContext = AccessController.getContext();
819         return installWorker(location, new PrivilegedExceptionAction() {
820             public Object JavaDoc run() throws BundleException {
821                 /* Map the InputStream to a URLConnection */
822                 URLConnection source = new BundleSource(in);
823                 /* call the worker to install the bundle */
824                 return installWorkerPrivileged(location, source, callerContext);
825             }
826         });
827     }
828
829     /**
830      * Worker method to install a bundle. It obtains the reservation for the
831      * location and calls the specified action.
832      *
833      * @param location
834      * The location identifier of the bundle to install.
835      * @param action
836      * A PrivilegedExceptionAction which calls the real worker.
837      * @return The {@link AbstractBundle}of the installed bundle.
838      * @exception BundleException
839      * If the action throws an error.
840      */

841     protected AbstractBundle installWorker(String JavaDoc location, PrivilegedExceptionAction action) throws BundleException {
842         synchronized (installLock) {
843             while (true) {
844                 /* Check that the bundle is not already installed. */
845                 AbstractBundle bundle = getBundleByLocation(location);
846                 /* If already installed, return bundle object */
847                 if (bundle != null) {
848                     return bundle;
849                 }
850                 Thread JavaDoc current = Thread.currentThread();
851                 /* Check for and make reservation */
852                 Thread JavaDoc reservation = (Thread JavaDoc) installLock.put(location, current);
853                 /* if the location is not already reserved */
854                 if (reservation == null) {
855                     /* we have made the reservation and can continue */
856                     break;
857                 }
858                 /* the location was already reserved */
859                 /*
860                  * If the reservation is held by the current thread, we have
861                  * recursed to install the same bundle!
862                  */

863                 if (current.equals(reservation)) {
864                     throw new BundleException(Msg.BUNDLE_INSTALL_RECURSION_EXCEPTION);
865                 }
866                 try {
867                     /* wait for the reservation to be released */
868                     installLock.wait();
869                 } catch (InterruptedException JavaDoc e) {
870                 }
871             }
872         }
873         /* Don't call adaptor while holding the install lock */
874         try {
875             AbstractBundle bundle = (AbstractBundle) AccessController.doPrivileged(action);
876             publishBundleEvent(BundleEvent.INSTALLED, bundle);
877             return bundle;
878         } catch (PrivilegedActionException e) {
879             if (e.getException() instanceof RuntimeException JavaDoc)
880                 throw (RuntimeException JavaDoc) e.getException();
881             throw (BundleException) e.getException();
882         } finally {
883             synchronized (installLock) {
884                 /* release reservation */
885                 installLock.remove(location);
886                 /* wake up all waiters */
887                 installLock.notifyAll();
888             }
889         }
890     }
891
892     /**
893      * Worker method to install a bundle. It calls the FrameworkAdaptor object
894      * to install the bundle in persistent storage.
895      *
896      * @param location
897      * The location identifier of the bundle to install.
898      * @param source
899      * The URLConnection from which the bundle will be read.
900      * @return The {@link AbstractBundle}of the installed bundle.
901      * @exception BundleException
902      * If the provided stream cannot be read.
903      */

904     protected AbstractBundle installWorkerPrivileged(String JavaDoc location, URLConnection source, AccessControlContext callerContext) throws BundleException {
905         BundleOperation storage = adaptor.installBundle(location, source);
906         final AbstractBundle bundle;
907         try {
908             BundleData bundledata = storage.begin();
909             bundle = createAndVerifyBundle(bundledata);
910             if (Debug.DEBUG) {
911                 BundleWatcher bundleStats = adaptor.getBundleWatcher();
912                 if (bundleStats != null)
913                     bundleStats.watchBundle(bundle, BundleWatcher.START_INSTALLING);
914             }
915             try {
916                 // Select the native code paths for the bundle;
917
// this is not done by the adaptor because this
918
// should be a static algorithm spec'ed by OSGi
919
// that we do not allow to be adapted.
920
String JavaDoc[] nativepaths = selectNativeCode(bundle);
921                 if (nativepaths != null) {
922                     bundledata.installNativeCode(nativepaths);
923                 }
924                 bundle.load();
925                 if (System.getSecurityManager() != null) {
926                     final boolean extension = (bundledata.getType() & (BundleData.TYPE_BOOTCLASSPATH_EXTENSION | BundleData.TYPE_FRAMEWORK_EXTENSION)) != 0;
927                     // must check for AllPermission before allow a bundle extension to be installed
928
if (extension && !bundle.hasPermission(new AllPermission()))
929                         throw new BundleException(Msg.BUNDLE_EXTENSION_PERMISSION, new SecurityException JavaDoc(Msg.BUNDLE_EXTENSION_PERMISSION));
930                     try {
931                         AccessController.doPrivileged(new PrivilegedExceptionAction() {
932                             public Object JavaDoc run() throws Exception JavaDoc {
933                                 checkAdminPermission(bundle, AdminPermission.LIFECYCLE);
934                                 if (extension) // need special permission to install extension bundles
935
checkAdminPermission(bundle, AdminPermission.EXTENSIONLIFECYCLE);
936                                 return null;
937                             }
938                         }, callerContext);
939                     } catch (PrivilegedActionException e) {
940                         throw e.getException();
941                     }
942                 }
943                 storage.commit(false);
944             } catch (Throwable JavaDoc error) {
945                 synchronized (bundles) {
946                     bundle.unload();
947                 }
948                 bundle.close();
949                 throw error;
950             } finally {
951                 if (Debug.DEBUG) {
952                     BundleWatcher bundleStats = adaptor.getBundleWatcher();
953                     if (bundleStats != null)
954                         bundleStats.watchBundle(bundle, BundleWatcher.END_INSTALLING);
955                 }
956             }
957             /* bundle has been successfully installed */
958             bundles.add(bundle);
959         } catch (Throwable JavaDoc t) {
960             try {
961                 storage.undo();
962             } catch (BundleException ee) {
963                 publishFrameworkEvent(FrameworkEvent.ERROR, systemBundle, ee);
964             }
965             if (t instanceof SecurityException JavaDoc)
966                 throw (SecurityException JavaDoc) t;
967             if (t instanceof BundleException)
968                 throw (BundleException) t;
969             throw new BundleException(t.getMessage(), t);
970         }
971         return bundle;
972     }
973
974     /**
975      * Selects a native code clause and return a list of the bundle entries for
976      * native code to be installed.
977      *
978      * @param bundle
979      * Bundle's manifest
980      * @return a list of Strings of the bundle entries to install or <tt>null</tt>
981      * if there are no native code clauses.
982      * @throws BundleException
983      * If there is no suitable clause.
984      */

985     String JavaDoc[] selectNativeCode(org.osgi.framework.Bundle bundle) throws BundleException {
986         String JavaDoc headerValue = (String JavaDoc) ((AbstractBundle) bundle).getBundleData().getManifest().get(Constants.BUNDLE_NATIVECODE);
987         if (headerValue == null) {
988             return (null);
989         }
990         ManifestElement[] elements = ManifestElement.parseHeader(Constants.BUNDLE_NATIVECODE, headerValue);
991         ArrayList bundleNativeCodes = new ArrayList(elements.length);
992         int length = elements.length;
993         boolean optional = false;
994         if (elements[length - 1].getValue().equals("*")) { //$NON-NLS-1$
995
optional = true;
996             length--;
997         }
998         String JavaDoc processor = getProperty(Constants.FRAMEWORK_PROCESSOR);
999         String JavaDoc osname = getProperty(Constants.FRAMEWORK_OS_NAME);
1000        Version osversion;
1001        try {
1002            osversion = Version.parseVersion(getProperty(Constants.FRAMEWORK_OS_VERSION));
1003        } catch (Exception JavaDoc e) {
1004            osversion = Version.emptyVersion;
1005        }
1006        String JavaDoc language = getProperty(Constants.FRAMEWORK_LANGUAGE);
1007        for (int i = 0; i < length; i++) {
1008            BundleNativeCode bnc = new BundleNativeCode(elements[i], (AbstractBundle) bundle);
1009            // Pass 1: perform processor/osname/filter matching
1010
// Pass 2: perform osversion matching
1011
// Pass 3: perform language matching
1012
// If there is not a match on all three, then the native code clause is not selected.
1013
if (bnc.matchProcessorOSNameFilter(processor, osname) > 0 && bnc.matchOSVersion(osversion) != null && bnc.matchLanguage(language) > 0)
1014                bundleNativeCodes.add(bnc);
1015        }
1016
1017        if (bundleNativeCodes.size() == 0)
1018            return noMatches(optional);
1019        // find the highest ranking one with priority on the osversion then the language
1020
Iterator iter = bundleNativeCodes.iterator();
1021        BundleNativeCode highestRanking = (BundleNativeCode) iter.next();
1022        while (iter.hasNext()) {
1023            BundleNativeCode bnc = (BundleNativeCode) iter.next();
1024            if (isBncGreaterThan(bnc, highestRanking, osversion, language))
1025                highestRanking = bnc;
1026        }
1027        return highestRanking.getPaths();
1028    }
1029
1030    private boolean isBncGreaterThan(BundleNativeCode candidate, BundleNativeCode highestRanking, Version version, String JavaDoc language) {
1031        Version currentHigh = highestRanking.matchOSVersion(version);
1032        Version candidateHigh = candidate.matchOSVersion(version);
1033        if (currentHigh.compareTo(candidateHigh) < 0)
1034            return true;
1035        if (highestRanking.matchLanguage(language) < candidate.matchLanguage(language))
1036            return true;
1037        return false;
1038    }
1039
1040    /**
1041     * Retrieve the bundle that has the given unique identifier.
1042     *
1043     * @param id
1044     * The identifier of the bundle to retrieve.
1045     * @return A {@link AbstractBundle}object, or <code>null</code> if the
1046     * identifier doesn't match any installed bundle.
1047     */

1048    // changed visibility to gain access through the adaptor
1049
public AbstractBundle getBundle(long id) {
1050        synchronized (bundles) {
1051            return bundles.getBundle(id);
1052        }
1053    }
1054
1055    /**
1056     * Retrieve the bundle that has the given symbolic name and version.
1057     *
1058     * @param symbolicName
1059     * The symbolic name of the bundle to retrieve
1060     * @param version The version of the bundle to retrieve
1061     * @return A {@link AbstractBundle}object, or <code>null</code> if the
1062     * identifier doesn't match any installed bundle.
1063     */

1064    public AbstractBundle getBundleBySymbolicName(String JavaDoc symbolicName, Version version) {
1065        synchronized (bundles) {
1066            return bundles.getBundle(symbolicName, version);
1067        }
1068    }
1069
1070    /**
1071     * Retrieve the BundleRepository of all installed bundles. The list is
1072     * valid at the time of the call to getBundles, but the framework is a very
1073     * dynamic environment and bundles can be installed or uninstalled at
1074     * anytime.
1075     *
1076     * @return The BundleRepository.
1077     */

1078    protected BundleRepository getBundles() {
1079        return (bundles);
1080    }
1081
1082    /**
1083     * Retrieve a list of all installed bundles. The list is valid at the time
1084     * of the call to getBundleAlls, but the framework is a very dynamic
1085     * environment and bundles can be installed or uninstalled at anytime.
1086     *
1087     * @return An Array of {@link AbstractBundle}objects, one object per installed
1088     * bundle.
1089     */

1090    protected AbstractBundle[] getAllBundles() {
1091        synchronized (bundles) {
1092            List allBundles = bundles.getBundles();
1093            int size = allBundles.size();
1094            if (size == 0) {
1095                return (null);
1096            }
1097            AbstractBundle[] bundlelist = new AbstractBundle[size];
1098            allBundles.toArray(bundlelist);
1099            return (bundlelist);
1100        }
1101    }
1102
1103    /**
1104     * Resume a bundle.
1105     *
1106     * @param bundle
1107     * Bundle to resume.
1108     */

1109    protected void resumeBundle(AbstractBundle bundle) {
1110        if (bundle.isActive()) {
1111            // if bundle is active.
1112
return;
1113        }
1114        try {
1115            if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
1116                Debug.println("Trying to resume bundle " + bundle); //$NON-NLS-1$
1117
}
1118            bundle.resume();
1119        } catch (BundleException be) {
1120            if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
1121                Debug.println("Bundle resume exception: " + be.getMessage()); //$NON-NLS-1$
1122
Debug.printStackTrace(be.getNestedException() == null ? be : be.getNestedException());
1123            }
1124            publishFrameworkEvent(FrameworkEvent.ERROR, bundle, be);
1125        }
1126    }
1127
1128    /**
1129     * Suspend a bundle.
1130     *
1131     * @param bundle
1132     * Bundle to suspend.
1133     * @param lock
1134     * true if state change lock should be held when returning from
1135     * this method.
1136     * @return true if bundle was active and is now suspended.
1137     */

1138    protected boolean suspendBundle(AbstractBundle bundle, boolean lock) {
1139        boolean changed = false;
1140        if (!bundle.isActive() || bundle.isFragment()) {
1141            // if bundle is not active or is a fragment then do nothing.
1142
return changed;
1143        }
1144        try {
1145            if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
1146                Debug.println("Trying to suspend bundle " + bundle); //$NON-NLS-1$
1147
}
1148            bundle.suspend(lock);
1149        } catch (BundleException be) {
1150            if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
1151                Debug.println("Bundle suspend exception: " + be.getMessage()); //$NON-NLS-1$
1152
Debug.printStackTrace(be.getNestedException() == null ? be : be.getNestedException());
1153            }
1154            publishFrameworkEvent(FrameworkEvent.ERROR, bundle, be);
1155        }
1156        if (!bundle.isActive()) {
1157            changed = true;
1158        }
1159        return (changed);
1160    }
1161
1162    /**
1163     * Locate an installed bundle with a given identity.
1164     *
1165     * @param location
1166     * string for the bundle
1167     * @return Bundle object for bundle with the specified location or null if
1168     * no bundle is installed with the specified location.
1169     */

1170    protected AbstractBundle getBundleByLocation(String JavaDoc location) {
1171        synchronized (bundles) {
1172            // this is not optimized; do not think it will get called
1173
// that much.
1174
final String JavaDoc finalLocation = location;
1175
1176            //Bundle.getLocation requires AdminPermission (metadata)
1177
return (AbstractBundle) AccessController.doPrivileged(new PrivilegedAction() {
1178                public Object JavaDoc run() {
1179                    List allBundles = bundles.getBundles();
1180                    int size = allBundles.size();
1181                    for (int i = 0; i < size; i++) {
1182                        AbstractBundle bundle = (AbstractBundle) allBundles.get(i);
1183                        if (finalLocation.equals(bundle.getLocation())) {
1184                            return (bundle);
1185                        }
1186                    }
1187                    return (null);
1188                }
1189            });
1190        }
1191    }
1192
1193    /**
1194     * Locate an installed bundle with a given symbolic name
1195     *
1196     * @param symbolicName
1197     * The symbolic name for the bundle
1198     * @return Bundle object for bundle with the specified Unique or null if no
1199     * bundle is installed with the specified location.
1200     */

1201    protected AbstractBundle[] getBundleBySymbolicName(String JavaDoc symbolicName) {
1202        synchronized (bundles) {
1203            return bundles.getBundles(symbolicName);
1204        }
1205    }
1206
1207    /**
1208     * Returns a list of <tt>ServiceReference</tt> objects. This method
1209     * returns a list of <tt>ServiceReference</tt> objects for services which
1210     * implement and were registered under the specified class and match the
1211     * specified filter criteria.
1212     *
1213     * <p>
1214     * The list is valid at the time of the call to this method, however as the
1215     * Framework is a very dynamic environment, services can be modified or
1216     * unregistered at anytime.
1217     *
1218     * <p>
1219     * <tt>filter</tt> is used to select the registered service whose
1220     * properties objects contain keys and values which satisfy the filter. See
1221     * {@link FilterImpl}for a description of the filter string syntax.
1222     *
1223     * <p>
1224     * If <tt>filter</tt> is <tt>null</tt>, all registered services are
1225     * considered to match the filter.
1226     * <p>
1227     * If <tt>filter</tt> cannot be parsed, an {@link InvalidSyntaxException}
1228     * will be thrown with a human readable message where the filter became
1229     * unparsable.
1230     *
1231     * <p>
1232     * The following steps are required to select a service:
1233     * <ol>
1234     * <li>If the Java Runtime Environment supports permissions, the caller is
1235     * checked for the <tt>ServicePermission</tt> to get the service with the
1236     * specified class. If the caller does not have the correct permission,
1237     * <tt>null</tt> is returned.
1238     * <li>If the filter string is not <tt>null</tt>, the filter string is
1239     * parsed and the set of registered services which satisfy the filter is
1240     * produced. If the filter string is <tt>null</tt>, then all registered
1241     * services are considered to satisfy the filter.
1242     * <li>If <code>clazz</code> is not <tt>null</tt>, the set is further
1243     * reduced to those services which are an <tt>instanceof</tt> and were
1244     * registered under the specified class. The complete list of classes of
1245     * which a service is an instance and which were specified when the service
1246     * was registered is available from the service's
1247     * {@link Constants#OBJECTCLASS}property.
1248     * <li>An array of <tt>ServiceReference</tt> to the selected services is
1249     * returned.
1250     * </ol>
1251     *
1252     * @param clazz
1253     * The class name with which the service was registered, or <tt>null</tt>
1254     * for all services.
1255     * @param filterstring
1256     * The filter criteria.
1257     * @return An array of <tt>ServiceReference</tt> objects, or <tt>null</tt>
1258     * if no services are registered which satisfy the search.
1259     * @exception InvalidSyntaxException
1260     * If <tt>filter</tt> contains an invalid filter string
1261     * which cannot be parsed.
1262     */

1263    protected ServiceReference[] getServiceReferences(String JavaDoc clazz, String JavaDoc filterstring, BundleContextImpl context, boolean allservices) throws InvalidSyntaxException {
1264        FilterImpl filter = (filterstring == null) ? null : new FilterImpl(filterstring);
1265        ServiceReference[] services = null;
1266        if (clazz != null) {
1267            try /* test for permission to get clazz */{
1268                checkGetServicePermission(clazz);
1269            } catch (SecurityException JavaDoc se) {
1270                return (null);
1271            }
1272        }
1273        synchronized (serviceRegistry) {
1274            services = serviceRegistry.lookupServiceReferences(clazz, filter);
1275            if (services == null) {
1276                return null;
1277            }
1278            int removed = 0;
1279            for (int i = services.length - 1; i >= 0; i--) {
1280                ServiceReferenceImpl ref = (ServiceReferenceImpl) services[i];
1281                String JavaDoc[] classes = ref.getClasses();
1282                if (allservices || context.isAssignableTo((ServiceReferenceImpl) services[i])) {
1283                    if (clazz == null)
1284                        try { /* test for permission to the classes */
1285                            checkGetServicePermission(classes);
1286                        } catch (SecurityException JavaDoc se) {
1287                            services[i] = null;
1288                            removed++;
1289                        }
1290                } else {
1291                    services[i] = null;
1292                    removed++;
1293                }
1294            }
1295            if (removed > 0) {
1296                ServiceReference[] temp = services;
1297                services = new ServiceReference[temp.length - removed];
1298                for (int i = temp.length - 1; i >= 0; i--) {
1299                    if (temp[i] == null)
1300                        removed--;
1301                    else
1302                        services[i - removed] = temp[i];
1303                }
1304            }
1305
1306        }
1307        return services == null || services.length == 0 ? null : services;
1308    }
1309
1310    /**
1311     * Method to return the next available service id. This method should be
1312     * called while holding the registrations lock.
1313     *
1314     * @return next service id.
1315     */

1316    protected long getNextServiceId() {
1317        long id = serviceid;
1318        serviceid++;
1319        return (id);
1320    }
1321
1322    /**
1323     * Creates a <code>File</code> object for a file in the persistent
1324     * storage area provided for the bundle by the framework. If the adaptor
1325     * does not have file system support, this method will return <code>null</code>.
1326     *
1327     * <p>
1328     * A <code>File</code> object for the base directory of the persistent
1329     * storage area provided for the context bundle by the framework can be
1330     * obtained by calling this method with the empty string ("") as the
1331     * parameter.
1332     */

1333    protected File getDataFile(final AbstractBundle bundle, final String JavaDoc filename) {
1334        return (File) AccessController.doPrivileged(new GetDataFileAction(bundle, filename));
1335            }
1336
1337    /**
1338     * Check for specific AdminPermission (RFC 73)
1339     */

1340    protected void checkAdminPermission(Bundle bundle, String JavaDoc action) {
1341        SecurityManager JavaDoc sm = System.getSecurityManager();
1342        if (sm != null)
1343            sm.checkPermission(getAdminPermission(bundle, action));
1344    }
1345
1346    // gets AdminPermission objects from a cache to reduce the number of AdminPermission
1347
// objects that are created.
1348
private AdminPermission getAdminPermission(Bundle bundle, String JavaDoc action) {
1349        synchronized(adminPermissions) {
1350            Long JavaDoc ID = new Long JavaDoc(bundle.getBundleId());
1351            HashMap bundlePermissions = (HashMap) adminPermissions.get(ID);
1352            if (bundlePermissions == null) {
1353                bundlePermissions = new HashMap();
1354                adminPermissions.put(ID, bundlePermissions);
1355            }
1356            AdminPermission result = (AdminPermission) bundlePermissions.get(action);
1357            if (result == null) {
1358                result = new AdminPermission(bundle, action);
1359                bundlePermissions.put(action, result);
1360            }
1361            return result;
1362        }
1363    }
1364
1365    /**
1366     * Check for permission to register a service.
1367     *
1368     * The caller must have permission for ALL names.
1369     */

1370    protected void checkRegisterServicePermission(String JavaDoc[] names) {
1371        SecurityManager JavaDoc sm = System.getSecurityManager();
1372        if (sm != null) {
1373            int len = names.length;
1374            for (int i = 0; i < len; i++) {
1375                sm.checkPermission(new ServicePermission(names[i], ServicePermission.REGISTER));
1376            }
1377        }
1378    }
1379
1380    /**
1381     * Check for permission to get a service.
1382     *
1383     * The caller must have permission for at least ONE name.
1384     */

1385    protected void checkGetServicePermission(String JavaDoc[] names) {
1386        SecurityManager JavaDoc sm = System.getSecurityManager();
1387        if (sm != null) {
1388            SecurityException JavaDoc se = null;
1389            int len = names.length;
1390            for (int i = 0; i < len; i++) {
1391                try {
1392                    sm.checkPermission(new ServicePermission(names[i], ServicePermission.GET));
1393                    return;
1394                } catch (SecurityException JavaDoc e) {
1395                    se = e;
1396                }
1397            }
1398            throw se;
1399        }
1400    }
1401
1402    /**
1403     * Check for permission to get a service.
1404     */

1405    protected void checkGetServicePermission(String JavaDoc name) {
1406        SecurityManager JavaDoc sm = System.getSecurityManager();
1407        if (sm != null) {
1408            sm.checkPermission(new ServicePermission(name, ServicePermission.GET));
1409        }
1410    }
1411
1412    /**
1413     * This is necessary for running from a JXE, otherwise the SecurityManager
1414     * is set much later than we would like!
1415     */

1416    protected void installSecurityManager() {
1417        String JavaDoc securityManager = System.getProperty("java.security.manager"); //$NON-NLS-1$
1418
if (securityManager != null) {
1419            SecurityManager JavaDoc sm = System.getSecurityManager();
1420            if (sm == null) {
1421                if (securityManager.length() < 1) {
1422                    securityManager = "java.lang.SecurityManager"; //$NON-NLS-1$
1423
}
1424                try {
1425                    Class JavaDoc clazz = Class.forName(securityManager);
1426                    sm = (SecurityManager JavaDoc) clazz.newInstance();
1427                    if (Debug.DEBUG && Debug.DEBUG_SECURITY) {
1428                        Debug.println("Setting SecurityManager to: " + sm); //$NON-NLS-1$
1429
}
1430                    System.setSecurityManager(sm);
1431                    return;
1432                } catch (ClassNotFoundException JavaDoc e) {
1433                    // do nothing
1434
} catch (ClassCastException JavaDoc e) {
1435                    // do nothing
1436
} catch (InstantiationException JavaDoc e) {
1437                    // do nothing
1438
} catch (IllegalAccessException JavaDoc e) {
1439                    // do nothing
1440
}
1441                throw new NoClassDefFoundError JavaDoc(securityManager);
1442            }
1443        }
1444    }
1445
1446    /**
1447     * Deliver a FrameworkEvent.
1448     *
1449     * @param type
1450     * FrameworkEvent type.
1451     * @param bundle
1452     * Affected bundle or null for system bundle.
1453     * @param throwable
1454     * Related exception or null.
1455     */

1456    public void publishFrameworkEvent(int type, org.osgi.framework.Bundle bundle, Throwable JavaDoc throwable) {
1457        if (frameworkEvent != null) {
1458            if (bundle == null)
1459                bundle = systemBundle;
1460            final FrameworkEvent event = new FrameworkEvent(type, bundle, throwable);
1461            if (System.getSecurityManager() == null) {
1462                publishFrameworkEventPrivileged(event);
1463            } else {
1464                AccessController.doPrivileged(new PrivilegedAction() {
1465                    public Object JavaDoc run() {
1466                        publishFrameworkEventPrivileged(event);
1467                        return null;
1468                    }
1469                });
1470            }
1471        }
1472    }
1473
1474    public void publishFrameworkEventPrivileged(FrameworkEvent event) {
1475        /* if the event is an error then it should be logged */
1476        if (event.getType() == FrameworkEvent.ERROR) {
1477            FrameworkLog frameworkLog = adaptor.getFrameworkLog();
1478            if (frameworkLog != null)
1479                frameworkLog.log(event);
1480        }
1481        /* queue to hold set of listeners */
1482        ListenerQueue listeners = new ListenerQueue(eventManager);
1483        /* queue to hold set of BundleContexts w/ listeners */
1484        ListenerQueue contexts = new ListenerQueue(eventManager);
1485        /* synchronize while building the listener list */
1486        synchronized (frameworkEvent) {
1487            /* add set of BundleContexts w/ listeners to queue */
1488            contexts.queueListeners(frameworkEvent, this);
1489            /* synchronously dispatch to populate listeners queue */
1490            contexts.dispatchEventSynchronous(FRAMEWORKEVENT, listeners);
1491        }
1492        /* dispatch event to set of listeners */
1493        listeners.dispatchEventAsynchronous(FRAMEWORKEVENT, event);
1494    }
1495
1496    /**
1497     * Deliver a BundleEvent to SynchronousBundleListeners (synchronous). and
1498     * BundleListeners (asynchronous).
1499     *
1500     * @param type
1501     * BundleEvent type.
1502     * @param bundle
1503     * Affected bundle or null.
1504     */

1505    public void publishBundleEvent(int type, org.osgi.framework.Bundle bundle) {
1506        if ((bundleEventSync != null) || (bundleEvent != null)) {
1507            final BundleEvent event = new BundleEvent(type, bundle);
1508            if (System.getSecurityManager() == null) {
1509                publishBundleEventPrivileged(event);
1510            } else {
1511                AccessController.doPrivileged(new PrivilegedAction() {
1512                    public Object JavaDoc run() {
1513                        publishBundleEventPrivileged(event);
1514                        return null;
1515                    }
1516                });
1517            }
1518        }
1519    }
1520
1521    public void publishBundleEventPrivileged(BundleEvent event) {
1522        /*
1523         * We must collect the snapshots of the sync and async listeners
1524         * BEFORE we dispatch the event.
1525         */

1526        /* Collect snapshot of SynchronousBundleListeners */
1527        ListenerQueue listenersSync = null;
1528        if (bundleEventSync != null) {
1529            /* queue to hold set of listeners */
1530            listenersSync = new ListenerQueue(eventManager);
1531            /* queue to hold set of BundleContexts w/ listeners */
1532            ListenerQueue contexts = new ListenerQueue(eventManager);
1533            /* synchronize while building the listener list */
1534            synchronized (bundleEventSync) {
1535                /* add set of BundleContexts w/ listeners to queue */
1536                contexts.queueListeners(bundleEventSync, this);
1537                /* synchronously dispatch to populate listeners queue */
1538                contexts.dispatchEventSynchronous(BUNDLEEVENTSYNC, listenersSync);
1539            }
1540        }
1541        /* Collect snapshot of BundleListeners; only if the event is NOT STARTING or STOPPING or LAZY_ACTIVATION */
1542        ListenerQueue listenersAsync = null;
1543        if (bundleEvent != null && (event.getType() & (BundleEvent.STARTING | BundleEvent.STOPPING | BundleEvent.LAZY_ACTIVATION)) == 0) {
1544            /* queue to hold set of listeners */
1545            listenersAsync = new ListenerQueue(eventManager);
1546            /* queue to hold set of BundleContexts w/ listeners */
1547            ListenerQueue contexts = new ListenerQueue(eventManager);
1548            /* synchronize while building the listener list */
1549            synchronized (bundleEvent) {
1550                /* add set of BundleContexts w/ listeners to queue */
1551                contexts.queueListeners(bundleEvent, this);
1552                /* synchronously dispatch to populate listeners queue */
1553                contexts.dispatchEventSynchronous(BUNDLEEVENT, listenersAsync);
1554            }
1555        }
1556        /* Dispatch BundleEvent to SynchronousBundleListeners */
1557        if (listenersSync != null) {
1558            listenersSync.dispatchEventSynchronous(BUNDLEEVENTSYNC, event);
1559        }
1560        /* Dispatch BundleEvent to BundleListeners */
1561        if (listenersAsync != null) {
1562            listenersAsync.dispatchEventAsynchronous(BUNDLEEVENT, event);
1563        }
1564    }
1565
1566    /**
1567     * Deliver a ServiceEvent.
1568     *
1569     * @param type
1570     * ServiceEvent type.
1571     * @param reference
1572     * Affected service reference.
1573     */

1574    public void publishServiceEvent(int type, org.osgi.framework.ServiceReference reference) {
1575        if (serviceEvent != null) {
1576            final ServiceEvent event = new ServiceEvent(type, reference);
1577            if (System.getSecurityManager() == null) {
1578                publishServiceEventPrivileged(event);
1579            } else {
1580                AccessController.doPrivileged(new PrivilegedAction() {
1581                    public Object JavaDoc run() {
1582                        publishServiceEventPrivileged(event);
1583                        return null;
1584                    }
1585                });
1586            }
1587        }
1588    }
1589
1590    public void publishServiceEventPrivileged(ServiceEvent event) {
1591        /* queue to hold set of listeners */
1592        ListenerQueue listeners = new ListenerQueue(eventManager);
1593        /* queue to hold set of BundleContexts w/ listeners */
1594        ListenerQueue contexts = new ListenerQueue(eventManager);
1595        /* synchronize while building the listener list */
1596        synchronized (serviceEvent) {
1597            /* add set of BundleContexts w/ listeners to queue */
1598            contexts.queueListeners(serviceEvent, this);
1599            /* synchronously dispatch to populate listeners queue */
1600            contexts.dispatchEventSynchronous(SERVICEEVENT, listeners);
1601        }
1602        /* dispatch event to set of listeners */
1603        listeners.dispatchEventSynchronous(SERVICEEVENT, event);
1604    }
1605
1606    /**
1607     * Top level event dispatcher for the framework.
1608     *
1609     * @param l
1610     * BundleContext for receiving bundle
1611     * @param lo
1612     * BundleContext for receiving bundle
1613     * @param action
1614     * Event class type
1615     * @param object
1616     * ListenerQueue to populate
1617     */

1618    public void dispatchEvent(Object JavaDoc l, Object JavaDoc lo, int action, Object JavaDoc object) {
1619        try {
1620            BundleContextImpl context = (BundleContextImpl) l;
1621            if (context.isValid()) /* if context still valid */{
1622                ListenerQueue queue = (ListenerQueue) object;
1623                switch (action) {
1624                    case BUNDLEEVENT : {
1625                        queue.queueListeners(context.bundleEvent, context);
1626                        break;
1627                    }
1628                    case BUNDLEEVENTSYNC : {
1629                        queue.queueListeners(context.bundleEventSync, context);
1630                        break;
1631                    }
1632                    case SERVICEEVENT : {
1633                        queue.queueListeners(context.serviceEvent, context);
1634                        break;
1635                    }
1636                    case FRAMEWORKEVENT : {
1637                        queue.queueListeners(context.frameworkEvent, context);
1638                        break;
1639                    }
1640                }
1641            }
1642        } catch (Throwable JavaDoc t) {
1643            if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
1644                Debug.println("Exception in Top level event dispatcher: " + t.getMessage()); //$NON-NLS-1$
1645
Debug.printStackTrace(t);
1646            }
1647            // allow the adaptor to handle this unexpected error
1648
adaptor.handleRuntimeError(t);
1649            publisherror: {
1650                if (action == FRAMEWORKEVENT) {
1651                    FrameworkEvent event = (FrameworkEvent) object;
1652                    if (event.getType() == FrameworkEvent.ERROR) {
1653                        break publisherror; /* avoid infinite loop */
1654                    }
1655                }
1656                BundleContextImpl context = (BundleContextImpl) l;
1657                publishFrameworkEvent(FrameworkEvent.ERROR, context.bundle, t);
1658            }
1659        }
1660    }
1661
1662    private String JavaDoc[] noMatches(boolean optional) throws BundleException {
1663        if (optional) {
1664            return null;
1665        }
1666        throw new BundleException(Msg.BUNDLE_NATIVECODE_MATCH_EXCEPTION);
1667    }
1668
1669    private void initializeContextFinder() {
1670        Thread JavaDoc current = Thread.currentThread();
1671        Throwable JavaDoc error = null;
1672        try {
1673            ClassLoader JavaDoc parent = null;
1674            // check property for specified parent
1675
String JavaDoc type = FrameworkProperties.getProperty(PROP_CONTEXTCLASSLOADER_PARENT);
1676            if (CONTEXTCLASSLOADER_PARENT_APP.equals(type))
1677                parent = ClassLoader.getSystemClassLoader();
1678            else if (CONTEXTCLASSLOADER_PARENT_BOOT.equals(type))
1679                parent = null;
1680            else if (CONTEXTCLASSLOADER_PARENT_FWK.equals(type))
1681                parent = Framework.class.getClassLoader();
1682            else if (CONTEXTCLASSLOADER_PARENT_EXT.equals(type)) {
1683                ClassLoader JavaDoc appCL = ClassLoader.getSystemClassLoader();
1684                if (appCL != null)
1685                    parent = appCL.getParent();
1686            } else { // default is ccl (null or any other value will use ccl)
1687
Method getContextClassLoader = Thread JavaDoc.class.getMethod("getContextClassLoader", null); //$NON-NLS-1$
1688
parent = (ClassLoader JavaDoc) getContextClassLoader.invoke(current, null);
1689            }
1690            Method setContextClassLoader = Thread JavaDoc.class.getMethod("setContextClassLoader", new Class JavaDoc[] {ClassLoader JavaDoc.class}); //$NON-NLS-1$
1691
Object JavaDoc[] params = new Object JavaDoc[] {new ContextFinder(parent)};
1692            setContextClassLoader.invoke(current, params);
1693            return;
1694        } catch (SecurityException JavaDoc e) {
1695            // log the error
1696
error = e;
1697        } catch (NoSuchMethodException JavaDoc e) {
1698            // Ignore; must be running on a class library that does not support context class loaders.
1699
return; // we really do not want to log this
1700
} catch (IllegalArgumentException JavaDoc e) {
1701            // log the error
1702
error = e;
1703        } catch (IllegalAccessException JavaDoc e) {
1704            // log the error
1705
error = e;
1706        } catch (InvocationTargetException e) {
1707            // log the error; get the target exception
1708
error = e.getTargetException();
1709        }
1710        FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.INFO, 0, NLS.bind(Msg.CANNOT_SET_CONTEXTFINDER, null), 0, error, null);
1711        adaptor.getFrameworkLog().log(entry);
1712    }
1713
1714    private static Field getStaticField(Class JavaDoc clazz, Class JavaDoc type) {
1715        Field[] fields = clazz.getDeclaredFields();
1716        for (int i = 0; i < fields.length; i++)
1717            if (Modifier.isStatic(fields[i].getModifiers()) && fields[i].getType().equals(type)) {
1718                fields[i].setAccessible(true);
1719                return fields[i];
1720            }
1721        return null;
1722    }
1723
1724    private void installContentHandlerFactory(BundleContext context, FrameworkAdaptor frameworkAdaptor) {
1725        ContentHandlerFactory chf = new ContentHandlerFactory(context, frameworkAdaptor);
1726        try {
1727            // first try the standard way
1728
URLConnection.setContentHandlerFactory(chf);
1729        } catch (Error JavaDoc err) {
1730            // ok we failed now use more drastic means to set the factory
1731
try {
1732                forceContentHandlerFactory(chf);
1733            } catch (Exception JavaDoc ex) {
1734                // this is unexpected, log the exception and throw the original error
1735
adaptor.getFrameworkLog().log(new FrameworkEvent(FrameworkEvent.ERROR, context.getBundle(), ex));
1736                throw err;
1737            }
1738        }
1739        contentHandlerFactory = chf;
1740    }
1741
1742    private static void forceContentHandlerFactory(ContentHandlerFactory chf) throws Exception JavaDoc{
1743        Field factoryField = getStaticField(URLConnection.class, java.net.ContentHandlerFactory JavaDoc.class);
1744        if (factoryField == null)
1745            throw new Exception JavaDoc("Could not find ContentHandlerFactory field"); //$NON-NLS-1$
1746
synchronized(URLConnection.class) {
1747            java.net.ContentHandlerFactory JavaDoc factory = (java.net.ContentHandlerFactory JavaDoc) factoryField.get(null);
1748            // doing a null check here just in case, but it would be really strange if it was null,
1749
// because we failed to set the factory normally!!
1750

1751            if (factory != null) {
1752                try {
1753                    factory.getClass().getMethod("isMultiplexing", null); //$NON-NLS-1$
1754
Method register = factory.getClass().getMethod("register", new Class JavaDoc[] {Object JavaDoc.class}); //$NON-NLS-1$
1755
register.invoke(factory, new Object JavaDoc[] {chf});
1756                } catch (NoSuchMethodException JavaDoc e) {
1757                    // current factory does not support multiplexing, ok we'll wrap it
1758
chf.setParentFactory(factory);
1759                    factory = chf;
1760                }
1761            }
1762            // null out the field so that we can successfully call setContentHandlerFactory
1763
factoryField.set(null, null);
1764            // always attempt to clear the handlers cache
1765
// This allows an optomization for the single framework use-case
1766
resetContentHandlers();
1767            URLConnection.setContentHandlerFactory(factory);
1768        }
1769    }
1770
1771    private void uninstallContentHandlerFactory() {
1772        try {
1773            Field factoryField = getStaticField(URLConnection.class, java.net.ContentHandlerFactory JavaDoc.class);
1774            if (factoryField == null)
1775                return; // oh well, we tried.
1776
synchronized(URLConnection.class) {
1777                java.net.ContentHandlerFactory JavaDoc factory = (java.net.ContentHandlerFactory JavaDoc) factoryField.get(null);
1778                
1779                if (factory == contentHandlerFactory) {
1780                    factory = (java.net.ContentHandlerFactory JavaDoc) contentHandlerFactory.designateSuccessor();
1781                } else {
1782                    Method unregister = factory.getClass().getMethod("unregister", new Class JavaDoc[] {Object JavaDoc.class}); //$NON-NLS-1$
1783
unregister.invoke(factory, new Object JavaDoc[] {contentHandlerFactory});
1784                }
1785                // null out the field so that we can successfully call setContentHandlerFactory
1786
factoryField.set(null, null);
1787                // always attempt to clear the handlers cache
1788
// This allows an optomization for the single framework use-case
1789
// Note that the call to setContentHandlerFactory below may clear this cache
1790
// but we want to be sure to clear it here just incase the parent is null.
1791
// In this case the call below would not occur.
1792
// Also it appears most java libraries actually do not clear the cache
1793
// when setContentHandlerFactory is called, go figure!!
1794
resetContentHandlers();
1795                if (factory != null)
1796                    URLConnection.setContentHandlerFactory(factory);
1797            }
1798        } catch (Exception JavaDoc e) {
1799            // ignore and continue closing the framework
1800
}
1801    }
1802
1803    private static void resetContentHandlers() throws IllegalAccessException JavaDoc {
1804        Field handlersField = getStaticField(URLConnection.class, Hashtable.class);
1805        if (handlersField != null) {
1806            Hashtable handlers = (Hashtable) handlersField.get(null);
1807            if (handlers != null)
1808                handlers.clear();
1809        }
1810    }
1811
1812    private void installURLStreamHandlerFactory(BundleContext context, FrameworkAdaptor frameworkAdaptor) {
1813        StreamHandlerFactory shf = new StreamHandlerFactory(context, frameworkAdaptor);
1814        try {
1815            // first try the standard way
1816
URL.setURLStreamHandlerFactory(shf);
1817        } catch (Error JavaDoc err) {
1818            try {
1819                // ok we failed now use more drastic means to set the factory
1820
forceURLStreamHandlerFactory(shf);
1821            } catch (Exception JavaDoc ex) {
1822                adaptor.getFrameworkLog().log(new FrameworkEvent(FrameworkEvent.ERROR, context.getBundle(), ex));
1823                throw err;
1824            }
1825        }
1826        streamHandlerFactory = shf;
1827    }
1828
1829    private static void forceURLStreamHandlerFactory(StreamHandlerFactory shf) throws Exception JavaDoc{
1830        Field factoryField = getStaticField(URL.class, URLStreamHandlerFactory.class);
1831        if (factoryField == null)
1832            throw new Exception JavaDoc("Could not find URLStreamHandlerFactory field"); //$NON-NLS-1$
1833
// look for a lock to synchronize on
1834
Object JavaDoc lock = getURLStreamHandlerFactoryLock();
1835        synchronized(lock) {
1836            URLStreamHandlerFactory factory = (URLStreamHandlerFactory) factoryField.get(null);
1837            // doing a null check here just in case, but it would be really strange if it was null,
1838
// because we failed to set the factory normally!!
1839
if (factory != null) {
1840                try {
1841                    factory.getClass().getMethod("isMultiplexing", null); //$NON-NLS-1$
1842
Method register = factory.getClass().getMethod("register", new Class JavaDoc[] {Object JavaDoc.class}); //$NON-NLS-1$
1843
register.invoke(factory, new Object JavaDoc[] {shf});
1844                } catch (NoSuchMethodException JavaDoc e) {
1845                    // current factory does not support multiplexing, ok we'll wrap it
1846
shf.setParentFactory(factory);
1847                    factory = shf;
1848                }
1849            }
1850            factoryField.set(null, null);
1851            // always attempt to clear the handlers cache
1852
// This allows an optomization for the single framework use-case
1853
resetURLStreamHandlers();
1854            URL.setURLStreamHandlerFactory(factory);
1855        }
1856    }
1857
1858    private void uninstallURLStreamHandlerFactory() {
1859        try {
1860            Field factoryField = getStaticField(URL.class, URLStreamHandlerFactory.class);
1861            if (factoryField == null)
1862                return; // oh well, we tried
1863
Object JavaDoc lock = getURLStreamHandlerFactoryLock();
1864            synchronized (lock) {
1865                URLStreamHandlerFactory factory = (URLStreamHandlerFactory) factoryField.get(null);
1866                if (factory == streamHandlerFactory) {
1867                    factory = (URLStreamHandlerFactory) streamHandlerFactory.designateSuccessor();
1868                } else {
1869                    Method unregister = factory.getClass().getMethod("unregister", new Class JavaDoc[] {Object JavaDoc.class}); //$NON-NLS-1$
1870
unregister.invoke(factory, new Object JavaDoc[] {streamHandlerFactory});
1871                }
1872                factoryField.set(null, null);
1873                // always attempt to clear the handlers cache
1874
// This allows an optomization for the single framework use-case
1875
// Note that the call to setURLStreamHandlerFactory below may clear this cache
1876
// but we want to be sure to clear it here just in case the parent is null.
1877
// In this case the call below would not occur.
1878
resetURLStreamHandlers();
1879                if (factory != null)
1880                    URL.setURLStreamHandlerFactory(factory);
1881            }
1882        } catch (Exception JavaDoc e) {
1883            // ignore and continue closing the framework
1884
}
1885    }
1886
1887    private static Object JavaDoc getURLStreamHandlerFactoryLock() throws IllegalAccessException JavaDoc {
1888        Object JavaDoc lock;
1889        try {
1890            Field streamHandlerLockField = URL.class.getDeclaredField("streamHandlerLock"); //$NON-NLS-1$
1891
streamHandlerLockField.setAccessible(true);
1892            lock = streamHandlerLockField.get(null);
1893        } catch (NoSuchFieldException JavaDoc noField) {
1894            // could not find the lock, lets sync on the class object
1895
lock = URL.class;
1896        }
1897        return lock;
1898    }
1899    
1900    private static void resetURLStreamHandlers() throws IllegalAccessException JavaDoc {
1901        Field handlersField = getStaticField(URL.class, Hashtable.class);
1902        if (handlersField != null) {
1903            Hashtable handlers = (Hashtable) handlersField.get(null);
1904            if (handlers != null)
1905                handlers.clear();
1906        }
1907    }
1908}
1909
Popular Tags