diff options
author | Thomas Watson | 2011-08-29 21:25:51 +0000 |
---|---|---|
committer | Thomas Watson | 2011-09-08 18:57:21 +0000 |
commit | a4439d90f4dd7d1033f3dca6e92c3b7064b6f47f (patch) | |
tree | 43630c2205abc59ca64dab2de6d419c09d15d8a9 | |
parent | 9a365c23db3abf8409d7c09a8973e514ab11437d (diff) | |
download | rt.equinox.framework-a4439d90f4dd7d1033f3dca6e92c3b7064b6f47f.tar.gz rt.equinox.framework-a4439d90f4dd7d1033f3dca6e92c3b7064b6f47f.tar.xz rt.equinox.framework-a4439d90f4dd7d1033f3dca6e92c3b7064b6f47f.zip |
Bug 357137 - Changes to equinox resolver to support RFC 112 resolverv20110908-1857
16 files changed, 490 insertions, 120 deletions
diff --git a/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF index 5cc0727b8..142a91e4b 100644 --- a/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF @@ -10,7 +10,8 @@ Export-Package: org.eclipse.osgi.event;version="1.0", org.eclipse.osgi.service.environment;version="1.3", org.eclipse.osgi.service.localization;version="1.1", org.eclipse.osgi.service.pluginconversion;version="1.0", - org.eclipse.osgi.service.resolver;version="1.5", + org.eclipse.osgi.service.resolver;version="1.6", + org.eclipse.osgi.service.resolver.extras;version="1.0"; x-friends:="org.eclipse.equinox.resolver", org.eclipse.osgi.service.runnable;version="1.1", org.eclipse.osgi.service.security; version="1.0", org.eclipse.osgi.service.urlconversion;version="1.0", diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/BaseDescription.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/BaseDescription.java index c9b02b724..3c70068a9 100644 --- a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/BaseDescription.java +++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/BaseDescription.java @@ -71,4 +71,27 @@ public interface BaseDescription { * @since 3.7 */ public BundleCapability getCapability(); + + /** + * Returns the user object associated to this description, or + * <code>null</code> if none exists. + * + * @return the user object associated to this description, + * or <code>null</code> + * @since 3.8 + */ + public Object getUserObject(); + + /** + * Associates a user-provided object to this description, or + * removes an existing association, if <code>null</code> is provided. The + * provided object is not interpreted in any ways by this + * description. + * + * @param userObject an arbitrary object provided by the user, or + * <code>null</code> + * @since 3.8 + */ + public void setUserObject(Object userObject); + } diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/BundleDescription.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/BundleDescription.java index 38f02beb7..b7acfcc21 100644 --- a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/BundleDescription.java +++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/BundleDescription.java @@ -223,26 +223,6 @@ public interface BundleDescription extends BaseDescription, BundleRevision { public BundleDescription[] getDependents(); /** - * Returns the user object associated to this bundle description, or - * <code>null</code> if none exists. - * - * @return the user object associated to this bundle description, - * or <code>null</code> - */ - public Object getUserObject(); - - /** - * Associates a user-provided object to this bundle description, or - * removes an existing association, if <code>null</code> is provided. The - * provided object is not interpreted in any ways by this bundle - * description. - * - * @param userObject an arbitrary object provided by the user, or - * <code>null</code> - */ - public void setUserObject(Object userObject); - - /** * Returns the platform filter in the form of an LDAP filter * @return the platfomr filter in the form of an LDAP filter */ diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/StateObjectFactory.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/StateObjectFactory.java index 3367b0da6..c0f6701bc 100644 --- a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/StateObjectFactory.java +++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/StateObjectFactory.java @@ -11,8 +11,7 @@ package org.eclipse.osgi.service.resolver; import java.io.*; -import java.util.Dictionary; -import java.util.Map; +import java.util.*; import org.eclipse.osgi.internal.resolver.StateObjectFactoryImpl; import org.osgi.framework.*; @@ -162,6 +161,27 @@ public interface StateObjectFactory { public BundleDescription createBundleDescription(long id, String symbolicName, Version version, String location, BundleSpecification[] required, HostSpecification host, ImportPackageSpecification[] imports, ExportPackageDescription[] exports, boolean singleton, boolean attachFragments, boolean dynamicFragments, String platformFilter, String[] executionEnvironments, GenericSpecification[] genericRequires, GenericDescription[] genericCapabilities, NativeCodeSpecification nativeCode); /** + * Creates a bundle description from the given parameters. + * + * @param id id for the bundle + * @param symbolicName the symbolic name of the bundle. This may include directives and/or attributes encoded using the Bundle-SymbolicName header. + * @param version version for the bundle (may be <code>null</code>) + * @param location location for the bundle (may be <code>null</code>) + * @param required version constraints for all required bundles (may be <code>null</code>) + * @param host version constraint specifying the host for the bundle to be created. Should be <code>null</code> if the bundle is not a fragment + * @param imports version constraints for all packages imported (may be <code>null</code>) + * @param exports package descriptions of all the exported packages (may be <code>null</code>) + * @param platformFilter the platform filter (may be <code>null</code>) + * @param executionEnvironments the execution environment (may be <code>null</code>) + * @param genericRequires the version constraints for all required capabilities (may be <code>null</code>) + * @param genericCapabilities the specifications of all the capabilities of the bundle (may be <code>null</code>) + * @param nativeCode the native code specification of the bundle (may be <code>null</code>) + * @return the created bundle description + * @since 3.8 + */ + public BundleDescription createBundleDescription(long id, String symbolicName, Version version, String location, BundleSpecification[] required, HostSpecification host, ImportPackageSpecification[] imports, ExportPackageDescription[] exports, String platformFilter, String[] executionEnvironments, GenericSpecification[] genericRequires, GenericDescription[] genericCapabilities, NativeCodeSpecification nativeCode); + + /** * Returns a bundle description based on the information in the supplied manifest dictionary. * The manifest should contain String keys and String values which correspond to * proper OSGi manifest headers and values. @@ -219,6 +239,15 @@ public interface StateObjectFactory { public BundleSpecification createBundleSpecification(BundleSpecification original); /** + * Creates bundle specifications from the given declaration. The declaration uses + * the bundle manifest syntax for the Require-Bundle header. + * @param declaration a string declaring bundle specifications + * @return the bundle specifications + * @since 3.8 + */ + public List<BundleSpecification> createBundleSpecifications(String declaration); + + /** * Creates a host specification from the given parameters. * * @param hostSymbolicName the symbolic name for the host bundle @@ -229,6 +258,15 @@ public interface StateObjectFactory { public HostSpecification createHostSpecification(String hostSymbolicName, VersionRange hostVersionRange); /** + * Creates host specifications from the given declaration. The declaration uses + * the bundle manifest syntax for the Fragment-Host header. + * @param declaration a string declaring host specifications + * @return the host specifications + * @since 3.8 + */ + public List<HostSpecification> createHostSpecifications(String declaration); + + /** * Creates a host specification that is a copy of the given constraint. * * @param original the constraint to be copied @@ -258,6 +296,15 @@ public interface StateObjectFactory { public ImportPackageSpecification createImportPackageSpecification(ImportPackageSpecification original); /** + * Creates an import package specifications from the given declaration. The declaration uses + * the bundle manifest syntax for the Import-Package header. + * @param declaration a string declaring import package specifications + * @return the import package specifications + * @since 3.8 + */ + public List<ImportPackageSpecification> createImportPackageSpecifications(String declaration); + + /** * Used by the Resolver to dynamically create ExportPackageDescription objects during the resolution process. * The Resolver needs to create ExportPackageDescriptions dynamically for a host when a fragment. * exports a package<p> @@ -295,6 +342,15 @@ public interface StateObjectFactory { public GenericDescription createGenericDescription(String type, Map<String, ?> attributes, Map<String, String> directives, BundleDescription supplier); /** + * Creates generic descriptions from the given declaration. The declaration uses + * the bundle manifest syntax for the Provide-Capability header. + * @param declaration a string declaring generic descriptions + * @return the generic descriptions + * @since 3.8 + */ + public List<GenericDescription> createGenericDescriptions(String declaration); + + /** * Creates a generic specification from the given parameters * @param name the name of the generic specification * @param type the type of the generic specification (may be <code>null</code>) @@ -307,6 +363,15 @@ public interface StateObjectFactory { public GenericSpecification createGenericSpecification(String name, String type, String matchingFilter, boolean optional, boolean multiple) throws InvalidSyntaxException; /** + * Creates generic specifications from the given declaration. The declaration uses + * the bundle manifest syntax for the Require-Capability header. + * @param declaration a string declaring generic specifications + * @return the generic specifications + * @since 3.8 + */ + public List<GenericSpecification> createGenericSpecifications(String declaration); + + /** * Creates a native code specification from the given parameters * @param nativeCodeDescriptions the native code descriptors * @param optional whether the specification is optional @@ -330,13 +395,22 @@ public interface StateObjectFactory { public NativeCodeDescription createNativeCodeDescription(String[] nativePaths, String[] processors, String[] osNames, VersionRange[] osVersions, String[] languages, String filter) throws InvalidSyntaxException; /** - * Creates an import package specification that is a copy of the given constraint + * Creates an export package specification that is a copy of the given constraint * @param original the export package to be copied * @return the created package */ public ExportPackageDescription createExportPackageDescription(ExportPackageDescription original); /** + * Creates export package descriptions from the given declaration. The declaration uses + * the bundle manifest syntax for the Export-Package header. + * @param declaration a string declaring export package descriptions + * @return the export package descriptions + * @since 3.8 + */ + public List<ExportPackageDescription> createExportPackageDescriptions(String declaration); + + /** * Persists the given state in the given output stream. Closes the stream. * * @param state the state to be written diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/VersionConstraint.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/VersionConstraint.java index 3b3be74e2..2f15515f8 100644 --- a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/VersionConstraint.java +++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/VersionConstraint.java @@ -82,4 +82,26 @@ public interface VersionConstraint extends Cloneable { * @since 3.7 */ public BundleRequirement getRequirement(); + + /** + * Returns the user object associated to this constraint, or + * <code>null</code> if none exists. + * + * @return the user object associated to this constraint, + * or <code>null</code> + * @since 3.8 + */ + public Object getUserObject(); + + /** + * Associates a user-provided object to this constraint, or + * removes an existing association, if <code>null</code> is provided. The + * provided object is not interpreted in any ways by this + * constrain. + * + * @param userObject an arbitrary object provided by the user, or + * <code>null</code> + * @since 3.8 + */ + public void setUserObject(Object userObject); } diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/extras/DescriptionReference.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/extras/DescriptionReference.java new file mode 100644 index 000000000..d7d32cbf4 --- /dev/null +++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/extras/DescriptionReference.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2011 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.service.resolver.extras; + +import org.eclipse.osgi.service.resolver.BaseDescription; + +/** + * A reference to a {@link BaseDescription}. + * @since 3.8 + */ +public interface DescriptionReference { + /** + * Returns the {@code BaseDescription} object associated with this + * reference. + * + * @return The {@code BaseDescription} object associated with this + * reference. + */ + public BaseDescription getDescription(); +} diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/extras/Sortable.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/extras/Sortable.java new file mode 100644 index 000000000..2442c5e2f --- /dev/null +++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/extras/Sortable.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2011 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.service.resolver.extras; + +import java.util.Comparator; + +/** + * Represents a collection of elements which can be sorted. + * @since 3.8 + */ +public interface Sortable<E> { + /** + * Sorts collection of elements represented by this sortable according + * to the specified comparator. + * @param comparator the comparator used to sort the collection + * of elements represented by this sortable. + */ + void sort(Comparator<E> comparator); +}
\ No newline at end of file diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/extras/SpecificationReference.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/extras/SpecificationReference.java new file mode 100644 index 000000000..c63e2c181 --- /dev/null +++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/extras/SpecificationReference.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2011 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.service.resolver.extras; + +import org.eclipse.osgi.service.resolver.VersionConstraint; + +/** + * A reference to a {@link VersionConstraint} specification. + * @since 3.8 + */ +public interface SpecificationReference { + /** + * Returns the {@code VersionConstraint} object associated with this + * reference. + * + * @return The {@code VersionConstraint} object associated with this + * reference. + */ + public VersionConstraint getSpecification(); +}
\ No newline at end of file diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/ArrayMap.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/ArrayMap.java index 14512dd09..0eb15e7fa 100644 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/ArrayMap.java +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/ArrayMap.java @@ -11,6 +11,7 @@ package org.eclipse.osgi.internal.baseadaptor; import java.util.*; +import org.eclipse.osgi.service.resolver.extras.Sortable; /** * Simple map when dealing with small amounts of entries. @@ -19,7 +20,7 @@ import java.util.*; * @param <K> The key type * @param <V> the value type */ -public class ArrayMap<K, V> implements Collection<K> { +public class ArrayMap<K, V> implements Collection<K>, Sortable<K> { final List<K> keys; final List<V> values; @@ -157,4 +158,17 @@ public class ArrayMap<K, V> implements Collection<K> { public V getValue(int index) { return values.get(index); } + + public void sort(Comparator<K> comparator) { + List<K> sortedKeys = new ArrayList<K>(keys); + Collections.sort(sortedKeys, comparator); + List<V> sortedValues = new ArrayList<V>(sortedKeys.size()); + for (K key : sortedKeys) { + sortedValues.add(get(key)); + } + clear(); + for (int i = 0; i < sortedKeys.size(); i++) { + put(sortedKeys.get(i), sortedValues.get(i)); + } + } } diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/ResolverImpl.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/ResolverImpl.java index f750efb63..8493bd23c 100644 --- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/ResolverImpl.java +++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/ResolverImpl.java @@ -11,8 +11,6 @@ ******************************************************************************/ package org.eclipse.osgi.internal.module; -import org.osgi.framework.resource.ResourceConstants; - import java.security.AccessController; import java.util.*; import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; @@ -29,7 +27,9 @@ import org.eclipse.osgi.util.ManifestElement; import org.osgi.framework.Filter; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.hooks.resolver.ResolverHook; -import org.osgi.framework.wiring.*; +import org.osgi.framework.resource.ResourceConstants; +import org.osgi.framework.wiring.BundleCapability; +import org.osgi.framework.wiring.BundleRevision; public class ResolverImpl implements Resolver { // Debug fields @@ -348,23 +348,28 @@ public class ResolverImpl implements Resolver { // find all available hosts to attach to. boolean foundMatch = false; BundleConstraint hostConstraint = bundle.getHost(); - List<ResolverBundle> hosts = resolverBundles.get(hostConstraint.getVersionConstraint().getName()); - List<ResolverBundle> candidates = new ArrayList<ResolverBundle>(hosts); - List<BundleCapability> hostCapabilities = new ArrayList<BundleCapability>(hosts.size()); - // Must remove candidates that do not match before calling hooks. - for (Iterator<ResolverBundle> iCandidates = candidates.iterator(); iCandidates.hasNext();) { - ResolverBundle host = iCandidates.next(); - if (!host.isResolvable() || !host.getBundleDescription().attachFragments() || !hostConstraint.isSatisfiedBy(host)) { - iCandidates.remove(); - } else { - List<BundleCapability> h = host.getBundleDescription().getDeclaredCapabilities(BundleRevision.HOST_NAMESPACE); - // the bundle must have 1 host capability. - hostCapabilities.add(h.get(0)); + long timestamp; + List<ResolverBundle> candidates; + do { + timestamp = state.getTimeStamp(); + List<ResolverBundle> hosts = resolverBundles.get(hostConstraint.getVersionConstraint().getName()); + candidates = new ArrayList<ResolverBundle>(hosts); + List<BundleCapability> hostCapabilities = new ArrayList<BundleCapability>(hosts.size()); + // Must remove candidates that do not match before calling hooks. + for (Iterator<ResolverBundle> iCandidates = candidates.iterator(); iCandidates.hasNext();) { + ResolverBundle host = iCandidates.next(); + if (!host.isResolvable() || !host.getBundleDescription().attachFragments() || !hostConstraint.isSatisfiedBy(host)) { + iCandidates.remove(); + } else { + List<BundleCapability> h = host.getBundleDescription().getDeclaredCapabilities(BundleRevision.HOST_NAMESPACE); + // the bundle must have 1 host capability. + hostCapabilities.add(h.get(0)); + } } - } - if (hook != null) - hook.filterMatches(hostConstraint.getRequirement(), asCapabilities(new ArrayMap<BundleCapability, ResolverBundle>(hostCapabilities, candidates))); + if (hook != null) + hook.filterMatches(hostConstraint.getRequirement(), asCapabilities(new ArrayMap<BundleCapability, ResolverBundle>(hostCapabilities, candidates))); + } while (timestamp != state.getTimeStamp()); // we are left with only candidates that satisfy the host constraint for (ResolverBundle host : candidates) { foundMatch = true; @@ -372,6 +377,7 @@ public class ResolverImpl implements Resolver { } if (!foundMatch) state.addResolverError(bundle.getBundleDescription(), ResolverError.MISSING_FRAGMENT_HOST, bundle.getHost().getVersionConstraint().toString(), bundle.getHost().getVersionConstraint()); + } public synchronized void resolve(BundleDescription[] reRefresh, Dictionary<Object, Object>[] platformProperties) { @@ -564,7 +570,7 @@ public class ResolverImpl implements Resolver { if (DEBUG_WIRING) printWirings(); // set the resolved status of the bundles in the State - stateResolveBundles(bundles); + stateResolveBundles(bundleMapping.values().toArray(new ResolverBundle[bundleMapping.size()])); } private void selectSingletons(ResolverBundle[] bundles) { @@ -1340,26 +1346,31 @@ public class ResolverImpl implements Resolver { ResolverImpl.log(" - already wired"); //$NON-NLS-1$ return true; // Already wired (due to grouping dependencies) so just return } - VersionHashMap<GenericCapability> namespace = resolverGenerics.get(constraint.getNameSpace()); - String name = constraint.getName(); - List<GenericCapability> capabilities; - if (namespace == null) - capabilities = Collections.EMPTY_LIST; - else - capabilities = name == null || name.indexOf('*') >= 0 ? namespace.getAllValues() : namespace.get(name); - List<GenericCapability> candidates = new ArrayList<GenericCapability>(capabilities); - List<BundleCapability> genCapabilities = new ArrayList<BundleCapability>(candidates.size()); - // Must remove candidates that do not match before calling hooks. - for (Iterator<GenericCapability> iCandidates = candidates.iterator(); iCandidates.hasNext();) { - GenericCapability capability = iCandidates.next(); - if (!constraint.isSatisfiedBy(capability)) { - iCandidates.remove(); - } else { - genCapabilities.add(capability.getCapability()); + List<GenericCapability> candidates; + long timestamp; + do { + timestamp = state.getTimeStamp(); + VersionHashMap<GenericCapability> namespace = resolverGenerics.get(constraint.getNameSpace()); + String name = constraint.getName(); + List<GenericCapability> capabilities; + if (namespace == null) + capabilities = Collections.EMPTY_LIST; + else + capabilities = name == null || name.indexOf('*') >= 0 ? namespace.getAllValues() : namespace.get(name); + candidates = new ArrayList<GenericCapability>(capabilities); + List<BundleCapability> genCapabilities = new ArrayList<BundleCapability>(candidates.size()); + // Must remove candidates that do not match before calling hooks. + for (Iterator<GenericCapability> iCandidates = candidates.iterator(); iCandidates.hasNext();) { + GenericCapability capability = iCandidates.next(); + if (!constraint.isSatisfiedBy(capability)) { + iCandidates.remove(); + } else { + genCapabilities.add(capability.getCapability()); + } } - } - if (hook != null) - hook.filterMatches(constraint.getRequirement(), asCapabilities(new ArrayMap<BundleCapability, GenericCapability>(genCapabilities, candidates))); + if (hook != null) + hook.filterMatches(constraint.getRequirement(), asCapabilities(new ArrayMap<BundleCapability, GenericCapability>(genCapabilities, candidates))); + } while (timestamp != state.getTimeStamp()); boolean result = false; // We are left with only capabilities that satisfy the constraint. for (GenericCapability capability : candidates) { @@ -1416,20 +1427,25 @@ public class ResolverImpl implements Resolver { ResolverImpl.log(" - already wired"); //$NON-NLS-1$ return true; // Already wired (due to grouping dependencies) so just return } - List<ResolverBundle> bundles = resolverBundles.get(req.getVersionConstraint().getName()); - List<ResolverBundle> candidates = new ArrayList<ResolverBundle>(bundles); - List<BundleCapability> capabilities = new ArrayList<BundleCapability>(candidates.size()); - // Must remove candidates that do not match before calling hooks. - for (Iterator<ResolverBundle> iCandidates = candidates.iterator(); iCandidates.hasNext();) { - ResolverBundle bundle = iCandidates.next(); - if (!req.isSatisfiedBy(bundle)) { - iCandidates.remove(); - } else { - capabilities.add(bundle.getCapability()); + List<ResolverBundle> candidates; + long timestamp; + do { + timestamp = state.getTimeStamp(); + List<ResolverBundle> bundles = resolverBundles.get(req.getVersionConstraint().getName()); + candidates = new ArrayList<ResolverBundle>(bundles); + List<BundleCapability> capabilities = new ArrayList<BundleCapability>(candidates.size()); + // Must remove candidates that do not match before calling hooks. + for (Iterator<ResolverBundle> iCandidates = candidates.iterator(); iCandidates.hasNext();) { + ResolverBundle bundle = iCandidates.next(); + if (!req.isSatisfiedBy(bundle)) { + iCandidates.remove(); + } else { + capabilities.add(bundle.getCapability()); + } } - } - if (hook != null) - hook.filterMatches(req.getRequirement(), asCapabilities(new ArrayMap<BundleCapability, ResolverBundle>(capabilities, candidates))); + if (hook != null) + hook.filterMatches(req.getRequirement(), asCapabilities(new ArrayMap<BundleCapability, ResolverBundle>(capabilities, candidates))); + } while (timestamp != state.getTimeStamp()); // We are left with only capabilities that satisfy the require bundle. boolean result = false; for (ResolverBundle bundle : candidates) { @@ -1483,20 +1499,25 @@ public class ResolverImpl implements Resolver { } boolean result = false; ResolverExport[] substitutableExps = imp.getBundle().getExports(imp.getName()); - List<ResolverExport> exports = resolverExports.get(imp.getName()); - List<ResolverExport> candidates = new ArrayList<ResolverExport>(exports); - List<BundleCapability> capabilities = new ArrayList<BundleCapability>(candidates.size()); - // Must remove candidates that do not match before calling hooks. - for (Iterator<ResolverExport> iCandidates = candidates.iterator(); iCandidates.hasNext();) { - ResolverExport export = iCandidates.next(); - if (!imp.isSatisfiedBy(export)) { - iCandidates.remove(); - } else { - capabilities.add(export.getCapability()); + long timestamp; + List<ResolverExport> candidates; + do { + timestamp = state.getTimeStamp(); + List<ResolverExport> exports = resolverExports.get(imp.getName()); + candidates = new ArrayList<ResolverExport>(exports); + List<BundleCapability> capabilities = new ArrayList<BundleCapability>(candidates.size()); + // Must remove candidates that do not match before calling hooks. + for (Iterator<ResolverExport> iCandidates = candidates.iterator(); iCandidates.hasNext();) { + ResolverExport export = iCandidates.next(); + if (!imp.isSatisfiedBy(export)) { + iCandidates.remove(); + } else { + capabilities.add(export.getCapability()); + } } - } - if (hook != null) - hook.filterMatches(imp.getRequirement(), asCapabilities(new ArrayMap<BundleCapability, ResolverExport>(capabilities, candidates))); + if (hook != null) + hook.filterMatches(imp.getRequirement(), asCapabilities(new ArrayMap<BundleCapability, ResolverExport>(capabilities, candidates))); + } while (timestamp != state.getTimeStamp()); // We are left with only capabilities that satisfy the import. for (ResolverExport export : candidates) { if (DEBUG_IMPORTS) @@ -1892,6 +1913,9 @@ public class ResolverImpl implements Resolver { resolverExports.put(rb.getExportPackages()); resolverBundles.put(rb.getName(), rb); addGenerics(rb.getGenericCapabilities()); + if (hook != null && rb.isFragment()) { + attachFragment0(rb); + } } public void bundleRemoved(BundleDescription bundle, boolean pending) { diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/BaseDescriptionImpl.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/BaseDescriptionImpl.java index 471631850..a24cf9b0b 100644 --- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/BaseDescriptionImpl.java +++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/BaseDescriptionImpl.java @@ -14,6 +14,7 @@ package org.eclipse.osgi.internal.resolver; import java.util.*; import java.util.Map.Entry; import org.eclipse.osgi.service.resolver.BaseDescription; +import org.eclipse.osgi.service.resolver.extras.DescriptionReference; import org.osgi.framework.Version; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRevision; @@ -26,6 +27,8 @@ public abstract class BaseDescriptionImpl implements BaseDescription { private volatile Version version; + private volatile Object userObject; + public String getName() { return name; } @@ -104,7 +107,15 @@ public abstract class BaseDescriptionImpl implements BaseDescription { return new BaseCapability(namespace); } - class BaseCapability implements BundleCapability { + public Object getUserObject() { + return userObject; + } + + public void setUserObject(Object userObject) { + this.userObject = userObject; + } + + class BaseCapability implements BundleCapability, DescriptionReference { private final String namespace; public BaseCapability(String namespace) { @@ -160,5 +171,9 @@ public abstract class BaseDescriptionImpl implements BaseDescription { public BundleRevision getResource() { return getRevision(); } + + public BaseDescription getDescription() { + return BaseDescriptionImpl.this; + } } } diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/BundleDescriptionImpl.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/BundleDescriptionImpl.java index 22c38d221..e88293c9b 100644 --- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/BundleDescriptionImpl.java +++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/BundleDescriptionImpl.java @@ -53,7 +53,6 @@ public final class BundleDescriptionImpl extends BaseDescriptionImpl implements volatile HostSpecification host; //null if the bundle is not a fragment. volatile to allow unsynchronized checks for null private volatile StateImpl containingState; - private volatile Object userObject; private volatile int lazyDataOffset = -1; private volatile int lazyDataSize = -1; @@ -581,14 +580,6 @@ public final class BundleDescriptionImpl extends BaseDescriptionImpl implements } } - public Object getUserObject() { - return userObject; - } - - public void setUserObject(Object userObject) { - this.userObject = userObject; - } - protected void addDependent(BundleDescription dependent) { synchronized (this.monitor) { if (dependents == null) diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateBuilder.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateBuilder.java index 114b86c65..a93479068 100644 --- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateBuilder.java +++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateBuilder.java @@ -31,8 +31,8 @@ public class StateBuilder { private static final String[] DEFINED_PACKAGE_MATCHING_ATTRS = {Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, Constants.BUNDLE_VERSION_ATTRIBUTE, Constants.PACKAGE_SPECIFICATION_VERSION, Constants.VERSION_ATTRIBUTE}; private static final String[] DEFINED_REQUIRE_BUNDLE_DIRECTIVES = {Constants.RESOLUTION_DIRECTIVE, Constants.VISIBILITY_DIRECTIVE}; private static final String[] DEFINED_FRAGMENT_HOST_DIRECTIVES = {Constants.EXTENSION_DIRECTIVE}; - private static final String[] DEFINED_BSN_DIRECTIVES = {Constants.SINGLETON_DIRECTIVE, Constants.FRAGMENT_ATTACHMENT_DIRECTIVE, Constants.MANDATORY_DIRECTIVE}; - private static final String[] DEFINED_BSN_MATCHING_ATTRS = {Constants.BUNDLE_VERSION_ATTRIBUTE, Constants.OPTIONAL_ATTRIBUTE, Constants.REPROVIDE_ATTRIBUTE}; + static final String[] DEFINED_BSN_DIRECTIVES = {Constants.SINGLETON_DIRECTIVE, Constants.FRAGMENT_ATTACHMENT_DIRECTIVE, Constants.MANDATORY_DIRECTIVE}; + static final String[] DEFINED_BSN_MATCHING_ATTRS = {Constants.BUNDLE_VERSION_ATTRIBUTE, Constants.OPTIONAL_ATTRIBUTE, Constants.REPROVIDE_ATTRIBUTE}; private static final String[] DEFINED_REQUIRE_CAPABILITY_DIRECTIVES = {Constants.RESOLUTION_DIRECTIVE, Constants.FILTER_DIRECTIVE}; private static final String[] DEFINED_REQUIRE_CAPABILITY_ATTRS = {}; private static final String[] DEFINED_OSGI_VALIDATE_HEADERS = {Constants.IMPORT_PACKAGE, Constants.DYNAMICIMPORT_PACKAGE, Constants.EXPORT_PACKAGE, Constants.FRAGMENT_HOST, Constants.BUNDLE_SYMBOLICNAME, Constants.REQUIRE_BUNDLE}; @@ -108,7 +108,7 @@ public class StateBuilder { ManifestElement[] provides = ManifestElement.parseHeader(Constants.PROVIDE_PACKAGE, manifest.get(Constants.PROVIDE_PACKAGE)); boolean strict = state != null && state.inStrictMode(); List<String> providedExports = new ArrayList<String>(provides == null ? 0 : provides.length); - result.setExportPackages(createExportPackages(exports, provides, providedExports, manifestVersion, strict)); + result.setExportPackages(createExportPackages(exports, provides, providedExports, strict)); ManifestElement[] imports = ManifestElement.parseHeader(Constants.IMPORT_PACKAGE, manifest.get(Constants.IMPORT_PACKAGE)); ManifestElement[] dynamicImports = ManifestElement.parseHeader(Constants.DYNAMICIMPORT_PACKAGE, manifest.get(Constants.DYNAMICIMPORT_PACKAGE)); result.setImportPackages(createImportPackages(result.getExportPackages(), providedExports, imports, dynamicImports, manifestVersion)); @@ -194,7 +194,7 @@ public class StateBuilder { return result; } - private static String getPlatformProperty(StateImpl state, String key) { + private static String getPlatformProperty(State state, String key) { Dictionary<Object, Object>[] platformProps = state == null ? null : state.getPlatformProperties(); return platformProps == null || platformProps.length == 0 ? null : (String) platformProps[0].get(key); } @@ -228,7 +228,7 @@ public class StateBuilder { return result; } - private static BundleSpecification createRequiredBundle(ManifestElement spec) { + static BundleSpecification createRequiredBundle(ManifestElement spec) { BundleSpecificationImpl result = new BundleSpecificationImpl(); result.setName(spec.getValue()); result.setVersionRange(getVersionRange(spec.getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE))); @@ -306,25 +306,25 @@ public class StateBuilder { private static String getResolution(String resolution) { String result = ImportPackageSpecification.RESOLUTION_STATIC; - if (Constants.RESOLUTION_OPTIONAL.equals(resolution)) - result = ImportPackageSpecification.RESOLUTION_OPTIONAL; + if (Constants.RESOLUTION_OPTIONAL.equals(resolution) || ImportPackageSpecification.RESOLUTION_DYNAMIC.equals(resolution)) + result = resolution; return result; } - static ExportPackageDescription[] createExportPackages(ManifestElement[] exported, ManifestElement[] provides, List<String> providedExports, int manifestVersion, boolean strict) { + static ExportPackageDescription[] createExportPackages(ManifestElement[] exported, ManifestElement[] provides, List<String> providedExports, boolean strict) { int numExports = (exported == null ? 0 : exported.length) + (provides == null ? 0 : provides.length); if (numExports == 0) return null; List<ExportPackageDescription> allExports = new ArrayList<ExportPackageDescription>(numExports); if (exported != null) for (int i = 0; i < exported.length; i++) - addExportPackages(exported[i], allExports, manifestVersion, strict); + addExportPackages(exported[i], allExports, strict); if (provides != null) addProvidePackages(provides, allExports, providedExports); return allExports.toArray(new ExportPackageDescription[allExports.size()]); } - private static void addExportPackages(ManifestElement exportPackage, List<ExportPackageDescription> allExports, int manifestVersion, boolean strict) { + static void addExportPackages(ManifestElement exportPackage, List<ExportPackageDescription> allExports, boolean strict) { String[] exportNames = exportPackage.getValueComponents(); for (int i = 0; i < exportNames.length; i++) { // if we are in strict mode and the package is marked as internal, skip it. @@ -367,7 +367,7 @@ public class StateBuilder { } } - private static Map<String, String> getDirectives(ManifestElement element, String[] definedDirectives) { + static Map<String, String> getDirectives(ManifestElement element, String[] definedDirectives) { Enumeration<String> keys = element.getDirectiveKeys(); if (keys == null) return null; @@ -385,7 +385,7 @@ public class StateBuilder { return arbitraryDirectives; } - private static Map<String, Object> getAttributes(ManifestElement element, String[] definedAttrs) { + static Map<String, Object> getAttributes(ManifestElement element, String[] definedAttrs) { Enumeration<String> keys = element.getKeys(); Map<String, Object> arbitraryAttrs = null; if (keys == null) @@ -463,7 +463,7 @@ public class StateBuilder { return components; } - private static HostSpecification createHostSpecification(ManifestElement spec, StateImpl state) { + static HostSpecification createHostSpecification(ManifestElement spec, State state) { if (spec == null) return null; HostSpecificationImpl result = new HostSpecificationImpl(); @@ -484,7 +484,7 @@ public class StateBuilder { return result == null ? null : result.toArray(new GenericSpecification[result.size()]); } - private static List<GenericSpecification> createOSGiRequires(ManifestElement[] osgiRequires, List<GenericSpecification> result) throws BundleException { + static List<GenericSpecification> createOSGiRequires(ManifestElement[] osgiRequires, List<GenericSpecification> result) throws BundleException { if (osgiRequires == null) return result; if (result == null) @@ -562,7 +562,7 @@ public class StateBuilder { return result == null ? null : result.toArray(new GenericDescription[result.size()]); } - private static List<GenericDescription> createOSGiCapabilities(ManifestElement[] osgiCapabilities, List<GenericDescription> result, BundleDescription description) throws BundleException { + static List<GenericDescription> createOSGiCapabilities(ManifestElement[] osgiCapabilities, List<GenericDescription> result, BundleDescription description) throws BundleException { if (result == null) result = new ArrayList<GenericDescription>(osgiCapabilities == null ? 1 : osgiCapabilities.length + 1); // Always have an osgi.identity capability if there is a symbolic name. @@ -770,7 +770,7 @@ public class StateBuilder { } } - private static GenericDescription createOsgiIdentityCapability(BundleDescription description) { + static GenericDescription createOsgiIdentityCapability(BundleDescription description) { if (description.getSymbolicName() == null) return null; GenericDescriptionImpl result = new GenericDescriptionImpl(); diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateImpl.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateImpl.java index 68f61b241..383b33a78 100644 --- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateImpl.java +++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateImpl.java @@ -836,7 +836,7 @@ public abstract class StateImpl implements State { private void addSystemExports(List<ExportPackageDescription> exports, ManifestElement[] elements, int index) { if (elements == null) return; - ExportPackageDescription[] systemExports = StateBuilder.createExportPackages(elements, null, null, 2, false); + ExportPackageDescription[] systemExports = StateBuilder.createExportPackages(elements, null, null, false); Integer profInx = new Integer(index); for (int j = 0; j < systemExports.length; j++) { ((ExportPackageDescriptionImpl) systemExports[j]).setDirective(ExportPackageDescriptionImpl.EQUINOX_EE, profInx); diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateObjectFactoryImpl.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateObjectFactoryImpl.java index df97bf13a..264ead854 100644 --- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateObjectFactoryImpl.java +++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateObjectFactoryImpl.java @@ -74,6 +74,52 @@ public class StateObjectFactoryImpl implements StateObjectFactory { return bundle; } + public BundleDescription createBundleDescription(long id, String symbolicName, Version version, String location, BundleSpecification[] required, HostSpecification host, ImportPackageSpecification[] imports, ExportPackageDescription[] exports, String platformFilter, String[] executionEnvironments, GenericSpecification[] genericRequires, GenericDescription[] genericCapabilities, NativeCodeSpecification nativeCode) { + BundleDescriptionImpl bundle = new BundleDescriptionImpl(); + bundle.setBundleId(id); + + try { + ManifestElement[] symbolicNameElements = ManifestElement.parseHeader(Constants.BUNDLE_SYMBOLICNAME, symbolicName); + if (symbolicNameElements.length > 0) { + ManifestElement bsnElement = symbolicNameElements[0]; + bundle.setSymbolicName(bsnElement.getValue()); + bundle.setStateBit(BundleDescriptionImpl.SINGLETON, "true".equals(bsnElement.getDirective(Constants.SINGLETON_DIRECTIVE))); //$NON-NLS-1$ + String fragmentAttachment = bsnElement.getDirective(Constants.FRAGMENT_ATTACHMENT_DIRECTIVE); + if (fragmentAttachment != null) { + if (fragmentAttachment.equals(Constants.FRAGMENT_ATTACHMENT_RESOLVETIME)) { + bundle.setStateBit(BundleDescriptionImpl.ATTACH_FRAGMENTS, true); + bundle.setStateBit(BundleDescriptionImpl.DYNAMIC_FRAGMENTS, false); + } else if (fragmentAttachment.equals(Constants.FRAGMENT_ATTACHMENT_NEVER)) { + bundle.setStateBit(BundleDescriptionImpl.ATTACH_FRAGMENTS, false); + bundle.setStateBit(BundleDescriptionImpl.DYNAMIC_FRAGMENTS, false); + } + } + bundle.setDirective(Constants.MANDATORY_DIRECTIVE, ManifestElement.getArrayFromList(bsnElement.getDirective(Constants.MANDATORY_DIRECTIVE))); + bundle.setAttributes(StateBuilder.getAttributes(bsnElement, StateBuilder.DEFINED_BSN_MATCHING_ATTRS)); + bundle.setArbitraryDirectives(StateBuilder.getDirectives(bsnElement, StateBuilder.DEFINED_BSN_DIRECTIVES)); + } + } catch (BundleException e) { + throw (IllegalArgumentException) new IllegalArgumentException("Illegal symbolic name: " + symbolicName).initCause(e); //$NON-NLS-1$ + } + + bundle.setVersion(version); + bundle.setLocation(location); + bundle.setRequiredBundles(required); + bundle.setHost(host); + bundle.setImportPackages(imports); + bundle.setExportPackages(exports); + bundle.setPlatformFilter(platformFilter); + bundle.setExecutionEnvironments(executionEnvironments); + bundle.setGenericRequires(genericRequires); + GenericDescription[] includeIdentity = new GenericDescription[genericCapabilities == null ? 1 : genericCapabilities.length + 1]; + if (genericCapabilities != null) + System.arraycopy(genericCapabilities, 0, includeIdentity, 1, genericCapabilities.length); + includeIdentity[0] = StateBuilder.createOsgiIdentityCapability(bundle); + bundle.setGenericCapabilities(includeIdentity); + bundle.setNativeCodeSpecification(nativeCode); + return bundle; + } + public BundleDescription createBundleDescription(BundleDescription original) { BundleDescriptionImpl bundle = new BundleDescriptionImpl(); bundle.setBundleId(original.getBundleId()); @@ -464,4 +510,88 @@ public class StateObjectFactoryImpl implements StateObjectFactory { StateWriter writer = new StateWriter(); writer.saveStateDeprecated((StateImpl) state, stream); } + + @SuppressWarnings("unchecked") + public List<BundleSpecification> createBundleSpecifications(String declaration) { + try { + ManifestElement[] elements = ManifestElement.parseHeader(Constants.REQUIRE_BUNDLE, declaration); + if (elements == null) + return Collections.EMPTY_LIST; + List<BundleSpecification> result = new ArrayList<BundleSpecification>(elements.length); + for (ManifestElement element : elements) + result.add(StateBuilder.createRequiredBundle(element)); + return result; + } catch (BundleException e) { + throw (IllegalArgumentException) new IllegalArgumentException("Declaration is invalid: " + declaration).initCause(e); //$NON-NLS-1$ + } + } + + @SuppressWarnings("unchecked") + public List<HostSpecification> createHostSpecifications(String declaration) { + try { + ManifestElement[] elements = ManifestElement.parseHeader(Constants.FRAGMENT_HOST, declaration); + if (elements == null) + return Collections.EMPTY_LIST; + List<HostSpecification> result = new ArrayList<HostSpecification>(elements.length); + for (ManifestElement element : elements) + result.add(StateBuilder.createHostSpecification(element, null)); + return result; + } catch (BundleException e) { + throw (IllegalArgumentException) new IllegalArgumentException("Declaration is invalid: " + declaration).initCause(e); //$NON-NLS-1$ + } + } + + @SuppressWarnings("unchecked") + public List<ImportPackageSpecification> createImportPackageSpecifications(String declaration) { + try { + ManifestElement[] elements = ManifestElement.parseHeader(Constants.IMPORT_PACKAGE, declaration); + if (elements == null) + return Collections.EMPTY_LIST; + List<ImportPackageSpecification> result = new ArrayList<ImportPackageSpecification>(elements.length); + for (ManifestElement element : elements) + StateBuilder.addImportPackages(element, result, 2, false); + return result; + } catch (BundleException e) { + throw (IllegalArgumentException) new IllegalArgumentException("Declaration is invalid: " + declaration).initCause(e); //$NON-NLS-1$ + } + } + + @SuppressWarnings("unchecked") + public List<GenericDescription> createGenericDescriptions(String declaration) { + try { + ManifestElement[] elements = ManifestElement.parseHeader(Constants.PROVIDE_CAPABILITY, declaration); + if (elements == null) + return Collections.EMPTY_LIST; + return StateBuilder.createOSGiCapabilities(elements, new ArrayList<GenericDescription>(elements.length), (Integer) null); + } catch (BundleException e) { + throw (IllegalArgumentException) new IllegalArgumentException("Declaration is invalid: " + declaration).initCause(e); //$NON-NLS-1$ + } + } + + @SuppressWarnings("unchecked") + public List<GenericSpecification> createGenericSpecifications(String declaration) { + try { + ManifestElement[] elements = ManifestElement.parseHeader(Constants.REQUIRE_CAPABILITY, declaration); + if (elements == null) + return Collections.EMPTY_LIST; + return StateBuilder.createOSGiRequires(elements, new ArrayList<GenericSpecification>(elements.length)); + } catch (BundleException e) { + throw (IllegalArgumentException) new IllegalArgumentException("Declaration is invalid: " + declaration).initCause(e); //$NON-NLS-1$ + } + } + + @SuppressWarnings("unchecked") + public List<ExportPackageDescription> createExportPackageDescriptions(String declaration) { + try { + ManifestElement[] elements = ManifestElement.parseHeader(Constants.IMPORT_PACKAGE, declaration); + if (elements == null) + return Collections.EMPTY_LIST; + List<ExportPackageDescription> result = new ArrayList<ExportPackageDescription>(elements.length); + for (ManifestElement element : elements) + StateBuilder.addExportPackages(element, result, false); + return result; + } catch (BundleException e) { + throw (IllegalArgumentException) new IllegalArgumentException("Declaration is invalid: " + declaration).initCause(e); //$NON-NLS-1$ + } + } } diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/VersionConstraintImpl.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/VersionConstraintImpl.java index a88af773a..45359bf6e 100644 --- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/VersionConstraintImpl.java +++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/VersionConstraintImpl.java @@ -12,16 +12,16 @@ *******************************************************************************/ package org.eclipse.osgi.internal.resolver; -import org.osgi.framework.resource.Capability; -import org.osgi.framework.resource.ResourceConstants; - import java.util.Collections; import java.util.Map; import org.eclipse.osgi.framework.internal.core.Constants; import org.eclipse.osgi.internal.resolver.BaseDescriptionImpl.BaseCapability; import org.eclipse.osgi.service.resolver.*; +import org.eclipse.osgi.service.resolver.extras.SpecificationReference; import org.eclipse.osgi.util.ManifestElement; import org.osgi.framework.*; +import org.osgi.framework.resource.Capability; +import org.osgi.framework.resource.ResourceConstants; import org.osgi.framework.wiring.*; abstract class VersionConstraintImpl implements VersionConstraint { @@ -32,6 +32,7 @@ abstract class VersionConstraintImpl implements VersionConstraint { private VersionRange versionRange; private BundleDescription bundle; private BaseDescription supplier; + private volatile Object userObject; public String getName() { synchronized (this.monitor) { @@ -114,7 +115,15 @@ abstract class VersionConstraintImpl implements VersionConstraint { return new BundleRequirementImpl(namespace); } - class BundleRequirementImpl implements BundleRequirement { + public Object getUserObject() { + return userObject; + } + + public void setUserObject(Object userObject) { + this.userObject = userObject; + } + + class BundleRequirementImpl implements BundleRequirement, SpecificationReference { private final String namespace; public BundleRequirementImpl(String namespace) { @@ -182,6 +191,10 @@ abstract class VersionConstraintImpl implements VersionConstraint { public BundleRevision getResource() { return getRevision(); } + + public VersionConstraint getSpecification() { + return VersionConstraintImpl.this; + } } static StringBuffer addFilterAttributes(StringBuffer filter, Map<String, ?> attributes) { |