| /******************************************************************************* |
| * 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.internal.resolver; |
| |
| import java.util.*; |
| import org.eclipse.osgi.framework.debug.DebugOptions; |
| import org.eclipse.osgi.framework.internal.core.KeyedElement; |
| import org.eclipse.osgi.framework.internal.core.KeyedHashSet; |
| import org.eclipse.osgi.service.resolver.*; |
| import org.osgi.framework.Bundle; |
| |
| public class StateImpl implements State { |
| transient private Resolver resolver; |
| transient private StateDeltaImpl changes; |
| transient private Map listeners = new HashMap(11); |
| transient private KeyedHashSet resolvedBundles = new KeyedHashSet(); |
| private boolean resolved = true; |
| protected long timeStamp = System.currentTimeMillis(); |
| private KeyedHashSet bundleDescriptions = new KeyedHashSet(false); |
| private StateObjectFactory factory; |
| |
| private static long cumulativeTime; |
| |
| protected StateImpl() { |
| // to prevent extra-package instantiation |
| } |
| |
| public boolean addBundle(BundleDescription description) { |
| if (description.getBundleId() < 0) |
| throw new IllegalArgumentException("no id set"); |
| if (!basicAddBundle(description)) |
| return false; |
| resolved = false; |
| getDelta().recordBundleAdded((BundleDescriptionImpl) description); |
| if (resolver != null) |
| resolver.bundleAdded(description); |
| return true; |
| } |
| |
| public StateChangeEvent compare(State state) { |
| throw new UnsupportedOperationException("not implemented"); //$NON-NLS-1$ |
| } |
| |
| public BundleDescription removeBundle(long bundleId) { |
| BundleDescription toRemove = getBundle(bundleId); |
| if (toRemove == null || !removeBundle(toRemove)) |
| return null; |
| return toRemove; |
| } |
| |
| public boolean removeBundle(BundleDescription toRemove) { |
| if (!bundleDescriptions.remove((KeyedElement) toRemove)) |
| return false; |
| resolved = false; |
| getDelta().recordBundleRemoved((BundleDescriptionImpl) toRemove); |
| if (resolver != null) |
| resolver.bundleRemoved(toRemove); |
| return true; |
| } |
| |
| public StateDelta getChanges() { |
| return getDelta(); |
| } |
| |
| private StateDeltaImpl getDelta() { |
| if (changes == null) |
| changes = getNewDelta(); |
| return changes; |
| } |
| |
| private StateDeltaImpl getNewDelta() { |
| return new StateDeltaImpl(this); |
| } |
| |
| public BundleDescription[] getBundles(final String symbolicName) { |
| final List bundles = new ArrayList(); |
| for (Iterator iter = bundleDescriptions.iterator(); iter.hasNext();) { |
| BundleDescription bundle = (BundleDescription) iter.next(); |
| if (symbolicName.equals(bundle.getUniqueId())) |
| bundles.add(bundle); |
| } |
| return (BundleDescription[]) bundles.toArray(new BundleDescription[bundles.size()]); |
| } |
| |
| public BundleDescription[] getBundles() { |
| return (BundleDescription[]) bundleDescriptions.elements(new BundleDescription[bundleDescriptions.size()]); |
| } |
| |
| public BundleDescription getBundle(long id) { |
| return (BundleDescription) bundleDescriptions.getByKey(new Long(id)); |
| } |
| |
| // TODO: this does not comply with the spec |
| public BundleDescription getBundle(String requiredUniqueId, Version requiredVersion) { |
| BundleDescription[] bundles = getBundles(); |
| for (int i = 0; i < bundles.length; i++) { |
| if (requiredUniqueId.equals(bundles[i].getUniqueId()) && bundles[i].getVersion().equals(requiredVersion)) |
| return bundles[i]; |
| } |
| return null; |
| } |
| |
| public long getTimeStamp() { |
| return timeStamp; |
| } |
| |
| public boolean isResolved() { |
| return resolved || isEmpty(); |
| } |
| |
| public void resolveConstraint(VersionConstraint constraint, Version actualVersion, BundleDescription supplier) { |
| VersionConstraintImpl modifiable = ((VersionConstraintImpl) constraint); |
| if (modifiable.getActualVersion() != actualVersion || modifiable.getSupplier() != supplier) { |
| modifiable.setActualVersion(actualVersion); |
| modifiable.setSupplier(supplier); |
| if (constraint instanceof BundleSpecification || constraint instanceof HostSpecification) { |
| boolean optional = (constraint instanceof BundleSpecification) && ((BundleSpecification) constraint).isOptional(); |
| getDelta().recordConstraintResolved((BundleDescriptionImpl) constraint.getBundle(), optional); |
| } |
| } |
| } |
| |
| public void resolveBundle(BundleDescription bundle, int status) { |
| ((BundleDescriptionImpl) bundle).setState(status); |
| getDelta().recordBundleResolved((BundleDescriptionImpl) bundle, status); |
| if (status == Bundle.RESOLVED) |
| resolvedBundles.add((KeyedElement) bundle); |
| else { |
| // ensures no links are left |
| unresolveConstraints(bundle); |
| // remove the bundle from the resolved pool |
| resolvedBundles.remove((KeyedElement) bundle); |
| } |
| } |
| |
| private void unresolveConstraints(BundleDescription bundle) { |
| HostSpecification host = bundle.getHost(); |
| if (host != null) |
| ((VersionConstraintImpl) host).unresolve(); |
| PackageSpecification[] packages = bundle.getPackages(); |
| for (int i = 0; i < packages.length; i++) |
| ((VersionConstraintImpl) packages[i]).unresolve(); |
| BundleSpecification[] requiredBundles = bundle.getRequiredBundles(); |
| for (int i = 0; i < requiredBundles.length; i++) |
| ((VersionConstraintImpl) requiredBundles[i]).unresolve(); |
| } |
| |
| public Resolver getResolver() { |
| return resolver; |
| } |
| |
| public void setResolver(Resolver newResolver) { |
| if (resolver == newResolver) |
| return; |
| if (resolver != null) { |
| Resolver oldResolver = resolver; |
| resolver = null; |
| oldResolver.setState(null); |
| } |
| resolver = newResolver; |
| if (resolver == null) |
| return; |
| resolver.setState(this); |
| } |
| |
| private StateDelta resolve(boolean incremental, BundleDescription[] reResolve) { |
| if (resolver == null) |
| throw new IllegalStateException("no resolver set"); //$NON-NLS-1$ |
| long start = 0; |
| if (StateManager.DEBUG_PLATFORM_ADMIN) |
| start = System.currentTimeMillis(); |
| if (!incremental) |
| flush(); |
| if (resolved && reResolve == null) |
| return new StateDeltaImpl(this); |
| if (reResolve != null) |
| resolver.resolve(reResolve); |
| else |
| resolver.resolve(); |
| resolved = true; |
| // TODO: need to fire events for listeners |
| StateDelta savedChanges = changes == null ? new StateDeltaImpl(this) : changes; |
| changes = new StateDeltaImpl(this); |
| |
| if (StateManager.DEBUG_PLATFORM_ADMIN) { |
| cumulativeTime = cumulativeTime + (System.currentTimeMillis() - start); |
| DebugOptions.getDefault().setOption("org.eclipse.core.runtime.adaptor/resolver/timing/value", Long.toString(cumulativeTime)); |
| } |
| |
| return savedChanges; |
| } |
| |
| private void flush() { |
| resolver.flush(); |
| resolved = false; |
| if (resolvedBundles.isEmpty()) |
| return; |
| for (Iterator iter = resolvedBundles.iterator(); iter.hasNext();) { |
| BundleDescriptionImpl resolvedBundle = (BundleDescriptionImpl) iter.next(); |
| resolvedBundle.setState(0); |
| } |
| resolvedBundles.clear(); |
| } |
| |
| public StateDelta resolve() { |
| return resolve(true, null); |
| } |
| |
| public StateDelta resolve(boolean incremental) { |
| return resolve(incremental, null); |
| } |
| |
| public StateDelta resolve(BundleDescription[] reResolve) { |
| return resolve(true, reResolve); |
| } |
| |
| public void setOverrides(Object value) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| public BundleDescription[] getResolvedBundles() { |
| return (BundleDescription[]) resolvedBundles.elements(new BundleDescription[resolvedBundles.size()]); |
| } |
| |
| public void addStateChangeListener(StateChangeListener listener, int flags) { |
| if (listeners.containsKey(listener)) |
| return; |
| listeners.put(listener, new Integer(flags)); |
| } |
| |
| public void removeStateChangeListener(StateChangeListener listener) { |
| listeners.remove(listener); |
| } |
| |
| public boolean isEmpty() { |
| return bundleDescriptions.isEmpty(); |
| } |
| |
| public void setResolved(boolean resolved) { |
| this.resolved = resolved; |
| } |
| |
| public boolean basicAddBundle(BundleDescription description) { |
| ((BundleDescriptionImpl) description).setContainingState(this); |
| return bundleDescriptions.add((BundleDescriptionImpl) description); |
| } |
| |
| void addResolvedBundle(BundleDescriptionImpl resolved) { |
| resolvedBundles.add(resolved); |
| } |
| |
| public PackageSpecification[] getExportedPackages() { |
| final List allExportedPackages = new ArrayList(); |
| for (Iterator iter = resolvedBundles.iterator(); iter.hasNext();) { |
| BundleDescription bundle = (BundleDescription) iter.next(); |
| PackageSpecification[] bundlePackages = bundle.getPackages(); |
| for (int i = 0; i < bundlePackages.length; i++) |
| if (bundlePackages[i].isExported() && bundlePackages[i].getSupplier() == bundle) |
| allExportedPackages.add(bundlePackages[i]); |
| } |
| return (PackageSpecification[]) allExportedPackages.toArray(new PackageSpecification[allExportedPackages.size()]); |
| } |
| |
| public BundleDescription[] getImportingBundles(final PackageSpecification exportedPackage) { |
| if (!exportedPackage.isResolved()) |
| return null; |
| final List allImportingBundles = new ArrayList(); |
| for (Iterator iter = resolvedBundles.iterator(); iter.hasNext();) { |
| BundleDescription bundle = (BundleDescription) iter.next(); |
| PackageSpecification[] bundlePackages = bundle.getPackages(); |
| for (int i = 0; i < bundlePackages.length; i++) |
| if (bundlePackages[i].getName().equals(exportedPackage.getName()) && bundlePackages[i].getSupplier() == exportedPackage.getBundle()) { |
| allImportingBundles.add(bundle); |
| break; |
| } |
| } |
| return (BundleDescription[]) allImportingBundles.toArray(new BundleDescription[allImportingBundles.size()]); |
| } |
| |
| public BundleDescription[] getFragments(final BundleDescription host) { |
| final List fragments = new ArrayList(); |
| for (Iterator iter = bundleDescriptions.iterator(); iter.hasNext();) { |
| BundleDescription bundle = (BundleDescription) iter.next(); |
| HostSpecification hostSpec = bundle.getHost(); |
| if (hostSpec != null && hostSpec.getSupplier() == host) |
| fragments.add(bundle); |
| } |
| return (BundleDescription[]) fragments.toArray(new BundleDescription[fragments.size()]); |
| } |
| |
| public void setTimeStamp(long newTimeStamp) { |
| timeStamp = newTimeStamp; |
| } |
| |
| public StateObjectFactory getFactory() { |
| return factory; |
| } |
| |
| void setFactory(StateObjectFactory factory) { |
| this.factory = factory; |
| } |
| } |