KickJava   Java API By Example, From Geeks To Geeks.

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


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
12 package org.eclipse.osgi.framework.internal.core;
13
14 import java.io.IOException JavaDoc;
15 import java.net.URL JavaDoc;
16 import java.util.Enumeration JavaDoc;
17 import org.eclipse.osgi.framework.adaptor.*;
18 import org.eclipse.osgi.framework.debug.Debug;
19 import org.eclipse.osgi.framework.log.FrameworkLogEntry;
20 import org.eclipse.osgi.service.resolver.BundleDescription;
21 import org.eclipse.osgi.util.NLS;
22 import org.osgi.framework.*;
23
24 public class BundleHost extends AbstractBundle {
25     /**
26      * The BundleLoader proxy; a lightweight object that acts as a proxy
27      * to the BundleLoader and allows lazy creation of the BundleLoader object
28      */

29     private BundleLoaderProxy proxy;
30
31     /** The BundleContext that represents this Bundle and all of its fragments */
32     protected BundleContextImpl context;
33
34     /** The List of BundleFragments */
35     protected BundleFragment[] fragments;
36
37     public BundleHost(BundleData bundledata, Framework framework) throws BundleException {
38         super(bundledata, framework);
39         context = null;
40         fragments = null;
41     }
42
43     /**
44      * Load the bundle.
45      */

46     protected void load() {
47         if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
48             if ((state & (INSTALLED)) == 0) {
49                 Debug.println("Bundle.load called when state != INSTALLED: " + this); //$NON-NLS-1$
50
Debug.printStackTrace(new Exception JavaDoc("Stack trace")); //$NON-NLS-1$
51
}
52             if (proxy != null) {
53                 Debug.println("Bundle.load called when proxy != null: " + this); //$NON-NLS-1$
54
Debug.printStackTrace(new Exception JavaDoc("Stack trace")); //$NON-NLS-1$
55
}
56         }
57
58         if (framework.isActive()) {
59             SecurityManager JavaDoc sm = System.getSecurityManager();
60
61             if (sm != null && framework.permissionAdmin != null) {
62                 domain = framework.permissionAdmin.createProtectionDomain(this);
63             }
64
65         }
66         proxy = null;
67     }
68
69     /**
70      * Reload from a new bundle.
71      * This method must be called while holding the bundles lock.
72      *
73      * @param newBundle Dummy Bundle which contains new data.
74      * @return true if an exported package is "in use". i.e. it has been imported by a bundle
75      */

76     protected boolean reload(AbstractBundle newBundle) {
77         if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
78             if ((state & (INSTALLED | RESOLVED)) == 0) {
79                 Debug.println("Bundle.reload called when state != INSTALLED | RESOLVED: " + this); //$NON-NLS-1$
80
Debug.printStackTrace(new Exception JavaDoc("Stack trace")); //$NON-NLS-1$
81
}
82         }
83
84         boolean exporting = false;
85
86         if (framework.isActive()) {
87             if (state == RESOLVED) {
88                 BundleLoaderProxy curProxy = getLoaderProxy();
89                 exporting = curProxy.inUse();
90                 if (exporting)
91                     // make sure the BundleLoader is created.
92
curProxy.getBundleLoader().createClassLoader();
93                 else
94                     closeBundleLoader(proxy);
95                 state = INSTALLED;
96                 proxy = null;
97                 fragments = null;
98             }
99
100         } else {
101             /* close the outgoing jarfile */
102             try {
103                 this.bundledata.close();
104             } catch (IOException JavaDoc e) {
105                 // Do Nothing
106
}
107         }
108         this.bundledata = newBundle.bundledata;
109         this.bundledata.setBundle(this);
110         // create a new domain for the bundle because its signers/symbolic-name may have changed
111
if (framework.isActive() && System.getSecurityManager() != null && framework.permissionAdmin != null)
112             domain = framework.permissionAdmin.createProtectionDomain(this);
113         return (exporting);
114     }
115
116     /**
117      * Refresh the bundle. This is called by Framework.refreshPackages.
118      * This method must be called while holding the bundles lock.
119      */

120     protected void refresh() {
121         if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
122             if ((state & (UNINSTALLED | INSTALLED | RESOLVED)) == 0) {
123                 Debug.println("Bundle.reload called when state != UNINSTALLED | INSTALLED | RESOLVED: " + this); //$NON-NLS-1$
124
Debug.printStackTrace(new Exception JavaDoc("Stack trace")); //$NON-NLS-1$
125
}
126         }
127         if (state == RESOLVED) {
128             closeBundleLoader(proxy);
129             proxy = null;
130             fragments = null;
131             state = INSTALLED;
132             // Do not publish UNRESOLVED event here. This is done by caller
133
// to resolve if appropriate.
134
}
135         manifestLocalization = null;
136     }
137
138     /**
139      * Unload the bundle.
140      * This method must be called while holding the bundles lock.
141      *
142      * @return true if an exported package is "in use". i.e. it has been imported by a bundle
143      */

144     protected boolean unload() {
145         if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
146             if ((state & (UNINSTALLED | INSTALLED | RESOLVED)) == 0) {
147                 Debug.println("Bundle.unload called when state != UNINSTALLED | INSTALLED | RESOLVED: " + this); //$NON-NLS-1$
148
Debug.printStackTrace(new Exception JavaDoc("Stack trace")); //$NON-NLS-1$
149
}
150         }
151
152         boolean exporting = false;
153
154         if (framework.isActive()) {
155             if (state == RESOLVED) {
156                 BundleLoaderProxy curProxy = getLoaderProxy();
157                 exporting = curProxy.inUse();
158                 if (exporting)
159                     // make sure the BundleLoader is created.
160
curProxy.getBundleLoader().createClassLoader();
161                 else
162                     closeBundleLoader(proxy);
163
164                 state = INSTALLED;
165                 proxy = null;
166                 fragments = null;
167                 domain = null;
168             }
169         }
170         if (!exporting) {
171             try {
172                 this.bundledata.close();
173             } catch (IOException JavaDoc e) { // Do Nothing.
174
}
175         }
176
177         return (exporting);
178     }
179
180     private BundleLoader checkLoader() {
181         checkValid();
182
183         // check to see if the bundle is resolved
184
if (!isResolved()) {
185             if (!framework.packageAdmin.resolveBundles(new Bundle[] {this})) {
186                 return null;
187             }
188         }
189         if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
190             if ((state & (STARTING | ACTIVE | STOPPING | RESOLVED)) == 0) {
191                 Debug.println("Bundle.checkLoader() called when state != STARTING | ACTIVE | STOPPING | RESOLVED: " + this); //$NON-NLS-1$
192
Debug.printStackTrace(new Exception JavaDoc("Stack trace")); //$NON-NLS-1$
193
}
194         }
195
196         BundleLoader loader = getBundleLoader();
197         if (loader == null) {
198             if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
199                 Debug.println("Bundle.checkLoader() called when loader == null: " + this); //$NON-NLS-1$
200
Debug.printStackTrace(new Exception JavaDoc("Stack trace")); //$NON-NLS-1$
201
}
202             return null;
203         }
204         return loader;
205     }
206
207     /**
208      * This method loads a class from the bundle.
209      *
210      * @param name the name of the desired Class.
211      * @param checkPermission indicates whether a permission check should be done.
212      * @return the resulting Class
213      * @exception java.lang.ClassNotFoundException if the class definition was not found.
214      */

215     protected Class JavaDoc loadClass(String JavaDoc name, boolean checkPermission) throws ClassNotFoundException JavaDoc {
216         if (checkPermission) {
217             try {
218                 framework.checkAdminPermission(this, AdminPermission.CLASS);
219             } catch (SecurityException JavaDoc e) {
220                 throw new ClassNotFoundException JavaDoc();
221             }
222         }
223         BundleLoader loader = checkLoader();
224         if (loader == null)
225             throw new ClassNotFoundException JavaDoc(NLS.bind(Msg.BUNDLE_CNFE_NOT_RESOLVED, name, getBundleData().getLocation()));
226         try {
227             return (loader.loadClass(name));
228         } catch (ClassNotFoundException JavaDoc e) {
229             // this is to support backward compatibility in eclipse
230
// we always attempted to start a bundle even if the class was not found
231
if (!(e instanceof StatusException) && (bundledata.getStatus() & Constants.BUNDLE_LAZY_START) != 0 && !testStateChanging(Thread.currentThread()))
232                 try {
233                     // only start the bundle if this is a simple CNFE
234
framework.secureAction.start(this, START_TRANSIENT);
235                 } catch (BundleException be) {
236                     framework.adaptor.getFrameworkLog().log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, be.getMessage(), 0, be, null));
237                 }
238             throw e;
239         }
240     }
241
242     /**
243      * Find the specified resource in this bundle.
244      *
245      * This bundle's class loader is called to search for the named resource.
246      * If this bundle's state is <tt>INSTALLED</tt>, then only this bundle will
247      * be searched for the specified resource. Imported packages cannot be searched
248      * when a bundle has not been resolved.
249      *
250      * @param name The name of the resource.
251      * See <tt>java.lang.ClassLoader.getResource</tt> for a description of
252      * the format of a resource name.
253      * @return a URL to the named resource, or <tt>null</tt> if the resource could
254      * not be found or if the caller does not have
255      * the <tt>AdminPermission</tt>, and the Java Runtime Environment supports permissions.
256      *
257      * @exception java.lang.IllegalStateException If this bundle has been uninstalled.
258      */

259     public URL JavaDoc getResource(String JavaDoc name) {
260         BundleLoader loader = null;
261         try {
262             framework.checkAdminPermission(this, AdminPermission.RESOURCE);
263         } catch (SecurityException JavaDoc ee) {
264             return null;
265         }
266         loader = checkLoader();
267         if (loader == null)
268             return null;
269         return (loader.findResource(name));
270     }
271
272     public Enumeration JavaDoc getResources(String JavaDoc name) throws IOException JavaDoc {
273         BundleLoader loader = null;
274         try {
275             framework.checkAdminPermission(this, AdminPermission.RESOURCE);
276         } catch (SecurityException JavaDoc ee) {
277             return null;
278         }
279         loader = checkLoader();
280         if (loader == null)
281             return null;
282         Enumeration JavaDoc result = loader.getResources(name);
283         if (result != null && result.hasMoreElements())
284             return result;
285         return null;
286     }
287
288     /**
289      * Internal worker to start a bundle.
290      *
291      * @param options the start options
292      */

293     protected void startWorker(int options) throws BundleException {
294         if ((options & START_TRANSIENT) == 0) {
295             setStatus(Constants.BUNDLE_STARTED, true);
296             setStatus(Constants.BUNDLE_ACTIVATION_POLICY, (options & START_ACTIVATION_POLICY) != 0);
297             if (Debug.DEBUG && Debug.MONITOR_ACTIVATION)
298                 new Exception JavaDoc("A persistent start has been called on bundle: " + getBundleData()).printStackTrace();
299         }
300         if (!framework.active || (state & ACTIVE) != 0)
301             return;
302
303         if (state == INSTALLED) {
304             if (!framework.packageAdmin.resolveBundles(new Bundle[] {this}))
305                 throw new BundleException(getResolutionFailureMessage());
306         }
307
308         if (getStartLevel() > framework.startLevelManager.getStartLevel()){
309             if ((options & START_TRANSIENT) != 0) {
310                 // throw exception if this is a transient start
311
String JavaDoc msg = NLS.bind(Msg.BUNDLE_TRANSIENT_START_ERROR, this);
312                 // Use a StatusException to indicate to the lazy starter that this should result in a warning
313
throw new BundleException(msg, new BundleStatusException(msg, StatusException.CODE_WARNING, this));
314             }
315             return;
316         }
317         if ((options & START_ACTIVATION_POLICY) != 0 && (state & STARTING) == 0) {
318             // the bundle must use the activation policy here.
319
if ((bundledata.getStatus() & Constants.BUNDLE_LAZY_START) != 0) {
320                 // now we must publish the LAZY_ACTIVATION event and return
321
state = STARTING;
322                 framework.publishBundleEvent(BundleEvent.LAZY_ACTIVATION, this);
323                 return;
324             }
325         }
326
327         if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
328             Debug.println("Bundle: Active sl = " + framework.startLevelManager.getStartLevel() + "; Bundle " + getBundleId() + " sl = " + getStartLevel()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
329
}
330
331         state = STARTING;
332         framework.publishBundleEvent(BundleEvent.STARTING, this);
333         context = getContext();
334         //STARTUP TIMING Start here
335
long start = 0;
336         if (Debug.DEBUG) {
337             BundleWatcher bundleStats = framework.adaptor.getBundleWatcher();
338             if (bundleStats != null)
339                 bundleStats.watchBundle(this, BundleWatcher.START_ACTIVATION);
340             if (Debug.DEBUG_BUNDLE_TIME) {
341                 start = System.currentTimeMillis();
342                 System.out.println("Starting " + getSymbolicName()); //$NON-NLS-1$
343
}
344         }
345         try {
346             context.start();
347
348             if (framework.active) {
349                 state = ACTIVE;
350
351                 if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
352                     Debug.println("->started " + this); //$NON-NLS-1$
353
}
354
355                 framework.publishBundleEvent(BundleEvent.STARTED, this);
356             }
357
358         } catch (BundleException e) {
359             // we must fire the stopping event
360
state = STOPPING;
361             framework.publishBundleEvent(BundleEvent.STOPPING, this);
362
363             context.close();
364             context = null;
365
366             state = RESOLVED;
367             // if this is a lazy start bundle that fails to start then
368
// we must fire the stopped event
369
framework.publishBundleEvent(BundleEvent.STOPPED, this);
370             throw e;
371         } finally {
372             if (Debug.DEBUG) {
373                 BundleWatcher bundleStats = framework.adaptor.getBundleWatcher();
374                 if (bundleStats != null)
375                     bundleStats.watchBundle(this, BundleWatcher.END_ACTIVATION);
376                 if (Debug.DEBUG_BUNDLE_TIME)
377                     System.out.println("End starting " + getSymbolicName() + " " + (System.currentTimeMillis() - start)); //$NON-NLS-1$ //$NON-NLS-2$
378
}
379         }
380
381         if (state == UNINSTALLED) {
382             context.close();
383             context = null;
384             throw new BundleException(NLS.bind(Msg.BUNDLE_UNINSTALLED_EXCEPTION, getBundleData().getLocation()));
385         }
386     }
387
388     protected boolean readyToResume() {
389         // Return false if the bundle is not at the correct start-level
390
if (getStartLevel() > framework.startLevelManager.getStartLevel())
391             return false;
392         int status = bundledata.getStatus();
393         // Return false if the bundle is not persistently marked for start
394
if ((status & Constants.BUNDLE_STARTED) == 0)
395             return false;
396         if ((status & Constants.BUNDLE_ACTIVATION_POLICY) == 0 || (status & Constants.BUNDLE_LAZY_START) == 0)
397             return true;
398         if (!isResolved())
399             // should never transition from UNRESOLVED -> STARTING
400
return false;
401         // now we can publish the LAZY_ACTIVATION event
402
state = STARTING;
403         framework.publishBundleEvent(BundleEvent.LAZY_ACTIVATION, this);
404         return false;
405     }
406
407     /**
408      * Create a BundleContext for this bundle.
409      *
410      * @return BundleContext for this bundle.
411      */

412     protected BundleContextImpl createContext() {
413         return (new BundleContextImpl(this));
414     }
415
416     /**
417      * Return the current context for this bundle.
418      *
419      * @return BundleContext for this bundle.
420      */

421     protected synchronized BundleContextImpl getContext() {
422         if (context == null) {
423             // only create the context if we are starting, active or stopping
424
// this is so that SCR can get the context for lazy-start bundles
425
if ((state & (STARTING | ACTIVE | STOPPING)) != 0)
426                 context = createContext();
427         }
428         return (context);
429     }
430
431     /**
432      * Internal worker to stop a bundle.
433      *
434      * @param options the stop options
435      */

436     protected void stopWorker(int options) throws BundleException {
437         if ((options & STOP_TRANSIENT) == 0) {
438             setStatus(Constants.BUNDLE_STARTED, false);
439             setStatus(Constants.BUNDLE_ACTIVATION_POLICY, false);
440             if (Debug.DEBUG && Debug.MONITOR_ACTIVATION)
441                 new Exception JavaDoc("A persistent start has been called on bundle: " + getBundleData()).printStackTrace();
442         }
443         if (framework.active) {
444             if ((state & (STOPPING | RESOLVED | INSTALLED)) != 0) {
445                 return;
446             }
447             if (Debug.DEBUG) {
448                 BundleWatcher bundleStats = framework.adaptor.getBundleWatcher();
449                 if (bundleStats != null)
450                     bundleStats.watchBundle(this, BundleWatcher.START_DEACTIVATION);
451             }
452             state = STOPPING;
453             framework.publishBundleEvent(BundleEvent.STOPPING, this);
454             try {
455                 // context may be null if a lazy-start bundle is STARTING
456
if (context != null)
457                     context.stop();
458             } finally {
459                 if (context != null) {
460                     context.close();
461                     context = null;
462                 }
463
464                 checkValid();
465
466                 state = RESOLVED;
467
468                 if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
469                     Debug.println("->stopped " + this); //$NON-NLS-1$
470
}
471
472                 framework.publishBundleEvent(BundleEvent.STOPPED, this);
473                 if (Debug.DEBUG) {
474                     BundleWatcher bundleStats = framework.adaptor.getBundleWatcher();
475                     if (bundleStats != null)
476                         bundleStats.watchBundle(this, BundleWatcher.END_DEACTIVATION);
477                 }
478             }
479         }
480     }
481
482     /**
483      * Provides a list of {@link ServiceReferenceImpl}s for the services
484      * registered by this bundle
485      * or <code>null</code> if the bundle has no registered
486      * services.
487      *
488      * <p>The list is valid at the time
489      * of the call to this method, but the framework is a very dynamic
490      * environment and services can be modified or unregistered at anytime.
491      *
492      * @return An array of {@link ServiceReferenceImpl} or <code>null</code>.
493      * @exception java.lang.IllegalStateException If the
494      * bundle has been uninstalled.
495      * @see ServiceRegistrationImpl
496      * @see ServiceReferenceImpl
497      */

498     public org.osgi.framework.ServiceReference[] getRegisteredServices() {
499         checkValid();
500
501         if (context == null) {
502             return (null);
503         }
504
505         return (context.getRegisteredServices());
506     }
507
508     /**
509      * Provides a list of {@link ServiceReferenceImpl}s for the
510      * services this bundle is using,
511      * or <code>null</code> if the bundle is not using any services.
512      * A bundle is considered to be using a service if the bundle's
513      * use count for the service is greater than zero.
514      *
515      * <p>The list is valid at the time
516      * of the call to this method, but the framework is a very dynamic
517      * environment and services can be modified or unregistered at anytime.
518      *
519      * @return An array of {@link ServiceReferenceImpl} or <code>null</code>.
520      * @exception java.lang.IllegalStateException If the
521      * bundle has been uninstalled.
522      * @see ServiceReferenceImpl
523      */

524     public org.osgi.framework.ServiceReference[] getServicesInUse() {
525         checkValid();
526
527         if (context == null) {
528             return (null);
529         }
530
531         return (context.getServicesInUse());
532     }
533
534     protected Bundle[] getFragments() {
535         synchronized (framework.bundles) {
536             if (fragments == null)
537                 return null;
538             Bundle[] result = new Bundle[fragments.length];
539             System.arraycopy(fragments, 0, result, 0, result.length);
540             return result;
541         }
542     }
543
544     /**
545      * Attaches a fragment to this BundleHost. Fragments must be attached to
546      * the host by ID order. If the ClassLoader of the host is already created
547      * then the fragment must be attached to the host ClassLoader
548      * @param fragment The fragment bundle to attach
549      * return true if the fragment successfully attached; false if the fragment
550      * could not be logically inserted at the end of the fragment chain.
551      */

552     protected void attachFragment(BundleFragment fragment) throws BundleException {
553         // do not force the creation of the bundle loader here
554
BundleLoader loader = getLoaderProxy().getBasicBundleLoader();
555         // If the Host ClassLoader exists then we must attach
556
// the fragment to the ClassLoader.
557
if (loader != null)
558             loader.attachFragment(fragment);
559
560         if (fragments == null) {
561             fragments = new BundleFragment[] {fragment};
562         } else {
563             boolean inserted = false;
564             // We must keep our fragments ordered by bundle ID; or
565
// install order.
566
BundleFragment[] newFragments = new BundleFragment[fragments.length + 1];
567             for (int i = 0; i < fragments.length; i++) {
568                 if (fragment == fragments[i])
569                     return; // this fragment is already attached
570
if (!inserted && fragment.getBundleId() < fragments[i].getBundleId()) {
571                     // if the loader has already been created
572
// then we cannot attach a fragment into the middle
573
// of the fragment chain.
574
if (loader != null) {
575                         throw new BundleException(NLS.bind(Msg.BUNDLE_LOADER_ATTACHMENT_ERROR, fragments[i].getSymbolicName(), getSymbolicName()));
576                     }
577                     newFragments[i] = fragment;
578                     inserted = true;
579                 }
580                 newFragments[inserted ? i + 1 : i] = fragments[i];
581             }
582             if (!inserted)
583                 newFragments[newFragments.length - 1] = fragment;
584             fragments = newFragments;
585         }
586     }
587
588     protected BundleLoader getBundleLoader() {
589         BundleLoaderProxy curProxy = getLoaderProxy();
590         return curProxy == null ? null : curProxy.getBundleLoader();
591     }
592
593     protected synchronized BundleLoaderProxy getLoaderProxy() {
594         if (proxy != null)
595             return proxy;
596         BundleDescription bundleDescription = getBundleDescription();
597         if (bundleDescription == null)
598             return null;
599         proxy = new BundleLoaderProxy(this, bundleDescription);
600         bundleDescription.setUserObject(proxy);
601         return proxy;
602     }
603
604     static void closeBundleLoader(BundleLoaderProxy proxy) {
605         if (proxy == null)
606             return;
607         // First close the BundleLoader
608
BundleLoader loader = proxy.getBasicBundleLoader();
609         if (loader != null)
610             loader.close();
611         proxy.setStale();
612         // if proxy is not null then make sure to unset user object
613
// associated with the proxy in the state
614
BundleDescription description = proxy.getBundleDescription();
615         description.setUserObject(null);
616     }
617 }
618
Popular Tags