KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*******************************************************************************
2  * Copyright (c) 2003, 2007 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.IOException JavaDoc;
14 import java.io.InputStream JavaDoc;
15 import java.net.URL JavaDoc;
16 import java.net.URLConnection JavaDoc;
17 import java.security.*;
18 import java.util.*;
19 import org.eclipse.osgi.framework.adaptor.*;
20 import org.eclipse.osgi.framework.debug.Debug;
21 import org.eclipse.osgi.framework.util.KeyedElement;
22 import org.eclipse.osgi.service.resolver.*;
23 import org.eclipse.osgi.util.NLS;
24 import org.osgi.framework.*;
25
26 /**
27  * This object is given out to bundles and wraps the internal Bundle object. It
28  * is destroyed when a bundle is uninstalled and reused if a bundle is updated.
29  * This class is abstract and is extended by BundleHost and BundleFragment.
30  */

31 public abstract class AbstractBundle implements Bundle, Comparable JavaDoc, KeyedElement {
32     /** The Framework this bundle is part of */
33     protected Framework framework;
34     /** The state of the bundle. */
35     protected volatile int state;
36     /** A flag to denote whether a bundle state change is in progress */
37     protected volatile Thread JavaDoc stateChanging;
38     /** Bundle's BundleData object */
39     protected BundleData bundledata;
40     /** Internal object used for state change synchronization */
41     protected Object JavaDoc statechangeLock = new Object JavaDoc();
42     /** ProtectionDomain for the bundle */
43     protected BundleProtectionDomain domain;
44
45     protected ManifestLocalization manifestLocalization = null;
46
47     /**
48      * Bundle object constructor. This constructor should not perform any real
49      * work.
50      *
51      * @param bundledata
52      * BundleData for this bundle
53      * @param framework
54      * Framework this bundle is running in
55      */

56     protected static AbstractBundle createBundle(BundleData bundledata, Framework framework) throws BundleException {
57         if ((bundledata.getType() & BundleData.TYPE_FRAGMENT) > 0)
58             return new BundleFragment(bundledata, framework);
59         return new BundleHost(bundledata, framework);
60     }
61
62     /**
63      * Bundle object constructor. This constructor should not perform any real
64      * work.
65      *
66      * @param bundledata
67      * BundleData for this bundle
68      * @param framework
69      * Framework this bundle is running in
70      */

71     protected AbstractBundle(BundleData bundledata, Framework framework) {
72         state = INSTALLED;
73         stateChanging = null;
74         this.bundledata = bundledata;
75         this.framework = framework;
76         bundledata.setBundle(this);
77     }
78
79     /**
80      * Load the bundle.
81      */

82     protected abstract void load();
83
84     /**
85      * Reload from a new bundle. This method must be called while holding the
86      * bundles lock.
87      *
88      * @param newBundle
89      * Dummy Bundle which contains new data.
90      * @return true if an exported package is "in use". i.e. it has been
91      * imported by a bundle
92      */

93     protected abstract boolean reload(AbstractBundle newBundle);
94
95     /**
96      * Refresh the bundle. This is called by Framework.refreshPackages. This
97      * method must be called while holding the bundles lock.
98      * this.loader.unimportPackages must have already been called before
99      * calling this method!
100      */

101     protected abstract void refresh();
102
103     /**
104      * Unload the bundle. This method must be called while holding the bundles
105      * lock.
106      *
107      * @return true if an exported package is "in use". i.e. it has been
108      * imported by a bundle
109      */

110     protected abstract boolean unload();
111
112     /**
113      * Close the the Bundle's file.
114      *
115      */

116     protected void close() {
117         if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
118             if ((state & (INSTALLED)) == 0) {
119                 Debug.println("Bundle.close called when state != INSTALLED: " + this); //$NON-NLS-1$
120
Debug.printStackTrace(new Exception JavaDoc("Stack trace")); //$NON-NLS-1$
121
}
122         }
123         state = UNINSTALLED;
124     }
125
126     /**
127      * Load and instantiate bundle's BundleActivator class
128      */

129     protected BundleActivator loadBundleActivator() throws BundleException {
130         /* load Bundle's BundleActivator if it has one */
131         String JavaDoc activatorClassName = bundledata.getActivator();
132         if (activatorClassName != null) {
133             try {
134                 Class JavaDoc activatorClass = loadClass(activatorClassName, false);
135                 /* Create the activator for the bundle */
136                 return (BundleActivator) (activatorClass.newInstance());
137             } catch (Throwable JavaDoc t) {
138                 if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
139                     Debug.printStackTrace(t);
140                 }
141                 throw new BundleException(NLS.bind(Msg.BUNDLE_INVALID_ACTIVATOR_EXCEPTION, activatorClassName, bundledata.getSymbolicName()), t);
142             }
143         }
144         return (null);
145     }
146
147     /**
148      * This method loads a class from the bundle.
149      *
150      * @param name
151      * the name of the desired Class.
152      * @param checkPermission
153      * indicates whether a permission check should be done.
154      * @return the resulting Class
155      * @exception java.lang.ClassNotFoundException
156      * if the class definition was not found.
157      */

158     protected abstract Class JavaDoc loadClass(String JavaDoc name, boolean checkPermission) throws ClassNotFoundException JavaDoc;
159
160     /**
161      * Returns the current state of the bundle.
162      *
163      * A bundle can only be in one state at any time.
164      *
165      * @return bundle's state.
166      */

167     public int getState() {
168         return (state);
169     }
170
171     /**
172      * Return true if the bundle is starting or active.
173      *
174      */

175     protected boolean isActive() {
176         return ((state & (ACTIVE | STARTING)) != 0);
177     }
178
179     /**
180      * Return true if the bundle is resolved.
181      *
182      */

183     protected boolean isResolved() {
184         return (state & (INSTALLED | UNINSTALLED)) == 0;
185     }
186
187     /**
188      * Start this bundle.
189      *
190      * If the current start level is less than this bundle's start level, then
191      * the Framework must persistently mark this bundle as started and delay
192      * the starting of this bundle until the Framework's current start level
193      * becomes equal or more than the bundle's start level.
194      * <p>
195      * Otherwise, the following steps are required to start a bundle:
196      * <ol>
197      * <li>If the bundle is {@link #UNINSTALLED}then an <code>IllegalStateException</code>
198      * is thrown.
199      * <li>If the bundle is {@link #ACTIVE}or {@link #STARTING}then this
200      * method returns immediately.
201      * <li>If the bundle is {@link #STOPPING}then this method may wait for
202      * the bundle to return to the {@link #RESOLVED}state before continuing.
203      * If this does not occur in a reasonable time, a {@link BundleException}
204      * is thrown to indicate the bundle was unable to be started.
205      * <li>If the bundle is not {@link #RESOLVED}, an attempt is made to
206      * resolve the bundle. If the bundle cannot be resolved, a
207      * {@link BundleException}is thrown.
208      * <li>The state of the bundle is set to {@link #STARTING}.
209      * <li>The {@link BundleActivator#start(BundleContext) start}method of the bundle's
210      * {@link BundleActivator}, if one is specified, is called. If the
211      * {@link BundleActivator}is invalid or throws an exception, the state of
212      * the bundle is set back to {@link #RESOLVED}, the bundle's listeners, if
213      * any, are removed, service's registered by the bundle, if any, are
214      * unregistered, and service's used by the bundle, if any, are released. A
215      * {@link BundleException}is then thrown.
216      * <li>It is recorded that this bundle has been started, so that when the
217      * framework is restarted, this bundle will be automatically started.
218      * <li>The state of the bundle is set to {@link #ACTIVE}.
219      * <li>A {@link BundleEvent}of type {@link BundleEvent#STARTED}is
220      * broadcast.
221      * </ol>
222      *
223      * <h5>Preconditons</h5>
224      * <ul>
225      * <li>getState() in {{@link #INSTALLED},{@link #RESOLVED}}.
226      * </ul>
227      * <h5>Postconditons, no exceptions thrown</h5>
228      * <ul>
229      * <li>getState() in {{@link #ACTIVE}}.
230      * <li>{@link BundleActivator#start(BundleContext) BundleActivator.start}has been called
231      * and did not throw an exception.
232      * </ul>
233      * <h5>Postconditions, when an exception is thrown</h5>
234      * <ul>
235      * <li>getState() not in {{@link #STARTING},{@link #ACTIVE}}.
236      * </ul>
237      *
238      * @exception BundleException
239      * If the bundle couldn't be started. This could be because
240      * a code dependency could not be resolved or the specified
241      * BundleActivator could not be loaded or threw an
242      * exception.
243      * @exception java.lang.IllegalStateException
244      * If the bundle has been uninstalled or the bundle tries to
245      * change its own state.
246      * @exception java.lang.SecurityException
247      * If the caller does not have {@link AdminPermission}
248      * permission and the Java runtime environment supports
249      * permissions.
250      */

251     public void start() throws BundleException {
252         start(0);
253     }
254
255     public void start(int options) throws BundleException {
256         framework.checkAdminPermission(this, AdminPermission.EXECUTE);
257         checkValid();
258         beginStateChange();
259         try {
260             startWorker(options);
261         } finally {
262             completeStateChange();
263         }
264     }
265
266     /**
267      * Internal worker to start a bundle.
268      *
269      * @param options
270      */

271     protected abstract void startWorker(int options) throws BundleException;
272
273     /**
274      * This method does the following
275      * <ol>
276      * <li> Return false if the bundle is a fragment
277      * <li> Return false if the bundle is not at the correct start-level
278      * <li> Return false if the bundle is not persistently marked for start
279      * <li> Return true if the bundle's activation policy is persistently ignored
280      * <li> Return true if the bundle does not define an activation policy
281      * <li> Transition to STARTING state and Fire LAZY_ACTIVATION event
282      * <li> Return false
283      * </ol>
284      * @return true if the bundle should be resumed
285      */

286     protected boolean readyToResume() {
287         return false;
288     }
289
290     /**
291      * Start this bundle w/o marking is persistently started.
292      *
293      * <p>
294      * The following steps are followed to start a bundle:
295      * <ol>
296      * <li>If the bundle is {@link #UNINSTALLED}then an <code>IllegalStateException</code>
297      * is thrown.
298      * <li>If the bundle is {@link #ACTIVE}or {@link #STARTING}then this
299      * method returns immediately.
300      * <li>If the bundle is {@link #STOPPING}then this method may wait for
301      * the bundle to return to the {@link #RESOLVED}state before continuing.
302      * If this does not occur in a reasonable time, a {@link BundleException}
303      * is thrown to indicate the bundle was unable to be started.
304      * <li>If the bundle is not {@link #RESOLVED}, an attempt is made to
305      * resolve the bundle. If the bundle cannot be resolved, a
306      * {@link BundleException}is thrown.
307      * <li>The state of the bundle is set to {@link #STARTING}.
308      * <li>The {@link BundleActivator#start(BundleContext) start}method of the bundle's
309      * {@link BundleActivator}, if one is specified, is called. If the
310      * {@link BundleActivator}is invalid or throws an exception, the state of
311      * the bundle is set back to {@link #RESOLVED}, the bundle's listeners, if
312      * any, are removed, service's registered by the bundle, if any, are
313      * unregistered, and service's used by the bundle, if any, are released. A
314      * {@link BundleException}is then thrown.
315      * <li>The state of the bundle is set to {@link #ACTIVE}.
316      * <li>A {@link BundleEvent}of type {@link BundleEvent#STARTED}is
317      * broadcast.
318      * </ol>
319      *
320      * <h5>Preconditons</h5>
321      * <ul>
322      * <li>getState() in {{@link #INSTALLED},{@link #RESOLVED}}.
323      * </ul>
324      * <h5>Postconditons, no exceptions thrown</h5>
325      * <ul>
326      * <li>getState() in {{@link #ACTIVE}}.
327      * <li>{@link BundleActivator#start(BundleContext) BundleActivator.start}has been called
328      * and did not throw an exception.
329      * </ul>
330      * <h5>Postconditions, when an exception is thrown</h5>
331      * <ul>
332      * <li>getState() not in {{@link #STARTING},{@link #ACTIVE}}.
333      * </ul>
334      *
335      * @exception BundleException
336      * If the bundle couldn't be started. This could be because
337      * a code dependency could not be resolved or the specified
338      * BundleActivator could not be loaded or threw an
339      * exception.
340      * @exception java.lang.IllegalStateException
341      * If the bundle tries to change its own state.
342      */

343     protected void resume() throws BundleException {
344         if (state == UNINSTALLED) {
345             return;
346         }
347         beginStateChange();
348         try {
349             if (readyToResume())
350                 startWorker(START_TRANSIENT);
351         } finally {
352             completeStateChange();
353         }
354     }
355
356     /**
357      * Stop this bundle.
358      *
359      * Any services registered by this bundle will be unregistered. Any
360      * services used by this bundle will be released. Any listeners registered
361      * by this bundle will be removed.
362      *
363      * <p>
364      * The following steps are followed to stop a bundle:
365      * <ol>
366      * <li>If the bundle is {@link #UNINSTALLED}then an <code>IllegalStateException</code>
367      * is thrown.
368      * <li>If the bundle is {@link #STOPPING},{@link #RESOLVED}, or
369      * {@link #INSTALLED}then this method returns immediately.
370      * <li>If the bundle is {@link #STARTING}then this method may wait for
371      * the bundle to reach the {@link #ACTIVE}state before continuing. If this
372      * does not occur in a reasonable time, a {@link BundleException}is thrown
373      * to indicate the bundle was unable to be stopped.
374      * <li>The state of the bundle is set to {@link #STOPPING}.
375      * <li>It is recorded that this bundle has been stopped, so that when the
376      * framework is restarted, this bundle will not be automatically started.
377      * <li>The {@link BundleActivator#stop(BundleContext) stop}method of the bundle's
378      * {@link BundleActivator}, if one is specified, is called. If the
379      * {@link BundleActivator}throws an exception, this method will continue
380      * to stop the bundle. A {@link BundleException}will be thrown after
381      * completion of the remaining steps.
382      * <li>The bundle's listeners, if any, are removed, service's registered
383      * by the bundle, if any, are unregistered, and service's used by the
384      * bundle, if any, are released.
385      * <li>The state of the bundle is set to {@link #RESOLVED}.
386      * <li>A {@link BundleEvent}of type {@link BundleEvent#STOPPED}is
387      * broadcast.
388      * </ol>
389      *
390      * <h5>Preconditons</h5>
391      * <ul>
392      * <li>getState() in {{@link #ACTIVE}}.
393      * </ul>
394      * <h5>Postconditons, no exceptions thrown</h5>
395      * <ul>
396      * <li>getState() not in {{@link #ACTIVE},{@link #STOPPING}}.
397      * <li>{@link BundleActivator#stop(BundleContext) BundleActivator.stop}has been called
398      * and did not throw an exception.
399      * </ul>
400      * <h5>Postconditions, when an exception is thrown</h5>
401      * <ul>
402      * <li>None.
403      * </ul>
404      *
405      * @exception BundleException
406      * If the bundle's BundleActivator could not be loaded or
407      * threw an exception.
408      * @exception java.lang.IllegalStateException
409      * If the bundle has been uninstalled or the bundle tries to
410      * change its own state.
411      * @exception java.lang.SecurityException
412      * If the caller does not have {@link AdminPermission}
413      * permission and the Java runtime environment supports
414      * permissions.
415      */

416     public void stop() throws BundleException {
417         stop(0);
418     }
419
420     public void stop(int options) throws BundleException {
421         framework.checkAdminPermission(this, AdminPermission.EXECUTE);
422         checkValid();
423         beginStateChange();
424         try {
425             stopWorker(options);
426         } finally {
427             completeStateChange();
428         }
429     }
430     
431     /**
432      * Internal worker to stop a bundle.
433      *
434      * @param options
435      */

436     protected abstract void stopWorker(int options) throws BundleException;
437
438     /**
439      * Set the persistent status bit for the bundle.
440      *
441      * @param mask
442      * Mask for bit to set/clear
443      * @param state
444      * true to set bit, false to clear bit
445      */

446     protected void setStatus(final int mask, final boolean state) {
447         try {
448             AccessController.doPrivileged(new PrivilegedExceptionAction() {
449                 public Object JavaDoc run() throws BundleException, IOException JavaDoc {
450                     int status = bundledata.getStatus();
451                     boolean test = ((status & mask) != 0);
452                     if (test != state) {
453                         bundledata.setStatus(state ? (status | mask) : (status & ~mask));
454                         bundledata.save();
455                     }
456                     return null;
457                 }
458             });
459         } catch (PrivilegedActionException pae) {
460             framework.publishFrameworkEvent(FrameworkEvent.ERROR, this, pae.getException());
461         }
462     }
463
464     /**
465      * Stop this bundle w/o marking is persistently stopped.
466      *
467      * Any services registered by this bundle will be unregistered. Any
468      * services used by this bundle will be released. Any listeners registered
469      * by this bundle will be removed.
470      *
471      * <p>
472      * The following steps are followed to stop a bundle:
473      * <ol>
474      * <li>If the bundle is {@link #UNINSTALLED}then an <code>IllegalStateException</code>
475      * is thrown.
476      * <li>If the bundle is {@link #STOPPING},{@link #RESOLVED}, or
477      * {@link #INSTALLED}then this method returns immediately.
478      * <li>If the bundle is {@link #STARTING}then this method may wait for
479      * the bundle to reach the {@link #ACTIVE}state before continuing. If this
480      * does not occur in a reasonable time, a {@link BundleException}is thrown
481      * to indicate the bundle was unable to be stopped.
482      * <li>The state of the bundle is set to {@link #STOPPING}.
483      * <li>The {@link BundleActivator#stop(BundleContext) stop}method of the bundle's
484      * {@link BundleActivator}, if one is specified, is called. If the
485      * {@link BundleActivator}throws an exception, this method will continue
486      * to stop the bundle. A {@link BundleException}will be thrown after
487      * completion of the remaining steps.
488      * <li>The bundle's listeners, if any, are removed, service's registered
489      * by the bundle, if any, are unregistered, and service's used by the
490      * bundle, if any, are released.
491      * <li>The state of the bundle is set to {@link #RESOLVED}.
492      * <li>A {@link BundleEvent}of type {@link BundleEvent#STOPPED}is
493      * broadcast.
494      * </ol>
495      *
496      * <h5>Preconditons</h5>
497      * <ul>
498      * <li>getState() in {{@link #ACTIVE}}.
499      * </ul>
500      * <h5>Postconditons, no exceptions thrown</h5>
501      * <ul>
502      * <li>getState() not in {{@link #ACTIVE},{@link #STOPPING}}.
503      * <li>{@link BundleActivator#stop(BundleContext) BundleActivator.stop}has been called
504      * and did not throw an exception.
505      * </ul>
506      * <h5>Postconditions, when an exception is thrown</h5>
507      * <ul>
508      * <li>None.
509      * </ul>
510      *
511      * @param lock
512      * true if state change lock should be held when returning from
513      * this method.
514      * @exception BundleException
515      * If the bundle's BundleActivator could not be loaded or
516      * threw an exception.
517      * @exception java.lang.IllegalStateException
518      * If the bundle tries to change its own state.
519      */

520     protected void suspend(boolean lock) throws BundleException {
521         if (state == UNINSTALLED) {
522             return;
523         }
524         beginStateChange();
525         try {
526             stopWorker(STOP_TRANSIENT);
527         } finally {
528             if (!lock) {
529                 completeStateChange();
530             }
531         }
532     }
533
534     /**
535      * Update this bundle. If the bundle is {@link #ACTIVE}, the bundle will
536      * be stopped before the update and started after the update successfully
537      * completes.
538      *
539      * <p>
540      * The following steps are followed to update a bundle:
541      * <ol>
542      * <li>If the bundle is {@link #UNINSTALLED}then an <code>IllegalStateException</code>
543      * is thrown.
544      * <li>If the bundle is {@link #ACTIVE}or {@link #STARTING}, the bundle
545      * is stopped as described in the {@link #stop()}method. If {@link #stop()}
546      * throws an exception, the exception is rethrown terminating the update.
547      * <li>The location for the new version of the bundle is determined from
548      * either the manifest header <code>Bundle-UpdateLocation</code> if
549      * available or the original location.
550      * <li>The location is interpreted in an implementation dependent way
551      * (typically as a URL) and the new version of the bundle is obtained from
552      * the location.
553      * <li>The new version of the bundle is installed. If the framework is
554      * unable to install the new version of the bundle, the original version of
555      * the bundle will be restored and a {@link BundleException}will be thrown
556      * after completion of the remaining steps.
557      * <li>The state of the bundle is set to {@link #INSTALLED}.
558      * <li>If the new version of the bundle was successfully installed, a
559      * {@link BundleEvent}of type {@link BundleEvent#UPDATED}is broadcast.
560      * <li>If the bundle was originally {@link #ACTIVE}, the updated bundle
561      * is started as described in the {@link #start()}method. If {@link #start()}
562      * throws an exception, a {@link FrameworkEvent}of type
563      * {@link FrameworkEvent#ERROR}is broadcast containing the exception.
564      * </ol>
565      *
566      * <h5>Preconditions</h5>
567      * <ul>
568      * <li>getState() not in {{@link #UNINSTALLED}}.
569      * </ul>
570      * <h5>Postconditons, no exceptions thrown</h5>
571      * <ul>
572      * <li>getState() in {{@link #INSTALLED},{@link #RESOLVED},
573      * {@link #ACTIVE}}.
574      * <li>The bundle has been updated.
575      * </ul>
576      * <h5>Postconditions, when an exception is thrown</h5>
577      * <ul>
578      * <li>getState() in {{@link #INSTALLED},{@link #RESOLVED},
579      * {@link #ACTIVE}}.
580      * <li>Original bundle is still used, no update took place.
581      * </ul>
582      *
583      * @exception BundleException
584      * If the update fails.
585      * @exception java.lang.IllegalStateException
586      * If the bundle has been uninstalled or the bundle tries to
587      * change its own state.
588      * @exception java.lang.SecurityException
589      * If the caller does not have {@link AdminPermission}
590      * permission and the Java runtime environment supports
591      * permissions.
592      * @see #stop()
593      * @see #start()
594      */

595     public void update() throws BundleException {
596         if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
597             Debug.println("update location " + bundledata.getLocation()); //$NON-NLS-1$
598
}
599         framework.checkAdminPermission(this, AdminPermission.LIFECYCLE);
600         if ((bundledata.getType() & (BundleData.TYPE_BOOTCLASSPATH_EXTENSION | BundleData.TYPE_FRAMEWORK_EXTENSION)) != 0)
601             // need special permission to update extensions
602
framework.checkAdminPermission(this, AdminPermission.EXTENSIONLIFECYCLE);
603         checkValid();
604         beginStateChange();
605         try {
606             final AccessControlContext callerContext = AccessController.getContext();
607             //note AdminPermission is checked again after updated bundle is loaded
608
updateWorker(new PrivilegedExceptionAction() {
609                 public Object JavaDoc run() throws BundleException {
610                     /* compute the update location */
611                     String JavaDoc updateLocation = bundledata.getLocation();
612                     if (bundledata.getManifest().get(Constants.BUNDLE_UPDATELOCATION) != null) {
613                         updateLocation = (String JavaDoc) bundledata.getManifest().get(Constants.BUNDLE_UPDATELOCATION);
614                         if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
615                             Debug.println(" from location: " + updateLocation); //$NON-NLS-1$
616
}
617                     }
618                     /* Map the identity to a URLConnection */
619                     URLConnection JavaDoc source = framework.adaptor.mapLocationToURLConnection(updateLocation);
620                     /* call the worker */
621                     updateWorkerPrivileged(source, callerContext);
622                     return null;
623                 }
624             });
625         } finally {
626             completeStateChange();
627         }
628     }
629
630     /**
631      * Update this bundle from an InputStream.
632      *
633      * <p>
634      * This method performs all the steps listed in {@link #update()}, except
635      * the bundle will be read in through the supplied <code>InputStream</code>,
636      * rather than a <code>URL</code>.
637      *
638      * @param in
639      * The InputStream from which to read the new bundle.
640      * @see #update()
641      */

642     public void update(final InputStream JavaDoc in) throws BundleException {
643         if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
644             Debug.println("update location " + bundledata.getLocation()); //$NON-NLS-1$
645
Debug.println(" from: " + in); //$NON-NLS-1$
646
}
647         framework.checkAdminPermission(this, AdminPermission.LIFECYCLE);
648         if ((bundledata.getType() & (BundleData.TYPE_BOOTCLASSPATH_EXTENSION | BundleData.TYPE_FRAMEWORK_EXTENSION)) != 0)
649             // need special permission to update extensions
650
framework.checkAdminPermission(this, AdminPermission.EXTENSIONLIFECYCLE);
651         checkValid();
652         beginStateChange();
653         try {
654             final AccessControlContext callerContext = AccessController.getContext();
655             //note AdminPermission is checked again after updated bundle is loaded
656
updateWorker(new PrivilegedExceptionAction() {
657                 public Object JavaDoc run() throws BundleException {
658                     /* Map the InputStream to a URLConnection */
659                     URLConnection JavaDoc source = new BundleSource(in);
660                     /* call the worker */
661                     updateWorkerPrivileged(source, callerContext);
662                     return null;
663                 }
664             });
665         } finally {
666             completeStateChange();
667         }
668     }
669
670     /**
671      * Update worker. Assumes the caller has the state change lock.
672      */

673     protected void updateWorker(PrivilegedExceptionAction action) throws BundleException {
674         boolean bundleActive = false;
675         if (!isFragment())
676             bundleActive = (state & (ACTIVE | STARTING)) != 0;
677         if (bundleActive) {
678             try {
679                 stopWorker(STOP_TRANSIENT);
680             } catch (BundleException e) {
681                 framework.publishFrameworkEvent(FrameworkEvent.ERROR, this, e);
682                 if ((state & (ACTIVE | STARTING)) != 0) /* if the bundle is still active */{
683                     throw e;
684                 }
685             }
686         }
687         try {
688             AccessController.doPrivileged(action);
689             framework.publishBundleEvent(BundleEvent.UPDATED, this);
690         } catch (PrivilegedActionException pae) {
691             if (pae.getException() instanceof RuntimeException JavaDoc)
692                 throw (RuntimeException JavaDoc) pae.getException();
693             throw (BundleException) pae.getException();
694         } finally {
695             if (bundleActive) {
696                 try {
697                     startWorker(START_TRANSIENT);
698                 } catch (BundleException e) {
699                     framework.publishFrameworkEvent(FrameworkEvent.ERROR, this, e);
700                 }
701             }
702         }
703     }
704
705     /**
706      * Update worker. Assumes the caller has the state change lock.
707      */

708     protected void updateWorkerPrivileged(URLConnection JavaDoc source, AccessControlContext callerContext) throws BundleException {
709         AbstractBundle oldBundle = AbstractBundle.createBundle(bundledata, framework);
710         boolean reloaded = false;
711         BundleOperation storage = framework.adaptor.updateBundle(this.bundledata, source);
712         BundleRepository bundles = framework.getBundles();
713         try {
714             BundleData newBundleData = storage.begin();
715             // Must call framework createBundle to check execution environment.
716
final AbstractBundle newBundle = framework.createAndVerifyBundle(newBundleData);
717             String JavaDoc[] nativepaths = framework.selectNativeCode(newBundle);
718             if (nativepaths != null) {
719                 newBundleData.installNativeCode(nativepaths);
720             }
721             boolean exporting;
722             int st = getState();
723             synchronized (bundles) {
724                 exporting = reload(newBundle);
725                 manifestLocalization = null;
726             }
727             // indicate we have loaded from the new version of the bundle
728
reloaded = true;
729             if (System.getSecurityManager() != null) {
730                 final boolean extension = (bundledata.getType() & (BundleData.TYPE_BOOTCLASSPATH_EXTENSION | BundleData.TYPE_FRAMEWORK_EXTENSION)) != 0;
731                 // must check for AllPermission before allow a bundle extension to be updated
732
if (extension && !hasPermission(new AllPermission()))
733                     throw new BundleException(Msg.BUNDLE_EXTENSION_PERMISSION, new SecurityException JavaDoc(Msg.BUNDLE_EXTENSION_PERMISSION));
734                 try {
735                     AccessController.doPrivileged(new PrivilegedExceptionAction() {
736                         public Object JavaDoc run() throws Exception JavaDoc {
737                             framework.checkAdminPermission(newBundle, AdminPermission.LIFECYCLE);
738                             if (extension) // need special permission to update extension bundles
739
framework.checkAdminPermission(newBundle, AdminPermission.EXTENSIONLIFECYCLE);
740                             return null;
741                         }
742                     }, callerContext);
743                 } catch (PrivilegedActionException e) {
744                     throw e.getException();
745                 }
746             }
747             // send out unresolved events outside synch block (defect #80610)
748
if (st == RESOLVED)
749                 framework.publishBundleEvent(BundleEvent.UNRESOLVED, this);
750             storage.commit(exporting);
751         } catch (Throwable JavaDoc t) {
752             try {
753                 storage.undo();
754                 if (reloaded) /*
755                  * if we loaded from the new version of the
756                  * bundle
757                  */
{
758                     synchronized (bundles) {
759                         reload(oldBundle); /* revert to old version */
760                     }
761                 }
762             } catch (BundleException ee) {
763                 /* if we fail to revert then we are in big trouble */
764                 framework.publishFrameworkEvent(FrameworkEvent.ERROR, this, ee);
765             }
766             if (t instanceof SecurityException JavaDoc)
767                 throw (SecurityException JavaDoc) t;
768             if (t instanceof BundleException)
769                 throw (BundleException) t;
770             throw new BundleException(t.getMessage(), t);
771         }
772     }
773
774     /**
775      * Uninstall this bundle.
776      * <p>
777      * This method removes all traces of the bundle, including any data in the
778      * persistent storage area provided for the bundle by the framework.
779      *
780      * <p>
781      * The following steps are followed to uninstall a bundle:
782      * <ol>
783      * <li>If the bundle is {@link #UNINSTALLED}then an <code>IllegalStateException</code>
784      * is thrown.
785      * <li>If the bundle is {@link #ACTIVE}or {@link #STARTING}, the bundle
786      * is stopped as described in the {@link #stop()}method. If {@link #stop()}
787      * throws an exception, a {@link FrameworkEvent}of type
788      * {@link FrameworkEvent#ERROR}is broadcast containing the exception.
789      * <li>A {@link BundleEvent}of type {@link BundleEvent#UNINSTALLED}is
790      * broadcast.
791      * <li>The state of the bundle is set to {@link #UNINSTALLED}.
792      * <li>The bundle and the persistent storage area provided for the bundle
793      * by the framework, if any, is removed.
794      * </ol>
795      *
796      * <h5>Preconditions</h5>
797      * <ul>
798      * <li>getState() not in {{@link #UNINSTALLED}}.
799      * </ul>
800      * <h5>Postconditons, no exceptions thrown</h5>
801      * <ul>
802      * <li>getState() in {{@link #UNINSTALLED}}.
803      * <li>The bundle has been uninstalled.
804      * </ul>
805      * <h5>Postconditions, when an exception is thrown</h5>
806      * <ul>
807      * <li>getState() not in {{@link #UNINSTALLED}}.
808      * <li>The Bundle has not been uninstalled.
809      * </ul>
810      *
811      * @exception BundleException
812      * If the uninstall failed.
813      * @exception java.lang.IllegalStateException
814      * If the bundle has been uninstalled or the bundle tries to
815      * change its own state.
816      * @exception java.lang.SecurityException
817      * If the caller does not have {@link AdminPermission}
818      * permission and the Java runtime environment supports
819      * permissions.
820      * @see #stop()
821      */

822     public void uninstall() throws BundleException {
823         if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
824             Debug.println("uninstall location: " + bundledata.getLocation()); //$NON-NLS-1$
825
}
826         framework.checkAdminPermission(this, AdminPermission.LIFECYCLE);
827         if ((bundledata.getType() & (BundleData.TYPE_BOOTCLASSPATH_EXTENSION | BundleData.TYPE_FRAMEWORK_EXTENSION)) != 0)
828             // need special permission to uninstall extensions
829
framework.checkAdminPermission(this, AdminPermission.EXTENSIONLIFECYCLE);
830         checkValid();
831         beginStateChange();
832         try {
833             uninstallWorker(new PrivilegedExceptionAction() {
834                 public Object JavaDoc run() throws BundleException {
835                     uninstallWorkerPrivileged();
836                     return null;
837                 }
838             });
839         } finally {
840             completeStateChange();
841         }
842     }
843
844     /**
845      * Uninstall worker. Assumes the caller has the state change lock.
846      */

847     protected void uninstallWorker(PrivilegedExceptionAction action) throws BundleException {
848         boolean bundleActive = false;
849         if (!isFragment())
850             bundleActive = (state & (ACTIVE | STARTING)) != 0;
851         if (bundleActive) {
852             try {
853                 stopWorker(STOP_TRANSIENT);
854             } catch (BundleException e) {
855                 framework.publishFrameworkEvent(FrameworkEvent.ERROR, this, e);
856             }
857         }
858         try {
859             AccessController.doPrivileged(action);
860         } catch (PrivilegedActionException pae) {
861             if (bundleActive) /* if we stopped the bundle */{
862                 try {
863                     startWorker(START_TRANSIENT);
864                 } catch (BundleException e) {
865                     /*
866                      * if we fail to start the original bundle then we are in
867                      * big trouble
868                      */

869                     framework.publishFrameworkEvent(FrameworkEvent.ERROR, this, e);
870                 }
871             }
872             throw (BundleException) pae.getException();
873         }
874         framework.publishBundleEvent(BundleEvent.UNINSTALLED, this);
875     }
876
877     /**
878      * Uninstall worker. Assumes the caller has the state change lock.
879      */

880     protected void uninstallWorkerPrivileged() throws BundleException {
881         if (Debug.DEBUG) {
882             BundleWatcher bundleStats = framework.adaptor.getBundleWatcher();
883   &n