diff options
author | Thomas Watson | 2013-08-29 20:00:15 +0000 |
---|---|---|
committer | Thomas Watson | 2013-08-30 16:36:44 +0000 |
commit | f71c31ff5bfff75903926ab7448b1f14a8f91c2c (patch) | |
tree | 9819160812466b59fa446955eb207b166b5dcb2b /bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi | |
parent | 634c7448ee842e6c320b4efc4014b83be4513be2 (diff) | |
download | rt.equinox.framework-f71c31ff5bfff75903926ab7448b1f14a8f91c2c.tar.gz rt.equinox.framework-f71c31ff5bfff75903926ab7448b1f14a8f91c2c.tar.xz rt.equinox.framework-f71c31ff5bfff75903926ab7448b1f14a8f91c2c.zip |
Bug 416097 - Platform.getPlatformAdmin().getState(false) returns unresolved State
Diffstat (limited to 'bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi')
4 files changed, 231 insertions, 9 deletions
diff --git a/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/PlatformAdminImpl.java b/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/PlatformAdminImpl.java index 95cc2bfa0..55ace736b 100644 --- a/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/PlatformAdminImpl.java +++ b/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/PlatformAdminImpl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012 IBM Corporation and others. All rights reserved. + * Copyright (c) 2012, 2013 IBM Corporation and others. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html @@ -23,17 +23,28 @@ public class PlatformAdminImpl implements PlatformAdmin { private final StateObjectFactory factory = new StateObjectFactoryImpl(); private final Object monitor = new Object(); private EquinoxContainer equinoxContainer; + private BundleContext bc; private State systemState; + private PlatformBundleListener synchronizer; private ServiceRegistration<PlatformAdmin> reg; void start(BundleContext context) { synchronized (this.monitor) { equinoxContainer = ((BundleContextImpl) context).getContainer(); + this.bc = context; } this.reg = context.registerService(PlatformAdmin.class, this, null); } void stop(BundleContext context) { + synchronized (this.monitor) { + if (synchronizer != null) { + context.removeBundleListener(synchronizer); + context.removeFrameworkListener(synchronizer); + } + synchronizer = null; + systemState = null; + } this.reg.unregister(); } @@ -71,16 +82,20 @@ public class PlatformAdminImpl implements PlatformAdmin { ModuleDatabase database = equinoxContainer.getStorage().getModuleDatabase(); database.readLock(); try { + ModuleContainer container = equinoxContainer.getStorage().getModuleContainer(); List<Module> modules = equinoxContainer.getStorage().getModuleContainer().getModules(); for (Module module : modules) { ModuleRevision current = module.getCurrentRevision(); BundleDescription description = converter.createDescription(current); state.addBundle(description); - state.setPlatformProperties(asDictionary(equinoxContainer.getConfiguration().getInitialConfig())); } + state.setPlatformProperties(asDictionary(equinoxContainer.getConfiguration().getInitialConfig())); + synchronizer = new PlatformBundleListener(state, converter, database, container); + state.setResolverHookFactory(synchronizer); + bc.addBundleListener(synchronizer); + bc.addFrameworkListener(synchronizer); + state.resolve(); state.setTimeStamp(database.getRevisionsTimestamp()); - // TODO add hooks to get the resolution correct - // TODO add listeners to keep state copy in sync } finally { database.readUnlock(); } diff --git a/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/PlatformBundleListener.java b/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/PlatformBundleListener.java new file mode 100644 index 000000000..361c30b5c --- /dev/null +++ b/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/PlatformBundleListener.java @@ -0,0 +1,198 @@ +/******************************************************************************* + * Copyright (c) 2013 IBM Corporation and others. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package org.eclipse.osgi.compatibility.state; + +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; +import org.eclipse.osgi.container.*; +import org.eclipse.osgi.internal.resolver.BaseDescriptionImpl.BaseCapability; +import org.eclipse.osgi.service.resolver.BundleDescription; +import org.eclipse.osgi.service.resolver.State; +import org.osgi.framework.*; +import org.osgi.framework.hooks.resolver.ResolverHook; +import org.osgi.framework.hooks.resolver.ResolverHookFactory; +import org.osgi.framework.namespace.ExecutionEnvironmentNamespace; +import org.osgi.framework.namespace.HostNamespace; +import org.osgi.framework.wiring.*; + +class PlatformBundleListener implements SynchronousBundleListener, FrameworkListener, ResolverHookFactory { + + private final State systemState; + private final StateConverter converter; + private final ModuleDatabase database; + private final ModuleContainer container; + private long lastResolveStamp = -1; + private AtomicBoolean gotUnresolved = new AtomicBoolean(false); + + PlatformBundleListener(State systemState, StateConverter converter, ModuleDatabase database, ModuleContainer container) { + this.systemState = systemState; + this.converter = converter; + this.database = database; + this.container = container; + } + + @Override + public void bundleChanged(BundleEvent event) { + switch (event.getType()) { + case BundleEvent.INSTALLED : { + BundleRevision revision = event.getBundle().adapt(BundleRevision.class); + if (revision != null) { + systemState.addBundle(converter.createDescription(revision)); + systemState.setTimeStamp(database.getRevisionsTimestamp()); + } + break; + } + case BundleEvent.UNINSTALLED : { + systemState.removeBundle(event.getBundle().getBundleId()); + systemState.setTimeStamp(database.getRevisionsTimestamp()); + break; + } + case BundleEvent.UPDATED : { + BundleRevision revision = event.getBundle().adapt(BundleRevision.class); + if (revision != null) { + systemState.updateBundle(converter.createDescription(revision)); + systemState.setTimeStamp(database.getRevisionsTimestamp()); + } + break; + } + case BundleEvent.UNRESOLVED : { + gotUnresolved.set(true); + break; + } + case BundleEvent.RESOLVED : { + resolve(gotUnresolved.getAndSet(false)); + break; + } + default : + // do nothing + break; + } + } + + private void resolve(boolean uninstalled) { + database.readLock(); + try { + if (lastResolveStamp != database.getRevisionsTimestamp()) { + Collection<ModuleRevision> containerRemovalPending = container.getRemovalPending(); + BundleDescription[] stateRemovalPendingDescs = systemState.getRemovalPending(); + Collection<BundleDescription> stateRemovalPending = new ArrayList<BundleDescription>(stateRemovalPendingDescs.length); + for (BundleDescription description : stateRemovalPendingDescs) { + if (!containerRemovalPending.contains(description.getUserObject())) { + stateRemovalPending.add(description); + } + } + if (!stateRemovalPending.isEmpty()) { + systemState.resolve(stateRemovalPending.toArray(new BundleDescription[stateRemovalPending.size()]), true); + } else { + systemState.resolve(!uninstalled); + } + lastResolveStamp = database.getRevisionsTimestamp(); + systemState.setTimeStamp(database.getRevisionsTimestamp()); + } + } finally { + database.readUnlock(); + } + } + + @Override + public void frameworkEvent(FrameworkEvent event) { + if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED) { + resolve(gotUnresolved.getAndSet(false)); + } + } + + @Override + public ResolverHook begin(Collection<BundleRevision> triggers) { + return new ResolverHook() { + + @Override + public void filterSingletonCollisions(BundleCapability singleton, Collection<BundleCapability> collisionCandidates) { + BundleDescription desc = (BundleDescription) singleton.getRevision(); + ModuleRevision revision = (ModuleRevision) desc.getUserObject(); + if (revision.getWiring() != null) { + collisionCandidates.clear(); + } else { + for (Iterator<BundleCapability> iCandidates = collisionCandidates.iterator(); iCandidates.hasNext();) { + BundleDescription candDesc = (BundleDescription) iCandidates.next().getRevision(); + ModuleRevision candRevision = (ModuleRevision) candDesc.getUserObject(); + if (candRevision.getWiring() == null) { + iCandidates.remove(); + } + } + } + } + + @Override + public void filterResolvable(Collection<BundleRevision> candidates) { + for (Iterator<BundleRevision> iCandidates = candidates.iterator(); iCandidates.hasNext();) { + BundleDescription candDesc = (BundleDescription) iCandidates.next(); + ModuleRevision candRevision = (ModuleRevision) candDesc.getUserObject(); + if (candRevision.getWiring() == null) { + iCandidates.remove(); + } + } + } + + @Override + public void filterMatches(BundleRequirement requirement, Collection<BundleCapability> candidates) { + String namespace = requirement.getNamespace(); + BundleDescription reqDesc = (BundleDescription) requirement.getRevision(); + ModuleRevision reqRevision = (ModuleRevision) reqDesc.getUserObject(); + ModuleWiring reqWiring = reqRevision.getWiring(); + if (reqWiring == null) { + candidates.clear(); + return; + } + Collection<ModuleWiring> wirings = new ArrayList<ModuleWiring>(1); + if ((reqRevision.getTypes() & BundleRevision.TYPE_FRAGMENT) != 0) { + if (ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE.equals(namespace) || HostNamespace.HOST_NAMESPACE.equals(namespace)) { + wirings.add(reqWiring); + } else { + List<ModuleWire> hostWires = reqWiring.getRequiredModuleWires(namespace); + for (ModuleWire hostWire : hostWires) { + ModuleWiring hostWiring = hostWire.getProviderWiring(); + if (hostWiring != null) { + wirings.add(hostWiring); + } + } + } + } else { + wirings.add(reqWiring); + } + for (Iterator<BundleCapability> iCandidates = candidates.iterator(); iCandidates.hasNext();) { + BaseCapability baseCapability = (BaseCapability) iCandidates.next(); + Object userObject = baseCapability.getBaseDescription().getUserObject(); + boolean foundCandidate = false; + wirings: for (ModuleWiring wiring : wirings) { + List<ModuleWire> wires = wiring.getRequiredModuleWires(namespace); + for (ModuleWire wire : wires) { + if (userObject instanceof ModuleRevision && userObject.equals(wire.getProvider())) { + foundCandidate = true; + } else if (userObject instanceof ModuleCapability && userObject.equals(wire.getCapability())) { + foundCandidate = true; + } + if (foundCandidate) + break wirings; + } + } + if (!foundCandidate) { + iCandidates.remove(); + } + } + } + + @Override + public void end() { + // nothing + } + }; + } + +} diff --git a/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/StateConverter.java b/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/StateConverter.java index 7c6754e7d..dbf45aba4 100644 --- a/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/StateConverter.java +++ b/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/StateConverter.java @@ -1,3 +1,12 @@ +/******************************************************************************* + * Copyright (c) 2013 IBM Corporation and others. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ package org.eclipse.osgi.compatibility.state; import java.util.*; @@ -68,7 +77,7 @@ class StateConverter { } } - BundleDescription result = state.getFactory().createBundleDescription(resource.getBundle().getBundleId(), symbolicNameSpecification, version, null, requireBundles.toArray(new BundleSpecification[requireBundles.size()]), fragmentHost.size() == 0 ? null : fragmentHost.get(0), importPackages.toArray(new ImportPackageSpecification[importPackages.size()]), exportPackages.toArray(new ExportPackageDescription[exportPackages.size()]), null, null, requireCapabilities.toArray(new GenericSpecification[requireCapabilities.size()]), provideCapabilities.toArray(new GenericDescription[provideCapabilities.size()]), null); + BundleDescription result = state.getFactory().createBundleDescription(resource.getBundle().getBundleId(), symbolicNameSpecification, version, resource.getBundle().getLocation(), requireBundles.toArray(new BundleSpecification[requireBundles.size()]), fragmentHost.size() == 0 ? null : fragmentHost.get(0), importPackages.toArray(new ImportPackageSpecification[importPackages.size()]), exportPackages.toArray(new ExportPackageDescription[exportPackages.size()]), null, null, requireCapabilities.toArray(new GenericSpecification[requireCapabilities.size()]), provideCapabilities.toArray(new GenericDescription[provideCapabilities.size()]), null); result.setUserObject(resource); GenericDescription[] genericDescs = result.getGenericCapabilities(); for (GenericDescription genericDesc : genericDescs) { @@ -85,7 +94,7 @@ class StateConverter { String packageName = (String) attributes.remove(PackageNamespace.PACKAGE_NAMESPACE); // remove invalid attributes attributes.remove(PackageNamespace.CAPABILITY_BUNDLE_SYMBOLICNAME_ATTRIBUTE); - attributes.remove(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE); + attributes.remove(AbstractWiringNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE); String declaration = packageName + toString(attributes, "=", true) + toString(directives, ":=", true); //$NON-NLS-1$//$NON-NLS-2$ List<ExportPackageDescription> result = state.getFactory().createExportPackageDescriptions(declaration); for (ExportPackageDescription export : result) { diff --git a/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/internal/resolver/BaseDescriptionImpl.java b/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/internal/resolver/BaseDescriptionImpl.java index 60d3f2b30..3abcdfdb6 100644 --- a/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/internal/resolver/BaseDescriptionImpl.java +++ b/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/internal/resolver/BaseDescriptionImpl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2011 IBM Corporation and others. + * Copyright (c) 2004, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -114,7 +114,7 @@ public abstract class BaseDescriptionImpl implements BaseDescription { this.userObject = userObject; } - class BaseCapability implements BundleCapability { + public class BaseCapability implements BundleCapability { private final String namespace; public BaseCapability(String namespace) { @@ -151,7 +151,7 @@ public abstract class BaseDescriptionImpl implements BaseDescription { return System.identityHashCode(BaseDescriptionImpl.this); } - protected BaseDescriptionImpl getBaseDescription() { + public BaseDescriptionImpl getBaseDescription() { return BaseDescriptionImpl.this; } |