blob: bf617c3c5c96db6f644d3f3dfe1a6175fdde02aa [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.osgi.framework.internal.core;
import java.io.IOException;
import java.util.*;
import org.eclipse.osgi.framework.debug.Debug;
import org.eclipse.osgi.framework.debug.DebugOptions;
import org.eclipse.osgi.framework.util.SecureAction;
import org.eclipse.osgi.service.resolver.*;
import org.osgi.framework.*;
import org.osgi.service.packageadmin.*;
import org.osgi.service.packageadmin.ExportedPackage;
import org.osgi.service.packageadmin.NamedClassSpace;
/**
* PackageAdmin service for the OSGi specification.
*
* Framework service which allows bundle programmers to inspect the packages
* exported in the framework and eagerly update or uninstall bundles.
*
* If present, there will only be a single instance of this service
* registered in the framework.
*
* <p> The term <i>exported package</i> (and the corresponding interface
* {@link ExportedPackage}) refers to a package that has actually been
* exported (as opposed to one that is available for export).
*
* <p> Note that the information about exported packages returned by this
* service is valid only until the next time {@link #refreshPackages} is
* called.
* If an ExportedPackage becomes stale, (that is, the package it references
* has been updated or removed as a result of calling
* PackageAdmin.refreshPackages()),
* its getName() and getSpecificationVersion() continue to return their
* old values, isRemovalPending() returns true, and getExportingBundle()
* and getImportingBundles() return null.
*/
public class PackageAdminImpl implements PackageAdmin {
/** framework object */
protected Framework framework;
/** BundleLoaders that are pending removal. Value is BundleLoader */
protected Vector removalPending;
protected KeyedHashSet exportedPackages;
protected KeyedHashSet exportedBundles;
private long cumulativeTime;
private static boolean restrictServiceClasses = false;
/**
* Constructor.
*
* @param framework Framework object.
*/
protected PackageAdminImpl(Framework framework) {
this.framework = framework;
}
protected void initialize() {
restrictServiceClasses = System.getProperty(Constants.OSGI_RESTRICTSERVICECLASSES) != null;
removalPending = new Vector(10, 10);
State state = framework.adaptor.getState();
if (!state.isResolved()) {
state.resolve(false);
}
exportedPackages = new KeyedHashSet(false);
exportedBundles = new KeyedHashSet(false);
}
private KeyedHashSet getExportedPackages(KeyedHashSet packageSet) {
State state = framework.adaptor.getState();
PackageSpecification[] packageSpecs = state.getExportedPackages();
for (int i = 0; i < packageSpecs.length; i++) {
BundleDescription bundleSpec = packageSpecs[i].getSupplier();
if (bundleSpec == null)
continue;
AbstractBundle bundle = framework.getBundle(bundleSpec.getBundleId());
if (bundle == null) {
BundleException be = new BundleException(Msg.formatter.getString("BUNDLE_NOT_IN_FRAMEWORK",bundleSpec)); //$NON-NLS-1$
framework.publishFrameworkEvent(FrameworkEvent.ERROR,framework.systemBundle,be);
continue;
}
// check export permissions before getting the host;
// we want to check the permissions of the fragment
if (!bundle.checkExportPackagePermission(packageSpecs[i].getName()))
continue;
// if we have a host then get the host bundle
HostSpecification hostSpec = bundleSpec.getHost();
if (hostSpec != null) {
bundleSpec = hostSpec.getSupplier();
if (bundleSpec == null)
continue;
bundle = framework.getBundle(bundleSpec.getBundleId());
if (bundle == null) {
BundleException be = new BundleException(Msg.formatter.getString("BUNDLE_NOT_IN_FRAMEWORK",bundleSpec)); //$NON-NLS-1$
framework.publishFrameworkEvent(FrameworkEvent.ERROR,framework.systemBundle,be);
continue;
}
}
if (bundle.isResolved() && bundle instanceof BundleHost) {
ExportedPackageImpl packagesource = new ExportedPackageImpl(packageSpecs[i], ((BundleHost) bundle).getLoaderProxy());
packageSet.add(packagesource);
}
}
return packageSet;
}
private KeyedHashSet getExportedBundles(KeyedHashSet bundleSet) {
State state = framework.adaptor.getState();
BundleDescription[] bundleDescripts = state.getResolvedBundles();
for (int i = 0; i < bundleDescripts.length; i++) {
BundleDescription bundledes = bundleDescripts[i];
AbstractBundle bundle = framework.getBundle(bundledes.getBundleId());
if (bundle != null && bundle.isResolved() && bundle.getSymbolicName() != null && bundle instanceof BundleHost && bundle.checkProvideBundlePermission(bundle.getSymbolicName())) {
BundleLoaderProxy loaderProxy = ((BundleHost) bundle).getLoaderProxy();
bundleSet.add(loaderProxy);
}
}
return bundleSet;
}
protected void cleanup() { //This is only called when the framework is shutting down
removalPending = null;
exportedPackages = null;
exportedBundles = null;
}
protected void addRemovalPending(BundleLoaderProxy loaderProxy) {
removalPending.addElement(loaderProxy);
}
protected void deleteRemovalPending(BundleLoaderProxy loaderProxy) throws BundleException {
boolean exporting = loaderProxy.inUse();
if (exporting) {
/* Reaching here is an internal error */
if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
Debug.println("BundleLoader.unexportPackager returned true! " + loaderProxy);
Debug.printStackTrace(new Exception("Stack trace"));
}
throw new BundleException(Msg.formatter.getString("OSGI_INTERNAL_ERROR")); //$NON-NLS-1$
}
unexportResources(loaderProxy);
BundleLoader loader = loaderProxy.getBundleLoader();
loader.clear();
loader.close();
removalPending.remove(loaderProxy);
}
/**
* Gets the packages exported by the specified bundle.
*
* @param bundle The bundle whose exported packages are to be returned,
* or <tt>null</tt> if all the packages currently
* exported in the framework are to be returned. If the
* specified bundle is the system bundle (that is, the
* bundle with id 0), this method returns all the packages
* on the system classpath whose name does not start with
* "java.". In an environment where the exhaustive list
* of packages on the system classpath is not known in
* advance, this method will return all currently known
* packages on the system classpath, that is, all packages
* on the system classpath that contains one or more classes
* that have been loaded.
*
* @return The array of packages exported by the specified bundle,
* or <tt>null</tt> if the specified bundle has not exported any packages.
*/
public org.osgi.service.packageadmin.ExportedPackage[] getExportedPackages(org.osgi.framework.Bundle bundle) {
// need to make sure the dependacies are marked before this call.
synchronized (framework.bundles) {
framework.bundles.markDependancies();
KeyedElement[] elements = exportedPackages.elements();
if (bundle != null) {
Vector result = new Vector();
for (int i = 0; i < elements.length; i++) {
ExportedPackageImpl pkgElement = (ExportedPackageImpl) elements[i];
if (pkgElement.supplier.getBundle() == bundle) {
result.add(pkgElement);
}
}
if (result.size() == 0) {
return null;
}
ExportedPackageImpl[] pkgElements = new ExportedPackageImpl[result.size()];
return (ExportedPackage[]) result.toArray(pkgElements);
} else {
if (elements.length == 0) {
return null;
}
ExportedPackageImpl[] pkgElements = new ExportedPackageImpl[elements.length];
System.arraycopy(elements, 0, pkgElements, 0, pkgElements.length);
return pkgElements;
}
}
}
/**
* Gets the ExportedPackage with the specified package name. All exported
* packages
* will be checked for the specified name. In an environment where the
* exhaustive list of packages on the system classpath is not known in
* advance, this method attempts to see if the named package is on the
* system classpath.
* This
* means that this method may discover an ExportedPackage that was
* not present in the list returned by <tt>getExportedPackages()</tt>.
*
* @param name The name of the exported package to be returned.
*
* @return The exported package with the specified name, or <tt>null</tt>
* if no expored package with that name exists.
*/
public org.osgi.service.packageadmin.ExportedPackage getExportedPackage(String packageName) {
// need to make sure the dependacies are marked before this call.
synchronized (framework.bundles) {
framework.bundles.markDependancies();
return (ExportedPackageImpl) exportedPackages.getByKey(packageName);
}
}
/**
* Forces the update (replacement) or removal of packages exported by
* the specified bundles.
*
* <p> If no bundles are specified, this method will update or remove any
* packages exported by any bundles that were previously updated or
* uninstalled. The technique by which this is accomplished
* may vary among different framework implementations. One permissible
* implementation is to stop and restart the Framework.
*
* <p> This method returns to the caller immediately and then performs the
* following steps in its own thread:
*
* <ol>
* <p>
* <li> Compute a graph of bundles starting with the specified ones. If no
* bundles are specified, compute a graph of bundles starting with
* previously updated or uninstalled ones.
* Any bundle that imports a package that is currently exported
* by a bundle in the graph is added to the graph. The graph is fully
* constructed when there is no bundle outside the graph that imports a
* package from a bundle in the graph. The graph may contain
* <tt>UNINSTALLED</tt> bundles that are currently still
* exporting packages.
*
* <p>
* <li> Each bundle in the graph will be stopped as described in the
* <tt>Bundle.stop</tt> method.
*
* <p>
* <li> Each bundle in the graph that is in the
* <tt>RESOLVED</tt> state is moved
* to the <tt>INSTALLED</tt> state.
* The effect of this step is that bundles in the graph are no longer
* <tt>RESOLVED</tt>.
*
* <p>
* <li> Each bundle in the graph that is in the UNINSTALLED state is
* removed from the graph and is now completely removed from the framework.
*
* <p>
* <li> Each bundle in the graph that was in the
* <tt>ACTIVE</tt> state prior to Step 2 is started as
* described in the <tt>Bundle.start</tt> method, causing all
* bundles required for the restart to be resolved.
* It is possible that, as a
* result of the previous steps, packages that were
* previously exported no longer are. Therefore, some bundles
* may be unresolvable until another bundle
* offering a compatible package for export has been installed in the
* framework.
* </ol>
*
* <p> For any exceptions that are thrown during any of these steps, a
* <tt>FrameworkEvent</tt> of type <tt>ERROR</tt> is
* broadcast, containing the exception.
*
* @param bundles the bundles whose exported packages are to be updated or
* removed,
* or <tt>null</tt> for all previously updated or uninstalled bundles.
*
* @exception SecurityException if the caller does not have the
* <tt>AdminPermission</tt> and the Java runtime environment supports
* permissions.
*/
public void refreshPackages(org.osgi.framework.Bundle[] input) {
framework.checkAdminPermission();
AbstractBundle[] copy = null;
if (input != null) {
synchronized (input) {
int size = input.length;
copy = new AbstractBundle[size];
System.arraycopy(input, 0, copy, 0, size);
}
}
final AbstractBundle[] bundles = copy;
Thread refresh = SecureAction.createThread(new Runnable() {
public void run() {
refreshPackages(bundles);
}
}, "Refresh Packages");
refresh.start();
}
/**
* Worker routine called on a seperate thread to perform the actual work.
*
* @param Seed for the graph.
*/
protected void refreshPackages(AbstractBundle[] refresh) {
try {
Vector graph = null;
synchronized (framework.bundles) {
if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
Debug.println("refreshPackages: Initialize graph");
}
// make sure the dependencies are marked first
framework.bundles.markDependancies();
graph = computeAffectedBundles(refresh);
// get the state.
State state = framework.adaptor.getState();
// resolve the state.
state.resolve(false);
// process the delta. This will set the state of all
// the bundles in the graph.
processDelta(graph);
}
/*
* Resume the suspended bundles outside of the synchronization block.
* This will cause the bundles to be resolved using the most up-to-date
* generations of the bundles.
*/
resumeBundles(graph);
} finally {
framework.publishFrameworkEvent(FrameworkEvent.PACKAGES_REFRESHED, framework.systemBundle, null);
}
}
private void resumeBundles(Vector graph) {
AbstractBundle[] refresh = new AbstractBundle[graph.size()];
boolean[] previouslyResolved = new boolean[graph.size()];
graph.copyInto(refresh);
Util.sort(refresh, 0, graph.size());
if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
Debug.println("refreshPackages: restart the bundles");
}
for (int i = 0; i < refresh.length; i++) {
AbstractBundle bundle = (AbstractBundle) refresh[i];
if (bundle.isResolved())
framework.resumeBundle(bundle);
}
}
private void processDelta(Vector graph) {
AbstractBundle[] refresh = new AbstractBundle[graph.size()];
boolean[] previouslyResolved = new boolean[graph.size()];
graph.copyInto(refresh);
Util.sort(refresh, 0, graph.size());
Vector notify = new Vector();
try {
try {
/*
* Suspend each bundle and grab its state change lock.
*/
if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
Debug.println("refreshPackages: Suspend each bundle and acquire its state change lock");
}
for (int i = refresh.length - 1; i >= 0; i--) {
AbstractBundle changedBundle = refresh[i];
previouslyResolved[i] = changedBundle.isResolved();
if (changedBundle.isActive() && !changedBundle.isFragment()) {
boolean suspended = framework.suspendBundle(changedBundle, true);
if (!suspended) {
throw new BundleException(Msg.formatter.getString("BUNDLE_STATE_CHANGE_EXCEPTION")); //$NON-NLS-1$
}
} else {
changedBundle.beginStateChange();
}
if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
if (changedBundle.stateChanging == null) {
Debug.println("Bundle state change lock is clear! " + changedBundle);
Debug.printStackTrace(new Exception("Stack trace"));
}
}
}
/*
* Refresh the bundles which will unexport the packages.
* This will move RESOLVED bundles to the INSTALLED state.
*/
if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
Debug.println("refreshPackages: refresh the bundles");
}
/*
* Unimport detached BundleLoaders for bundles in the graph.
*/
for (int i = removalPending.size() - 1; i >= 0; i--) {
BundleLoaderProxy loaderProxy = (BundleLoaderProxy) removalPending.elementAt(i);
if (graph.contains(loaderProxy.getBundle())) {
framework.bundles.unMarkDependancies(loaderProxy);
}
}
for (int i = 0; i < refresh.length; i++) {
AbstractBundle changedBundle = refresh[i];
changedBundle.refresh();
// send out unresolved events
if (previouslyResolved[i])
framework.publishBundleEvent(BundleEvent.UNRESOLVED, changedBundle);
}
/*
* Cleanup detached BundleLoaders for bundles in the graph.
*/
if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
Debug.println("refreshPackages: unexport the removal pending packages");
}
for (int i = removalPending.size() - 1; i >= 0; i--) {
BundleLoaderProxy loaderProxy = (BundleLoaderProxy) removalPending.elementAt(i);
AbstractBundle removedBundle = loaderProxy.getBundle();
if (graph.contains(removedBundle)) {
deleteRemovalPending(loaderProxy);
}
}
// set the resolved bundles state
List allBundles = framework.bundles.getBundles();
int size = allBundles.size();
for (int i = 0; i < size; i++) {
AbstractBundle bundle = (AbstractBundle) allBundles.get(i);
if (bundle.isResolved())
continue;
BundleDescription bundleDes = bundle.getBundleDescription();
if (bundleDes != null) {
if (bundleDes.isResolved()) {
if (bundle.isFragment()) {
BundleHost host = (BundleHost) framework.getBundle(bundleDes.getHost().getSupplier().getBundleId());
if (((BundleFragment) bundle).setHost(host)) {
bundle.resolve();
}
} else {
bundle.resolve();
}
if (bundle.isResolved()) {
notify.addElement(bundle);
}
}
}
}
// update the exported package and bundle lists.
exportedPackages = getExportedPackages(exportedPackages);
exportedBundles = getExportedBundles(exportedBundles);
} finally {
/*
* Release the state change locks.
*/
if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
Debug.println("refreshPackages: release the state change locks");
}
for (int i = 0; i < refresh.length; i++) {
AbstractBundle changedBundle = refresh[i];
changedBundle.completeStateChange();
}
}
/*
* Take this opportunity to clean up the adaptor storage.
*/
if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
Debug.println("refreshPackages: clean up adaptor storage");
}
try {
framework.adaptor.compactStorage();
} catch (IOException e) {
if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
Debug.println("refreshPackages exception: " + e.getMessage());
Debug.printStackTrace(e);
}
framework.publishFrameworkEvent(FrameworkEvent.ERROR, framework.systemBundle, new BundleException(Msg.formatter.getString("BUNDLE_REFRESH_FAILURE"), e)); //$NON-NLS-1$
}
} catch (BundleException e) {
if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
Debug.println("refreshPackages exception: " + e.getMessage());
Debug.printStackTrace(e.getNestedException());
}
framework.publishFrameworkEvent(FrameworkEvent.ERROR, framework.systemBundle, new BundleException(Msg.formatter.getString("BUNDLE_REFRESH_FAILURE"), e)); //$NON-NLS-1$
}
// send out any resolved/unresolved events
for (int i = 0; i < notify.size(); i++) {
AbstractBundle changedBundle = (AbstractBundle) notify.elementAt(i);
framework.publishBundleEvent(changedBundle.isResolved() ? BundleEvent.RESOLVED : BundleEvent.UNRESOLVED, changedBundle);
}
}
private void unresolvePermissions(Vector bundles, Hashtable packages) {
/*
* All bundles must be notified of the unexported packages so that
* they may unresolve permissions if necessary.
* This done after resolve bundles so that unresolved permissions
* can be immediately resolved.
*/
if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
Debug.println("refreshPackages: unresolve permissions");
}
int size = bundles.size();
for (int i = 0; i < size; i++) {
AbstractBundle bundle = (AbstractBundle) bundles.elementAt(i);
bundle.unresolvePermissions(packages);
}
}
private Vector computeAffectedBundles(AbstractBundle[] refresh) {
Vector graph = new Vector();
if (refresh == null) {
int size = removalPending.size();
for (int i = 0; i < size; i++) {
BundleLoaderProxy loaderProxy = (BundleLoaderProxy) removalPending.elementAt(i);
AbstractBundle bundle = loaderProxy.getBundle();
if (!graph.contains(bundle)) {
if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
Debug.println(" refresh: " + bundle);
}
graph.addElement(bundle);
// add in any dependents of the removal pending loader.
AbstractBundle[] dependents = loaderProxy.getDependentBundles();
for (int j = 0; j < dependents.length; j++) {
if (!graph.contains(dependents[j])) {
graph.addElement(dependents[j]);
}
}
}
}
} else {
for (int i = 0; i < refresh.length; i++) {
AbstractBundle bundle = refresh[i];
if (bundle == framework.systemBundle) {
continue;
}
if (bundle.isFragment()) {
// if it is a fragment then put the host in the graph
BundleHost host = (BundleHost) bundle.getHost();
if (host != null) {
if (!graph.contains(host)) {
graph.addElement(host);
}
}
}
if (!graph.contains(bundle)) {
if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
Debug.println(" refresh: " + bundle);
}
graph.addElement(bundle);
}
}
}
/*
* If there is nothing to do, then return.
*/
if (graph.size() == 0) {
if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
Debug.println("refreshPackages: Empty graph");
}
return graph;
}
/*
* Complete graph.
*/
if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
Debug.println("refreshPackages: Complete graph");
}
boolean changed;
do {
changed = false;
int size = graph.size();
for (int i = size - 1; i >= 0; i--) {
AbstractBundle bundle = (AbstractBundle) graph.elementAt(i);
if (!bundle.isFragment()) {
BundleLoaderProxy loaderProxy = ((BundleHost) bundle).getLoaderProxy();
if (loaderProxy != null) {
// add any dependents
AbstractBundle[] dependents = loaderProxy.getDependentBundles();
for (int j = 0; j < dependents.length; j++) {
if (!graph.contains(dependents[j])) {
graph.addElement(dependents[j]);
changed = true;
}
}
}
// add in any fragments
org.osgi.framework.Bundle[] frags = bundle.getFragments();
if (frags != null) {
for (int j = 0; j < frags.length; j++) {
if (!graph.contains(frags[j])) {
graph.addElement(frags[j]);
changed = true;
}
}
}
} else {
// add in the host.
AbstractBundle host = (AbstractBundle) bundle.getHost();
if (host != null) {
if (!graph.contains(host)) {
graph.addElement(host);
changed = true;
}
}
}
}
// look for the bundles in removalPending list
for (int i = removalPending.size() - 1; i >= 0; i--) {
BundleLoaderProxy removedLoaderProxy = (BundleLoaderProxy) removalPending.elementAt(i);
AbstractBundle removedBundle = removedLoaderProxy.getBundle();
if (graph.contains(removedBundle)) {
// add in the dependents of the removedLoaderProxy
AbstractBundle[] dependents = removedLoaderProxy.getDependentBundles();
for (int k = 0; k < dependents.length; k++) {
if (!graph.contains(dependents[k])) {
graph.addElement(dependents[k]);
changed = true;
}
}
}
}
} while (changed);
return graph;
}
/**
* Sets all the bundles in the state that are resolved to the resolved
* state. This should only be called when the framework is launching.
*
*/
protected void setResolvedBundles() {
State state = framework.adaptor.getState();
BundleDescription[] descriptions = state.getBundles();
for (int i = 0; i < descriptions.length; i++) {
long bundleId = descriptions[i].getBundleId();
AbstractBundle bundle = framework.getBundle(bundleId);
if (bundle == null ) {
BundleException be = new BundleException(Msg.formatter.getString("BUNDLE_NOT_IN_FRAMEWORK",descriptions[i])); //$NON-NLS-1$
framework.publishFrameworkEvent(FrameworkEvent.ERROR,framework.systemBundle,be);
}
if (bundle != framework.systemBundle) {
if (descriptions[i].isResolved()) {
if (bundle.isFragment()) {
BundleHost host = (BundleHost) framework.getBundle(descriptions[i].getHost().getSupplier().getBundleId());
if (((BundleFragment) bundle).setHost(host)) {
bundle.resolve();
}
} else {
bundle.resolve();
}
}
}
}
exportedPackages = getExportedPackages(exportedPackages);
exportedBundles = getExportedBundles(exportedBundles);
}
/**
* A permissible implementation of this method is to attempt to
* resolve all unresolved bundles installed in the framework.
* That is what this method does.
* @param bundles the set of bundles to attempt to resolve.
*/
public void resolveBundles(org.osgi.framework.Bundle[] bundles) {
resolveBundles();
}
/**
* Attempt to resolve all unresolved bundles. When this method returns
* all bundles are resolved that can be resolved. A resolved bundle
* has exported and imported packages. An unresolved bundle neither
* exports nor imports packages.
*
*/
protected void resolveBundles() {
long start = 0;
if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN_TIMING)
start = System.currentTimeMillis();
/*
* Resolve the bundles. This will make there exported packages available.
*/
if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN) {
Debug.println("refreshBundles: resolve bundles");
}
Vector notify = new Vector();
synchronized (framework.bundles) {
boolean resolveNeeded = false;
List allBundles = framework.bundles.getBundles();
int size = allBundles.size();
// first check to see if there is anything to resolve
for (int i = 0; i < size; i++) {
if (!((AbstractBundle) allBundles.get(i)).isResolved())
resolveNeeded = true;
}
if (!resolveNeeded)
return;
// get the state and resolve it.
framework.adaptor.getState().resolve(false);
for (int i = 0; i < size; i++) {
AbstractBundle bundle = (AbstractBundle) allBundles.get(i);
BundleDescription changedBundleDes = bundle.getBundleDescription();
boolean previouslyResolved = bundle.isResolved();
if (bundle != framework.systemBundle && changedBundleDes != null) {
if (changedBundleDes.isResolved() && !previouslyResolved) {
if (bundle.isFragment()) {
BundleHost host = (BundleHost) framework.getBundle(changedBundleDes.getHost().getSupplier().getBundleId());
if (((BundleFragment) bundle).setHost(host)) {
bundle.resolve();
}
} else {
bundle.resolve();
}
if (bundle.isResolved()) {
notify.add(bundle);
}
} else if (!changedBundleDes.isResolved() && previouslyResolved) {
// Need to log error. This should not happen since the state should not touch
// bundles that we did not pass in to the resolve() call.
framework.publishFrameworkEvent(FrameworkEvent.ERROR, bundle, new BundleException(Msg.formatter.getString("STATE_UNRESOLVED_WRONG_BUNDLE", bundle.getLocation()))); //$NON-NLS-1$
}
} else {
if (bundle != framework.systemBundle) {
framework.publishFrameworkEvent(FrameworkEvent.ERROR, bundle, new BundleException(Msg.formatter.getString("BUNDLE_NOT_IN_STATE", bundle.getLocation()))); //$NON-NLS-1$
}
}
}
// update the exported package and bundle lists.
exportedPackages = getExportedPackages(exportedPackages);
exportedBundles = getExportedBundles(exportedBundles);
}
for (int i = 0; i < notify.size(); i++) {
AbstractBundle bundle = (AbstractBundle) notify.elementAt(i);
if (bundle != null) {
framework.publishBundleEvent(bundle.isResolved() ? BundleEvent.RESOLVED : BundleEvent.UNRESOLVED, bundle);
}
}
if (Debug.DEBUG && Debug.DEBUG_PACKAGEADMIN_TIMING) {
cumulativeTime = cumulativeTime + System.currentTimeMillis() - start;
DebugOptions.getDefault().setOption(Debug.OPTION_DEBUG_PACKAGEADMIN_TIMING + "/value", Long.toString(cumulativeTime)); //$NON-NLS-1$
}
}
protected void unexportResources(BundleLoaderProxy proxy) {
KeyedElement[] bundles = exportedBundles.elements();
for (int i = 0; i < bundles.length; i++) {
BundleLoaderProxy loaderProxy = (BundleLoaderProxy) bundles[i];
if (loaderProxy == proxy) {
exportedBundles.remove(proxy);
}
}
KeyedElement[] packages = exportedPackages.elements();
for (int i = 0; i < packages.length; i++) {
PackageSource source = (PackageSource) packages[i];
BundleLoaderProxy sourceProxy = source.getSupplier();
if (sourceProxy == proxy) {
exportedPackages.remove(source);
}
}
// make the proxy stale
proxy.setStale();
}
protected BundleDescription[] getBundleDescriptions(Vector graph) {
ArrayList result = new ArrayList();
int size = graph.size();
for (int i = 0; i < size; i++) {
AbstractBundle bundle = (AbstractBundle) graph.elementAt(i);
BundleDescription bundleDes = bundle.getBundleDescription();
if (bundleDes != null) {
result.add(bundleDes);
}
}
return (BundleDescription[]) result.toArray(new BundleDescription[result.size()]);
}
public NamedClassSpace[] getNamedClassSpaces(String symbolicName) {
if (exportedBundles == null || exportedBundles.size() == 0)
return null;
// need to make sure the dependacies are marked before this call.
framework.bundles.markDependancies();
KeyedElement[] allSymbolicBundles = exportedBundles.elements();
if (symbolicName == null) {
if (allSymbolicBundles.length == 0) {
return null;
}
NamedClassSpace[] result = new NamedClassSpace[allSymbolicBundles.length];
System.arraycopy(allSymbolicBundles, 0, result, 0, result.length);
return result;
} else {
ArrayList result = new ArrayList();
for (int i = 0; i < allSymbolicBundles.length; i++) {
NamedClassSpace symBundle = (NamedClassSpace) allSymbolicBundles[i];
if (symBundle.getName().equals(symbolicName))
result.add(symBundle);
}
return (NamedClassSpace[]) result.toArray(new NamedClassSpace[result.size()]);
}
}
public org.osgi.framework.Bundle[] getBundles(String symbolicName, String version, String match) {
if (symbolicName == null) {
throw new IllegalArgumentException();
}
AbstractBundle bundles[] = framework.getBundleByUniqueId(symbolicName);
if (bundles == null)
return null;
if (version == null)
return bundles;
// This code depends on the array of bundles being in descending
// version order.
ArrayList result = new ArrayList();
Version ver = new Version(version);
for (int i = 0; i < bundles.length; i++) {
if (matchBundle(bundles[i], ver, match)) {
result.add(bundles[i]);
}
}
if (result.size() == 0)
return null;
else
return (AbstractBundle[]) result.toArray(new AbstractBundle[result.size()]);
}
private boolean matchBundle(AbstractBundle bundle, Version version, String match) {
match = match == null ? Constants.VERSION_MATCH_GREATERTHANOREQUAL : match;
boolean result = false;
if (match.equalsIgnoreCase(Constants.VERSION_MATCH_QUALIFIER))
result = bundle.getVersion().matchQualifier(version);
else if (match.equalsIgnoreCase(Constants.VERSION_MATCH_MICRO))
result = bundle.getVersion().matchMicro(version);
else if (match.equalsIgnoreCase(Constants.VERSION_MATCH_MINOR))
result = bundle.getVersion().matchMinor(version);
else if (match.equalsIgnoreCase(Constants.VERSION_MATCH_MAJOR))
result = bundle.getVersion().matchMajor(version);
else if (match.equalsIgnoreCase(Constants.VERSION_MATCH_GREATERTHANOREQUAL))
result = bundle.getVersion().matchGreaterOrEqualTo(version);
return result;
}
public org.osgi.framework.Bundle[] getFragments(org.osgi.framework.Bundle bundle) {
return ((AbstractBundle) bundle).getFragments();
}
public org.osgi.framework.Bundle[] getHosts(org.osgi.framework.Bundle bundle) {
org.osgi.framework.Bundle host = ((AbstractBundle) bundle).getHost();
if (host == null)
return null;
else
return new org.osgi.framework.Bundle[] {host};
}
public int getBundleType(org.osgi.framework.Bundle bundle) {
return ((AbstractBundle) bundle).isFragment() ? PackageAdminImpl.BUNDLE_TYPE_FRAGMENT : 0;
}
protected Class loadServiceClass(String className, AbstractBundle bundle) {
try {
if (restrictServiceClasses || bundle == null)
return framework.adaptor.getBundleClassLoaderParent().loadClass(className);
else
return bundle.loadClass(className, false);
} catch (ClassNotFoundException e) {
// do nothing; try exported packages
}
// try exported packages; SERVICE class space
String pkgname = BundleLoader.getPackageName(className);
if (pkgname != null) {
PackageSource exporter = (PackageSource) exportedPackages.getByKey(pkgname);
if (exporter != null) {
Class serviceClass = exporter.getSupplier().getBundleLoader().findLocalClass(className);
if (serviceClass != null)
return serviceClass;
}
}
// try bundle's PRIVATE class space if we are restricting service classes
if (restrictServiceClasses && bundle != null)
return bundle.getBundleLoader().findLocalClass(className);
return null;
}
}