Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/eclipse/osgi/framework/internal/core/PackageAdminImpl.java


1   /*******************************************************************************
2    * Copyright (c) 2003, 2004 IBM Corporation and others.
3    * All rights reserved. This program and the accompanying materials 
4    * are made available under the terms of the Common Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/cpl-v10.html
7    * 
8    * Contributors:
9    *     IBM Corporation - initial API and implementation
10   *******************************************************************************/
11  
12  package org.eclipse.osgi.framework.internal.core;
13  
14  import java.io.IOException;
15  import java.util.*;
16  import org.eclipse.osgi.framework.debug.Debug;
17  import org.eclipse.osgi.framework.debug.DebugOptions;
18  import org.eclipse.osgi.framework.util.SecureAction;
19  import org.eclipse.osgi.service.resolver.*;
20  import org.osgi.framework.*;
21  import org.osgi.service.packageadmin.*;
22  
23  /**
24   * PackageAdmin service for the OSGi specification.
25   *
26   * Framework service which allows bundle programmers to inspect the packages
27   * exported in the framework and eagerly update or uninstall bundles.
28   *
29   * If present, there will only be a single instance of this service
30   * registered in the framework.
31   *
32   * <p> The term <i>exported package</i> (and the corresponding interface
33   * {@link ExportedPackage}) refers to a package that has actually been
34   * exported (as opposed to one that is available for export).
35   *
36   * <p> Note that the information about exported packages returned by this
37   * service is valid only until the next time {@link #refreshPackages(org.osgi.framework.Bundle[])} is
38   * called.
39   * If an ExportedPackage becomes stale, (that is, the package it references
40   * has been updated or removed as a result of calling
41   * PackageAdmin.refreshPackages()),
42   * its getName() and getSpecificationVersion() continue to return their
43   * old values, isRemovalPending() returns true, and getExportingBundle()
44   * and getImportingBundles() return null.
45   */
46  public class PackageAdminImpl implements PackageAdmin {
47  
48    /** framework object */
49    protected Framework framework;
50  
51    /** BundleLoaders that are pending removal. Value is BundleLoader */
52    protected Vector removalPending;
53  
54    protected KeyedHashSet exportedPackages;
55    protected KeyedHashSet exportedBundles;
56  
57    private long cumulativeTime;
58  
59    private static boolean checkServiceClassSource = true;
60    private static boolean restrictServiceClasses = false;
61  
62    /**
63     * Constructor.
64     *
65     * @param framework Framework object.
66     */
67    protected PackageAdminImpl(Framework framework) {
68      this.framework = framework;
69    }
70  
71    protected void initialize() {
72      checkServiceClassSource = Boolean.valueOf(System.getProperty(Constants.OSGI_CHECKSERVICECLASSSOURCE,"true")).booleanValue(); //$NON-NLS-1$
73      restrictServiceClasses = Boolean.valueOf(System.getProperty(Constants.OSGI_RESTRICTSERVICECLASSES,"false")).booleanValue(); //$NON-NLS-1$
74      removalPending = new Vector(10, 10);
75  
76      State state = framework.adaptor.getState();
77      if (!state.isResolved()) {
78        state.resolve(false);
79      }
80      exportedPackages = new KeyedHashSet(false);
81      exportedBundles = new KeyedHashSet(false);
82    }
83  
84    private KeyedHashSet getExportedPackages(KeyedHashSet packageSet) {
85      State state = framework.adaptor.getState();
86      PackageSpecification[] packageSpecs = state.getExportedPackages();
87  
88      for (int i = 0; i < packageSpecs.length; i++) {
89        BundleDescription bundleSpec = packageSpecs[i].getSupplier();
90        if (bundleSpec == null)
91          continue;
92        AbstractBundle bundle = framework.getBundle(bundleSpec.getBundleId());
93        if (bundle == null) {
94          BundleException be = new BundleException(Msg.formatter.getString("BUNDLE_NOT_IN_FRAMEWORK", bundleSpec)); //$NON-NLS-1$
95          framework.publishFrameworkEvent(FrameworkEvent.ERROR, framework.systemBundle, be);
96          continue;
97        }
98        // check export permissions before getting the host;
99        // we want to check the permissions of the fragment
100       if (!bundle.checkExportPackagePermission(packageSpecs[i].getName()))
101         continue;
102       // if we have a host then get the host bundle
103       HostSpecification hostSpec = bundleSpec.getHost();
104       if (hostSpec != null) {
105         bundleSpec = hostSpec.getSupplier();
106         if (bundleSpec == null)
107           continue;
108         bundle = framework.getBundle(bundleSpec.getBundleId());
109         if (bundle == null) {
110           BundleException be = new BundleException(Msg.formatter.getString("BUNDLE_NOT_IN_FRAMEWORK", bundleSpec)); //$NON-NLS-1$
111           framework.publishFrameworkEvent(FrameworkEvent.ERROR, framework.systemBundle, be);
112           continue;
113         }
114       }
115 
116       if (bundle.isResolved() && bundle instanceof BundleHost) {
117         ExportedPackageImpl packagesource = new ExportedPackageImpl(packageSpecs[i], ((BundleHost) bundle).getLoaderProxy());
118         packageSet.add(packagesource);
119       }
120     }
121     return packageSet;
122   }
123 
124   private KeyedHashSet getExportedBundles(KeyedHashSet bundleSet) {
125     State state = framework.adaptor.getState();
126     BundleDescription[] bundleDescripts = state.getResolvedBundles();
127     for (int i = 0; i < bundleDescripts.length; i++) {
128       BundleDescription bundledes = bundleDescripts[i];
129       AbstractBundle bundle = framework.getBundle(bundledes.getBundleId());
130       if (bundle != null && bundle.isResolved() && bundle.getSymbolicName() != null && bundle instanceof BundleHost && bundle.checkProvideBundlePermission(bundle.getSymbolicName())) {
131         BundleLoaderProxy loaderProxy = ((BundleHost) bundle).getLoaderProxy();
132         bundleSet.add(loaderProxy);
133       }
134     }
135     return bundleSet;
136   }
137 
138   protected void cleanup() { //This is only called when the framework is shutting down
139     removalPending = null;
140     exportedPackages = null;
141     exportedBundles = null;
142   }
143 
144   protected void addRemovalPending(BundleLoaderProxy loaderProxy) {
145     removalPending.addElement(loaderProxy);
146   }
147 
148   protected void deleteRemovalPending(BundleLoaderProxy loaderProxy) throws BundleException {
149 
150     boolean exporting = loaderProxy.inUse();
151     if (exporting) {
152       /* Reaching here is an internal error */
153       if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
154         Debug.println("BundleLoader.unexportPackager returned true! " + loaderProxy); //$NON-NLS-1$
155         Debug.printStackTrace(new Exception("Stack trace")); //$NON-NLS-1$
156       }
157       throw new BundleException(Msg.formatter.getString("OSGI_INTERNAL_ERROR")); //$NON-NLS-1$
158     }
159     unexportResources(loaderProxy);
160     BundleLoader loader = loaderProxy.getBundleLoader();
161     loader.clear();
162     loader.close();
163     removalPending.remove(loaderProxy);
164   }
165 
166   /**
167    * Gets the packages exported by the specified bundle.
168    *
169    * @param bundle The bundle whose exported packages are to be returned,
170    *               or <tt>null</tt> if all the packages currently
171    *               exported in the framework are to be returned.  If the
172    *               specified bundle is the system bundle (that is, the
173    *               bundle with id 0), this method returns all the packages
174    *               on the system classpath whose name does not start with
175    *               "java.".  In an environment where the exhaustive list
176    *               of packages on the system classpath is not known in
177    *               advance, this method will return all currently known
178    *               packages on the system classpath, that is, all packages
179    *               on the system classpath that contains one or more classes
180    *               that have been loaded.
181    *
182    * @return The array of packages exported by the specified bundle,
183    * or <tt>null</tt> if the specified bundle has not exported any packages.
184    */
185   public org.osgi.service.packageadmin.ExportedPackage[] getExportedPackages(org.osgi.framework.Bundle bundle) {
186     // need to make sure the dependacies are marked before this call.
187     synchronized (framework.bundles) {
188       framework.bundles.markDependancies();
189 
190       KeyedElement[] elements = exportedPackages.elements();
191       if (bundle != null) {
192         Vector result = new Vector();
193         for (int i = 0; i < elements.length; i++) {
194           ExportedPackageImpl pkgElement = (ExportedPackageImpl) elements[i];
195           if (pkgElement.supplier.getBundleHost() == bundle) {
196             result.add(pkgElement);
197           }
198         }
199         if (result.size() == 0) {
200           return null;
201         }
202         ExportedPackageImpl[] pkgElements = new ExportedPackageImpl[result.size()];
203         return (ExportedPackage[]) result.toArray(pkgElements);
204       } else {
205         if (elements.length == 0) {
206           return null;
207         }
208         ExportedPackageImpl[] pkgElements = new ExportedPackageImpl[elements.length];
209         System.arraycopy(elements, 0, pkgElements, 0, pkgElements.length);
210         return pkgElements;
211       }
212     }
213   }
214 
215   /**
216    * Gets the ExportedPackage with the specified package name.  All exported
217    * packages
218    * will be checked for the specified name.  In an environment where the
219    * exhaustive list of packages on the system classpath is not known in
220    * advance, this method attempts to see if the named package is on the
221    * system classpath.
222    * This
223    * means that this method may discover an ExportedPackage that was
224    * not present in the list returned by <tt>getExportedPackages()</tt>.
225    *
226    * @param packageName The name of the exported package to be returned.
227    *
228    * @return The exported package with the specified name, or <tt>null</tt>
229    *         if no expored package with that name exists.
230    */
231   public org.osgi.service.packageadmin.ExportedPackage getExportedPackage(String packageName) {
232     // need to make sure the dependacies are marked before this call.
233     synchronized (framework.bundles) {
234       framework.bundles.markDependancies();
235       return (ExportedPackageImpl) exportedPackages.getByKey(packageName);
236     }
237   }
238 
239   /**
240    * Forces the update (replacement) or removal of packages exported by
241    * the specified bundles.
242    *
243    * <p> If no bundles are specified, this method will update or remove any
244    * packages exported by any bundles that were previously updated or
245    * uninstalled. The technique by which this is accomplished
246    * may vary among different framework implementations. One permissible
247    * implementation is to stop and restart the Framework.
248    *
249    * <p> This method returns to the caller immediately and then performs the
250    * following steps in its own thread:
251    *
252    * <ol>
253    * <p>
254    * <li> Compute a graph of bundles starting with the specified ones. If no
255    * bundles are specified, compute a graph of bundles starting with
256    * previously updated or uninstalled ones.
257    * Any bundle that imports a package that is currently exported
258    * by a bundle in the graph is added to the graph. The graph is fully
259    * constructed when there is no bundle outside the graph that imports a
260    * package from a bundle in the graph. The graph may contain
261    * <tt>UNINSTALLED</tt> bundles that are currently still
262    * exporting packages.
263    *
264    * <p>
265    * <li> Each bundle in the graph will be stopped as described in the
266    * <tt>Bundle.stop</tt> method.
267    *
268    * <p>
269    * <li> Each bundle in the graph that is in the
270    * <tt>RESOLVED</tt> state is moved
271    * to the <tt>INSTALLED</tt> state.
272    * The effect of this step is that bundles in the graph are no longer
273    * <tt>RESOLVED</tt>.
274    *
275    * <p>
276    * <li> Each bundle in the graph that is in the UNINSTALLED state is
277    * removed from the graph and is now completely removed from the framework.
278    *
279    * <p>
280    * <li> Each bundle in the graph that was in the
281    * <tt>ACTIVE</tt> state prior to Step 2 is started as
282    * described in the <tt>Bundle.start</tt> method, causing all
283    * bundles required for the restart to be resolved.
284    * It is possible that, as a
285    * result of the previous steps, packages that were
286    * previously exported no longer are. Therefore, some bundles
287    * may be unresolvable until another bundle
288    * offering a compatible package for export has been installed in the
289    * framework.
290    * </ol>
291    *
292    * <p> For any exceptions that are thrown during any of these steps, a
293    * <tt>FrameworkEvent</tt> of type <tt>ERROR</tt> is
294    * broadcast, containing the exception.
295    *
296    * @param input the bundles whose exported packages are to be updated or
297    * removed,
298    * or <tt>null</tt> for all previously updated or uninstalled bundles.
299    *
300    * @exception SecurityException if the caller does not have the
301    * <tt>AdminPermission</tt> and the Java runtime environment supports
302    * permissions.
303    */
304   public void refreshPackages(org.osgi.framework.Bundle[] input) {
305     framework.checkAdminPermission();
306 
307     AbstractBundle[] copy = null;
308     if (input != null) {
309       synchronized (input) {
310         int size = input.length;
311 
312         copy = new AbstractBundle[size];
313 
314         System.arraycopy(input, 0, copy, 0, size);
315       }
316     }
317 
318     final AbstractBundle[] bundles = copy;
319     Thread refresh = SecureAction.createThread(new Runnable() {
320       public void run() {
321         refreshPackages(bundles);
322       }
323     }, "Refresh Packages"); //$NON-NLS-1$
324 
325     refresh.start();
326   }
327 
328   /**
329    * Worker routine called on a seperate thread to perform the actual work.
330    *
331    * @param refresh the list of bundles to refresh 
332    */
333   protected void refreshPackages(AbstractBundle[] refresh) {
334     try {
335       Vector graph = null;
336       synchronized (framework.bundles) {
337         if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
338           Debug.println("refreshPackages: Initialize graph"); //$NON-NLS-1$
339         }
340         // make sure the dependencies are marked first
341         framework.bundles.markDependancies();
342 
343         graph = computeAffectedBundles(refresh);
344 
345         // get the state.
346         State state = framework.adaptor.getState();
347         // resolve the state.
348         state.resolve(false);
349 
350         // process the delta.  This will set the state of all
351         // the bundles in the graph.
352         processDelta(graph);
353       }
354       /*
355        * Resume the suspended bundles outside of the synchronization block.
356        * This will cause the bundles to be resolved using the most up-to-date
357        * generations of the bundles.
358        */
359       resumeBundles(graph);
360 
361     } finally {
362       framework.publishFrameworkEvent(FrameworkEvent.PACKAGES_REFRESHED, framework.systemBundle, null);
363     }
364 
365   }
366 
367   private void resumeBundles(Vector graph) {
368 
369     AbstractBundle[] refresh = new AbstractBundle[graph.size()];
370     boolean[] previouslyResolved = new boolean[graph.size()];
371     graph.copyInto(refresh);
372     Util.sort(refresh, 0, graph.size());
373     if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
374       Debug.println("refreshPackages: restart the bundles"); //$NON-NLS-1$
375     }
376     for (int i = 0; i < refresh.length; i++) {
377       AbstractBundle bundle = (AbstractBundle) refresh[i];
378       if (bundle.isResolved())
379         framework.resumeBundle(bundle);
380     }
381   }
382 
383   private void processDelta(Vector graph) {
384     AbstractBundle[] refresh = new AbstractBundle[graph.size()];
385     boolean[] previouslyResolved = new boolean[graph.size()];
386     graph.copyInto(refresh);
387     Util.sort(refresh, 0, graph.size());
388 
389     Vector notify = new Vector();
390     try {
391       try {
392         /*
393          * Suspend each bundle and grab its state change lock.
394          */
395         if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
396           Debug.println("refreshPackages: Suspend each bundle and acquire its state change lock"); //$NON-NLS-1$
397         }
398         for (int i = refresh.length - 1; i >= 0; i--) {
399           AbstractBundle changedBundle = refresh[i];
400           previouslyResolved[i] = changedBundle.isResolved();
401           if (changedBundle.isActive() && !changedBundle.isFragment()) {
402             boolean suspended = framework.suspendBundle(changedBundle, true);
403             if (!suspended) {
404               throw new BundleException(Msg.formatter.getString("BUNDLE_STATE_CHANGE_EXCEPTION")); //$NON-NLS-1$
405             }
406           } else {
407             changedBundle.beginStateChange();
408           }
409 
410           if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
411             if (changedBundle.stateChanging == null) {
412               Debug.println("Bundle state change lock is clear! " + changedBundle); //$NON-NLS-1$
413               Debug.printStackTrace(new Exception("Stack trace")); //$NON-NLS-1$
414             }
415           }
416         }
417         /*
418          * Refresh the bundles which will unexport the packages.
419          * This will move RESOLVED bundles to the INSTALLED state.
420          */
421         if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
422           Debug.println("refreshPackages: refresh the bundles"); //$NON-NLS-1$
423         }
424         /*
425          * Unimport detached BundleLoaders for bundles in the graph.
426          */
427         for (int i = removalPending.size() - 1; i >= 0; i--) {
428           BundleLoaderProxy loaderProxy = (BundleLoaderProxy) removalPending.elementAt(i);
429 
430           if (graph.contains(loaderProxy.getBundleHost())) {
431             framework.bundles.unMarkDependancies(loaderProxy);
432           }
433         }
434 
435         for (int i = 0; i < refresh.length; i++) {
436           AbstractBundle changedBundle = refresh[i];
437           changedBundle.refresh();
438           // send out unresolved events
439           if (previouslyResolved[i])
440             framework.publishBundleEvent(BundleEvent.UNRESOLVED, changedBundle);
441         }
442 
443         /*
444          * Cleanup detached BundleLoaders for bundles in the graph.
445          */
446         if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
447           Debug.println("refreshPackages: unexport the removal pending packages"); //$NON-NLS-1$
448         }
449         for (int i = removalPending.size() - 1; i >= 0; i--) {
450           BundleLoaderProxy loaderProxy = (BundleLoaderProxy) removalPending.elementAt(i);
451           AbstractBundle removedBundle = loaderProxy.getBundleHost();
452 
453           if (graph.contains(removedBundle)) {
454             deleteRemovalPending(loaderProxy);
455           }
456         }
457 
458         // set the resolved bundles state
459         List allBundles = framework.bundles.getBundles();
460         int size = allBundles.size();
461         for (int i = 0; i < size; i++) {
462           AbstractBundle bundle = (AbstractBundle) allBundles.get(i);
463           if (bundle.isResolved())
464             continue;
465           BundleDescription bundleDes = bundle.getBundleDescription();
466           if (bundleDes != null) {
467             if (bundleDes.isResolved()) {
468               if (bundle.isFragment()) {
469                 BundleHost host = (BundleHost) framework.getBundle(bundleDes.getHost().getSupplier().getBundleId());
470                 if (((BundleFragment) bundle).setHost(host)) {
471                   bundle.resolve(bundleDes.isSingleton());
472                 }
473               } else {
474                 bundle.resolve(bundleDes.isSingleton());
475               }
476               if (bundle.isResolved()) {
477                 notify.addElement(bundle);
478               }
479             }
480           }
481         }
482 
483         // update the exported package and bundle lists.
484         exportedPackages = getExportedPackages(exportedPackages);
485         exportedBundles = getExportedBundles(exportedBundles);
486       } finally {
487         /*
488          * Release the state change locks.
489          */
490         if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
491           Debug.println("refreshPackages: release the state change locks"); //$NON-NLS-1$
492         }
493         for (int i = 0; i < refresh.length; i++) {
494           AbstractBundle changedBundle = refresh[i];
495           changedBundle.completeStateChange();
496         }
497       }
498       /*
499        * Take this opportunity to clean up the adaptor storage.
500        */
501       if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
502         Debug.println("refreshPackages: clean up adaptor storage"); //$NON-NLS-1$
503       }
504       try {
505         framework.adaptor.compactStorage();
506       } catch (IOException e) {
507         if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
508           Debug.println("refreshPackages exception: " + e.getMessage()); //$NON-NLS-1$
509           Debug.printStackTrace(e);
510         }
511         framework.publishFrameworkEvent(FrameworkEvent.ERROR, framework.systemBundle, new BundleException(Msg.formatter.getString("BUNDLE_REFRESH_FAILURE"), e)); //$NON-NLS-1$
512       }
513     } catch (BundleException e) {
514       if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
515         Debug.println("refreshPackages exception: " + e.getMessage()); //$NON-NLS-1$
516         Debug.printStackTrace(e.getNestedException());
517       }
518       framework.publishFrameworkEvent(FrameworkEvent.ERROR, framework.systemBundle, new BundleException(Msg.formatter.getString("BUNDLE_REFRESH_FAILURE"), e)); //$NON-NLS-1$
519     }
520 
521     // send out any resolved/unresolved events
522     for (int i = 0; i < notify.size(); i++) {
523       AbstractBundle changedBundle = (AbstractBundle) notify.elementAt(i);
524       framework.publishBundleEvent(changedBundle.isResolved() ? BundleEvent.RESOLVED : BundleEvent.UNRESOLVED, changedBundle);
525     }
526 
527   }
528 
529   private void unresolvePermissions(Vector bundles, Hashtable packages) {
530     /*
531      * All bundles must be notified of the unexported packages so that
532      * they may unresolve permissions if necessary.
533      * This done after resolve bundles so that unresolved permissions
534      * can be immediately resolved.
535      */
536     if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
537       Debug.println("refreshPackages: unresolve permissions"); //$NON-NLS-1$
538     }
539     int size = bundles.size();
540     for (int i = 0; i < size; i++) {
541       AbstractBundle bundle = (AbstractBundle) bundles.elementAt(i);
542       bundle.unresolvePermissions(packages);
543     }
544   }
545 
546   private Vector computeAffectedBundles(AbstractBundle[] refresh) {
547     Vector graph = new Vector();
548 
549     if (refresh == null) {
550       int size = removalPending.size();
551       for (int i = 0; i < size; i++) {
552         BundleLoaderProxy loaderProxy = (BundleLoaderProxy) removalPending.elementAt(i);
553         AbstractBundle bundle = loaderProxy.getBundleHost();
554         if (!graph.contains(bundle)) {
555           if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
556             Debug.println(" refresh: " + bundle); //$NON-NLS-1$
557           }
558           graph.addElement(bundle);
559 
560           // add in any dependents of the removal pending loader.
561           AbstractBundle[] dependents = loaderProxy.getDependentBundles();
562           for (int j = 0; j < dependents.length; j++) {
563             if (!graph.contains(dependents[j])) {
564               graph.addElement(dependents[j]);
565             }
566           }
567         }
568       }
569     } else {
570       for (int i = 0; i < refresh.length; i++) {
571         AbstractBundle bundle = refresh[i];
572         if (bundle == framework.systemBundle) {
573           continue;
574         }
575         if (bundle.isFragment()) {
576           // if it is a fragment then put the host in the graph
577           BundleHost host = (BundleHost) bundle.getHost();
578           if (host != null) {
579             if (!graph.contains(host)) {
580               graph.addElement(host);
581             }
582           }
583         }
584 
585         if (!graph.contains(bundle)) {
586           if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
587             Debug.println(" refresh: " + bundle); //$NON-NLS-1$
588           }
589           graph.addElement(bundle);
590         }
591       }
592     }
593 
594     /*
595      * If there is nothing to do, then return.
596      */
597     if (graph.size() == 0) {
598       if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
599         Debug.println("refreshPackages: Empty graph"); //$NON-NLS-1$
600       }
601 
602       return graph;
603     }
604 
605     /*
606      * Complete graph.
607      */
608     if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
609       Debug.println("refreshPackages: Complete graph"); //$NON-NLS-1$
610     }
611 
612     boolean changed;
613     do {
614       changed = false;
615       int size = graph.size();
616       for (int i = size - 1; i >= 0; i--) {
617         AbstractBundle bundle = (AbstractBundle) graph.elementAt(i);
618         if (!bundle.isFragment()) {
619           BundleLoaderProxy loaderProxy = ((BundleHost) bundle).getLoaderProxy();
620           if (loaderProxy != null) {
621             // add any dependents
622             AbstractBundle[] dependents = loaderProxy.getDependentBundles();
623             for (int j = 0; j < dependents.length; j++) {
624               if (!graph.contains(dependents[j])) {
625                 graph.addElement(dependents[j]);
626                 changed = true;
627               }
628             }
629           }
630           // add in any fragments
631           org.osgi.framework.Bundle[] frags = bundle.getFragments();
632           if (frags != null) {
633             for (int j = 0; j < frags.length; j++) {
634               if (!graph.contains(frags[j])) {
635                 graph.addElement(frags[j]);
636                 changed = true;
637               }
638             }
639           }
640         } else {
641           // add in the host.
642           AbstractBundle host = (AbstractBundle) bundle.getHost();
643           if (host != null) {
644             if (!graph.contains(host)) {
645               graph.addElement(host);
646               changed = true;
647             }
648           }
649         }
650         // add in any singleton bundles if needed
651         AbstractBundle[] sameNames = framework.bundles.getBundles(bundle.getSymbolicName());
652         if (sameNames != null && sameNames.length > 1) {
653           for (int j = 0; j < sameNames.length; j++)
654             if (sameNames[j] != bundle && sameNames[j].isSingleton() && !graph.contains(sameNames[j])) {
655               graph.addElement(sameNames[j]);
656               changed = true;
657             }
658         }
659       }
660 
661       // look for the bundles in removalPending list
662       // we always add removalPending dependants here even if
663       // the removalpending bundle was not in the original list
664       for (int i = removalPending.size() - 1; i >= 0; i--) {
665         BundleLoaderProxy removedLoaderProxy = (BundleLoaderProxy) removalPending.elementAt(i);
666         AbstractBundle removedBundle = removedLoaderProxy.getBundleHost();
667         if (!graph.contains(removedBundle)) {
668           graph.addElement(removedBundle);
669           changed = true;
670         }
671         AbstractBundle[] dependents = removedLoaderProxy.getDependentBundles();
672         for (int k = 0; k < dependents.length; k++) {
673           if (!graph.contains(dependents[k])) {
674             graph.addElement(dependents[k]);
675             changed = true;
676           }
677         }
678       }
679     } while (changed);
680 
681     return graph;
682   }
683 
684   /**
685    * Sets all the bundles in the state that are resolved to the resolved
686    * state.  This should only be called when the framework is launching.
687    *
688    */
689   protected void setResolvedBundles() {
690     State state = framework.adaptor.getState();
691     BundleDescription[] descriptions = state.getBundles();
692     for (int i = 0; i < descriptions.length; i++) {
693       long bundleId = descriptions[i].getBundleId();
694       AbstractBundle bundle = framework.getBundle(bundleId);
695       if (bundle == null) {
696         BundleException be = new BundleException(Msg.formatter.getString("BUNDLE_NOT_IN_FRAMEWORK", descriptions[i])); //$NON-NLS-1$
697         framework.publishFrameworkEvent(FrameworkEvent.ERROR, framework.systemBundle, be);
698       }
699       if (bundle != framework.systemBundle) {
700         if (descriptions[i].isResolved()) {
701           if (bundle.isFragment()) {
702             BundleHost host = (BundleHost) framework.getBundle(descriptions[i].getHost().getSupplier().getBundleId());
703             if (((BundleFragment) bundle).setHost(host)) {
704               bundle.resolve(descriptions[i].isSingleton());
705             }
706           } else {
707             bundle.resolve(descriptions[i].isSingleton());
708           }
709         }
710       }
711     }
712     exportedPackages = getExportedPackages(exportedPackages);
713     exportedBundles = getExportedBundles(exportedBundles);
714   }
715 
716   /**
717    * A permissible implementation of this method is to attempt to 
718    * resolve all unresolved bundles installed in the framework.
719    * That is what this method does.
720    * @param bundles the set of bundles to attempt to resolve.
721    */
722   public boolean resolveBundles(org.osgi.framework.Bundle[] bundles) {
723     resolveBundles();
724     if (bundles == null)
725       synchronized (framework.bundles) {
726         List bundleList = framework.bundles.getBundles();
727         bundles = (Bundle[]) bundleList.toArray(new AbstractBundle[bundleList.size()]);
728       }
729     for (int i = 0; i < bundles.length; i++)
730       if (!((AbstractBundle) bundles[i]).isResolved())
731         return false;
732 
733     return true;
734   }
735 
736   /**
737    * Attempt to resolve all unresolved bundles. When this method returns
738    * all bundles are resolved that can be resolved. A resolved bundle
739    * has exported and imported packages. An unresolved bundle neither
740    * exports nor imports packages.
741    *
742    */
743   protected void resolveBundles() {
744     long start = 0;
745     if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN_TIMING)
746       start = System.currentTimeMillis();
747     /*
748      * Resolve the bundles. This will make there exported packages available.
749      */
750     if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
751       Debug.println("refreshBundles: resolve bundles"); //$NON-NLS-1$
752     }
753 
754     Vector notify = new Vector();
755     synchronized (framework.bundles) {
756       boolean resolveNeeded = false;
757       List allBundles = framework.bundles.getBundles();
758       int size = allBundles.size();
759 
760       // first check to see if there is anything to resolve
761       for (int i = 0; i < size; i++) {
762         if (!((AbstractBundle) allBundles.get(i)).isResolved())
763           resolveNeeded = true;
764       }
765       if (!resolveNeeded)
766         return;
767 
768       // get the state and resolve it.
769       framework.adaptor.getState().resolve(false);
770       for (int i = 0; i < size; i++) {
771         AbstractBundle bundle = (AbstractBundle) allBundles.get(i);
772         if (bundle.isResolved() || bundle == framework.systemBundle)
773           continue;
774 
775         BundleDescription changedBundleDes = bundle.getBundleDescription();
776         if (changedBundleDes == null) {
777           framework.publishFrameworkEvent(FrameworkEvent.ERROR, bundle, new BundleException(Msg.formatter.getString("BUNDLE_NOT_IN_STATE", bundle.getLocation()))); //$NON-NLS-1$
778         }
779 
780         if (changedBundleDes.isResolved()) {
781           if (bundle.isFragment()) {
782             BundleHost host = (BundleHost) framework.getBundle(changedBundleDes.getHost().getSupplier().getBundleId());
783             if (((BundleFragment) bundle).setHost(host)) {
784               bundle.resolve(changedBundleDes.isSingleton());
785             }
786           } else {
787             bundle.resolve(changedBundleDes.isSingleton());
788           }
789           if (bundle.isResolved()) {
790             notify.add(bundle);
791           }
792         }
793       }
794 
795       // update the exported package and bundle lists.
796       exportedPackages = getExportedPackages(exportedPackages);
797       exportedBundles = getExportedBundles(exportedBundles);
798     }
799     for (int i = 0; i < notify.size(); i++) {
800       AbstractBundle bundle = (AbstractBundle) notify.elementAt(i);
801       if (bundle != null) {
802         framework.publishBundleEvent(bundle.isResolved() ? BundleEvent.RESOLVED : BundleEvent.UNRESOLVED, bundle);
803       }
804     }
805     if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN_TIMING) {
806       cumulativeTime = cumulativeTime + System.currentTimeMillis() - start;
807       DebugOptions.getDefault().setOption(Debug.OPTION_DEBUG_PACKAGEADMIN_TIMING + "/value", Long.toString(cumulativeTime)); //$NON-NLS-1$
808     }
809   }
810 
811   protected void unexportResources(BundleLoaderProxy proxy) {
812     KeyedElement[] bundles = exportedBundles.elements();
813     for (int i = 0; i < bundles.length; i++) {
814       BundleLoaderProxy loaderProxy = (BundleLoaderProxy) bundles[i];
815       if (loaderProxy == proxy) {
816         exportedBundles.remove(proxy);
817       }
818     }
819 
820     KeyedElement[] packages = exportedPackages.elements();
821     for (int i = 0; i < packages.length; i++) {
822       PackageSource source = (PackageSource) packages[i];
823       BundleLoaderProxy sourceProxy = source.getSupplier();
824       if (sourceProxy == proxy) {
825         exportedPackages.remove(source);
826       }
827     }
828     // make the proxy stale
829     proxy.setStale();
830   }
831 
832   protected BundleDescription[] getBundleDescriptions(Vector graph) {
833     ArrayList result = new ArrayList();
834     int size = graph.size();
835     for (int i = 0; i < size; i++) {
836       AbstractBundle bundle = (AbstractBundle) graph.elementAt(i);
837       BundleDescription bundleDes = bundle.getBundleDescription();
838       if (bundleDes != null) {
839         result.add(bundleDes);
840       }
841     }
842     return (BundleDescription[]) result.toArray(new BundleDescription[result.size()]);
843   }
844 
845   public ProvidingBundle[] getProvidingBundles(String symbolicName) {
846     if (exportedBundles == null || exportedBundles.size() == 0)
847       return null;
848 
849     // need to make sure the dependacies are marked before this call.
850     framework.bundles.markDependancies();
851 
852     KeyedElement[] allSymbolicBundles = exportedBundles.elements();
853     if (symbolicName == null) {
854       if (allSymbolicBundles.length == 0) {
855         return null;
856       }
857       ProvidingBundle[] result = new ProvidingBundle[allSymbolicBundles.length];
858       System.arraycopy(allSymbolicBundles, 0, result, 0, result.length);
859       return result;
860     } else {
861       ArrayList result = new ArrayList();
862       for (int i = 0; i < allSymbolicBundles.length; i++) {
863         ProvidingBundle symBundle = (ProvidingBundle) allSymbolicBundles[i];
864         if (symBundle.getSymbolicName().equals(symbolicName))
865           result.add(symBundle);
866       }
867       return (ProvidingBundle[]) result.toArray(new ProvidingBundle[result.size()]);
868     }
869   }
870 
871   public org.osgi.framework.Bundle[] getBundles(String symbolicName, String versionRange) {
872     if (symbolicName == null) {
873       throw new IllegalArgumentException();
874     }
875     AbstractBundle bundles[] = framework.getBundleBySymbolicName(symbolicName);
876     if (bundles == null)
877       return null;
878 
879     if (versionRange == null) {
880       AbstractBundle[] result = new AbstractBundle[bundles.length];
881       System.arraycopy(bundles, 0, result, 0, result.length);
882       return result;
883     }
884 
885     // This code depends on the array of bundles being in descending
886     // version order.
887     ArrayList result = new ArrayList(bundles.length);
888     VersionRange range = new VersionRange(versionRange);
889     for (int i = 0; i < bundles.length; i++) {
890       if (range.isIncluded(bundles[i].getVersion())) {
891         result.add(bundles[i]);
892       }
893     }
894 
895     if (result.size() == 0)
896       return null;
897     else
898       return (AbstractBundle[]) result.toArray(new AbstractBundle[result.size()]);
899 
900   }
901 
902   public org.osgi.framework.Bundle[] getFragments(org.osgi.framework.Bundle bundle) {
903     return ((AbstractBundle) bundle).getFragments();
904   }
905 
906   public org.osgi.framework.Bundle[] getHosts(org.osgi.framework.Bundle bundle) {
907     org.osgi.framework.Bundle host = ((AbstractBundle) bundle).getHost();
908     if (host == null)
909       return null;
910     else
911       return new org.osgi.framework.Bundle[] {host};
912   }
913 
914   public int getBundleType(org.osgi.framework.Bundle bundle) {
915     return ((AbstractBundle) bundle).isFragment() ? PackageAdminImpl.BUNDLE_TYPE_FRAGMENT : 0;
916   }
917 
918   protected Class loadServiceClass(String className, AbstractBundle bundle) {
919     try {
920       // first try the PARENT class space
921       return framework.adaptor.getBundleClassLoaderParent().loadClass(className);
922     } catch (ClassNotFoundException e) {
923       // do nothing; try exported packages
924     }
925     // try exported packages; SERVICE class space
926     String pkgname = BundleLoader.getPackageName(className);
927     if (pkgname != null) {
928       PackageSource exporter = (PackageSource) exportedPackages.getByKey(pkgname);
929       if (exporter != null) {
930         Class serviceClass = exporter.getSupplier().getBundleLoader().findLocalClass(className);
931         if (serviceClass != null)
932           return serviceClass;
933       }
934     }
935     // try bundle's PRIVATE class space
936     if (bundle == null)
937       return null;
938     BundleLoader loader = bundle.getBundleLoader();
939     if (!checkServiceClassSource) {
940       try {
941         return loader.findClass(className);
942       } catch (ClassNotFoundException e1) {
943         return null;
944       }
945     }
946     if (restrictServiceClasses) {
947       // cannot have a service class from a package that a bundle 
948       // provides to a NAMED class space (unless it is exported also).
949       if (pkgname == null)
950         pkgname = BundleLoader.DEFAULT_PACKAGE;
951       if (loader.getProvidedPackage(pkgname) != null)
952         return null;
953     }
954     Class  serviceClass = loader.findLocalClass(className);
955     if (serviceClass == null || bundle.getBundleId() == 0)
956       return serviceClass;
957     return serviceClass.getClassLoader() == loader.createClassLoader() ? serviceClass : null;
958   }
959 }