blob: 25279a7373b2cef3977a6ea34e72f8eb3f0fc92e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003 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.util.ArrayList;
import org.eclipse.osgi.framework.debug.Debug;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.osgi.service.resolver.BundleSpecification;
import org.eclipse.osgi.service.resolver.PackageSpecification;
import org.eclipse.osgi.service.resolver.Version;
import org.osgi.service.packageadmin.NamedClassSpace;
/**
* The BundleLoaderProxy proxies a BundleLoader object for a Bundle. This
* allows for a Bundle's depedencies to be linked without forcing the
* creating of the BundleLoader or BundleClassLoader objects. This class
* keeps track of the depedencies between the bundles installed in the
* Framework.
*/
public class BundleLoaderProxy implements KeyedElement, NamedClassSpace{
/** The BundleLoader that this BundleLoaderProxy is managing */
private BundleLoader loader;
/** The Bundle that this BundleLoaderProxy is for*/
private BundleHost bundle;
/** The Symbolic Name of the Bundle; this must be cached incase the Bundle is updated */
private String symbolicName;
/** The Version of the Bundle; this must be cached incase the Bundle is updated */
private Version version;
/** The unique hash key for this KeyedElemetn */
private String key;
/**
* Indicates if this BundleLoaderProxy is stale;
* this is true when the bundle is updated or uninstalled.
*/
private boolean stale = false;
/**
* The set of users that are dependant on this BundleLoaderProxy
*/
private KeyedHashSet users;
/**
* Indicates if the dependencies of this BundleLoaderProxy have been marked
*/
protected boolean markedUsedDependencies = false;
public BundleLoaderProxy(BundleHost bundle) {
this.bundle = bundle;
this.symbolicName = bundle.getSymbolicName();
if (this.symbolicName == null) {
this.symbolicName = new StringBuffer().append(bundle.getBundleId()).append("NOSYMBOLICNAME").toString(); //$NON-NLS-1$
}
this.version = bundle.getVersion();
this.key = new StringBuffer(symbolicName).append("_").append(this.version.toString()).toString(); //$NON-NLS-1$
this.users = new KeyedHashSet(false);
}
public BundleLoader getBundleLoader() {
if (loader == null)
loader = bundle.getBundleLoader();
return loader;
}
public Bundle getBundle() {
return bundle;
}
public void setBundleLoader(BundleLoader value) {
loader = value;
}
public void markUsed(BundleLoaderProxy user) {
// only mark as used if the user is not our own bundle.
if (user.getBundle() != bundle) {
users.add(user);
}
}
public void unMarkUsed(BundleLoaderProxy user) {
users.removeByKey(user.getKey());
}
public int getKeyHashCode() {
return key.hashCode();
}
public boolean compare(KeyedElement other) {
if (!(other instanceof BundleLoaderProxy))
return false;
BundleLoaderProxy otherLoaderProxy = (BundleLoaderProxy) other;
return (symbolicName.equals(otherLoaderProxy.symbolicName) && version.matchQualifier(otherLoaderProxy.version));
}
public Object getKey() {
return key;
}
public void setStale() {
stale = true;
}
public boolean isStale() {
return stale;
}
public boolean inUse() {
return (users.size() > 0);
}
public Bundle[] getDependentBundles() {
KeyedElement[] proxyLoaders = users.elements();
KeyedHashSet bundles = new KeyedHashSet(proxyLoaders.length, false);
for (int i = 0; i < proxyLoaders.length; i++) {
BundleLoaderProxy loaderProxy = (BundleLoaderProxy) proxyLoaders[i];
bundles.add(loaderProxy.getBundle());
}
KeyedElement[] elements = bundles.elements();
Bundle[] result = new Bundle[elements.length];
System.arraycopy(elements, 0, result, 0, elements.length);
return result;
}
public String toString() {
String symbolicName = bundle.getSymbolicName();
StringBuffer sb = new StringBuffer(symbolicName == null ? bundle.getLocation() : symbolicName);
sb.append("; ").append(Constants.BUNDLE_VERSION_ATTRIBUTE); //$NON-NLS-1$
sb.append("=\"").append(version.toString()).append("\""); //$NON-NLS-1$//$NON-NLS-2$
return sb.toString();
}
protected void markDependencies() {
if (markedUsedDependencies || !bundle.isResolved()) { //TODO Can we get a bundleLoaderProxy is we are unresolved. If we can get one when the bundle is unresolved is it correct?
return;
}
markedUsedDependencies = true;
BundleDescription bundleDes = bundle.getBundleDescription();
if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
if (bundleDes == null) {
Debug.println("Bundle.resolved called and getBundleDescription returned null: " + this); //$NON-NLS-1$
Debug.printStackTrace(new Exception("Stack trace")); //$NON-NLS-1$
}
}
PackageSpecification[] packages = bundleDes.getPackages();
BundleSpecification[] requiredBundles = bundleDes.getRequiredBundles();
BundleDescription[] fragDescriptions = bundleDes.getFragments();
markUsedPackages(packages);
markUsedBundles(requiredBundles);
for (int i = 0; i < fragDescriptions.length; i++) {
if (fragDescriptions[i].isResolved()) {
markUsedPackages(fragDescriptions[i].getPackages());
markUsedBundles(fragDescriptions[i].getRequiredBundles());
}
}
// besure to create the BundleLoader;
getBundleLoader();
}
private void markUsedPackages(PackageSpecification[] packages) {
if (packages != null) {
for (int i = 0; i < packages.length; i++) {
SingleSourcePackage packagesource = (SingleSourcePackage) bundle.framework.packageAdmin.exportedPackages.getByKey(packages[i].getName());
if (packagesource != null) {
packagesource.getSupplier().markUsed(this);
}
}
}
}
private void markUsedBundles(BundleSpecification[] requiredBundles) {
if (requiredBundles != null) {
for (int i = 0; i < requiredBundles.length; i++) {
if (requiredBundles[i].isResolved()) {
String bundleKey = new StringBuffer(requiredBundles[i].getName()).append("_").append(requiredBundles[i].getActualVersion().toString()).toString(); //$NON-NLS-1$
BundleLoaderProxy loaderProxy = (BundleLoaderProxy) bundle.framework.packageAdmin.exportedBundles.getByKey(bundleKey);
if (loaderProxy != null) {
loaderProxy.markUsed(this);
}
}
}
}
}
public org.osgi.framework.Bundle getProvidingBundle() {
if (isStale())
return null;
return bundle;
}
public org.osgi.framework.Bundle[] getRequiringBundles() {
if (isStale())
return null;
KeyedElement[] requiringProxies = users.elements();
ArrayList requiringBundles = new ArrayList();
for (int i = 0; i < requiringProxies.length; i++) {
BundleLoaderProxy requiringProxy = (BundleLoaderProxy) requiringProxies[i];
BundleLoader requiringLoader = requiringProxy.getBundleLoader();
BundleLoaderProxy[] reqBundles = requiringLoader.requiredBundles;
if (reqBundles != null)
for (int j=0; j<reqBundles.length; j++)
if (reqBundles[j] == this)
requiringBundles.add(requiringProxy.getBundle());
}
return (Bundle[]) requiringBundles.toArray(new Bundle[requiringBundles.size()]);
}
public String getName() {
return symbolicName;
}
public String getVersion() {
return version.toString();
}
public boolean isRemovalPending() {
return bundle.framework.packageAdmin.removalPending.contains(this);
}
}