diff options
Diffstat (limited to 'bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/ResolverImpl.java')
-rw-r--r-- | bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/ResolverImpl.java | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/ResolverImpl.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/ResolverImpl.java new file mode 100644 index 000000000..c8b3dbcfb --- /dev/null +++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/ResolverImpl.java @@ -0,0 +1,190 @@ +/******************************************************************************* + * 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.internal.resolver; + +import java.util.*; + +import org.eclipse.core.dependencies.*; +import org.eclipse.osgi.service.resolver.*; +import org.osgi.framework.Bundle; + +public class ResolverImpl implements Resolver { + private State state; + private IDependencySystem dependencies; + public void resolve(BundleDescription[] reRefresh) { + // unresolving the given bundles will force them to be re-resolved + for (int i = 0; i < reRefresh.length; i++) + unresolveBundle(reRefresh[i]); + resolve(); + } + /** + * TODO: need to devise a way to report problems (a la IStatus) + */ + public synchronized void resolve() { + if (state == null) + throw new IllegalStateException("no state set"); //$NON-NLS-1$ + if (dependencies == null) + dependencies = ResolverHelper.buildDependencySystem(state, new Eclipse30SelectionPolicy()); + IResolutionDelta delta; + try { + delta = dependencies.resolve(); + } catch (IDependencySystem.CyclicSystemException e) { + e.printStackTrace(); + return; + } + processInnerDelta(delta); + resolvePackages(); + } + public void setState(State newState) { + // to avoid infinite (mutual) recursion + if (state == newState) + return; + // if it was linked to a previous state, unlink first + if (state != null) + state.setResolver(null); + state = newState; + if (newState != null) + state.setResolver(this); + // forget any dependency state created before + flush(); + } + /* + * Applies changes in the constraint system to the state object. + */ + private void processInnerDelta(IResolutionDelta delta) { + // now apply changes reported in the inner delta to the state + IElementChange[] changes = delta.getAllChanges(); + for (int i = 0; i < changes.length; i++) { + IElement element = changes[i].getElement(); + BundleDescription bundle = (BundleDescription) element.getUserObject(); + int kind = changes[i].getKind(); + if ((kind & IElementChange.RESOLVED) != 0) { + state.resolveBundle(bundle, Bundle.RESOLVED); + resolveConstraints(element, bundle); + } else if (kind == (IElementChange.UNRESOLVED | IElementChange.REMOVED)) { + state.resolveBundle(bundle, Bundle.INSTALLED); + } else if (kind == IElementChange.UNRESOLVED) + state.resolveBundle(bundle, Bundle.INSTALLED); + else if (kind == IElementChange.LINKAGE_CHANGED) + resolveConstraints(element, bundle); + } + } + private void resolveConstraints(IElement element, BundleDescription bundle) { + // tells the state that some of the constraints have + // changed + IDependency[] dependencies = element.getDependencies(); + for (int j = 0; j < dependencies.length; j++) { + if (dependencies[j].getResolvedVersionId() == null) + // an optional requisite that was not resolved + continue; + VersionConstraint constraint = (VersionConstraint) dependencies[j].getUserObject(); + Version actualVersion = (Version) dependencies[j].getResolvedVersionId(); + BundleDescription supplier = state.getBundle(constraint.getName(), actualVersion); + state.resolveConstraint(constraint, actualVersion, supplier); + } + } + public void bundleAdded(BundleDescription bundle) { + if (dependencies == null) + return; + ResolverHelper.add(bundle, dependencies); + } + public void bundleRemoved(BundleDescription bundle) { + if (dependencies == null) + return; + ResolverHelper.remove(bundle, dependencies); + } + public State getState() { + return state; + } + public void flush() { + dependencies = null; + } + /* + * Ensures that all currently resolved bundles have their import-package + * clauses satisfied. + */ + private boolean resolvePackages() { + /* attempt to resolve the proposed bundles */ + Map availablePackages; + boolean success; + int tries = 0; + do { + tries++; + success = true; + BundleDescription[] initialBundles = state.getResolvedBundles(); + availablePackages = new HashMap(11); + /* do all exports first */ + for (int i = 0; i < initialBundles.length; i++) { + PackageSpecification[] required = initialBundles[i].getPackages(); + for (int j = 0; j < required.length; j++) + // override previously exported package if any (could + // preserve instead) + if (required[j].isExported()) { + Version toExport = required[j].getVersionSpecification(); + PackageSpecification existing = (PackageSpecification) availablePackages.get(required[j].getName()); + Version existingVersion = existing == null ? null : existing.getVersionSpecification(); + if (existingVersion == null || (toExport != null && toExport.isGreaterThan(existingVersion))) + availablePackages.put(required[j].getName(), required[j]); + } + } + /* now try to resolve imported packages */ + for (int i = 0; i < initialBundles.length; i++) { + PackageSpecification[] required = initialBundles[i].getPackages(); + for (int j = 0; j < required.length; j++) { + PackageSpecification exported = (PackageSpecification) availablePackages.get(required[j].getName()); + Version exportedVersion = exported == null ? null : exported.getVersionSpecification(); + Version importedVersion = required[j].getVersionSpecification(); + if (exported == null || (importedVersion != null && (exportedVersion == null || !exportedVersion.isGreaterOrEqualTo(importedVersion)))) { + unresolveRequirementChain(initialBundles[i]); + success = false; + // one missing import is enough to discard this bundle + break; + } + } + } + } while (!success); + /* now bind the exports/imports */ + BundleDescription[] resolvedBundles = state.getResolvedBundles(); + for (int i = 0; i < resolvedBundles.length; i++) { + PackageSpecification[] required = resolvedBundles[i].getPackages(); + for (int j = 0; j < required.length; j++) { + PackageSpecification exported = (PackageSpecification) availablePackages.get(required[j].getName()); + state.resolveConstraint(required[j], exported.getVersionSpecification(), exported.getBundle()); + } + } + /* return false if a at least one bundle was unresolved during this */ + return tries > 1; + } + /* + * Unresolves a bundle and all bundles that require it. + */ + private void unresolveRequirementChain(BundleDescription bundle) { + if (!bundle.isResolved()) + return; + state.resolveBundle(bundle, Bundle.INSTALLED); + if (bundle.getUniqueId() == null) + return; + IElementSet bundleElementSet = dependencies.getElementSet(bundle.getUniqueId()); + Collection requiring = bundleElementSet.getRequiringElements(bundle.getVersion()); + for (Iterator requiringIter = requiring.iterator(); requiringIter.hasNext(); ) { + IElement requiringElement = (IElement) requiringIter.next(); + BundleDescription requiringBundle = state.getBundle((String) requiringElement.getId(), (Version) requiringElement.getVersionId()); + if (requiringBundle != null) + unresolveRequirementChain(requiringBundle); + } + } + private void unresolveBundle(BundleDescription bundle) { + if (!bundle.isResolved()) + return; + if (dependencies != null) + ResolverHelper.unresolve(bundle, dependencies); + } +}
\ No newline at end of file |