Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Watson2006-03-17 14:47:21 +0000
committerThomas Watson2006-03-17 14:47:21 +0000
commitae17b137d9a857e925149f706498edcd1b63ba5b (patch)
treed214047411e84adba252dd3b56e9de4cac1ab670
parent16a7c7d7c3bb7bee0f0a017c162dd00e74087a00 (diff)
downloadrt.equinox.framework-ae17b137d9a857e925149f706498edcd1b63ba5b.tar.gz
rt.equinox.framework-ae17b137d9a857e925149f706498edcd1b63ba5b.tar.xz
rt.equinox.framework-ae17b137d9a857e925149f706498edcd1b63ba5b.zip
Bug 123707 consider resolver support for matching arbitrary properties
-rw-r--r--bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/AllTests.java1
-rw-r--r--bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/GenericCapabilityTest.java310
-rw-r--r--bundles/org.eclipse.osgi/.options1
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/BaseDescription.java10
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/BundleDescription.java18
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/GenericDescription.java36
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/GenericSpecification.java56
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/ResolverError.java8
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/StateObjectFactory.java73
-rw-r--r--bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/util/ManifestElement.java93
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/GenericCapability.java35
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/GenericConstraint.java49
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/ResolverBundle.java59
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/ResolverImpl.java121
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/BaseDescriptionImpl.java4
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/BundleDescriptionImpl.java48
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/ExportPackageDescriptionImpl.java30
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/GenericDescriptionImpl.java59
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/GenericSpecificationImpl.java99
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/ResolverErrorImpl.java1
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateBuilder.java197
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateHelperImpl.java43
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateImpl.java20
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateObjectFactoryImpl.java85
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateReader.java85
-rw-r--r--bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateWriter.java88
-rw-r--r--bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/util/ManifestElement.java93
27 files changed, 1544 insertions, 178 deletions
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/AllTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/AllTests.java
index f936cf2e8..f77b54999 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/AllTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/AllTests.java
@@ -31,6 +31,7 @@ public class AllTests extends TestCase {
suite.addTest(VersionRangeTests.suite());
suite.addTest(R4ResolverTest.suite());
suite.addTest(XFriendsInternalResolverTest.suite());
+ suite.addTest(GenericCapabilityTest.suite());
return suite;
}
}
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/GenericCapabilityTest.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/GenericCapabilityTest.java
new file mode 100644
index 000000000..e6eef306a
--- /dev/null
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/GenericCapabilityTest.java
@@ -0,0 +1,310 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2005 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.tests.services.resolver;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.eclipse.osgi.service.resolver.*;
+import org.osgi.framework.*;
+
+public class GenericCapabilityTest extends AbstractStateTest {
+ private static final String GENERIC_REQUIRE = "Eclipse-GenericRequire"; //$NON-NLS-1$
+ private static final String GENERIC_CAPABILITY = "Eclipse-GenericCapability"; //$NON-NLS-1$
+ public static Test suite() {
+ return new TestSuite(GenericCapabilityTest.class);
+ }
+
+ public GenericCapabilityTest(String name) {
+ super(name);
+ }
+
+ public void testGenericsBasics() throws BundleException {
+ State state = buildEmptyState();
+ Hashtable manifest = new Hashtable();
+ long bundleID = 0;
+ manifest.put(Constants.BUNDLE_MANIFESTVERSION, "2");
+ manifest.put(Constants.BUNDLE_SYMBOLICNAME, "genericCapablity");
+ manifest.put(Constants.BUNDLE_VERSION, "1.0.0");
+ StringBuffer capabililty = new StringBuffer();
+ capabililty.append("foo; version=\"1.3.1\"; attr1=\"value1\"; attr2=\"value2\",");
+ capabililty.append("bar:bartype; version=\"1.4.1\"; attr1=\"value1\"; attr2=\"value2\",");
+ capabililty.append("test.types:testtype;");
+ capabililty.append(" aVersion:version=\"2.0.0\";");
+ capabililty.append(" aLong:long=\"10000000000\";");
+ capabililty.append(" aDouble:double=\"1.000109\";");
+ capabililty.append(" aUri:uri=\"file:/test\";");
+ capabililty.append(" aSet:set=\"a,b,c,d\";");
+ capabililty.append(" aString:string=\"someString\"");
+ manifest.put(GENERIC_CAPABILITY, capabililty.toString());
+ BundleDescription genCap = state.getFactory().createBundleDescription(state, manifest, (String) manifest.get(Constants.BUNDLE_SYMBOLICNAME), bundleID++);
+
+ manifest = new Hashtable();
+ manifest.put(Constants.BUNDLE_MANIFESTVERSION, "2");
+ manifest.put(Constants.BUNDLE_SYMBOLICNAME, "genericRequire");
+ manifest.put(Constants.BUNDLE_VERSION, "1.0.0");
+ StringBuffer required = new StringBuffer();
+ required.append("foo; selection-filter=\"(version>=1.3.0)\",");
+ required.append("bar:bartype; selection-filter=\"(attr1=value1)\",");
+ required.append("test.types:testtype; selection-filter=\"(&(aVersion>=2.0.0)(aLong>=5555)(aDouble>=1.00)(aUri=file:/test)(aSet=c)(aString=someString))\"");
+ manifest.put(GENERIC_REQUIRE, required.toString());
+ BundleDescription genReq = state.getFactory().createBundleDescription(state, manifest, (String) manifest.get(Constants.BUNDLE_SYMBOLICNAME), bundleID++);
+
+ state.addBundle(genCap);
+ state.addBundle(genReq);
+
+ state.resolve();
+ assertTrue("1.0", genCap.isResolved());
+ assertTrue("1.1", genReq.isResolved());
+ GenericSpecification[] genSpecs = genReq.getGenericRequires();
+ assertTrue("2.0", genSpecs.length == 3);
+ assertTrue("2.1", genSpecs[0].isResolved());
+ assertEquals("2.1.1", genSpecs[0].getSupplier(), genCap.getGenericCapabilities()[0]);
+ assertTrue("2.2", genSpecs[1].isResolved());
+ assertEquals("2.2.1", genSpecs[1].getSupplier(), genCap.getGenericCapabilities()[1]);
+ assertTrue("2.3", genSpecs[2].isResolved());
+ assertEquals("2.3.1", genSpecs[2].getSupplier(), genCap.getGenericCapabilities()[2]);
+ }
+
+ public void testGenericsFrags() throws BundleException {
+ State state = buildEmptyState();
+ Hashtable manifest = new Hashtable();
+ long bundleID = 0;
+
+ manifest.put(Constants.BUNDLE_MANIFESTVERSION, "2");
+ manifest.put(Constants.BUNDLE_SYMBOLICNAME, "genericCapablity");
+ manifest.put(Constants.BUNDLE_VERSION, "1.0.0");
+ StringBuffer capabililty = new StringBuffer();
+ capabililty.append("foo; version=\"1.3.1\"; attr1=\"value1\"; attr2=\"value2\",");
+ capabililty.append("bar:bartype; version=\"1.4.1\"; attr1=\"value1\"; attr2=\"value2\",");
+ capabililty.append("test.types:testtype;");
+ capabililty.append(" aVersion:version=\"2.0.0\";");
+ capabililty.append(" aLong:long=\"10000000000\";");
+ capabililty.append(" aDouble:double=\"1.000109\";");
+ capabililty.append(" aUri:uri=\"file:/test\";");
+ capabililty.append(" aSet:set=\"a,b,c,d\";");
+ capabililty.append(" aString:string=\"someString\"");
+ manifest.put(GENERIC_CAPABILITY, capabililty.toString());
+ BundleDescription genCap = state.getFactory().createBundleDescription(state, manifest, (String) manifest.get(Constants.BUNDLE_SYMBOLICNAME), bundleID++);
+
+ manifest.put(Constants.BUNDLE_MANIFESTVERSION, "2");
+ manifest.put(Constants.BUNDLE_SYMBOLICNAME, "genericCapability.frag1");
+ manifest.put(Constants.BUNDLE_VERSION, "1.0.0");
+ manifest.put(Constants.FRAGMENT_HOST, "genericCapablity;bundle-version=\"[1.0.0,2.0.0)\"");
+ capabililty = new StringBuffer();
+ capabililty.append("fragmentStuff");
+ manifest.put(GENERIC_CAPABILITY, capabililty.toString());
+ BundleDescription genCapFrag = state.getFactory().createBundleDescription(state, manifest, (String) manifest.get(Constants.BUNDLE_SYMBOLICNAME), bundleID++);
+
+ manifest = new Hashtable();
+ manifest.put(Constants.BUNDLE_MANIFESTVERSION, "2");
+ manifest.put(Constants.BUNDLE_SYMBOLICNAME, "genericRequire");
+ manifest.put(Constants.BUNDLE_VERSION, "1.0.0");
+ StringBuffer required = new StringBuffer();
+ required.append("foo; selection-filter=\"(version>=1.3.0)\",");
+ required.append("bar:bartype; selection-filter=\"(attr1=value1)\",");
+ required.append("test.types:testtype; selection-filter=\"(&(aVersion>=2.0.0)(aLong>=5555)(aDouble>=1.00)(aUri=file:/test)(aSet=c)(aString=someString))\",");
+ required.append("fragmentStuff");
+ manifest.put(GENERIC_REQUIRE, required.toString());
+ BundleDescription genReq = state.getFactory().createBundleDescription(state, manifest, (String) manifest.get(Constants.BUNDLE_SYMBOLICNAME), bundleID++);
+
+ state.addBundle(genCap);
+ state.addBundle(genCapFrag);
+ state.addBundle(genReq);
+
+ state.resolve();
+ assertTrue("1.0", genCap.isResolved());
+ assertTrue("1.1", genReq.isResolved());
+ assertTrue("1.2", genCapFrag.isResolved());
+ GenericSpecification[] genSpecs = genReq.getGenericRequires();
+ assertTrue("2.0", genSpecs.length == 4);
+ assertTrue("2.1", genSpecs[0].isResolved());
+ assertEquals("2.1.1", genSpecs[0].getSupplier(), genCap.getGenericCapabilities()[0]);
+ assertTrue("2.2", genSpecs[1].isResolved());
+ assertEquals("2.2.1", genSpecs[1].getSupplier(), genCap.getGenericCapabilities()[1]);
+ assertTrue("2.3", genSpecs[2].isResolved());
+ assertEquals("2.3.1", genSpecs[2].getSupplier(), genCap.getGenericCapabilities()[2]);
+ assertTrue("2.4", genSpecs[3].isResolved());
+ assertEquals("2.4.1", genSpecs[3].getSupplier(), genCapFrag.getGenericCapabilities()[0]);
+ }
+
+ public void testGenericsAliases() throws BundleException {
+ State state = buildEmptyState();
+ Dictionary[] allPlatProps = state.getPlatformProperties();
+ Dictionary platProps = (Dictionary) ((Hashtable)allPlatProps[0]).clone();
+ platProps.put("osgi.genericAliases", "Export-Service:Import-Service:service,TJW-Export:TJW-Import:tjw");
+ state.setPlatformProperties(platProps);
+
+ Hashtable manifest = new Hashtable();
+ long bundleID = 0;
+ manifest.put(Constants.BUNDLE_MANIFESTVERSION, "2");
+ manifest.put(Constants.BUNDLE_SYMBOLICNAME, "genericCapablity");
+ manifest.put(Constants.BUNDLE_VERSION, "1.0.0");
+ manifest.put(Constants.EXPORT_SERVICE, "org.osgi.service.log.LogService; version=1.2");
+ manifest.put("TJW-Export", "my.great.stuff; aLong:long=5150; aDouble:double=3.14; aVersion:version=1.2.0");
+ BundleDescription genCap = state.getFactory().createBundleDescription(state, manifest, (String) manifest.get(Constants.BUNDLE_SYMBOLICNAME), bundleID++);
+
+ manifest = new Hashtable();
+ manifest.put(Constants.BUNDLE_MANIFESTVERSION, "2");
+ manifest.put(Constants.BUNDLE_SYMBOLICNAME, "genericRequire");
+ manifest.put(Constants.BUNDLE_VERSION, "1.0.0");
+ manifest.put(Constants.IMPORT_SERVICE, "org.osgi.service.log.LogService; selection-filter=(version>=1.0.0)");
+ manifest.put("TJW-Import", "my.great.stuff; selection-filter=(&(aLong<=10000)(aLong>=5000))");
+ BundleDescription genReq = state.getFactory().createBundleDescription(state, manifest, (String) manifest.get(Constants.BUNDLE_SYMBOLICNAME), bundleID++);
+
+ state.addBundle(genCap);
+ state.addBundle(genReq);
+
+ state.resolve();
+ assertTrue("1.0", genCap.isResolved());
+ assertTrue("1.1", genReq.isResolved());
+ GenericSpecification[] genSpecs = genReq.getGenericRequires();
+ assertTrue("2.0", genSpecs.length == 2);
+ assertTrue("2.1", genSpecs[0].isResolved());
+ assertEquals("2.1.1", genSpecs[0].getSupplier(), genCap.getGenericCapabilities()[0]);
+ assertTrue("2.2", genSpecs[1].isResolved());
+ assertEquals("2.2.1", genSpecs[1].getSupplier(), genCap.getGenericCapabilities()[1]);
+ }
+
+ public void testGenericsOptionalMultiple() throws BundleException {
+ State state = buildEmptyState();
+ Hashtable manifest = new Hashtable();
+ long bundleID = 0;
+ manifest.put(Constants.BUNDLE_MANIFESTVERSION, "2");
+ manifest.put(Constants.BUNDLE_SYMBOLICNAME, "genericCapablity");
+ manifest.put(Constants.BUNDLE_VERSION, "1.0.0");
+ StringBuffer capabililty = new StringBuffer();
+ capabililty.append("foo; version=\"1.3.1\"; attr1=\"value1\"; attr2=\"value2\",");
+ capabililty.append("bar:bartype; version=\"1.4.1\"; attr1=\"value1\"; attr2=\"value2\",");
+ capabililty.append("test.types:testtype;");
+ capabililty.append(" aVersion:version=\"2.0.0\";");
+ capabililty.append(" aLong:long=\"10000000000\";");
+ capabililty.append(" aDouble:double=\"1.000109\";");
+ capabililty.append(" aUri:uri=\"file:/test\";");
+ capabililty.append(" aSet:set=\"a,b,c,d\";");
+ capabililty.append(" aString:string=\"someString\",");
+ capabililty.append("test.real.optional:thisisoptional,");
+ capabililty.append("test.real.multiple:thisismultiple; version=1.0,");
+ capabililty.append("test.real.multiple:thisismultiple; version=2.0");
+ manifest.put(GENERIC_CAPABILITY, capabililty.toString());
+ BundleDescription genCap = state.getFactory().createBundleDescription(state, manifest, (String) manifest.get(Constants.BUNDLE_SYMBOLICNAME), bundleID++);
+
+ manifest = new Hashtable();
+ manifest.put(Constants.BUNDLE_MANIFESTVERSION, "2");
+ manifest.put(Constants.BUNDLE_SYMBOLICNAME, "genericRequire");
+ manifest.put(Constants.BUNDLE_VERSION, "1.0.0");
+ StringBuffer required = new StringBuffer();
+ required.append("foo; selection-filter=\"(version>=1.3.0)\",");
+ required.append("bar:bartype; selection-filter=\"(attr1=value1)\",");
+ required.append("test.types:testtype; selection-filter=\"(&(aVersion>=2.0.0)(aLong>=5555)(aDouble>=1.00)(aUri=file:/test)(aSet=c)(aString=someString))\",");
+ required.append("test.optional:thisisoptional; optional=true,");
+ required.append("test.real.optional:thisisoptional; optional=true,");
+ required.append("test.real.multiple:thisismultiple; multiple=true");
+ manifest.put(GENERIC_REQUIRE, required.toString());
+ BundleDescription genReq = state.getFactory().createBundleDescription(state, manifest, (String) manifest.get(Constants.BUNDLE_SYMBOLICNAME), bundleID++);
+
+ state.addBundle(genCap);
+ state.addBundle(genReq);
+
+ state.resolve();
+ assertTrue("1.0", genCap.isResolved());
+ assertTrue("1.1", genReq.isResolved());
+ GenericSpecification[] genSpecs = genReq.getGenericRequires();
+ assertTrue("2.0", genSpecs.length == 6);
+ assertTrue("2.1", genSpecs[0].isResolved());
+ assertEquals("2.1.1", genSpecs[0].getSupplier(), genCap.getGenericCapabilities()[0]);
+ assertTrue("2.2", genSpecs[1].isResolved());
+ assertEquals("2.2.1", genSpecs[1].getSupplier(), genCap.getGenericCapabilities()[1]);
+ assertTrue("2.3", genSpecs[2].isResolved());
+ assertEquals("2.3.1", genSpecs[2].getSupplier(), genCap.getGenericCapabilities()[2]);
+ assertFalse("2.4", genSpecs[3].isResolved());
+ assertTrue("2.5", genSpecs[4].isResolved());
+ assertEquals("2.5.1", genSpecs[4].getSupplier(), genCap.getGenericCapabilities()[3]);
+ assertTrue("2.6", genSpecs[5].isResolved());
+ GenericDescription[] suppliers = genSpecs[5].getSuppliers();
+ assertTrue("2.6.1", suppliers != null && suppliers.length == 2);
+ assertEquals("2.6.2", suppliers[0], genCap.getGenericCapabilities()[5]);
+ assertEquals("2.6.3", suppliers[1], genCap.getGenericCapabilities()[4]);
+ }
+
+ public void testGenericsCycles() throws BundleException {
+ State state = buildEmptyState();
+ Hashtable manifest = new Hashtable();
+ long bundleID = 0;
+
+ manifest.put(Constants.BUNDLE_MANIFESTVERSION, "2");
+ manifest.put(Constants.BUNDLE_SYMBOLICNAME, "genericCapablity");
+ manifest.put(Constants.BUNDLE_VERSION, "1.0.0");
+ StringBuffer capabililty = new StringBuffer();
+ capabililty.append("foo; version=\"1.3.1\"; attr1=\"value1\"; attr2=\"value2\",");
+ capabililty.append("bar:bartype; version=\"1.4.1\"; attr1=\"value1\"; attr2=\"value2\",");
+ capabililty.append("test.types:testtype;");
+ capabililty.append(" aVersion:version=\"2.0.0\";");
+ capabililty.append(" aLong:long=\"10000000000\";");
+ capabililty.append(" aDouble:double=\"1.000109\";");
+ capabililty.append(" aUri:uri=\"file:/test\";");
+ capabililty.append(" aSet:set=\"a,b,c,d\";");
+ capabililty.append(" aString:string=\"someString\"");
+ manifest.put(GENERIC_CAPABILITY, capabililty.toString());
+ StringBuffer required = new StringBuffer();
+ required.append("foo:cycle; selection-filter=\"(version>=1.3.0)\"");
+ manifest.put(GENERIC_REQUIRE, required.toString());
+ BundleDescription genCap = state.getFactory().createBundleDescription(state, manifest, (String) manifest.get(Constants.BUNDLE_SYMBOLICNAME), bundleID++);
+
+ manifest.put(Constants.BUNDLE_MANIFESTVERSION, "2");
+ manifest.put(Constants.BUNDLE_SYMBOLICNAME, "genericCapability.frag1");
+ manifest.put(Constants.BUNDLE_VERSION, "1.0.0");
+ manifest.put(Constants.FRAGMENT_HOST, "genericCapablity;bundle-version=\"[1.0.0,2.0.0)\"");
+ capabililty = new StringBuffer();
+ capabililty.append("fragmentStuff");
+ manifest.put(GENERIC_CAPABILITY, capabililty.toString());
+ BundleDescription genCapFrag = state.getFactory().createBundleDescription(state, manifest, (String) manifest.get(Constants.BUNDLE_SYMBOLICNAME), bundleID++);
+
+ manifest = new Hashtable();
+ manifest.put(Constants.BUNDLE_MANIFESTVERSION, "2");
+ manifest.put(Constants.BUNDLE_SYMBOLICNAME, "genericRequire");
+ manifest.put(Constants.BUNDLE_VERSION, "1.0.0");
+ capabililty = new StringBuffer();
+ capabililty.append("foo:cycle; version:version=\"2.0\"");
+ manifest.put(GENERIC_CAPABILITY, capabililty.toString());
+ required = new StringBuffer();
+ required.append("foo; selection-filter=\"(version>=1.3.0)\",");
+ required.append("bar:bartype; selection-filter=\"(attr1=value1)\",");
+ required.append("test.types:testtype; selection-filter=\"(&(aVersion>=2.0.0)(aLong>=5555)(aDouble>=1.00)(aUri=file:/test)(aSet=c)(aString=someString))\",");
+ required.append("fragmentStuff");
+ manifest.put(GENERIC_REQUIRE, required.toString());
+ BundleDescription genReq = state.getFactory().createBundleDescription(state, manifest, (String) manifest.get(Constants.BUNDLE_SYMBOLICNAME), bundleID++);
+
+ state.addBundle(genCap);
+ state.addBundle(genCapFrag);
+ state.addBundle(genReq);
+
+ state.resolve();
+ assertTrue("1.0", genCap.isResolved());
+ assertTrue("1.1", genReq.isResolved());
+ assertTrue("1.2", genCapFrag.isResolved());
+ GenericSpecification[] genSpecs = genReq.getGenericRequires();
+ assertTrue("2.0", genSpecs.length == 4);
+ assertTrue("2.1", genSpecs[0].isResolved());
+ assertEquals("2.1.1", genSpecs[0].getSupplier(), genCap.getGenericCapabilities()[0]);
+ assertTrue("2.2", genSpecs[1].isResolved());
+ assertEquals("2.2.1", genSpecs[1].getSupplier(), genCap.getGenericCapabilities()[1]);
+ assertTrue("2.3", genSpecs[2].isResolved());
+ assertEquals("2.3.1", genSpecs[2].getSupplier(), genCap.getGenericCapabilities()[2]);
+ assertTrue("2.4", genSpecs[3].isResolved());
+ assertEquals("2.4.1", genSpecs[3].getSupplier(), genCapFrag.getGenericCapabilities()[0]);
+ genSpecs = genCap.getGenericRequires();
+ assertTrue("3.0", genSpecs.length == 1);
+ assertTrue("3.1", genSpecs[0].isResolved());
+ assertEquals("3.1.1", genSpecs[0].getSupplier(), genReq.getGenericCapabilities()[0]);
+ }
+}
diff --git a/bundles/org.eclipse.osgi/.options b/bundles/org.eclipse.osgi/.options
index 8bbbdde11..1bd2359d1 100644
--- a/bundles/org.eclipse.osgi/.options
+++ b/bundles/org.eclipse.osgi/.options
@@ -63,6 +63,7 @@ org.eclipse.osgi/resolver/imports = false
org.eclipse.osgi/resolver/requires = false
org.eclipse.osgi/resolver/grouping = false
org.eclipse.osgi/resolver/cycles = false
+org.eclipse.osgi/resolver/generics = false
#### Profile settings
org.eclipse.osgi/profile/startup = false
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 1ae732049..32f60a0c4 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2005 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 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
@@ -26,9 +26,17 @@ public interface BaseDescription {
* @return the name
*/
public String getName();
+
/**
* Returns the version.
* @return the version
*/
public Version getVersion();
+
+ /**
+ * Returns the bundle which supplies this base description
+ * @return the bundle which supplies this base description
+ * @since 3.2
+ */
+ public BundleDescription getSupplier();
}
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 be37cd5c0..344406736 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2003, 2005 IBM Corporation and others.
+ * Copyright (c) 2003, 2006 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
@@ -17,7 +17,7 @@ package org.eclipse.osgi.service.resolver;
* </p>
* @since 3.1
*/
-public interface BundleDescription extends BaseDescription{
+public interface BundleDescription extends BaseDescription {
/**
* Gets the Bundle-SymbolicName of this BundleDescription.
@@ -58,6 +58,20 @@ public interface BundleDescription extends BaseDescription{
public ImportPackageSpecification[] getImportPackages();
/**
+ * Returns an array of generic specifications constraints required by this bundle.
+ * @return an array of generic specifications
+ * @since 3.2
+ */
+ public GenericSpecification[] getGenericRequires();
+
+ /**
+ * Returns an array of generic descriptions for the capabilities of this bundle.
+ * @return an array of generic descriptions
+ * @since 3.2
+ */
+ public GenericDescription[] getGenericCapabilities();
+
+ /**
* Returns true if this bundle has one or more dynamically imported packages.
* @return true if this bundle has one or more dynamically imported packages.
*/
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/GenericDescription.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/GenericDescription.java
new file mode 100644
index 000000000..39e5de970
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/GenericDescription.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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;
+
+import java.util.Dictionary;
+
+/**
+ * A description of a generic capability.
+ * @since 3.2
+ */
+public interface GenericDescription extends BaseDescription {
+ /**
+ * The default type of generic capability.
+ */
+ public static String DEFAULT_TYPE = "generic"; //$NON-NLS-1$
+
+ /**
+ * Returns the arbitrary attributes for this description
+ * @return the arbitrary attributes for this description
+ */
+ public Dictionary getAttributes();
+
+ /**
+ * Returns the type of generic description capability
+ * @return the type of generic description capability
+ */
+ public String getType();
+}
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/GenericSpecification.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/GenericSpecification.java
new file mode 100644
index 000000000..4b0a12d5b
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/GenericSpecification.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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;
+
+/**
+ * A specification which depends on a generic capability
+ * @since 3.2
+ */
+public interface GenericSpecification extends VersionConstraint {
+ /**
+ * The optional resolution type
+ * @see #getResolution()
+ */
+ public static final int RESOLUTION_OPTIONAL = 0x01;
+ /**
+ * The multiple resolution type
+ * @see #getResolution()
+ */
+ public static final int RESOLUTION_MULTIPLE = 0x02;
+
+ /**
+ * Returns a matching filter used to match with a suppliers attributes
+ * @return a matching filter used to match with a suppliers attributes
+ */
+ public String getMatchingFilter();
+
+ /**
+ * Returns the type of generic specification
+ * @return the type of generic specification
+ */
+ public String getType();
+
+ /**
+ * Returns the resolution type of the required capability. The returned
+ * value is a bit mask that may have the optional bit {@link #RESOLUTION_OPTIONAL}
+ * and/or the multiple bit {@link #RESOLUTION_MULTIPLE} set.
+ *
+ * @return the resolution type of the required capability
+ */
+ public int getResolution();
+
+ /**
+ * Returns the suppliers of the capability. If the the resolution is multiple then
+ * more than one supplier may be returned
+ * @return the suppliers of the capability
+ */
+ public GenericDescription[] getSuppliers();
+}
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/ResolverError.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/ResolverError.java
index 0e1b4c5d4..f325615c8 100644
--- a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/ResolverError.java
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/ResolverError.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2003, 2005 IBM Corporation and others.
+ * Copyright (c) 2003, 2006 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
@@ -116,6 +116,12 @@ public interface ResolverError {
public static final int MISSING_EXECUTION_ENVIRONMENT = 0x4000;
/**
+ * Error type constant (bit mask) indicating that a bundle could not be
+ * resolved because the required generic capability could not be resolved.
+ */
+ public static final int MISSING_GENERIC_CAPABILITY = 0x8000;
+
+ /**
* Returns the bundle which this ResolverError is for
* @return the bundle which this ResolverError is for
*/
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 94e505adc..51ec03d88 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2003, 2005 IBM Corporation and others.
+ * Copyright (c) 2003, 2006 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
@@ -14,8 +14,7 @@ import java.io.*;
import java.util.Dictionary;
import java.util.Map;
import org.eclipse.osgi.internal.resolver.StateObjectFactoryImpl;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.Version;
+import org.osgi.framework.*;
/**
* A factory for states and their component objects.
@@ -32,7 +31,7 @@ public interface StateObjectFactory {
* of a running Equinox framework.
*/
public static final StateObjectFactory defaultFactory = new StateObjectFactoryImpl();
-
+
/**
* Creates an empty state. The returned state does not have an
* attached resolver.
@@ -84,6 +83,34 @@ public interface StateObjectFactory {
public BundleDescription createBundleDescription(long id, String symbolicName, Version version, String location, BundleSpecification[] required, HostSpecification host, ImportPackageSpecification[] imports, ExportPackageDescription[] exports, String[] providedPackages, boolean singleton);
/**
+ * Creates a bundle description from the given parameters.
+ *
+ * @param id id for the bundle
+ * @param symbolicName symbolic name for the bundle (may be
+ * <code>null</code>)
+ * @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 providedPackages the list of provided packages (may be <code>null</code>)
+ * @param singleton whether the bundle created should be a singleton
+ * @param attachFragments whether the bundle allows fragments to attach
+ * @param dynamicFragments whether the bundle allows fragments to dynamically attach
+ * @param platformFilter the platform filter (may be <code>null</code>)
+ * @param executionEnvironment 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>)
+ * @return the created bundle description
+ */
+ public BundleDescription createBundleDescription(long id, String symbolicName, Version version, String location, BundleSpecification[] required, HostSpecification host, ImportPackageSpecification[] imports, ExportPackageDescription[] exports, String[] providedPackages, boolean singleton, boolean attachFragments, boolean dynamicFragments, String platformFilter, String executionEnvironment, GenericSpecification[] genericRequires, GenericDescription[] genericCapabilities);
+
+ /**
* 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.
@@ -164,9 +191,9 @@ public interface StateObjectFactory {
* @param versionRange the package versionRange (may be <code>null</code>).
* @param bundleSymbolicName the Bundle-SymbolicName of the bundle that must export the package (may be <code>null</code>)
* @param bundleVersionRange the bundle versionRange (may be <code>null</code>).
- * @param directives the directives for this package
+ * @param directives the directives for this package (may be <code>null</code>)
* @param attributes the arbitrary attributes for the package import (may be <code>null</code>)
- * @param importer the importing bundle
+ * @param importer the importing bundle (may be <code>null</code>)
* @return the created package specification
*/
public ImportPackageSpecification createImportPackageSpecification(String packageName, VersionRange versionRange, String bundleSymbolicName, VersionRange bundleVersionRange, Map directives, Map attributes, BundleDescription importer);
@@ -183,17 +210,39 @@ public interface StateObjectFactory {
* The Resolver needs to create ExportPackageDescriptions dynamally for a host when a fragment.
* exports a package<p>
*
- * @param packageName
- * @param version
- * @param directives
- * @param attributes
- * @param root
- * @param exporter
+ * @param packageName the package name
+ * @param version the version of the package (may be <code>null</code>)
+ * @param directives the directives for the package (may be <code>null</code>)
+ * @param attributes the attributes for the package (may be <code>null</code>)
+ * @param root whether the package is a root package
+ * @param exporter the exporter of the package (may be <code>null</code>)
* @return the created package
*/
public ExportPackageDescription createExportPackageDescription(String packageName, Version version, Map directives, Map attributes, boolean root, BundleDescription exporter);
/**
+ * Creates a generic description from the given parameters
+ * @param name the name of the generic description
+ * @param type the type of the generic description (may be <code>null</code>)
+ * @param version the version of the generic description (may be <code>null</code>)
+ * @param attributes the attributes for the generic description (may be <code>null</code>)
+ * @return the created generic description
+ */
+ public GenericDescription createGenericDescription(String name, String type, Version version, Map attributes);
+
+ /**
+ * 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>)
+ * @param matchingFilter the matching filter (may be <code>null</code>)
+ * @param optional whether the specification is optional
+ * @param multiple whether the specification allows for multiple suppliers
+ * @return the created generic specification
+ * @throws InvalidSyntaxException if the matching filter is invalid
+ */
+ public GenericSpecification createGenericSpecification(String name, String type, String matchingFilter, boolean optional, boolean multiple) throws InvalidSyntaxException;
+
+ /**
* Creates an import package specification that is a copy of the given constraint
* @param original the export package to be copied
* @return the created package
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/util/ManifestElement.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/util/ManifestElement.java
index 90a58b436..48bd05567 100644
--- a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/util/ManifestElement.java
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/util/ManifestElement.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2003, 2005 IBM Corporation and others.
+ * Copyright (c) 2003, 2006 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
@@ -322,60 +322,70 @@ public class ManifestElement {
* @throws BundleException if the header value is invalid
*/
public static ManifestElement[] parseHeader(String header, String value) throws BundleException {
- if (value == null) {
+ if (value == null)
return (null);
- }
- Vector headerElements = new Vector(10, 10);
+ ArrayList headerElements = new ArrayList(10);
Tokenizer tokenizer = new Tokenizer(value);
parseloop: while (true) {
String next = tokenizer.getToken(";,"); //$NON-NLS-1$
- if (next == null) {
+ if (next == null)
throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
- }
ArrayList headerValues = new ArrayList();
StringBuffer headerValue = new StringBuffer(next);
headerValues.add(next);
- if (Debug.DEBUG && Debug.DEBUG_MANIFEST) {
+ if (Debug.DEBUG && Debug.DEBUG_MANIFEST)
Debug.print("paserHeader: " + next); //$NON-NLS-1$
- }
+ boolean directive = false;
char c = tokenizer.getChar();
// Header values may be a list of ';' separated values. Just append them all into one value until the first '=' or ','
while (c == ';') {
next = tokenizer.getToken(";,=:"); //$NON-NLS-1$
- if (next == null) {
+ if (next == null)
throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
- }
c = tokenizer.getChar();
+ while (c == ':') { // may not really be a :=
+ c = tokenizer.getChar();
+ if (c != '=') {
+ String restOfNext = tokenizer.getToken(";,=:"); //$NON-NLS-1$
+ if (restOfNext == null)
+ throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
+ next += ":" + c + restOfNext; //$NON-NLS-1$
+ c = tokenizer.getChar();
+ } else
+ directive = true;
+ }
if (c == ';' || c == '\0') /* more */{
headerValues.add(next);
headerValue.append(";").append(next); //$NON-NLS-1$
- if (Debug.DEBUG && Debug.DEBUG_MANIFEST) {
+ if (Debug.DEBUG && Debug.DEBUG_MANIFEST)
Debug.print(";" + next); //$NON-NLS-1$
- }
}
}
// found the header value create a manifestElement for it.
ManifestElement manifestElement = new ManifestElement();
manifestElement.value = headerValue.toString();
manifestElement.valueComponents = (String[]) headerValues.toArray(new String[headerValues.size()]);
- boolean directive = false;
- if (c == ':') {
- c = tokenizer.getChar();
- if (c != '=')
- throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
- directive = true;
- }
- // now add any attributes for the manifestElement.
- while (c == '=') {
+
+ // now add any attributes/directives for the manifestElement.
+ while (c == '=' || c == ':') {
+ while (c == ':') { // may not really be a :=
+ c = tokenizer.getChar();
+ if (c != '=') {
+ String restOfNext = tokenizer.getToken("=:"); //$NON-NLS-1$
+ if (restOfNext == null)
+ throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
+ next += ":" + c + restOfNext; //$NON-NLS-1$
+ c = tokenizer.getChar();
+ } else
+ directive = true;
+ }
String val = tokenizer.getString(";,"); //$NON-NLS-1$
- if (val == null) {
+ if (val == null)
throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
- }
- if (Debug.DEBUG && Debug.DEBUG_MANIFEST) {
+ if (Debug.DEBUG && Debug.DEBUG_MANIFEST)
Debug.print(";" + next + "=" + val); //$NON-NLS-1$ //$NON-NLS-2$
- }
try {
if (directive)
manifestElement.addDirective(next, val);
@@ -383,41 +393,30 @@ public class ManifestElement {
manifestElement.addAttribute(next, val);
directive = false;
} catch (Exception e) {
- throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
+ throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
}
c = tokenizer.getChar();
if (c == ';') /* more */{
next = tokenizer.getToken("=:"); //$NON-NLS-1$
- if (next == null) {
- throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
- }
+ if (next == null)
+ throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
c = tokenizer.getChar();
- if (c == ':') {
- c = tokenizer.getChar();
- if (c != '=')
- throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
- directive = true;
- }
}
}
- headerElements.addElement(manifestElement);
- if (Debug.DEBUG && Debug.DEBUG_MANIFEST) {
+ headerElements.add(manifestElement);
+ if (Debug.DEBUG && Debug.DEBUG_MANIFEST)
Debug.println(""); //$NON-NLS-1$
- }
- if (c == ',') /* another manifest element */{
+ if (c == ',') /* another manifest element */
continue parseloop;
- }
- if (c == '\0') /* end of value */{
+ if (c == '\0') /* end of value */
break parseloop;
- }
- throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
+ throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
}
int size = headerElements.size();
- if (size == 0) {
+ if (size == 0)
return (null);
- }
- ManifestElement[] result = new ManifestElement[size];
- headerElements.copyInto(result);
+
+ ManifestElement[] result = (ManifestElement[]) headerElements.toArray(new ManifestElement[size]);
return (result);
}
diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/GenericCapability.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/GenericCapability.java
new file mode 100644
index 000000000..daaf76af1
--- /dev/null
+++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/GenericCapability.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.internal.module;
+
+import org.eclipse.osgi.service.resolver.BaseDescription;
+import org.eclipse.osgi.service.resolver.BundleDescription;
+
+public class GenericCapability extends VersionSupplier {
+ ResolverBundle resolverBundle;
+
+ GenericCapability(ResolverBundle resolverBundle, BaseDescription base) {
+ super(base);
+ this.resolverBundle = resolverBundle;
+ }
+
+ public BundleDescription getBundle() {
+ return getBaseDescription().getSupplier();
+ }
+
+ public boolean isFromFragment() {
+ return resolverBundle.isFragment();
+ }
+
+ public ResolverBundle getResolverBundle() {
+ return resolverBundle;
+ }
+}
diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/GenericConstraint.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/GenericConstraint.java
new file mode 100644
index 000000000..d6533cd06
--- /dev/null
+++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/GenericConstraint.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.internal.module;
+
+import java.util.ArrayList;
+import org.eclipse.osgi.service.resolver.VersionConstraint;
+
+public class GenericConstraint extends ResolverConstraint {
+ private ArrayList matchingCapability;
+
+ GenericConstraint(ResolverBundle bundle, VersionConstraint constraint) {
+ super(bundle, constraint);
+ }
+
+ boolean isOptional() {
+ return false;
+ }
+
+ boolean isSatisfiedBy(VersionSupplier vs) {
+ return getVersionConstraint().isSatisfiedBy(vs.getBaseDescription());
+ }
+
+ public void setMatchingCapability(GenericCapability capability) {
+ if (capability == null) {
+ matchingCapability = null;
+ return;
+ }
+ if (matchingCapability == null)
+ matchingCapability = new ArrayList(1);
+ matchingCapability.add(capability);
+ }
+
+ public GenericCapability[] getMatchingCapabilities() {
+ return matchingCapability == null || matchingCapability.size() == 0 ? null : (GenericCapability[]) matchingCapability.toArray(new GenericCapability[matchingCapability.size()]);
+ }
+
+ void removeMatchingCapability(GenericCapability capability) {
+ if (matchingCapability != null)
+ matchingCapability.remove(capability);
+ }
+}
diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/ResolverBundle.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/ResolverBundle.java
index 529b6121c..9f3594871 100644
--- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/ResolverBundle.java
+++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/ResolverBundle.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2005 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 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
@@ -27,11 +27,14 @@ public class ResolverBundle extends VersionSupplier {
private ResolverImport[] imports;
private ResolverExport[] exports;
private BundleConstraint[] requires;
+ private GenericCapability[] capabilities;
+ private GenericConstraint[] genericReqiures;
// Fragment support
private ArrayList fragments;
private HashMap fragmentExports;
private HashMap fragmentImports;
private HashMap fragmentRequires;
+ private HashMap fragmentGenericRequires;
// Flag specifying whether this bundle is resolvable
private boolean resolvable = true;
// Internal resolver state for this bundle
@@ -51,11 +54,17 @@ public class ResolverBundle extends VersionSupplier {
void initialize(boolean useSelectedExports) {
if (getBundle().isSingleton())
refs = new ArrayList();
+ // always add generic capabilities
+ GenericDescription[] actualCapabilities = getBundle().getGenericCapabilities();
+ capabilities = new GenericCapability[actualCapabilities.length];
+ for (int i = 0; i < capabilities.length; i++)
+ capabilities[i] = new GenericCapability(this, actualCapabilities[i]);
if (getBundle().getHost() != null) {
host = new BundleConstraint(this, getBundle().getHost());
exports = new ResolverExport[0];
imports = new ResolverImport[0];
requires = new BundleConstraint[0];
+ genericReqiures = new GenericConstraint[0];
return;
}
@@ -79,10 +88,16 @@ public class ResolverBundle extends VersionSupplier {
for (int i = 0; i < requires.length; i++)
requires[i] = new BundleConstraint(this, actualRequires[i]);
+ GenericSpecification[] actualGenericRequires = getBundle().getGenericRequires();
+ genericReqiures = new GenericConstraint[actualGenericRequires.length];
+ for (int i = 0; i < genericReqiures.length; i++)
+ genericReqiures[i] = new GenericConstraint(this, actualGenericRequires[i]);
+
fragments = null;
fragmentExports = null;
fragmentImports = null;
fragmentRequires = null;
+ fragmentGenericRequires = null;
}
ResolverExport getExport(String name) {
@@ -114,6 +129,10 @@ public class ResolverBundle extends VersionSupplier {
BundleConstraint[] allRequires = getRequires();
for (int i = 0; i < allRequires.length; i++)
allRequires[i].setMatchingBundle(null);
+
+ GenericConstraint[] allGenericRequires = getGenericRequires();
+ for (int i = 0; i < allGenericRequires.length; i++)
+ allGenericRequires[i].setMatchingCapability(null);
}
boolean isResolved() {
@@ -189,6 +208,10 @@ public class ResolverBundle extends VersionSupplier {
return host;
}
+ GenericCapability[] getGenericCapabilities() {
+ return capabilities;
+ }
+
BundleConstraint[] getRequires() {
if (isFragment())
return new BundleConstraint[0];
@@ -206,6 +229,21 @@ public class ResolverBundle extends VersionSupplier {
return (BundleConstraint[]) resultList.toArray(new BundleConstraint[resultList.size()]);
}
+ GenericConstraint[] getGenericRequires() {
+ if (isFragment() || fragments == null || fragments.size() == 0)
+ return genericReqiures;
+ ArrayList resultList = new ArrayList(genericReqiures.length);
+ for (int i = 0; i < genericReqiures.length; i++)
+ resultList.add(genericReqiures[i]);
+ for (Iterator iter = fragments.iterator(); iter.hasNext();) {
+ ResolverBundle fragment = (ResolverBundle) iter.next();
+ ArrayList fragGenericRegs = (ArrayList) fragmentGenericRequires.get(fragment.bundleID);
+ if (fragGenericRegs != null)
+ resultList.addAll(fragGenericRegs);
+ }
+ return (GenericConstraint[]) resultList.toArray(new GenericConstraint[resultList.size()]);
+ }
+
BundleConstraint getRequire(String name) {
BundleConstraint[] allRequires = getRequires();
for (int i = 0; i < allRequires.length; i++)
@@ -241,6 +279,8 @@ public class ResolverBundle extends VersionSupplier {
fragmentImports = new HashMap(1);
if (fragmentRequires == null)
fragmentRequires = new HashMap(1);
+ if (fragmentGenericRequires == null)
+ fragmentGenericRequires = new HashMap(1);
}
private boolean isImported(String packageName) {
@@ -271,9 +311,10 @@ public class ResolverBundle extends VersionSupplier {
ImportPackageSpecification[] newImports = fragment.getBundle().getImportPackages();
BundleSpecification[] newRequires = fragment.getBundle().getRequiredBundles();
ExportPackageDescription[] newExports = fragment.getBundle().getExportPackages();
+ GenericSpecification[] newGenericRequires = fragment.getBundle().getGenericRequires();
// if this is not during initialization then check if constraints conflict
- if (dynamicAttach && constraintsConflict(fragment.getBundle(), newImports, newRequires))
+ if (dynamicAttach && constraintsConflict(fragment.getBundle(), newImports, newRequires, newGenericRequires))
return new ResolverExport[0]; // do not allow fragments with conflicting constraints
if (isResolved() && newExports.length > 0)
fragment.setNewFragmentExports(true);
@@ -300,6 +341,13 @@ public class ResolverBundle extends VersionSupplier {
fragmentRequires.put(fragment.bundleID, hostRequires);
}
+ if (newGenericRequires.length > 0) {
+ ArrayList hostGenericRequires = new ArrayList(newGenericRequires.length);
+ for (int i = 0; i < newGenericRequires.length; i++)
+ hostGenericRequires.add(new GenericConstraint(this, newGenericRequires[i]));
+ fragmentGenericRequires.put(fragment.bundleID, hostGenericRequires);
+ }
+
ArrayList hostExports = new ArrayList(newExports.length);
if (newExports.length > 0 && dynamicAttach) {
StateObjectFactory factory = resolver.getState().getFactory();
@@ -314,7 +362,7 @@ public class ResolverBundle extends VersionSupplier {
return (ResolverExport[]) hostExports.toArray(new ResolverExport[hostExports.size()]);
}
- private boolean constraintsConflict(BundleDescription fragment, ImportPackageSpecification[] newImports, BundleSpecification[] newRequires) {
+ private boolean constraintsConflict(BundleDescription fragment, ImportPackageSpecification[] newImports, BundleSpecification[] newRequires, GenericSpecification[] newGenericRequires) {
for (int i = 0; i < newImports.length; i++) {
ResolverImport importPkg = getImport(newImports[i].getName());
if ((importPkg == null && isResolved()) || (importPkg != null && !isIncluded(newImports[i].getVersionRange(), importPkg.getVersionConstraint().getVersionRange()))) {
@@ -329,7 +377,7 @@ public class ResolverBundle extends VersionSupplier {
return true; // do not allow additional constraints when host is already resolved
}
}
- return false;
+ return !isResolved() ? false : newGenericRequires != null && newGenericRequires.length > 0;
}
// checks that the inner VersionRange is included in the outer VersionRange
@@ -361,6 +409,7 @@ public class ResolverBundle extends VersionSupplier {
ArrayList fragImports = (ArrayList) fragmentImports.remove(fragment.bundleID);
ArrayList fragRequires = (ArrayList) fragmentRequires.remove(fragment.bundleID);
ArrayList removedExports = (ArrayList) fragmentExports.remove(fragment.bundleID);
+ fragmentGenericRequires.remove(fragment.bundleID);
if (reason != null) {
ResolverBundle[] remainingFrags = (ResolverBundle[]) fragments.toArray(new ResolverBundle[fragments.size()]);
for (int i = 0; i < remainingFrags.length; i++) {
@@ -431,10 +480,12 @@ public class ResolverBundle extends VersionSupplier {
if (refs != null)
refs.clear();
}
+
void addRef(ResolverBundle ref) {
if (refs != null && !refs.contains(ref))
refs.add(ref);
}
+
int getRefs() {
return refs == null ? 0 : refs.size();
}
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 883fefb24..9f31a29d7 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2005 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 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
@@ -26,12 +26,14 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver
private static final String OPTION_WIRING = RESOLVER + "/wiring"; //$NON-NLS-1$
private static final String OPTION_IMPORTS = RESOLVER + "/imports"; //$NON-NLS-1$
private static final String OPTION_REQUIRES = RESOLVER + "/requires"; //$NON-NLS-1$
+ private static final String OPTION_GENERICS = RESOLVER + "/generics"; //$NON-NLS-1$
private static final String OPTION_GROUPING = RESOLVER + "/grouping"; //$NON-NLS-1$
private static final String OPTION_CYCLES = RESOLVER + "/cycles"; //$NON-NLS-1$
public static boolean DEBUG = false;
public static boolean DEBUG_WIRING = false;
public static boolean DEBUG_IMPORTS = false;
public static boolean DEBUG_REQUIRES = false;
+ public static boolean DEBUG_GENERICS = false;
public static boolean DEBUG_GROUPING = false;
public static boolean DEBUG_CYCLES = false;
@@ -50,6 +52,8 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver
private VersionHashMap resolverExports = null;
// Repository for bundles
private VersionHashMap resolverBundles = null;
+ // Repository for generics
+ private VersionHashMap resolverGenerics = null;
// List of unresolved bundles
private ArrayList unresolvedBundles = null;
// Keys are BundleDescriptions, values are ResolverBundles
@@ -69,6 +73,7 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver
private void initialize() {
resolverExports = new VersionHashMap(this);
resolverBundles = new VersionHashMap(this);
+ resolverGenerics = new VersionHashMap(this);
unresolvedBundles = new ArrayList();
bundleMapping = new HashMap();
BundleDescription[] bundles = state.getBundles();
@@ -110,6 +115,7 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver
if (!pending || bundleDesc.isResolved()) {
resolverExports.put(bundle.getExportPackages());
resolverBundles.put(bundle.getName(), bundle);
+ resolverGenerics.put(bundle.getGenericCapabilities());
}
if (bundleDesc.isResolved()) {
bundle.setState(ResolverBundle.RESOLVED);
@@ -146,6 +152,29 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver
for (int i = 0; i < imports.length; i++) {
rewireImport(imports[i], visited);
}
+ // Wire generics
+ GenericConstraint[] genericRequires = rb.getGenericRequires();
+ for (int i = 0; i < genericRequires.length; i++)
+ rewireGeneric(genericRequires[i], visited);
+ }
+
+ private void rewireGeneric(GenericConstraint constraint, ArrayList visited) {
+ if (constraint.getMatchingCapabilities() != null)
+ return;
+ GenericDescription[] suppliers = ((GenericSpecification) constraint.getVersionConstraint()).getSuppliers();
+ if (suppliers == null)
+ return;
+ Object[] matches = resolverGenerics.get(constraint.getName());
+ for (int i = 0; i < matches.length; i++) {
+ GenericCapability match = (GenericCapability) matches[i];
+ for (int j = 0; j < suppliers.length; j++)
+ if (match.getBaseDescription() == suppliers[j])
+ constraint.setMatchingCapability(match);
+ }
+ GenericCapability[] matchingCapabilities = constraint.getMatchingCapabilities();
+ if (matchingCapabilities != null)
+ for (int i = 0; i < matchingCapabilities.length; i++)
+ rewireBundle(matchingCapabilities[i].getResolverBundle(), visited);
}
private void rewireRequire(BundleConstraint req, ArrayList visited) {
@@ -238,7 +267,7 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver
state.addResolverError(bundle, ResolverError.MISSING_EXECUTION_ENVIRONMENT, bundleEE.toString(), null);
return false;
}
-
+
// check the platform filter
String platformFilter = bundle.getPlatformFilter();
if (platformFilter == null)
@@ -313,11 +342,12 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver
// reorder exports and bundles after unresolving the bundles
resolverExports.reorder();
resolverBundles.reorder();
+ resolverGenerics.reorder();
// always get the latest EEs
getCurrentEEs(platformProperties);
// keep a list of rejected singltons
ArrayList rejectedSingletons = new ArrayList();
- boolean resolveOptional = platformProperties.length == 0 ? false : "true".equals(platformProperties[0].get("osgi.resolveOptional")); //$NON-NLS-1$//$NON-NLS-2$
+ boolean resolveOptional = platformProperties.length == 0 ? false : "true".equals(platformProperties[0].get("osgi.resolveOptional")); //$NON-NLS-1$//$NON-NLS-2$
ResolverBundle[] currentlyResolved = null;
if (resolveOptional) {
BundleDescription[] resolvedBundles = state.getResolvedBundles();
@@ -379,7 +409,7 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver
}
private void getCurrentEEs(Dictionary[] platformProperties) {
- CURRENT_EES = new String[platformProperties.length][];
+ CURRENT_EES = new String[platformProperties.length][];
for (int i = 0; i < platformProperties.length; i++) {
String eeSpecs = (String) platformProperties[i].get(Constants.FRAMEWORK_EXECUTIONENVIRONMENT);
CURRENT_EES[i] = ManifestElement.getArrayFromList(eeSpecs, ","); //$NON-NLS-1$
@@ -533,6 +563,23 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver
boolean failed = false;
if (!failed) {
+ GenericConstraint[] genericRequires = bundle.getGenericRequires();
+ for (int i = 0; i < genericRequires.length; i++) {
+ if (!resolveGenericReq(genericRequires[i], cycle)) {
+ if (DEBUG || DEBUG_GENERICS)
+ ResolverImpl.log("** GENERICS " + genericRequires[i].getVersionConstraint().getName() + "[" + genericRequires[i].getBundleDescription() + "] failed to resolve"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ state.addResolverError(genericRequires[i].getVersionConstraint().getBundle(), ResolverError.MISSING_GENERIC_CAPABILITY, genericRequires[i].getVersionConstraint().toString(), genericRequires[i].getVersionConstraint());
+ if (genericRequires[i].isFromFragment()) {
+ resolverExports.remove(bundle.detachFragment((ResolverBundle) bundleMapping.get(genericRequires[i].getVersionConstraint().getBundle()), null));
+ continue;
+ }
+ failed = true;
+ break;
+ }
+ }
+ }
+
+ if (!failed) {
// Iterate thru required bundles of 'bundle' trying to find matching bundles.
BundleConstraint[] requires = bundle.getRequires();
for (int i = 0; i < requires.length; i++) {
@@ -590,6 +637,58 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver
return bundle.getState() != ResolverBundle.UNRESOLVED;
}
+ private boolean resolveGenericReq(GenericConstraint constraint, ArrayList cycle) {
+ if (DEBUG_REQUIRES)
+ ResolverImpl.log("Trying to resolve: " + constraint.getBundle() + ", " + constraint.getVersionConstraint()); //$NON-NLS-1$ //$NON-NLS-2$
+ GenericCapability[] matchingCapabilities = constraint.getMatchingCapabilities();
+ if (matchingCapabilities != null) {
+ // Check for unrecorded cyclic dependency
+ for (int i = 0; i < matchingCapabilities.length; i++)
+ if (matchingCapabilities[i].getResolverBundle().getState() == ResolverBundle.RESOLVING)
+ if (!cycle.contains(constraint.getBundle()))
+ cycle.add(constraint.getBundle());
+ if (DEBUG_REQUIRES)
+ ResolverImpl.log(" - already wired"); //$NON-NLS-1$
+ return true; // Already wired (due to grouping dependencies) so just return
+ }
+ Object[] capabilities = resolverGenerics.get(constraint.getVersionConstraint().getName());
+ boolean result = false;
+ for (int i = 0; i < capabilities.length; i++) {
+ GenericCapability capability = (GenericCapability) capabilities[i];
+ if (DEBUG_GENERICS)
+ ResolverImpl.log("CHECKING GENERICS: " + capability.getBaseDescription()); //$NON-NLS-1$
+ // Check if capability matches
+ if (constraint.isSatisfiedBy(capability)) {
+ capability.getResolverBundle().addRef(constraint.getBundle());
+ if (result && (((GenericSpecification) constraint.getVersionConstraint()).getResolution() & GenericSpecification.RESOLUTION_MULTIPLE) == 0)
+ continue; // found a match already and this is not a multiple constraint
+ constraint.setMatchingCapability(capability); // Wire to the capability
+ if (constraint.getBundle() == capability.getResolverBundle()) {
+ result = true; // Wired to ourselves
+ continue;
+ }
+ ResolverBundle[] capabilityHosts = capability.isFromFragment() ? capability.getResolverBundle().getHost().getMatchingBundles() : new ResolverBundle[] {capability.getResolverBundle()};
+ boolean foundResolvedMatch = false;
+ for (int j = 0; capabilityHosts != null && j < capabilityHosts.length; j++)
+ if (capabilityHosts[j].getState() == ResolverBundle.RESOLVED || resolveBundle(capabilityHosts[j], cycle)) {
+ foundResolvedMatch |= !capability.isFromFragment() ? true : capability.getResolverBundle().getHost().getMatchingBundles() != null;
+ // Check cyclic dependencies
+ if (capabilityHosts[j].getState() == ResolverBundle.RESOLVING)
+ if (!cycle.contains(capabilityHosts[j]))
+ cycle.add(capabilityHosts[j]);
+ }
+ if (!foundResolvedMatch) {
+ constraint.removeMatchingCapability(capability);
+ continue; // constraint hasn't resolved
+ }
+ if (DEBUG_GENERICS)
+ ResolverImpl.log("Found match: " + capability.getBaseDescription() + ". Wiring"); //$NON-NLS-1$ //$NON-NLS-2$
+ result = true;
+ }
+ }
+ return result ? true : (((GenericSpecification) constraint.getVersionConstraint()).getResolution() & GenericSpecification.RESOLUTION_OPTIONAL) != 0;
+ }
+
// Resolve the supplied import. Returns true if the import can be resolved, false otherwise
private boolean resolveRequire(BundleConstraint req, ArrayList cycle) {
if (DEBUG_REQUIRES)
@@ -875,6 +974,15 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver
BaseDescription supplier = bundle == null ? null : bundle.getBundle();
state.resolveConstraint(requires[i].getVersionConstraint(), supplier);
}
+ GenericConstraint[] genericRequires = rb.getGenericRequires();
+ for (int i = 0; i < genericRequires.length; i++) {
+ GenericCapability[] matchingCapabilities = genericRequires[i].getMatchingCapabilities();
+ if (matchingCapabilities == null)
+ state.resolveConstraint(genericRequires[i].getVersionConstraint(), null);
+ else
+ for (int j = 0; j < matchingCapabilities.length; j++)
+ state.resolveConstraint(genericRequires[i].getVersionConstraint(), matchingCapabilities[j].getBaseDescription());
+ }
}
private void stateResolveFragConstraints(ResolverBundle rb) {
@@ -1021,6 +1129,7 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver
unresolvedBundles.add(rb);
resolverExports.put(rb.getExportPackages());
resolverBundles.put(rb.getName(), rb);
+ resolverGenerics.put(rb.getGenericCapabilities());
}
}
@@ -1041,6 +1150,7 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver
if (!pending || !bundle.isResolved()) {
resolverExports.remove(rb.getExportPackages());
resolverBundles.remove(rb);
+ resolverGenerics.remove(rb.getGenericCapabilities());
}
unresolvedBundles.remove(rb);
}
@@ -1056,6 +1166,7 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver
state.removeBundleComplete((BundleDescription) removedBundles[i]);
resolverExports.remove(re.getExportPackages());
resolverBundles.remove(re);
+ resolverGenerics.remove(re.getGenericCapabilities());
bundleMapping.remove(removedBundles[i]);
groupingChecker.removeAllExportConstraints(re);
// the bundle is removed
@@ -1083,6 +1194,7 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver
public void flush() {
resolverExports = null;
resolverBundles = null;
+ resolverGenerics = null;
unresolvedBundles = null;
bundleMapping = null;
Object[] removed = removalPending.getAllValues();
@@ -1110,6 +1222,7 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver
DEBUG_WIRING = options.getBooleanOption(OPTION_WIRING, false);
DEBUG_IMPORTS = options.getBooleanOption(OPTION_IMPORTS, false);
DEBUG_REQUIRES = options.getBooleanOption(OPTION_REQUIRES, false);
+ DEBUG_GENERICS = options.getBooleanOption(OPTION_GENERICS, false);
DEBUG_GROUPING = options.getBooleanOption(OPTION_GROUPING, false);
DEBUG_CYCLES = options.getBooleanOption(OPTION_CYCLES, false);
}
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 56a30da4f..b509586bd 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2005 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 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
@@ -13,7 +13,7 @@ package org.eclipse.osgi.internal.resolver;
import org.eclipse.osgi.service.resolver.BaseDescription;
import org.osgi.framework.Version;
-public class BaseDescriptionImpl implements BaseDescription {
+public abstract class BaseDescriptionImpl implements BaseDescription {
private String name;
private Version version;
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 b8c75671c..e846afbc4 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2003, 2005 IBM Corporation and others.
+ * Copyright (c) 2003, 2006 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
@@ -22,6 +22,8 @@ public class BundleDescriptionImpl extends BaseDescriptionImpl implements Bundle
static final BundleSpecification[] EMPTY_BUNDLESPECS = new BundleSpecification[0];
static final ExportPackageDescription[] EMPTY_EXPORTS = new ExportPackageDescription[0];
static final BundleDescription[] EMPTY_BUNDLEDESCS = new BundleDescription[0];
+ static final GenericSpecification[] EMPTY_GENERICSPECS = new GenericSpecification[0];
+ static final GenericDescription[] EMPTY_GENERICDESCS = new GenericDescription[0];
static final int RESOLVED = 0x01;
static final int SINGLETON = 0x02;
@@ -62,6 +64,10 @@ public class BundleDescriptionImpl extends BaseDescriptionImpl implements Bundle
return getName();
}
+ public BundleDescription getSupplier() {
+ return this;
+ }
+
public String getLocation() {
fullyLoad();
return lazyData.location;
@@ -93,6 +99,20 @@ public class BundleDescriptionImpl extends BaseDescriptionImpl implements Bundle
return lazyData.requiredBundles;
}
+ public GenericSpecification[] getGenericRequires() {
+ fullyLoad();
+ if (lazyData.genericRequires == null)
+ return EMPTY_GENERICSPECS;
+ return lazyData.genericRequires;
+ }
+
+ public GenericDescription[] getGenericCapabilities() {
+ fullyLoad();
+ if (lazyData.genericCapabilities == null)
+ return EMPTY_GENERICDESCS;
+ return lazyData.genericCapabilities;
+ }
+
public ExportPackageDescription[] getExportPackages() {
fullyLoad();
return lazyData.exportPackages == null ? EMPTY_EXPORTS : lazyData.exportPackages;
@@ -215,6 +235,22 @@ public class BundleDescriptionImpl extends BaseDescriptionImpl implements Bundle
}
}
+ protected void setGenericCapabilities(GenericDescription[] genericCapabilities) {
+ checkLazyData();
+ lazyData.genericCapabilities = genericCapabilities;
+ if (genericCapabilities != null)
+ for (int i = 0; i < genericCapabilities.length; i++)
+ ((GenericDescriptionImpl) genericCapabilities[i]).setSupplier(this);
+ }
+
+ protected void setGenericRequires(GenericSpecification[] genericRequires) {
+ checkLazyData();
+ lazyData.genericRequires = genericRequires;
+ if (genericRequires != null)
+ for (int i = 0; i < genericRequires.length; i++)
+ ((VersionConstraintImpl) genericRequires[i]).setBundle(this);
+ }
+
protected int getStateBits() {
return stateBits;
}
@@ -323,11 +359,7 @@ public class BundleDescriptionImpl extends BaseDescriptionImpl implements Bundle
}
protected synchronized void addDependency(BaseDescriptionImpl dependency) {
- BundleDescriptionImpl bundle;
- if (dependency instanceof ExportPackageDescription)
- bundle = (BundleDescriptionImpl) ((ExportPackageDescription) dependency).getExporter();
- else
- bundle = (BundleDescriptionImpl) dependency;
+ BundleDescriptionImpl bundle = (BundleDescriptionImpl) dependency.getSupplier();
if (bundle == this)
return;
if (dependencies == null)
@@ -412,7 +444,7 @@ public class BundleDescriptionImpl extends BaseDescriptionImpl implements Bundle
private void fullyLoad() {
if ((stateBits & LAZY_LOADED) == 0)
return;
- if (isFullyLoaded()){
+ if (isFullyLoaded()) {
containingState.getReader().setAccessedFlag(true); // set reader accessed flag
return;
}
@@ -501,6 +533,8 @@ public class BundleDescriptionImpl extends BaseDescriptionImpl implements Bundle
BundleSpecification[] requiredBundles;
ExportPackageDescription[] exportPackages;
ImportPackageSpecification[] importPackages;
+ GenericDescription[] genericCapabilities;
+ GenericSpecification[] genericRequires;
ExportPackageDescription[] selectedExports;
BundleDescription[] resolvedRequires;
diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/ExportPackageDescriptionImpl.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/ExportPackageDescriptionImpl.java
index 1de78413d..76c6ee821 100644
--- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/ExportPackageDescriptionImpl.java
+++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/ExportPackageDescriptionImpl.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2005 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 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
@@ -32,7 +32,7 @@ public class ExportPackageDescriptionImpl extends BaseDescriptionImpl implements
private int tableIndex;
public Map getDirectives() {
- Map result = new HashMap (5);
+ Map result = new HashMap(5);
if (uses != null)
result.put(Constants.USES_DIRECTIVE, uses);
if (exclude != null)
@@ -47,7 +47,7 @@ public class ExportPackageDescriptionImpl extends BaseDescriptionImpl implements
result.put(EQUINOX_EE, equinox_ee == -1 ? EQUINOX_EE_DEFAULT : new Integer(equinox_ee));
return result;
}
-
+
public Object getDirective(String key) {
if (key.equals(Constants.USES_DIRECTIVE))
return uses;
@@ -68,7 +68,7 @@ public class ExportPackageDescriptionImpl extends BaseDescriptionImpl implements
public Object setDirective(String key, Object value) {
if (key.equals(Constants.USES_DIRECTIVE))
- return uses = (String[])value;
+ return uses = (String[]) value;
if (key.equals(Constants.EXCLUDE_DIRECTIVE))
return exclude = (String) value;
if (key.equals(Constants.INCLUDE_DIRECTIVE))
@@ -89,19 +89,23 @@ public class ExportPackageDescriptionImpl extends BaseDescriptionImpl implements
public void setDirectives(Map directives) {
if (directives == null)
return;
- uses = (String[])directives.get(Constants.USES_DIRECTIVE);
- exclude = (String)directives.get(Constants.EXCLUDE_DIRECTIVE);
- include = (String)directives.get(Constants.INCLUDE_DIRECTIVE);
- mandatory = (String[])directives.get(Constants.MANDATORY_DIRECTIVE);
- friends = (String[])directives.get(Constants.FRIENDS_DIRECTIVE);
- internal = (Boolean)directives.get(Constants.INTERNAL_DIRECTIVE);
- equinox_ee = ((Integer)directives.get(EQUINOX_EE)).intValue();
+ uses = (String[]) directives.get(Constants.USES_DIRECTIVE);
+ exclude = (String) directives.get(Constants.EXCLUDE_DIRECTIVE);
+ include = (String) directives.get(Constants.INCLUDE_DIRECTIVE);
+ mandatory = (String[]) directives.get(Constants.MANDATORY_DIRECTIVE);
+ friends = (String[]) directives.get(Constants.FRIENDS_DIRECTIVE);
+ internal = (Boolean) directives.get(Constants.INTERNAL_DIRECTIVE);
+ equinox_ee = ((Integer) directives.get(EQUINOX_EE)).intValue();
}
-
+
public Map getAttributes() {
return attributes;
}
+ public BundleDescription getSupplier() {
+ return getExporter();
+ }
+
public BundleDescription getExporter() {
return exporter;
}
@@ -123,7 +127,7 @@ public class ExportPackageDescriptionImpl extends BaseDescriptionImpl implements
}
public String toString() {
- return "Export-Package: " + getName() + "; version=\"" + getVersion() + "\""; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
+ return "Export-Package: " + getName() + "; version=\"" + getVersion() + "\""; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
}
int getTableIndex() {
diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/GenericDescriptionImpl.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/GenericDescriptionImpl.java
new file mode 100644
index 000000000..09276606c
--- /dev/null
+++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/GenericDescriptionImpl.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.internal.resolver;
+
+import java.util.Dictionary;
+import org.eclipse.osgi.service.resolver.BundleDescription;
+import org.eclipse.osgi.service.resolver.GenericDescription;
+import org.osgi.framework.Constants;
+
+public class GenericDescriptionImpl extends BaseDescriptionImpl implements GenericDescription {
+ private Dictionary attributes;
+ private BundleDescription supplier;
+ private String type = GenericDescription.DEFAULT_TYPE;
+
+ public Dictionary getAttributes() {
+ return attributes;
+ }
+
+ public BundleDescription getSupplier() {
+ return supplier;
+ }
+
+ void setAttributes(Dictionary attributes) {
+ this.attributes = attributes;
+ // always add/replace the version attribute with the actual Version object
+ attributes.put(Constants.VERSION_ATTRIBUTE, getVersion());
+ }
+
+ void setSupplier(BundleDescription supplier) {
+ this.supplier = supplier;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(StateBuilder.GENERIC_CAPABILITY).append(": ").append(getName()); //$NON-NLS-1$
+ if (getType() != GenericDescription.DEFAULT_TYPE)
+ sb.append(':').append(getType());
+ return sb.toString();
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ void setType(String type) {
+ if (type == null || type.equals(GenericDescription.DEFAULT_TYPE))
+ this.type = GenericDescription.DEFAULT_TYPE;
+ else
+ this.type = type;
+ }
+}
diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/GenericSpecificationImpl.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/GenericSpecificationImpl.java
new file mode 100644
index 000000000..8f6d44bb4
--- /dev/null
+++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/GenericSpecificationImpl.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.internal.resolver;
+
+import org.eclipse.osgi.service.resolver.*;
+import org.osgi.framework.*;
+
+public class GenericSpecificationImpl extends VersionConstraintImpl implements GenericSpecification {
+ private Filter matchingFilter;
+ private String type = GenericDescription.DEFAULT_TYPE;
+ private int resolution = 0;
+ private GenericDescription[] suppliers;
+
+ public String getMatchingFilter() {
+ return matchingFilter == null ? null : matchingFilter.toString();
+ }
+
+ void setMatchingFilter(String matchingFilter) throws InvalidSyntaxException {
+ this.matchingFilter = matchingFilter == null ? null : FrameworkUtil.createFilter(matchingFilter);
+ }
+
+ public boolean isSatisfiedBy(BaseDescription supplier) {
+ if (!(supplier instanceof GenericDescription))
+ return false;
+ GenericDescription candidate = (GenericDescription) supplier;
+ if (getName() == null || !getName().equals(candidate.getName()))
+ return false;
+ if (getType() == null || !getType().equals(candidate.getType()))
+ return false;
+ // Note that versions are only matched by including them in the filter
+ return matchingFilter == null || matchingFilter.match(candidate.getAttributes());
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(StateBuilder.GENERIC_REQUIRE).append(": ").append(getName()); //$NON-NLS-1$
+ if (getType() != GenericDescription.DEFAULT_TYPE)
+ sb.append(':').append(getType());
+ if (matchingFilter != null)
+ sb.append("; ").append(getMatchingFilter()); //$NON-NLS-1$
+ return sb.toString();
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ void setType(String type) {
+ if (type == null || type.equals(GenericDescription.DEFAULT_TYPE))
+ this.type = GenericDescription.DEFAULT_TYPE;
+ else
+ this.type = type;
+ }
+
+ public int getResolution() {
+ return resolution;
+ }
+
+ public boolean isResolved() {
+ return suppliers != null && suppliers.length > 0;
+ }
+
+ void setResolution(int resolution) {
+ this.resolution = resolution;
+ }
+
+ public BaseDescription getSupplier() {
+ return suppliers == null || suppliers.length == 0 ? null : suppliers[0];
+ }
+
+ protected void setSupplier(BaseDescription supplier) {
+ if (supplier == null) {
+ suppliers = null;
+ return;
+ }
+ int len = suppliers == null ? 0 : suppliers.length;
+ GenericDescription[] temp = new GenericDescription[len + 1];
+ if (suppliers != null)
+ System.arraycopy(suppliers, 0, temp, 0, len);
+ temp[len] = (GenericDescription) supplier;
+ suppliers = temp;
+ }
+
+ public GenericDescription[] getSuppliers() {
+ return suppliers;
+ }
+
+ void setSupplers(GenericDescription[] suppliers) {
+ this.suppliers = suppliers;
+ }
+}
diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/ResolverErrorImpl.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/ResolverErrorImpl.java
index 6c8fa56dc..69b6dadf2 100644
--- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/ResolverErrorImpl.java
+++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/ResolverErrorImpl.java
@@ -54,6 +54,7 @@ public class ResolverErrorImpl implements ResolverError {
case ResolverError.MISSING_REQUIRE_BUNDLE :
case ResolverError.MISSING_FRAGMENT_HOST :
case ResolverError.MISSING_EXECUTION_ENVIRONMENT :
+ case ResolverError.MISSING_GENERIC_CAPABILITY :
return NLS.bind(StateMsg.RES_ERROR_MISSING_CONSTRAINT, getData());
case ResolverError.FRAGMENT_CONFLICT :
return NLS.bind(StateMsg.RES_ERROR_FRAGMENT_CONFLICT, getData());
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 d9490b1f6..ae19cf7ac 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2003, 2005 IBM Corporation and others.
+ * Copyright (c) 2003, 2006 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
@@ -10,21 +10,32 @@
*******************************************************************************/
package org.eclipse.osgi.internal.resolver;
+import java.lang.reflect.Constructor;
import java.util.*;
import org.eclipse.osgi.framework.internal.core.Constants;
import org.eclipse.osgi.service.resolver.*;
import org.eclipse.osgi.util.ManifestElement;
import org.eclipse.osgi.util.NLS;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.Version;
+import org.osgi.framework.*;
/**
* This class builds bundle description objects from manifests
*/
class StateBuilder {
- static String[] DEFINED_MATCHING_ATTRS = {Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, Constants.BUNDLE_VERSION_ATTRIBUTE, Constants.PACKAGE_SPECIFICATION_VERSION, Constants.VERSION_ATTRIBUTE};
+ static final String[] DEFINED_MATCHING_ATTRS = {Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, Constants.BUNDLE_VERSION_ATTRIBUTE, Constants.PACKAGE_SPECIFICATION_VERSION, Constants.VERSION_ATTRIBUTE};
+ static final String[] DEFINED_OSGI_VALIDATE_HEADERS = {Constants.IMPORT_PACKAGE, Constants.DYNAMICIMPORT_PACKAGE, Constants.EXPORT_PACKAGE, Constants.FRAGMENT_HOST, Constants.BUNDLE_SYMBOLICNAME, Constants.REEXPORT_PACKAGE, Constants.REQUIRE_BUNDLE};
+ static final String GENERIC_REQUIRE = "Eclipse-GenericRequire"; //$NON-NLS-1$
+ static final String GENERIC_CAPABILITY = "Eclipse-GenericCapability"; //$NON-NLS-1$
- static String[] DEFINED_OSGI_VALIDATE_HEADERS = {Constants.IMPORT_PACKAGE, Constants.DYNAMICIMPORT_PACKAGE, Constants.EXPORT_PACKAGE, Constants.FRAGMENT_HOST, Constants.BUNDLE_SYMBOLICNAME, Constants.REEXPORT_PACKAGE, Constants.REQUIRE_BUNDLE};
+ private static final String ATTR_TYPE_STRING = "string"; //$NON-NLS-1$
+ private static final String ATTR_TYPE_VERSION = "version"; //$NON-NLS-1$
+ private static final String ATTR_TYPE_URI = "uri"; //$NON-NLS-1$
+ private static final String ATTR_TYPE_LONG = "long"; //$NON-NLS-1$
+ private static final String ATTR_TYPE_DOUBLE = "double"; //$NON-NLS-1$
+ private static final String ATTR_TYPE_SET = "set"; //$NON-NLS-1$
+ private static final String OPTIONAL_ATTR = "optional"; //$NON-NLS-1$
+ private static final String MULTIPLE_ATTR = "multiple"; //$NON-NLS-1$
+ private static final String TRUE = "true"; //$NON-NLS-1$
static BundleDescription createBundleDescription(StateImpl state, Dictionary manifest, String location) throws BundleException {
BundleDescriptionImpl result = new BundleDescriptionImpl();
@@ -85,6 +96,80 @@ class StateBuilder {
result.setImportPackages(createImportPackages(result.getExportPackages(), providedExports, imports, dynamicImports, manifestVersion));
ManifestElement[] requires = ManifestElement.parseHeader(Constants.REQUIRE_BUNDLE, (String) manifest.get(Constants.REQUIRE_BUNDLE));
result.setRequiredBundles(createRequiredBundles(requires));
+ String[][] genericAliases = getGenericAliases(state);
+ ManifestElement[] genericRequires = getGenericRequires(manifest, genericAliases);
+ result.setGenericRequires(createGenericRequires(genericRequires));
+ ManifestElement[] genericCapabilities = getGenericCapabilities(manifest, genericAliases);
+ result.setGenericCapabilities(createGenericCapabilities(genericCapabilities));
+ return result;
+ }
+
+ private static ManifestElement[] getGenericRequires(Dictionary manifest, String[][] genericAliases) throws BundleException {
+ ManifestElement[] genericRequires = ManifestElement.parseHeader(GENERIC_REQUIRE, (String) manifest.get(GENERIC_REQUIRE));
+ ArrayList aliasList = null;
+ if (genericAliases.length > 0) {
+ aliasList = new ArrayList(genericRequires == null ? 0 : genericRequires.length);
+ for (int i = 0; i < genericAliases.length; i++) {
+ ManifestElement[] aliasReqs = ManifestElement.parseHeader(genericAliases[i][1], (String) manifest.get(genericAliases[i][1]));
+ if (aliasReqs == null)
+ continue;
+ for (int j = 0; j < aliasReqs.length; j++) {
+ StringBuffer strBuf = new StringBuffer();
+ strBuf.append(aliasReqs[j].getValue()).append(':').append(genericAliases[i][2]);
+ String filter = aliasReqs[j].getAttribute(Constants.SELECTION_FILTER_ATTRIBUTE);
+ if (filter != null)
+ strBuf.append("; ").append(Constants.SELECTION_FILTER_ATTRIBUTE).append(filter).append("=\"").append(filter).append("\""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ ManifestElement[] withType = ManifestElement.parseHeader(genericAliases[i][1], strBuf.toString());
+ aliasList.add(withType[0]);
+ }
+ }
+ }
+ if (aliasList == null || aliasList.size() == 0)
+ return genericRequires;
+ if (genericRequires != null)
+ for (int i = 0; i < genericRequires.length; i++)
+ aliasList.add(genericRequires[i]);
+ return (ManifestElement[]) aliasList.toArray(new ManifestElement[aliasList.size()]);
+ }
+
+ private static ManifestElement[] getGenericCapabilities(Dictionary manifest, String[][] genericAliases) throws BundleException {
+ ManifestElement[] genericCapabilities = ManifestElement.parseHeader(GENERIC_CAPABILITY, (String) manifest.get(GENERIC_CAPABILITY));
+ ArrayList aliasList = null;
+ if (genericAliases.length > 0) {
+ aliasList = new ArrayList(genericCapabilities == null ? 0 : genericCapabilities.length);
+ for (int i = 0; i < genericAliases.length; i++) {
+ ManifestElement[] aliasCapabilities = ManifestElement.parseHeader(genericAliases[i][0], (String) manifest.get(genericAliases[i][0]));
+ if (aliasCapabilities == null)
+ continue;
+ for (int j = 0; j < aliasCapabilities.length; j++) {
+ StringBuffer strBuf = new StringBuffer();
+ strBuf.append(aliasCapabilities[j].getValue()).append(':').append(genericAliases[i][2]);
+ for (Enumeration keys = aliasCapabilities[j].getKeys(); keys != null && keys.hasMoreElements();) {
+ String key = (String) keys.nextElement();
+ strBuf.append("; ").append(key).append("=\"").append(aliasCapabilities[j].getAttribute(key)).append("\""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ ManifestElement[] withTypes = ManifestElement.parseHeader(genericAliases[i][0], strBuf.toString());
+ aliasList.add(withTypes[0]);
+ }
+ }
+ }
+ if (aliasList == null || aliasList.size() == 0)
+ return genericCapabilities;
+ if (genericCapabilities != null)
+ for (int i = 0; i < genericCapabilities.length; i++)
+ aliasList.add(genericCapabilities[i]);
+ return (ManifestElement[]) aliasList.toArray(new ManifestElement[aliasList.size()]);
+ }
+
+ private static String[][] getGenericAliases(StateImpl state) {
+ Dictionary[] platformProps = state == null ? null : state.getPlatformProperties();
+ String genericAliasesProp = platformProps == null || platformProps.length == 0 ? null : (String) platformProps[0].get("osgi.genericAliases"); //$NON-NLS-1$
+ if (genericAliasesProp == null)
+ return new String[0][0];
+ String[] aliases = ManifestElement.getArrayFromList(genericAliasesProp, ","); //$NON-NLS-1$
+ String[][] result = new String[aliases.length][];
+ for (int i = 0; i < aliases.length; i++)
+ result[i] = ManifestElement.getArrayFromList(aliases[i], ":"); //$NON-NLS-1$
return result;
}
@@ -271,10 +356,41 @@ class StateBuilder {
break;
}
}
+ String value = exportPackage.getAttribute(key);
+ int colonIndex = key.indexOf(':');
+ String type = ATTR_TYPE_STRING;
+ if (colonIndex > 0) {
+ type = key.substring(colonIndex + 1);
+ key = key.substring(0, colonIndex);
+ }
if (!definedAttr) {
if (arbitraryAttrs == null)
arbitraryAttrs = new HashMap();
- arbitraryAttrs.put(key, exportPackage.getAttribute(key));
+ Object putValue = value;
+ if (ATTR_TYPE_STRING.equals(type))
+ putValue = value;
+ else if (ATTR_TYPE_DOUBLE.equals(type))
+ putValue = new Double(value);
+ else if (ATTR_TYPE_LONG.equals(type))
+ putValue = new Long(value);
+ else if (ATTR_TYPE_URI.equals(type))
+ try {
+ Class uriClazz = Class.forName("java.net.URI"); //$NON-NLS-1$
+ Constructor constructor = uriClazz.getConstructor(new Class[] {String.class});
+ putValue = constructor.newInstance(new Object[] {value});
+ } catch (ClassNotFoundException e) {
+ // oh well cannot support; just use string
+ putValue = value;
+ } catch (Exception e) { // got some reflection exception
+ if (e instanceof RuntimeException)
+ throw (RuntimeException) e;
+ throw new RuntimeException(e.getMessage());
+ }
+ else if (ATTR_TYPE_VERSION.equals(type))
+ putValue = new Version(value);
+ else if (ATTR_TYPE_SET.equals(type))
+ putValue = ManifestElement.getArrayFromList(value, ","); //$NON-NLS-1$
+ arbitraryAttrs.put(key, putValue);
}
}
return arbitraryAttrs;
@@ -290,6 +406,74 @@ class StateBuilder {
return result;
}
+ private static GenericSpecification[] createGenericRequires(ManifestElement[] genericRequires) throws BundleException {
+ if (genericRequires == null)
+ return null;
+ ArrayList results = new ArrayList(genericRequires.length);
+ for (int i = 0; i < genericRequires.length; i++) {
+ String[] genericNames = genericRequires[i].getValueComponents();
+ for (int j = 0; j < genericNames.length; j++) {
+ GenericSpecificationImpl spec = new GenericSpecificationImpl();
+ int colonIdx = genericNames[j].indexOf(':');
+ if (colonIdx > 0) {
+ spec.setName(genericNames[j].substring(0, colonIdx));
+ spec.setType(genericNames[j].substring(colonIdx + 1));
+ } else
+ spec.setName(genericNames[j]);
+ try {
+ spec.setMatchingFilter(genericRequires[i].getAttribute(Constants.SELECTION_FILTER_ATTRIBUTE));
+ } catch (InvalidSyntaxException e) {
+ throw new BundleException(Constants.SELECTION_FILTER_ATTRIBUTE, e);
+ }
+ String optional = genericRequires[i].getAttribute(OPTIONAL_ATTR);
+ String multiple = genericRequires[i].getAttribute(MULTIPLE_ATTR);
+ int resolution = 0;
+ if (TRUE.equals(optional))
+ resolution |= GenericSpecification.RESOLUTION_OPTIONAL;
+ if (TRUE.equals(multiple))
+ resolution |= GenericSpecification.RESOLUTION_MULTIPLE;
+ spec.setResolution(resolution);
+ results.add(spec);
+ }
+ }
+ return (GenericSpecification[]) results.toArray(new GenericSpecification[results.size()]);
+ }
+
+ private static GenericDescription[] createGenericCapabilities(ManifestElement[] genericCapabilities) {
+ if (genericCapabilities == null)
+ return null;
+ ArrayList results = new ArrayList(genericCapabilities.length);
+ for (int i = 0; i < genericCapabilities.length; i++) {
+ String[] genericNames = genericCapabilities[i].getValueComponents();
+ for (int j = 0; j < genericNames.length; j++) {
+ GenericDescriptionImpl desc = new GenericDescriptionImpl();
+ int colonIdx = genericNames[j].indexOf(':');
+ if (colonIdx > 0) {
+ desc.setName(genericNames[j].substring(0, colonIdx));
+ desc.setType(genericNames[j].substring(colonIdx + 1));
+ } else
+ desc.setName(genericNames[j]);
+ String versionString = genericCapabilities[i].getAttribute(Constants.VERSION_ATTRIBUTE);
+ if (versionString != null)
+ desc.setVersion(Version.parseVersion(versionString));
+ Map mapAttrs = getAttributes(genericCapabilities[i], new String[] {Constants.VERSION_ATTRIBUTE});
+ Object version = mapAttrs == null ? null : mapAttrs.remove(Constants.VERSION_ATTRIBUTE);
+ if (version instanceof Version) // this is just incase someone uses version:version as a key
+ desc.setVersion((Version) version);
+ Dictionary attrs = new Hashtable();
+ if (mapAttrs != null) {
+ for (Iterator keys = mapAttrs.keySet().iterator(); keys.hasNext();) {
+ Object key = keys.next();
+ attrs.put(key, mapAttrs.get(key));
+ }
+ }
+ desc.setAttributes(attrs);
+ results.add(desc);
+ }
+ }
+ return (GenericDescription[]) results.toArray(new GenericDescription[results.size()]);
+ }
+
private static VersionRange getVersionRange(String versionRange) {
if (versionRange == null)
return null;
@@ -351,7 +535,6 @@ class StateBuilder {
throw new BundleException(NLS.bind(StateMsg.HEADER_REEXPORT_USES, Constants.USES_DIRECTIVE, Constants.REEXPORT_PACKAGE));
}
-
private static void checkExtensionBundle(ManifestElement[] elements) throws BundleException {
if (elements.length == 0 || elements[0].getDirective(Constants.EXTENSION_DIRECTIVE) == null)
return;
diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateHelperImpl.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateHelperImpl.java
index 3b7b3413b..228245b1f 100644
--- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateHelperImpl.java
+++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateHelperImpl.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2005 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 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
@@ -85,8 +85,29 @@ public class StateHelperImpl implements StateHelper {
return result;
}
+ private Map getGenericsMap(State state, boolean resolved) {
+ Map result = new HashMap(11);
+ BundleDescription[] bundles = state.getBundles();
+ for (int i = 0; i < bundles.length; i++) {
+ if (resolved && !bundles[i].isResolved())
+ continue; // discard unresolved bundles
+ GenericDescription[] generics = bundles[i].getGenericCapabilities();
+ for (int j = 0; j < generics.length; j++) {
+ GenericDescription description = generics[j];
+ Set genericSet = (Set) result.get(description.getName());
+ if (genericSet == null) {
+ genericSet = new HashSet(1);
+ result.put(description.getName(), genericSet);
+ }
+ genericSet.add(description);
+ }
+ }
+ return result;
+ }
+
private VersionConstraint[] getUnsatisfiedLeaves(State state, BundleDescription[] bundles) {
Map packages = getExportedPackageMap(state);
+ Map generics = getGenericsMap(state, false);
HashSet result = new HashSet(11);
for (int i = 0; i < bundles.length; i++) {
BundleDescription description = bundles[i];
@@ -103,6 +124,11 @@ public class StateHelperImpl implements StateHelper {
if (exports != null)
for (Iterator iter = exports.iterator(); iter.hasNext() && !satisfied;)
satisfied |= constraint.isSatisfiedBy((ExportPackageDescription) iter.next());
+ } else if (constraint instanceof GenericSpecification) {
+ Set genericSet = (Set) generics.get(constraint.getName());
+ if (genericSet != null)
+ for (Iterator iter = genericSet.iterator(); iter.hasNext() && !satisfied;)
+ satisfied |= constraint.isSatisfiedBy((GenericDescription) iter.next());
}
if (!satisfied)
result.add(constraint);
@@ -140,6 +166,10 @@ public class StateHelperImpl implements StateHelper {
for (int i = 0; i < packages.length; i++)
if (!packages[i].isResolved() && !isResolvable(packages[i]))
unsatisfied.add(packages[i]);
+ GenericSpecification[] generics = bundle.getGenericRequires();
+ for (int i = 0; i < generics.length; i++)
+ if (!generics[i].isResolved() && !isResolvable(generics[i]))
+ unsatisfied.add(generics[i]);
return (VersionConstraint[]) unsatisfied.toArray(new VersionConstraint[unsatisfied.size()]);
}
@@ -154,6 +184,17 @@ public class StateHelperImpl implements StateHelper {
return false;
}
+ private boolean isResolvable(GenericSpecification constraint) {
+ Map genericCapabilities = getGenericsMap(constraint.getBundle().getContainingState(), true);
+ Set genericSet = (Set) genericCapabilities.get(constraint.getName());
+ if (genericSet == null)
+ return false;
+ for (Iterator iter = genericSet.iterator(); iter.hasNext();)
+ if (constraint.isSatisfiedBy((GenericDescription) iter.next()))
+ return true;
+ return false;
+ }
+
/**
* @see StateHelper
*/
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 c4c2186ba..6841f4d97 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2003, 2005 IBM Corporation and others.
+ * Copyright (c) 2003, 2006 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
@@ -24,7 +24,7 @@ import org.osgi.framework.BundleException;
import org.osgi.framework.Version;
public abstract class StateImpl implements State {
- public static final String[] PROPS = {"osgi.os", "osgi.ws", "osgi.nl", "osgi.arch", Constants.OSGI_FRAMEWORK_SYSTEM_PACKAGES, Constants.OSGI_RESOLVER_MODE, Constants.FRAMEWORK_EXECUTIONENVIRONMENT, "osgi.resolveOptional"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ public static final String[] PROPS = {"osgi.os", "osgi.ws", "osgi.nl", "osgi.arch", Constants.OSGI_FRAMEWORK_SYSTEM_PACKAGES, Constants.OSGI_RESOLVER_MODE, Constants.FRAMEWORK_EXECUTIONENVIRONMENT, "osgi.resolveOptional", "osgi.genericAliases"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
transient private Resolver resolver;
transient private StateDeltaImpl changes;
transient private boolean resolving = false;
@@ -266,6 +266,15 @@ public abstract class StateImpl implements State {
bundle.addDependencies(hosts);
bundle.addDependencies(resolvedRequires);
bundle.addDependencies(resolvedImports);
+ // add dependecies for generics
+ GenericSpecification[] genericRequires = bundle.getGenericRequires();
+ if (genericRequires.length > 0) {
+ ArrayList genericSuppliers = new ArrayList(genericRequires.length);
+ for (int i = 0; i < genericRequires.length; i++)
+ if (genericRequires[i].getSupplier() != null)
+ genericSuppliers.add(genericRequires[i].getSupplier());
+ bundle.addDependencies((BaseDescription[]) genericSuppliers.toArray(new BaseDescription[genericSuppliers.size()]));
+ }
}
private void unresolveConstraints(BundleDescriptionImpl bundle) {
@@ -508,7 +517,7 @@ public abstract class StateImpl implements State {
ExportPackageDescription[] exports = systemBundle.getExportPackages();
ArrayList newExports = new ArrayList(exports.length);
for (int i = 0; i < exports.length; i++)
- if (((Integer)exports[i].getDirective(ExportPackageDescriptionImpl.EQUINOX_EE)).intValue() < 0)
+ if (((Integer) exports[i].getDirective(ExportPackageDescriptionImpl.EQUINOX_EE)).intValue() < 0)
newExports.add(exports[i]);
addSystemExports(newExports);
systemBundle.setExportPackages((ExportPackageDescription[]) newExports.toArray(new ExportPackageDescription[newExports.size()]));
@@ -525,7 +534,7 @@ public abstract class StateImpl implements State {
ExportPackageDescription[] systemExports = StateBuilder.createExportPackages(elements, null, null, null, 2, false);
Integer profInx = new Integer(i);
for (int j = 0; j < systemExports.length; j++) {
- ((ExportPackageDescriptionImpl)systemExports[j]).setDirective(ExportPackageDescriptionImpl.EQUINOX_EE, profInx);
+ ((ExportPackageDescriptionImpl) systemExports[j]).setDirective(ExportPackageDescriptionImpl.EQUINOX_EE, profInx);
exports.add(systemExports[j]);
}
} catch (BundleException e) {
@@ -626,7 +635,6 @@ public abstract class StateImpl implements State {
}
}
-
public ExportPackageDescription[] getSystemPackages() {
ArrayList result = new ArrayList();
BundleDescription[] systemBundles = getBundles(Constants.getInternalSymbolicName());
@@ -634,7 +642,7 @@ public abstract class StateImpl implements State {
BundleDescriptionImpl systemBundle = (BundleDescriptionImpl) systemBundles[0];
ExportPackageDescription[] exports = systemBundle.getExportPackages();
for (int i = 0; i < exports.length; i++)
- if (((Integer)exports[i].getDirective(ExportPackageDescriptionImpl.EQUINOX_EE)).intValue() >= 0)
+ if (((Integer) exports[i].getDirective(ExportPackageDescriptionImpl.EQUINOX_EE)).intValue() >= 0)
result.add(exports[i]);
}
return (ExportPackageDescription[]) result.toArray(new ExportPackageDescription[result.size()]);
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 a161a073d..ab71b23c0 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2003, 2005 IBM Corporation and others.
+ * Copyright (c) 2003, 2006 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
@@ -11,12 +11,11 @@
package org.eclipse.osgi.internal.resolver;
import java.io.*;
-import java.util.Dictionary;
-import java.util.Map;
+import java.util.*;
+import org.eclipse.osgi.framework.internal.core.Constants;
import org.eclipse.osgi.internal.module.ResolverImpl;
import org.eclipse.osgi.service.resolver.*;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.Version;
+import org.osgi.framework.*;
public class StateObjectFactoryImpl implements StateObjectFactory {
@@ -25,12 +24,16 @@ public class StateObjectFactoryImpl implements StateObjectFactory {
}
public BundleDescription createBundleDescription(State state, Dictionary manifest, String location, long id) throws BundleException {
- BundleDescriptionImpl result = (BundleDescriptionImpl) StateBuilder.createBundleDescription((StateImpl)state, manifest, location);
+ BundleDescriptionImpl result = (BundleDescriptionImpl) StateBuilder.createBundleDescription((StateImpl) state, manifest, location);
result.setBundleId(id);
return result;
}
public BundleDescription createBundleDescription(long id, String symbolicName, Version version, String location, BundleSpecification[] required, HostSpecification host, ImportPackageSpecification[] imports, ExportPackageDescription[] exports, String[] providedPackages, boolean singleton) {
+ return createBundleDescription(id, symbolicName, version, location, required, host, imports, exports, providedPackages, singleton, true, true, null, null, null, null);
+ }
+
+ public BundleDescription createBundleDescription(long id, String symbolicName, Version version, String location, BundleSpecification[] required, HostSpecification host, ImportPackageSpecification[] imports, ExportPackageDescription[] exports, String[] providedPackages, boolean singleton, boolean attachFragments, boolean dynamicFragments, String platformFilter, String executionEnvironment, GenericSpecification[] genericRequires, GenericDescription[] genericCapabilities) {
BundleDescriptionImpl bundle = new BundleDescriptionImpl();
bundle.setBundleId(id);
bundle.setSymbolicName(symbolicName);
@@ -41,6 +44,11 @@ public class StateObjectFactoryImpl implements StateObjectFactory {
bundle.setImportPackages(imports);
bundle.setExportPackages(exports);
bundle.setStateBit(BundleDescriptionImpl.SINGLETON, singleton);
+ bundle.setStateBit(BundleDescriptionImpl.ATTACH_FRAGMENTS, attachFragments);
+ bundle.setStateBit(BundleDescriptionImpl.DYNAMIC_FRAGMENTS, dynamicFragments);
+ bundle.setPlatformFilter(platformFilter);
+ bundle.setGenericRequires(genericRequires);
+ bundle.setGenericCapabilities(genericCapabilities);
return bundle;
}
@@ -73,9 +81,42 @@ public class StateObjectFactoryImpl implements StateObjectFactory {
bundle.setStateBit(BundleDescriptionImpl.HAS_DYNAMICIMPORT, original.hasDynamicImports());
bundle.setPlatformFilter(original.getPlatformFilter());
bundle.setExecutionEnvironments(original.getExecutionEnvironments());
+ bundle.setGenericCapabilities(createGenericCapabilities(original.getGenericCapabilities()));
+ bundle.setGenericRequires(createGenericRequires(original.getGenericRequires()));
return bundle;
}
+ private GenericDescription[] createGenericCapabilities(GenericDescription[] genericCapabilities) {
+ if (genericCapabilities == null || genericCapabilities.length == 0)
+ return null;
+ GenericDescription[] result = new GenericDescription[genericCapabilities.length];
+ for (int i = 0; i < genericCapabilities.length; i++) {
+ GenericDescriptionImpl cap = new GenericDescriptionImpl();
+ cap.setName(genericCapabilities[i].getName());
+ cap.setVersion(genericCapabilities[i].getVersion());
+ cap.setAttributes(genericCapabilities[i].getAttributes());
+ result[i] = cap;
+ }
+ return result;
+ }
+
+ private GenericSpecification[] createGenericRequires(GenericSpecification[] genericRequires) {
+ if (genericRequires == null || genericRequires.length == 0)
+ return null;
+ GenericSpecification[] result = new GenericSpecification[genericRequires.length];
+ for (int i = 0; i < genericRequires.length; i++) {
+ GenericSpecificationImpl req = new GenericSpecificationImpl();
+ req.setName(genericRequires[i].getName());
+ try {
+ req.setMatchingFilter(genericRequires[i].getMatchingFilter());
+ } catch (InvalidSyntaxException e) {
+ // do nothing; this filter should aready have been tested
+ }
+ result[i] = req;
+ }
+ return result;
+ }
+
public BundleSpecification createBundleSpecification(String requiredSymbolicName, VersionRange requiredVersionRange, boolean export, boolean optional) {
BundleSpecificationImpl bundleSpec = new BundleSpecificationImpl();
bundleSpec.setName(requiredSymbolicName);
@@ -146,6 +187,38 @@ public class StateObjectFactoryImpl implements StateObjectFactory {
return exportPackage;
}
+ public GenericDescription createGenericDescription(String name, String type, Version version, Map attributes) {
+ GenericDescriptionImpl result = new GenericDescriptionImpl();
+ result.setName(name);
+ result.setType(type);
+ result.setVersion(version);
+ Object versionObj = attributes == null ? null : attributes.remove(Constants.VERSION_ATTRIBUTE);
+ if (versionObj instanceof Version) // this is just incase someone uses version:version as a key
+ result.setVersion((Version) versionObj);
+ Dictionary attrs = new Hashtable();
+ if (attributes != null)
+ for (Iterator keys = attributes.keySet().iterator(); keys.hasNext();) {
+ Object key = keys.next();
+ attrs.put(key, attributes.get(key));
+ }
+ result.setAttributes(attrs);
+ return result;
+ }
+
+ public GenericSpecification createGenericSpecification(String name, String type, String matchingFilter, boolean optional, boolean multiple) throws InvalidSyntaxException {
+ GenericSpecificationImpl result = new GenericSpecificationImpl();
+ result.setName(name);
+ result.setType(type);
+ result.setMatchingFilter(matchingFilter);
+ int resolution = 0;
+ if (optional)
+ resolution |= GenericSpecification.RESOLUTION_OPTIONAL;
+ if (multiple)
+ resolution |= GenericSpecification.RESOLUTION_MULTIPLE;
+ result.setResolution(resolution);
+ return result;
+ }
+
public SystemState createSystemState() {
SystemState state = new SystemState();
state.setFactory(this);
diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateReader.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateReader.java
index 5d339429e..17bb6ff7e 100644
--- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateReader.java
+++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateReader.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2003, 2005 IBM Corporation and others.
+ * Copyright (c) 2003, 2006 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
@@ -12,9 +12,11 @@ package org.eclipse.osgi.internal.resolver;
import java.io.*;
import java.lang.ref.WeakReference;
+import java.lang.reflect.Constructor;
import java.util.*;
import org.eclipse.osgi.framework.util.SecureAction;
import org.eclipse.osgi.service.resolver.*;
+import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.Version;
class StateReader {
@@ -35,7 +37,7 @@ class StateReader {
private int numBundles;
private boolean accessedFlag = false;
- public static final byte STATE_CACHE_VERSION = 24;
+ public static final byte STATE_CACHE_VERSION = 25;
public static final byte NULL = 0;
public static final byte OBJECT = 1;
public static final byte INDEX = 2;
@@ -303,6 +305,22 @@ class StateReader {
result.setDynamicStamps(dynamicStamps);
}
+ int genericCapCnt = in.readInt();
+ if (genericCapCnt > 0) {
+ GenericDescription[] capabilities = new GenericDescription[genericCapCnt];
+ for (int i = 0; i < capabilities.length; i++)
+ capabilities[i] = readGenericDescription(in);
+ result.setGenericCapabilities(capabilities);
+ }
+
+ int genericReqCnt = in.readInt();
+ if (genericReqCnt > 0) {
+ GenericSpecification[] reqs = new GenericSpecification[genericReqCnt];
+ for (int i = 0; i < reqs.length; i++)
+ reqs[i] = readGenericSpecification(in);
+ result.setGenericRequires(reqs);
+ }
+
result.setFullyLoaded(true); // set fully loaded before setting the dependencies
// No need to add bundle dependencies for hosts, imports or requires;
// This is done by readBundleDescription
@@ -345,13 +363,33 @@ class StateReader {
Object value = null;
byte type = in.readByte();
if (type == 0)
- value = readString(in, false);
+ value = readString(in, false);
else if (type == 1)
value = readList(in);
else if (type == 2)
value = in.readBoolean() ? Boolean.TRUE : Boolean.FALSE;
else if (type == 3)
value = new Integer(in.readInt());
+ else if (type == 4)
+ value = new Long(in.readLong());
+ else if (type == 5)
+ value = new Double(in.readDouble());
+ else if (type == 6)
+ value = readVersion(in);
+ else if (type == 7) {
+ value = readString(in, false);
+ try {
+ Class uriClazz = Class.forName("java.net.URI"); //$NON-NLS-1$
+ Constructor constructor = uriClazz.getConstructor(new Class[] {String.class});
+ value = constructor.newInstance(new Object[] {value});
+ } catch (ClassNotFoundException e) {
+ // oh well cannot support; just use the string
+ } catch (Exception e) { // got some reflection exception
+ if (e instanceof RuntimeException)
+ throw (RuntimeException) e;
+ throw new RuntimeException(e.getMessage());
+ }
+ }
result.put(key, value);
}
return result;
@@ -399,6 +437,47 @@ class StateReader {
return result;
}
+ private GenericDescription readGenericDescription(DataInputStream in) throws IOException {
+ byte tag = readTag(in);
+ if (tag == NULL)
+ return null;
+ if (tag == INDEX)
+ return (GenericDescription) getFromObjectTable(in.readInt());
+ int tableIndex = in.readInt();
+ GenericDescriptionImpl result = new GenericDescriptionImpl();
+ addToObjectTable(result, tableIndex);
+ readBaseDescription(result, in);
+ result.setType(readString(in, false));
+ Map mapAttrs = readMap(in);
+ Dictionary attrs = new Hashtable();
+ if (mapAttrs != null) {
+ for (Iterator keys = mapAttrs.keySet().iterator(); keys.hasNext();) {
+ Object key = keys.next();
+ attrs.put(key, mapAttrs.get(key));
+ }
+ }
+ result.setAttributes(attrs);
+ return result;
+ }
+
+ private GenericSpecification readGenericSpecification(DataInputStream in) throws IOException {
+ GenericSpecificationImpl result = new GenericSpecificationImpl();
+ readVersionConstraint(result, in);
+ result.setType(readString(in, false));
+ int num = in.readInt();
+ GenericDescription[] suppliers = num == 0 ? null : new GenericDescription[num];
+ for (int i = 0; i < num; i++)
+ suppliers[i] = readGenericDescription(in);
+ result.setSupplers(suppliers);
+ result.setResolution(in.readInt());
+ try {
+ result.setMatchingFilter(readString(in, false));
+ } catch (InvalidSyntaxException e) {
+ // do nothing this filter was tested before
+ }
+ return result;
+ }
+
// called by readers for VersionConstraintImpl subclasses
private void readVersionConstraint(VersionConstraintImpl version, DataInputStream in) throws IOException {
version.setName(readString(in, false));
diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateWriter.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateWriter.java
index 527f9d6bd..8cd2bad9c 100644
--- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateWriter.java
+++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateWriter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2003, 2005 IBM Corporation and others.
+ * Copyright (c) 2003, 2006 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
@@ -13,6 +13,7 @@ package org.eclipse.osgi.internal.resolver;
import java.io.*;
import java.util.*;
import org.eclipse.osgi.service.resolver.*;
+import org.osgi.framework.Constants;
import org.osgi.framework.Version;
class StateWriter {
@@ -60,7 +61,7 @@ class StateWriter {
out.writeLong(state.getTimeStamp());
Dictionary[] propSet = state.getPlatformProperties();
out.writeInt(propSet.length);
- for (int i = 0; i < propSet.length; i++){
+ for (int i = 0; i < propSet.length; i++) {
Dictionary props = propSet[i];
out.writeInt(StateImpl.PROPS.length);
for (int j = 0; j < StateImpl.PROPS.length; j++)
@@ -106,7 +107,7 @@ class StateWriter {
outState.writeLong(state.getTimeStamp());
Dictionary[] propSet = state.getPlatformProperties();
outState.writeInt(propSet.length);
- for (int i = 0; i < propSet.length; i++){
+ for (int i = 0; i < propSet.length; i++) {
Dictionary props = propSet[i];
outState.writeInt(StateImpl.PROPS.length);
for (int j = 0; j < StateImpl.PROPS.length; j++)
@@ -129,11 +130,11 @@ class StateWriter {
} catch (IOException e) {
// do nothing, we tried
}
- try {
- outLazy.close();
- } catch (IOException e) {
- // do nothing
- }
+ try {
+ outLazy.close();
+ } catch (IOException e) {
+ // do nothing
+ }
if (outState != null)
try {
outState.flush();
@@ -141,11 +142,11 @@ class StateWriter {
} catch (IOException e) {
// do nothing, we tried
}
- try {
- outState.close();
- } catch (IOException e) {
- // do nothing
- }
+ try {
+ outState.close();
+ } catch (IOException e) {
+ // do nothing
+ }
}
}
@@ -258,7 +259,7 @@ class StateWriter {
for (int i = 0; i < ees.length; i++)
writeStringOrNull(ees[i], out);
- HashMap dynamicStamps = ((BundleDescriptionImpl)bundle).getDynamicStamps();
+ HashMap dynamicStamps = ((BundleDescriptionImpl) bundle).getDynamicStamps();
if (dynamicStamps == null)
out.writeInt(0);
else {
@@ -266,10 +267,28 @@ class StateWriter {
for (Iterator pkgs = dynamicStamps.keySet().iterator(); pkgs.hasNext();) {
String pkg = (String) pkgs.next();
writeStringOrNull(pkg, out);
- out.writeLong(((Long)dynamicStamps.get(pkg)).longValue());
+ out.writeLong(((Long) dynamicStamps.get(pkg)).longValue());
}
}
+ GenericDescription[] genericCapabilities = bundle.getGenericCapabilities();
+ if (genericCapabilities == null)
+ out.writeInt(0);
+ else {
+ out.writeInt(genericCapabilities.length);
+ for (int i = 0; i < genericCapabilities.length; i++)
+ writeGenericDescription(genericCapabilities[i], out);
+ }
+
+ GenericSpecification[] genericRequires = bundle.getGenericRequires();
+ if (genericRequires == null)
+ out.writeInt(0);
+ else {
+ out.writeInt(genericRequires.length);
+ for (int i = 0; i < genericRequires.length; i++)
+ writeGenericSpecification(genericRequires[i], out);
+ }
+
// save the size of the lazy data
((BundleDescriptionImpl) bundle).setLazyDataSize(out.size() - dataStart);
}
@@ -290,6 +309,33 @@ class StateWriter {
writeMap(out, exportPackageDesc.getDirectives());
}
+ private void writeGenericDescription(GenericDescription description, DataOutputStream out) throws IOException {
+ if (writePrefix(description, out))
+ return;
+ writeBaseDescription(description, out);
+ writeStringOrNull(description.getType() == GenericDescription.DEFAULT_TYPE ? null : description.getType(), out);
+ Dictionary attrs = description.getAttributes();
+ Map mapAttrs = new HashMap(attrs.size());
+ for (Enumeration keys = attrs.keys(); keys.hasMoreElements();) {
+ Object key = keys.nextElement();
+ if (!Constants.VERSION_ATTRIBUTE.equals(key))
+ mapAttrs.put(key, attrs.get(key));
+ }
+ writeMap(out, mapAttrs);
+ }
+
+ private void writeGenericSpecification(GenericSpecification specification, DataOutputStream out) throws IOException {
+ writeVersionConstraint(specification, out);
+ writeStringOrNull(specification.getType() == GenericDescription.DEFAULT_TYPE ? null : specification.getType(), out);
+ GenericDescription[] suppliers = specification.getSuppliers();
+ out.writeInt(suppliers == null ? 0 : suppliers.length);
+ if (suppliers != null)
+ for (int i = 0; i < suppliers.length; i++)
+ writeGenericDescription(suppliers[i], out);
+ out.writeInt(specification.getResolution());
+ writeStringOrNull(specification.getMatchingFilter(), out);
+ }
+
private void writeMap(DataOutputStream out, Map source) throws IOException {
if (source == null) {
out.writeInt(0);
@@ -312,6 +358,18 @@ class StateWriter {
} else if (value instanceof Integer) {
out.writeByte(3);
out.writeInt(((Integer) value).intValue());
+ } else if (value instanceof Long) {
+ out.writeByte(4);
+ out.writeLong(((Long) value).longValue());
+ } else if (value instanceof Double) {
+ out.writeByte(5);
+ out.writeDouble(((Double) value).doubleValue());
+ } else if (value instanceof Version) {
+ out.writeByte(6);
+ writeVersion((Version) value, out);
+ } else if ("java.net.URI".equals(value.getClass().getName())) { //$NON-NLS-1$
+ out.writeByte(7);
+ writeStringOrNull(value.toString(), out);
}
}
}
diff --git a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/util/ManifestElement.java b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/util/ManifestElement.java
index 90a58b436..48bd05567 100644
--- a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/util/ManifestElement.java
+++ b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/util/ManifestElement.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2003, 2005 IBM Corporation and others.
+ * Copyright (c) 2003, 2006 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
@@ -322,60 +322,70 @@ public class ManifestElement {
* @throws BundleException if the header value is invalid
*/
public static ManifestElement[] parseHeader(String header, String value) throws BundleException {
- if (value == null) {
+ if (value == null)
return (null);
- }
- Vector headerElements = new Vector(10, 10);
+ ArrayList headerElements = new ArrayList(10);
Tokenizer tokenizer = new Tokenizer(value);
parseloop: while (true) {
String next = tokenizer.getToken(";,"); //$NON-NLS-1$
- if (next == null) {
+ if (next == null)
throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
- }
ArrayList headerValues = new ArrayList();
StringBuffer headerValue = new StringBuffer(next);
headerValues.add(next);
- if (Debug.DEBUG && Debug.DEBUG_MANIFEST) {
+ if (Debug.DEBUG && Debug.DEBUG_MANIFEST)
Debug.print("paserHeader: " + next); //$NON-NLS-1$
- }
+ boolean directive = false;
char c = tokenizer.getChar();
// Header values may be a list of ';' separated values. Just append them all into one value until the first '=' or ','
while (c == ';') {
next = tokenizer.getToken(";,=:"); //$NON-NLS-1$
- if (next == null) {
+ if (next == null)
throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
- }
c = tokenizer.getChar();
+ while (c == ':') { // may not really be a :=
+ c = tokenizer.getChar();
+ if (c != '=') {
+ String restOfNext = tokenizer.getToken(";,=:"); //$NON-NLS-1$
+ if (restOfNext == null)
+ throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
+ next += ":" + c + restOfNext; //$NON-NLS-1$
+ c = tokenizer.getChar();
+ } else
+ directive = true;
+ }
if (c == ';' || c == '\0') /* more */{
headerValues.add(next);
headerValue.append(";").append(next); //$NON-NLS-1$
- if (Debug.DEBUG && Debug.DEBUG_MANIFEST) {
+ if (Debug.DEBUG && Debug.DEBUG_MANIFEST)
Debug.print(";" + next); //$NON-NLS-1$
- }
}
}
// found the header value create a manifestElement for it.
ManifestElement manifestElement = new ManifestElement();
manifestElement.value = headerValue.toString();
manifestElement.valueComponents = (String[]) headerValues.toArray(new String[headerValues.size()]);
- boolean directive = false;
- if (c == ':') {
- c = tokenizer.getChar();
- if (c != '=')
- throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
- directive = true;
- }
- // now add any attributes for the manifestElement.
- while (c == '=') {
+
+ // now add any attributes/directives for the manifestElement.
+ while (c == '=' || c == ':') {
+ while (c == ':') { // may not really be a :=
+ c = tokenizer.getChar();
+ if (c != '=') {
+ String restOfNext = tokenizer.getToken("=:"); //$NON-NLS-1$
+ if (restOfNext == null)
+ throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
+ next += ":" + c + restOfNext; //$NON-NLS-1$
+ c = tokenizer.getChar();
+ } else
+ directive = true;
+ }
String val = tokenizer.getString(";,"); //$NON-NLS-1$
- if (val == null) {
+ if (val == null)
throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
- }
- if (Debug.DEBUG && Debug.DEBUG_MANIFEST) {
+ if (Debug.DEBUG && Debug.DEBUG_MANIFEST)
Debug.print(";" + next + "=" + val); //$NON-NLS-1$ //$NON-NLS-2$
- }
try {
if (directive)
manifestElement.addDirective(next, val);
@@ -383,41 +393,30 @@ public class ManifestElement {
manifestElement.addAttribute(next, val);
directive = false;
} catch (Exception e) {
- throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
+ throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
}
c = tokenizer.getChar();
if (c == ';') /* more */{
next = tokenizer.getToken("=:"); //$NON-NLS-1$
- if (next == null) {
- throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
- }
+ if (next == null)
+ throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
c = tokenizer.getChar();
- if (c == ':') {
- c = tokenizer.getChar();
- if (c != '=')
- throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
- directive = true;
- }
}
}
- headerElements.addElement(manifestElement);
- if (Debug.DEBUG && Debug.DEBUG_MANIFEST) {
+ headerElements.add(manifestElement);
+ if (Debug.DEBUG && Debug.DEBUG_MANIFEST)
Debug.println(""); //$NON-NLS-1$
- }
- if (c == ',') /* another manifest element */{
+ if (c == ',') /* another manifest element */
continue parseloop;
- }
- if (c == '\0') /* end of value */{
+ if (c == '\0') /* end of value */
break parseloop;
- }
- throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
+ throw new BundleException(NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, header, value));
}
int size = headerElements.size();
- if (size == 0) {
+ if (size == 0)
return (null);
- }
- ManifestElement[] result = new ManifestElement[size];
- headerElements.copyInto(result);
+
+ ManifestElement[] result = (ManifestElement[]) headerElements.toArray(new ManifestElement[size]);
return (result);
}

Back to the top