Bug 359310 - NPE writing the state when weaving hooks are present
diff --git a/bundles/org.eclipse.osgi.tests/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi.tests/META-INF/MANIFEST.MF
index e802321..b6266c6 100644
--- a/bundles/org.eclipse.osgi.tests/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.osgi.tests/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
Bundle-ManifestVersion: 2
Bundle-Name: Core OSGi Tests
Bundle-SymbolicName: org.eclipse.osgi.tests;singleton:=true
-Bundle-Version: 3.7.1.qualifier
+Bundle-Version: 3.7.2.qualifier
Bundle-ClassPath: osgitests.jar
Bundle-Vendor: Eclipse.org
Bundle-Localization: plugin
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java
index 6d8c18a..0f3d0f6 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java
@@ -22,8 +22,9 @@
import org.osgi.framework.*;
import org.osgi.framework.hooks.resolver.ResolverHook;
import org.osgi.framework.hooks.resolver.ResolverHookFactory;
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.framework.wiring.BundleRequirement;
+import org.osgi.framework.hooks.weaving.WeavingHook;
+import org.osgi.framework.hooks.weaving.WovenClass;
+import org.osgi.framework.wiring.*;
import org.osgi.service.packageadmin.ExportedPackage;
import org.osgi.service.packageadmin.PackageAdmin;
import org.osgi.service.startlevel.StartLevel;
@@ -1346,6 +1347,148 @@
doTestBug351519Refresh(null);
}
+ public void testWeavingPersistence() {
+ File config = OSGiTestsActivator.getContext().getDataFile(getName()); //$NON-NLS-1$
+ Properties configuration = new Properties();
+ configuration.put(Constants.FRAMEWORK_STORAGE, config.getAbsolutePath());
+ Equinox equinox = new Equinox(configuration);
+ try {
+ equinox.start();
+ } catch (BundleException e) {
+ fail("Unexpected exception in start()", e); //$NON-NLS-1$
+ }
+
+ BundleContext systemContext = equinox.getBundleContext();
+ assertNotNull("System context is null", systemContext); //$NON-NLS-1$
+
+ Bundle test1 = null;
+ try {
+ test1 = systemContext.installBundle(installer.getBundleLocation("substitutes.a"));
+ } catch (BundleException e) {
+ fail("Unexpected error installing bundle", e);//$NON-NLS-1$
+ }
+ long testID1 = test1.getBundleId();
+
+ final Bundle testFinal1 = test1;
+ ServiceRegistration reg = systemContext.registerService(WeavingHook.class, new WeavingHook() {
+ public void weave(WovenClass wovenClass) {
+ if (!testFinal1.equals(wovenClass.getBundleWiring().getBundle()))
+ return;
+ if (!"substitutes.x.Ax".equals(wovenClass.getClassName()))
+ return;
+ List dynamicImports = wovenClass.getDynamicImports();
+ dynamicImports.add("*");
+ }
+ }, null);
+
+ try {
+ testFinal1.loadClass("substitutes.x.Ax");
+ testFinal1.loadClass("org.osgi.framework.hooks.bundle.FindHook");
+ } catch (Throwable t) {
+ fail("Unexpected testing bundle", t);
+ } finally {
+ reg.unregister();
+ }
+ // put the framework back to the RESOLVED state
+ try {
+ equinox.stop();
+ } catch (BundleException e) {
+ fail("Unexpected error stopping framework", e); //$NON-NLS-1$
+ }
+ try {
+ equinox.waitForStop(10000);
+ } catch (InterruptedException e) {
+ fail("Unexpected interrupted exception", e); //$NON-NLS-1$
+ }
+
+ try {
+ equinox.start();
+ } catch (BundleException e) {
+ fail("Unexpected exception in start()", e); //$NON-NLS-1$
+ }
+
+ systemContext = equinox.getBundleContext();
+ test1 = systemContext.getBundle(testID1);
+
+ Bundle test2 = null;
+ try {
+ test2 = systemContext.installBundle(installer.getBundleLocation("exporter.importer1"));
+ } catch (BundleException e) {
+ fail("Unexpected error installing bundle", e);//$NON-NLS-1$
+ }
+ long testID2 = test2.getBundleId();
+
+ final Bundle testFinal2 = test2;
+ reg = systemContext.registerService(WeavingHook.class, new WeavingHook() {
+ public void weave(WovenClass wovenClass) {
+ if (!testFinal2.equals(wovenClass.getBundleWiring().getBundle()))
+ return;
+ if (!"exporter.importer.test.Test1".equals(wovenClass.getClassName()))
+ return;
+ List dynamicImports = wovenClass.getDynamicImports();
+ dynamicImports.add("*");
+ }
+ }, null);
+
+ try {
+ testFinal2.loadClass("exporter.importer.test.Test1");
+ testFinal2.loadClass("org.osgi.framework.hooks.service.FindHook");
+ } catch (Throwable t) {
+ fail("Unexpected testing bundle", t);
+ } finally {
+ reg.unregister();
+ }
+
+ // put the framework back to the RESOLVED state
+ try {
+ equinox.stop();
+ } catch (BundleException e) {
+ fail("Unexpected error stopping framework", e); //$NON-NLS-1$
+ }
+ try {
+ equinox.waitForStop(10000);
+ } catch (InterruptedException e) {
+ fail("Unexpected interrupted exception", e); //$NON-NLS-1$
+ }
+
+ try {
+ equinox.start();
+ } catch (BundleException e) {
+ fail("Unexpected exception in start()", e); //$NON-NLS-1$
+ }
+
+ systemContext = equinox.getBundleContext();
+ test1 = systemContext.getBundle(testID1);
+ test2 = systemContext.getBundle(testID2);
+
+ BundleRevision rev1 = (BundleRevision) test1.adapt(BundleRevision.class);
+ BundleRevision rev2 = (BundleRevision) test2.adapt(BundleRevision.class);
+ BundleWiring wiring1 = rev1.getWiring();
+ BundleWiring wiring2 = rev2.getWiring();
+
+ assertNotNull("wiring1 is null", wiring1);
+ assertNotNull("wiring2 is null", wiring2);
+
+ List packages1 = wiring1.getRequiredWires(BundleRevision.PACKAGE_NAMESPACE);
+ List packages2 = wiring2.getRequiredWires(BundleRevision.PACKAGE_NAMESPACE);
+
+ // could make this a more complete check, but with the bug the dynamic wires
+ // are missing altogether because we fail to save the resolver state cache.
+ assertEquals("Wrong number of wires for wiring1", 3, packages1.size());
+ assertEquals("Wrong number of wires for wiring2", 2, packages2.size());
+
+ try {
+ equinox.stop();
+ } catch (BundleException e) {
+ fail("Unexpected error stopping framework", e); //$NON-NLS-1$
+ }
+ try {
+ equinox.waitForStop(10000);
+ } catch (InterruptedException e) {
+ fail("Unexpected interrupted exception", e); //$NON-NLS-1$
+ }
+ }
+
private void doTestBug351519Refresh(Boolean refreshDuplicates) {
// Create a framework with equinox.refresh.duplicate.bsn=false configuration
File config = OSGiTestsActivator.getContext().getDataFile(getName()); //$NON-NLS-1$
diff --git a/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF
index 251c0e1..80db49e 100644
--- a/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF
@@ -75,7 +75,7 @@
Bundle-Description: %systemBundle
Bundle-Copyright: %copyright
Bundle-Vendor: %eclipse.org
-Bundle-Version: 3.7.1.qualifier
+Bundle-Version: 3.7.2.qualifier
Bundle-Localization: systembundle
Bundle-DocUrl: http://www.eclipse.org
Eclipse-ExtensibleAPI: true
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 f26ce5f..0c9205a 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
@@ -493,7 +493,7 @@
}
private Object readStateWire(DataInputStream in) throws IOException {
- VersionConstraint requirement;
+ VersionConstraintImpl requirement;
BundleDescription requirementHost;
BaseDescription capability;
BundleDescription capabilityHost;
@@ -522,6 +522,11 @@
requirementHost = readBundleDescription(in);
capabilityHost = readBundleDescription(in);
+
+ if (requirement.getBundle() == null) {
+ // Need to fix up dynamic imports added by weaving hook (bug 359394)
+ requirement.setBundle(requirementHost);
+ }
return new StateWire(requirementHost, requirement, capabilityHost, capability);
}
@@ -607,12 +612,12 @@
return result;
}
- private GenericSpecification readGenericSpecification(DataInputStream in) throws IOException {
+ private GenericSpecificationImpl readGenericSpecification(DataInputStream in) throws IOException {
byte tag = readTag(in);
if (tag == NULL)
return null;
if (tag == INDEX)
- return (GenericSpecification) getFromObjectTable(in.readInt());
+ return (GenericSpecificationImpl) getFromObjectTable(in.readInt());
GenericSpecificationImpl result = new GenericSpecificationImpl();
int tableIndex = in.readInt();
addToObjectTable(result, tableIndex);