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             if (bundleStats != null)
884                 bundleStats.watchBundle(this, BundleWatcher.START_UNINSTALLING);
885         }
886         boolean unloaded = false;
887         //cache the bundle's headers
888
getHeaders();
889         BundleOperation storage = framework.adaptor.uninstallBundle(this.bundledata);
890         BundleRepository bundles = framework.getBundles();
891         try {
892             storage.begin();
893             boolean exporting;
894             int st = getState();
895             synchronized (bundles) {
896                 bundles.remove(this); /* remove before calling unload */
897                 exporting = unload();
898             }
899             // send out unresolved events outside synch block (defect #80610)
900
if (st == RESOLVED)
901                 framework.publishBundleEvent(BundleEvent.UNRESOLVED, this);
902             unloaded = true;
903             storage.commit(exporting);
904             close();
905         } catch (BundleException e) {
906             try {
907                 storage.undo();
908                 if (unloaded) /* if we unloaded the bundle */{
909                     synchronized (bundles) {
910                         load(); /* reload the bundle */
911                         bundles.add(this);
912                     }
913                 }
914             } catch (BundleException ee) {
915                 /*
916                  * if we fail to load the original bundle then we are in big
917                  * trouble
918                  */

919                 framework.publishFrameworkEvent(FrameworkEvent.ERROR, this, ee);
920             }
921             throw e;
922         } finally {
923             if (Debug.DEBUG) {
924                 BundleWatcher bundleStats = framework.adaptor.getBundleWatcher();
925                 if (bundleStats != null)
926                     bundleStats.watchBundle(this, BundleWatcher.END_UNINSTALLING);
927             }
928         }
929     }
930
931     /**
932      * Return the bundle's manifest headers and values from the manifest's
933      * preliminary section. That is all the manifest's headers and values prior
934      * to the first blank line.
935      *
936      * <p>
937      * Manifest header names are case-insensitive. The methods of the returned
938      * <code>Dictionary</code> object will operate on header names in a
939      * case-insensitive manner.
940      *
941      * <p>
942      * For example, the following manifest headers and values are included if
943      * they are present in the manifest:
944      *
945      * <pre>
946      * Bundle-Name
947      * Bundle-Vendor
948      * Bundle-Version
949      * Bundle-Description
950      * Bundle-DocURL
951      * Bundle-ContactAddress
952      * </pre>
953      *
954      * <p>
955      * This method will continue to return this information when the bundle is
956      * in the {@link #UNINSTALLED}state.
957      *
958      * @return A <code>Dictionary</code> object containing the bundle's
959      * manifest headers and values.
960      * @exception java.lang.SecurityException
961      * If the caller does not have {@link AdminPermission}
962      * permission and the Java runtime environment supports
963      * permissions.
964      */

965     public Dictionary getHeaders() {
966         return getHeaders(null);
967     }
968
969     /**
970      * Returns this bundle's Manifest headers and values. This method returns
971      * all the Manifest headers and values from the main section of the
972      * bundle's Manifest file; that is, all lines prior to the first blank
973      * line.
974      *
975      * <p>
976      * Manifest header names are case-insensitive. The methods of the returned
977      * <tt>Dictionary</tt> object will operate on header names in a
978      * case-insensitive manner.
979      *
980      * If a Manifest header begins with a '%', it will be evaluated with the
981      * specified properties file for the specied Locale.
982      *
983      * <p>
984      * For example, the following Manifest headers and values are included if
985      * they are present in the Manifest file:
986      *
987      * <pre>
988      * Bundle-Name
989      * Bundle-Vendor
990      * Bundle-Version
991      * Bundle-Description
992      * Bundle-DocURL
993      * Bundle-ContactAddress
994      * </pre>
995      *
996      * <p>
997      * This method will continue to return Manifest header information while
998      * this bundle is in the <tt>UNINSTALLED</tt> state.
999      *
1000     * @return A <tt>Dictionary</tt> object containing this bundle's Manifest
1001     * headers and values.
1002     *
1003     * @exception java.lang.SecurityException
1004     * If the caller does not have the <tt>AdminPermission</tt>,
1005     * and the Java Runtime Environment supports permissions.
1006     */

1007    public Dictionary getHeaders(String JavaDoc localeString) {
1008        framework.checkAdminPermission(this, AdminPermission.METADATA);
1009        try {
1010            initializeManifestLocalization();
1011        } catch (BundleException e) {
1012            framework.publishFrameworkEvent(FrameworkEvent.ERROR, this, e);
1013            // return an empty dictinary.
1014
return new Hashtable();
1015        }
1016        if (localeString == null)
1017            localeString = Locale.getDefault().toString();
1018        return manifestLocalization.getHeaders(localeString);
1019    }
1020
1021    /**
1022     * Retrieve the bundle's unique identifier, which the framework assigned to
1023     * this bundle when it was installed.
1024     *
1025     * <p>
1026     * The unique identifier has the following attributes:
1027     * <ul>
1028     * <li>It is unique and persistent.
1029     * <li>The identifier is a long.
1030     * <li>Once its value is assigned to a bundle, that value is not reused
1031     * for another bundle, even after the bundle is uninstalled.
1032     * <li>Its value does not change as long as the bundle remains installed.
1033     * <li>Its value does not change when the bundle is updated
1034     * </ul>
1035     *
1036     * <p>
1037     * This method will continue to return the bundle's unique identifier when
1038     * the bundle is in the {@link #UNINSTALLED}state.
1039     *
1040     * @return This bundle's unique identifier.
1041     */

1042    public long getBundleId() {
1043        return (bundledata.getBundleID());
1044    }
1045
1046    /**
1047     * Retrieve the location identifier of the bundle. This is typically the
1048     * location passed to
1049     * {@link BundleContextImpl#installBundle(String) BundleContext.installBundle}when the
1050     * bundle was installed. The location identifier of the bundle may change
1051     * during bundle update. Calling this method while framework is updating
1052     * the bundle results in undefined behavior.
1053     *
1054     * <p>
1055     * This method will continue to return the bundle's location identifier
1056     * when the bundle is in the {@link #UNINSTALLED}state.
1057     *
1058     * @return A string that is the location identifier of the bundle.
1059     * @exception java.lang.SecurityException
1060     * If the caller does not have {@link AdminPermission}
1061     * permission and the Java runtime environment supports
1062     * permissions.
1063     */

1064    public String JavaDoc getLocation() {
1065        framework.checkAdminPermission(this, AdminPermission.METADATA);
1066        return (bundledata.getLocation());
1067    }
1068
1069    /**
1070     * Determine whether the bundle has the requested permission.
1071     *
1072     * <p>
1073     * If the Java runtime environment does not supports permissions this
1074     * method always returns <code>true</code>. The permission parameter is
1075     * of type <code>Object</code> to avoid referencing the <code>java.security.Permission</code>
1076     * class directly. This is to allow the framework to be implemented in Java
1077     * environments which do not support permissions.
1078     *
1079     * @param permission
1080     * The requested permission.
1081     * @return <code>true</code> if the bundle has the requested permission
1082     * or <code>false</code> if the bundle does not have the
1083     * permission or the permission parameter is not an <code>instanceof java.security.Permission</code>.
1084     * @exception java.lang.IllegalStateException
1085     * If the bundle has been uninstalled.
1086     */

1087    public boolean hasPermission(Object JavaDoc permission) {
1088        checkValid();
1089        if (domain != null) {
1090            if (permission instanceof Permission) {
1091                SecurityManager JavaDoc sm = System.getSecurityManager();
1092                if (sm instanceof FrameworkSecurityManager) {
1093                    /*
1094                     * If the FrameworkSecurityManager is active, we need to do checks the "right" way.
1095                     * We can exploit our knowledge that the security context of FrameworkSecurityManager
1096                     * is an AccessControlContext to invoke it properly with the ProtectionDomain.
1097                     */

1098                    AccessControlContext acc = new AccessControlContext(new ProtectionDomain[] {domain});
1099                    try {
1100                        sm.checkPermission((Permission) permission, acc);
1101                        return true;
1102                    } catch (Exception JavaDoc e) {
1103                        return false;
1104                    }
1105                }
1106                return domain.implies((Permission) permission);
1107            }
1108            return false;
1109        }
1110        return true;
1111    }
1112
1113    /**
1114     * This method marks the bundle's state as changing so that other calls to
1115     * start/stop/suspend/update/uninstall can wait until the state change is
1116     * complete. If stateChanging is non-null when this method is called, we
1117     * will wait for the state change to complete. If the timeout expires
1118     * without changing state (this may happen if the state change is back up
1119     * our call stack), a BundleException is thrown so that we don't wait
1120     * forever.
1121     *
1122     * A call to this method should be immediately followed by a try block
1123     * whose finally block calls completeStateChange().
1124     *
1125     * beginStateChange(); try { // change the bundle's state here... } finally {
1126     * completeStateChange(); }
1127     *
1128     * @exception org.osgi.framework.BundleException
1129     * if the bundles state is still changing after waiting for
1130     * the timeout.
1131     */

1132    protected void beginStateChange() throws BundleException {
1133        synchronized (statechangeLock) {
1134            boolean doubleFault = false;
1135            while (true) {
1136                if (stateChanging == null) {
1137                    stateChanging = Thread.currentThread();
1138                    return;
1139                }
1140                if (doubleFault || (stateChanging == Thread.currentThread())) {
1141                    throw new BundleException(NLS.bind(Msg.BUNDLE_STATE_CHANGE_EXCEPTION, getBundleData().getLocation(), stateChanging.getName()), new BundleStatusException(null, StatusException.CODE_WARNING, stateChanging));
1142                }
1143                try {
1144                    long start = 0;
1145                    if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
1146                        Debug.println(" Waiting for state to change in bundle " + this); //$NON-NLS-1$
1147
start = System.currentTimeMillis();
1148                    }
1149                    statechangeLock.wait(5000); /*
1150                     * wait for other thread to
1151                     * finish changing state
1152                     */

1153                    if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
1154                        long end = System.currentTimeMillis();
1155                        if (end - start > 0)
1156                            System.out.println("Waiting... : " + getSymbolicName() + ' ' + (end - start)); //$NON-NLS-1$
1157
}
1158                } catch (InterruptedException JavaDoc e) {
1159                    //Nothing to do
1160
}
1161                doubleFault = true;
1162            }
1163        }
1164    }
1165
1166    /**
1167     * This method completes the bundle state change by setting stateChanging
1168     * to null and notifying one waiter that the state change has completed.
1169     */

1170    protected void completeStateChange() {
1171        synchronized (statechangeLock) {
1172            if (stateChanging != null) {
1173                stateChanging = null;
1174                statechangeLock.notify(); /*
1175                 * notify one waiting thread that the
1176                 * state change is complete
1177                 */

1178            }
1179        }
1180    }
1181
1182    /**
1183     * Return a string representation of this bundle.
1184     *
1185     * @return String
1186     */

1187    public String JavaDoc toString() {
1188        return (bundledata.getLocation() + " [" + getBundleId() + "]"); //$NON-NLS-1$ //$NON-NLS-2$
1189
}
1190
1191    /**
1192     * Answers an integer indicating the relative positions of the receiver and
1193     * the argument in the natural order of elements of the receiver's class.
1194     *
1195     * @return int which should be <0 if the receiver should sort before the
1196     * argument, 0 if the receiver should sort in the same position as
1197     * the argument, and >0 if the receiver should sort after the
1198     * argument.
1199     * @param obj
1200     * another Bundle an object to compare the receiver to
1201     * @exception ClassCastException
1202     * if the argument can not be converted into something
1203     * comparable with the receiver.
1204     */

1205    public int compareTo(Object JavaDoc obj) {
1206        int slcomp = getStartLevel() - ((AbstractBundle) obj).getStartLevel();
1207        if (slcomp != 0) {
1208            return slcomp;
1209        }
1210        long idcomp = getBundleId() - ((AbstractBundle) obj).getBundleId();
1211        return (idcomp < 0L) ? -1 : ((idcomp > 0L) ? 1 : 0);
1212    }
1213
1214    /**
1215     * This method checks that the bundle is not uninstalled. If the bundle is
1216     * uninstalled, an IllegalStateException is thrown.
1217     *
1218     * @exception java.lang.IllegalStateException
1219     * If the bundle is uninstalled.
1220     */

1221    protected void checkValid() {
1222        if (state == UNINSTALLED) {
1223            throw new IllegalStateException JavaDoc(NLS.bind(Msg.BUNDLE_UNINSTALLED_EXCEPTION, getBundleData().getLocation()));
1224        }
1225    }
1226
1227    /**
1228     * Get the bundle's ProtectionDomain.
1229     *
1230     * @return bundle's ProtectionDomain.
1231     */

1232    protected BundleProtectionDomain getProtectionDomain() {
1233        return domain;
1234    }
1235
1236    /**
1237     * The bundle must unresolve the permissions.
1238     */

1239    protected void unresolvePermissions() {
1240        if (domain != null) {
1241            BundlePermissionCollection collection = (BundlePermissionCollection) domain.getPermissions();
1242            if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
1243                Debug.println("Unresolving permissions in bundle " + this); //$NON-NLS-1$
1244
}
1245            collection.unresolvePermissions();
1246        }
1247    }
1248
1249    protected Bundle[] getFragments() {
1250        checkValid();
1251        return null;
1252    }
1253
1254    protected boolean isFragment() {
1255        return false;
1256    }
1257
1258    protected BundleLoaderProxy[] getHosts() {
1259        checkValid();
1260        return null;
1261    }
1262
1263    /*
1264     * (non-Javadoc)
1265     *
1266     * @see org.osgi.framework.Bundle#findClass(java.lang.String)
1267     */

1268    public Class JavaDoc loadClass(String JavaDoc classname) throws ClassNotFoundException JavaDoc {
1269        return loadClass(classname, true);
1270    }
1271
1272    /*
1273     * (non-Javadoc)
1274     *
1275     * @see org.osgi.framework.Bundle#getResourcePaths(java.lang.String)
1276     */

1277    public Enumeration getEntryPaths(final String JavaDoc path) {
1278        try {
1279            framework.checkAdminPermission(this, AdminPermission.RESOURCE);
1280        } catch (SecurityException JavaDoc e) {
1281            return null;
1282        }
1283        checkValid();
1284        // TODO this doPrivileged is probably not needed. The adaptor isolates callers from disk access
1285
return (Enumeration) AccessController.doPrivileged(new PrivilegedAction() {
1286            public Object JavaDoc run() {
1287                return bundledata.getEntryPaths(path);
1288            }
1289        });
1290    }
1291
1292    /*
1293     * (non-Javadoc)
1294     *
1295     * @see org.osgi.framework.Bundle#getFile(java.lang.String)
1296     */

1297    public URL JavaDoc getEntry(String JavaDoc fileName) {
1298        try {
1299            framework.checkAdminPermission(this, AdminPermission.RESOURCE);
1300        } catch (SecurityException JavaDoc e) {
1301            return null;
1302        }
1303        checkValid();
1304        if (System.getSecurityManager() == null)
1305            return bundledata.getEntry(fileName);
1306        final String JavaDoc ffileName = fileName;
1307        // TODO this doPrivileged is probably not needed. The adaptor isolates callers from disk access
1308
return (URL JavaDoc) AccessController.doPrivileged(new PrivilegedAction() {
1309            public Object JavaDoc run() {
1310                return bundledata.getEntry(ffileName);
1311            }
1312        });
1313    }
1314
1315    public String JavaDoc getSymbolicName() {
1316        return bundledata.getSymbolicName();
1317    }
1318
1319    public long getLastModified() {
1320        return bundledata.getLastModified();
1321    }
1322
1323    public BundleData getBundleData() {
1324        return bundledata;
1325    }
1326
1327    public Version getVersion() {
1328        return bundledata.getVersion();
1329    }
1330
1331    protected BundleDescription getBundleDescription() {
1332        return framework.adaptor.getState().getBundle(getBundleId());
1333    }
1334
1335    protected int getStartLevel() {
1336        return bundledata.getStartLevel();
1337    }
1338
1339    protected abstract BundleLoader getBundleLoader();
1340
1341    /**
1342     * Mark this bundle as resolved.
1343     */

1344    protected void resolve() {
1345        if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
1346            if ((state & (INSTALLED)) == 0) {
1347                Debug.println("Bundle.resolve called when state != INSTALLED: " + this); //$NON-NLS-1$
1348
Debug.printStackTrace(new Exception JavaDoc("Stack trace")); //$NON-NLS-1$
1349
}
1350        }
1351        if (state == INSTALLED) {
1352            state = RESOLVED;
1353            // Do not publish RESOLVED event here. This is done by caller
1354
// to resolve if appropriate.
1355
}
1356    }
1357
1358    public BundleContext getBundleContext() {
1359        framework.checkAdminPermission(this, AdminPermission.CONTEXT);
1360        return getContext();
1361    }
1362
1363    /**
1364     * Return the current context for this bundle.
1365     *
1366     * @return BundleContext for this bundle.
1367     */

1368    abstract protected BundleContextImpl getContext();
1369
1370    public String JavaDoc getResolutionFailureMessage() {
1371        BundleDescription bundleDescription = getBundleDescription();
1372        if (bundleDescription == null)
1373            return Msg.BUNDLE_UNRESOLVED_EXCEPTION;
1374        // just a sanity check - this would be an inconsistency between the framework and the state
1375
if (bundleDescription.isResolved())
1376            throw new IllegalStateException JavaDoc(Msg.BUNDLE_UNRESOLVED_STATE_CONFLICT);
1377        return NLS.bind(Msg.BUNDLE_UNRESOLVED_UNSATISFIED_CONSTRAINT_EXCEPTION, getResolverError(bundleDescription));
1378    }
1379
1380    private String JavaDoc getResolverError(BundleDescription bundleDesc) {
1381        ResolverError[] errors = framework.adaptor.getState().getResolverErrors(bundleDesc);
1382        if (errors == null || errors.length == 0)
1383            return Msg.BUNDLE_UNRESOLVED_EXCEPTION;
1384        StringBuffer JavaDoc message = new StringBuffer JavaDoc();
1385        for (int i = 0; i < errors.length; i++) {
1386            message.append(errors[i].toString());
1387            if (i < errors.length - 1)
1388                message.append(", "); //$NON-NLS-1$
1389
}
1390        return message.toString();
1391    }
1392
1393    public int getKeyHashCode() {
1394        return (int) getBundleId();
1395    }
1396
1397    public boolean compare(KeyedElement other) {
1398        return getBundleId() == ((AbstractBundle) other).getBundleId();
1399    }
1400
1401    public Object JavaDoc getKey() {
1402        return new Long JavaDoc(getBundleId());
1403    }
1404
1405    /* This method is used by the Bundle Localization Service to obtain
1406     * a ResourceBundle that resides in a bundle. This is not an OSGi
1407     * defined method for org.osgi.framework.Bundle
1408     *
1409     */

1410    public ResourceBundle getResourceBundle(String JavaDoc localeString) {
1411        try {
1412            initializeManifestLocalization();
1413        } catch (BundleException ex) {
1414            return (null);
1415        }
1416        if (localeString == null) {
1417            localeString = Locale.getDefault().toString();
1418        }
1419        return manifestLocalization.getResourceBundle(localeString);
1420    }
1421
1422    private void initializeManifestLocalization() throws BundleException {
1423        if (manifestLocalization == null) {
1424            Dictionary rawHeaders;
1425            rawHeaders = bundledata.getManifest();
1426            manifestLocalization = new ManifestLocalization(this, rawHeaders);
1427        }
1428    }
1429
1430    public boolean testStateChanging(Object JavaDoc thread) {
1431        return stateChanging == thread;
1432    }
1433
1434    public Thread JavaDoc getStateChanging() {
1435        return stateChanging;
1436    }
1437
1438    public Enumeration findEntries(String JavaDoc path, String JavaDoc filePattern, boolean recurse) {
1439        try {
1440            framework.checkAdminPermission(this, AdminPermission.RESOURCE);
1441        } catch (SecurityException JavaDoc e) {
1442            return null;
1443        }
1444        checkValid();
1445        // check to see if the bundle is resolved
1446
if (!isResolved())
1447            framework.packageAdmin.resolveBundles(new Bundle[] {this});
1448
1449        // a list used to store the results of the search
1450
List pathList = new ArrayList();
1451        Filter patternFilter = null;
1452        Hashtable patternProps = null;
1453        if (filePattern != null)
1454            try {
1455                // create a file pattern filter with 'filename' as the key
1456
patternFilter = new FilterImpl("(filename=" + filePattern + ")"); //$NON-NLS-1$ //$NON-NLS-2$
1457
// create a single hashtable to be shared during the recursive search
1458
patternProps = new Hashtable(2);
1459            } catch (InvalidSyntaxException e) {
1460                // cannot happen
1461
}
1462        // find the local entries of this bundle
1463
findLocalEntryPaths(path, patternFilter, patternProps, recurse, pathList);
1464        // if this bundle is a host to fragments then search the fragments
1465
final Bundle[] fragments = getFragments();
1466        final int numFragments = fragments == null ? -1 : fragments.length;
1467        for (int i = 0; i < numFragments; i++)
1468            ((AbstractBundle) fragments[i]).findLocalEntryPaths(path, patternFilter, patternProps, recurse, pathList);
1469        // return null if no entries found
1470
if (pathList.size() == 0)
1471            return null;
1472        // create an enumeration to enumerate the pathList
1473
final String JavaDoc[] pathArray = (String JavaDoc[]) pathList.toArray(new String JavaDoc[pathList.size()]);
1474        return new Enumeration() {
1475            int curIndex = 0;
1476            int curFragment = -1;
1477            URL JavaDoc nextElement = null;
1478
1479            public boolean hasMoreElements() {
1480                if (nextElement != null)
1481                    return true;
1482                getNextElement();
1483                return nextElement != null;
1484            }
1485
1486            public Object JavaDoc nextElement() {
1487                if (!hasMoreElements())
1488                    throw new NoSuchElementException();
1489                URL JavaDoc result;
1490                result = nextElement;
1491                // force the next element search
1492
getNextElement();
1493                return result;
1494            }
1495
1496            private void getNextElement() {
1497                nextElement = null;
1498                if (curIndex >= pathArray.length)
1499                    // reached the end of the pathArray; no more elements
1500
return;
1501                String JavaDoc curPath = pathArray[curIndex];
1502                if (curFragment == -1) {
1503                    // need to search ourselves first
1504
nextElement = getEntry(curPath);
1505                    curFragment++;
1506                }
1507                // if the element is not in the host look in the fragments until we have searched them all
1508
while (nextElement == null && curFragment < numFragments)
1509                    nextElement = fragments[curFragment++].getEntry(curPath);
1510                // if we have no fragments or we have searched all fragments then advance to the next path
1511
if (numFragments == -1 || curFragment >= numFragments) {
1512                    curIndex++;
1513                    curFragment = -1;
1514                }
1515                // searched all fragments for the current path, move to the next one
1516
if (nextElement == null)
1517                    getNextElement();
1518            }
1519
1520        };
1521    }
1522
1523    protected void findLocalEntryPaths(String JavaDoc path, Filter patternFilter, Hashtable patternProps, boolean recurse, List pathList) {
1524        Enumeration entryPaths = bundledata.getEntryPaths(path);
1525        if (entryPaths == null)
1526            return;
1527        while (entryPaths.hasMoreElements()) {
1528            String JavaDoc entry = (String JavaDoc) entryPaths.nextElement();
1529            int lastSlash = entry.lastIndexOf('/');
1530            if (patternProps != null) {
1531                int secondToLastSlash = entry.lastIndexOf('/', lastSlash - 1);
1532                int fileStart;
1533                int fileEnd = entry.length();
1534                if (lastSlash < 0)
1535                    fileStart = 0;
1536                else if (lastSlash != entry.length() - 1)
1537                    fileStart = lastSlash + 1;
1538                else {
1539                    fileEnd = lastSlash; // leave the lastSlash out
1540
if (secondToLastSlash < 0)
1541                        fileStart = 0;
1542                    else
1543                        fileStart = secondToLastSlash + 1;
1544                }
1545                String JavaDoc fileName = entry.substring(fileStart, fileEnd);
1546                // set the filename to the current entry
1547
patternProps.put("filename", fileName); //$NON-NLS-1$
1548
}
1549            // prevent duplicates and match on the patterFilter
1550
if (!pathList.contains(entry) && (patternFilter == null || patternFilter.matchCase(patternProps)))
1551                pathList.add(entry);
1552            // rescurse only into entries that are directories
1553
if (recurse && !entry.equals(path) && entry.length() > 0 && lastSlash == (entry.length() - 1))
1554                findLocalEntryPaths(entry, patternFilter, patternProps, recurse, pathList);
1555        }
1556        return;
1557    }
1558
1559    class BundleStatusException extends Throwable JavaDoc implements StatusException {
1560        private static final long serialVersionUID = 7201911791818929100L;
1561        private int code;
1562        private Object JavaDoc status;
1563        BundleStatusException(String JavaDoc message, int code, Object JavaDoc status) {
1564            super(message);
1565            this.code = code;
1566            this.status = status;
1567        }
1568        public Object JavaDoc getStatus() {
1569            return status;
1570        }
1571        public int getStatusCode() {
1572            return code;
1573        }
1574        
1575    }
1576}
1577
Popular Tags