You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by jw...@apache.org on 2015/09/24 02:15:35 UTC

svn commit: r1704971 - in /aries/trunk/subsystem: subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/

Author: jwross
Date: Thu Sep 24 00:15:35 2015
New Revision: 1704971

URL: http://svn.apache.org/viewvc?rev=1704971&view=rev
Log:
ARIES-1416 BundleException "bundle is already installed" when the Preferred-Provider subsystem header points to a bundle.

First, fix issue where the wrong resource is used as part of the capability validity check in the preferred provider repository.

Second, wrap bundle revisions with a BundleResourceInstaller$BundleConstituent before invoking the contains method as part of the validity check.

Plus test.

Finally, SubsystemResourceInstallerInstallOrder.patch attached to ARIES-1357 by user Bas (baselzinga@gmail.com) applied.

This patch "installs" shared content before installable content which addresses an issue where the same preferred provider bundle is installed
twice in the same region because the already existing bundle from the system repository was considered invalid since it had not yet become a
constituent of the parent subsystem.

Plus test.

Added:
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1416Test.java
Modified:
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/PreferredProviderRepository.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResourceInstaller.java

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/PreferredProviderRepository.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/PreferredProviderRepository.java?rev=1704971&r1=1704970&r2=1704971&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/PreferredProviderRepository.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/PreferredProviderRepository.java Thu Sep 24 00:15:35 2015
@@ -20,9 +20,12 @@ import java.util.Map;
 import org.apache.aries.subsystem.core.archive.PreferredProviderHeader;
 import org.apache.aries.subsystem.core.archive.PreferredProviderRequirement;
 import org.apache.aries.subsystem.core.capabilityset.CapabilitySetRepository;
+import org.apache.aries.subsystem.core.internal.BundleResourceInstaller.BundleConstituent;
 import org.apache.aries.subsystem.core.repository.Repository;
+import org.osgi.framework.wiring.BundleRevision;
 import org.osgi.resource.Capability;
 import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
 
 public class PreferredProviderRepository implements org.apache.aries.subsystem.core.repository.Repository {
     private final CapabilitySetRepository repository;
@@ -62,9 +65,22 @@ public class PreferredProviderRepository
 		return result;
 	}
 	
+	/*
+	 * This check is only done on capabilities provided by resources in the
+	 * system repository. This currently includes only BasicSubsystem and
+	 * BundleRevision.
+	 */
 	private boolean isValid(Capability capability) {
 		for (BasicSubsystem parent : resource.getParents()) {
-		    if (parent.getConstituents().contains(resource)) {
+			Resource provider = capability.getResource();
+			if (provider instanceof BundleRevision) {
+				// To keep the optimization below, wrap bundle revisions with
+				// a bundle constituent so that the comparison works.
+				provider = new BundleConstituent(null, (BundleRevision)provider);
+			}
+			// Optimization from ARIES-1397. Perform a contains operation on the
+			// parent constituents rather than use ResourceHelper.
+		    if (parent.getConstituents().contains(provider)) {
 		        return true;
 		    }
 		}

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResourceInstaller.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResourceInstaller.java?rev=1704971&r1=1704970&r2=1704971&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResourceInstaller.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResourceInstaller.java Thu Sep 24 00:15:35 2015
@@ -106,15 +106,17 @@ public class SubsystemResourceInstaller
 				ResourceInstaller.newInstance(coordination, dependency, subsystem).install();
 		}
 		// ...followed by content.
+		// Simulate installation of shared content so that necessary relationships are established.
+		for (Resource content : subsystem.getResource().getSharedContent()) {
+			ResourceInstaller.newInstance(coordination, content, subsystem).install();
+		}
+		// Now take care of the installable content.
 		if (State.INSTALLING.equals(subsystem.getState())) {
 			List<Resource> installableContent = new ArrayList<Resource>(subsystem.getResource().getInstallableContent());
 			Collections.sort(installableContent, comparator);
 			for (Resource content : installableContent)
 				ResourceInstaller.newInstance(coordination, content, subsystem).install();
 		}
-		// Simulate installation of shared content so that necessary relationships are established.
-		for (Resource content : subsystem.getResource().getSharedContent())
-			ResourceInstaller.newInstance(coordination, content, subsystem).install();
 		// Only brand new subsystems should have acquired the INSTALLING state,
 		// in which case an INSTALLED event must be propagated.
 		if (State.INSTALLING.equals(subsystem.getState()))

Added: aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1416Test.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1416Test.java?rev=1704971&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1416Test.java (added)
+++ aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1416Test.java Thu Sep 24 00:15:35 2015
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.subsystem.itests.defect;
+
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.aries.subsystem.itests.Header;
+import org.apache.aries.subsystem.itests.SubsystemTest;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.service.subsystem.Subsystem;
+import org.osgi.service.subsystem.SubsystemConstants;
+import org.osgi.service.subsystem.SubsystemException;
+
+/*
+ * https://issues.apache.org/jira/browse/ARIES-1416
+ * 
+ * BundleException "bundle is already installed" when the Preferred-Provider 
+ * subsystem header points to a bundle.
+ */
+public class Aries1416Test extends SubsystemTest {
+    /*
+     * Subsystem-SymbolicName: application.a.esa
+     * Subsystem-Content: bundle.a.jar
+     * Preferred-Provider: bundle.b.jar;type=osgi.bundle
+     */
+    private static final String APPLICATION_A = "application.a.esa";
+    /*
+     * Subsystem-SymbolicName: feature.a.esa
+     * Subsystem-Content: application.a.esa
+     */
+    private static final String FEATURE_A = "feature.a.esa";
+    /*
+     * Subsystem-SymbolicName: feature.b.esa
+     * Subsystem-Content: application.a.esa
+     */
+    private static final String FEATURE_B = "feature.b.esa";
+	/*
+	 * Bundle-SymbolicName: bundle.a.jar
+	 * Require-Capability: b
+	 */
+	private static final String BUNDLE_A = "bundle.a.jar";
+	/*
+	 * Bundle-SymbolicName: bundle.b.jar
+	 * Provide-Capability: b
+	 */
+	private static final String BUNDLE_B = "bundle.b.jar";
+	
+	private static boolean createdTestFiles;
+	
+	@Before
+	public void createTestFiles() throws Exception {
+		if (createdTestFiles)
+			return;
+		createBundleA();
+		createBundleB();
+		createApplicationA();
+		createFeatureA();
+		createFeatureB();
+		createdTestFiles = true;
+	}
+	
+	private void createBundleA() throws IOException {
+		createBundle(name(BUNDLE_A), new Header(Constants.REQUIRE_CAPABILITY, "b"));
+	}
+	
+	private void createBundleB() throws IOException {
+		createBundle(name(BUNDLE_B), new Header(Constants.PROVIDE_CAPABILITY, "b"));
+	}
+    
+    private static void createApplicationA() throws IOException {
+        createApplicationAManifest();
+        createSubsystem(APPLICATION_A, BUNDLE_A, BUNDLE_B);
+    }
+    
+    private static void createApplicationAManifest() throws IOException {
+        Map<String, String> attributes = new HashMap<String, String>();
+        attributes.put(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, APPLICATION_A);
+        attributes.put(SubsystemConstants.SUBSYSTEM_CONTENT, BUNDLE_A);
+        attributes.put(SubsystemConstants.PREFERRED_PROVIDER, BUNDLE_B + ";type=osgi.bundle");
+        createManifest(APPLICATION_A + ".mf", attributes);
+    }
+    
+    private static void createFeatureA() throws IOException {
+        createFeatureAManifest();
+        createSubsystem(FEATURE_A, BUNDLE_B, APPLICATION_A);
+    }
+    
+    private static void createFeatureAManifest() throws IOException {
+        Map<String, String> attributes = new HashMap<String, String>();
+        attributes.put(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, FEATURE_A);
+        attributes.put(SubsystemConstants.SUBSYSTEM_CONTENT, BUNDLE_B + ',' + 
+        		APPLICATION_A + ";type=osgi.subsystem.application");
+        attributes.put(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_FEATURE);
+        createManifest(FEATURE_A + ".mf", attributes);
+    }
+    
+    private static void createFeatureB() throws IOException {
+        createFeatureBManifest();
+        createSubsystem(FEATURE_B, BUNDLE_B, APPLICATION_A);
+    }
+    
+    private static void createFeatureBManifest() throws IOException {
+        Map<String, String> attributes = new HashMap<String, String>();
+        attributes.put(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, FEATURE_B);
+        attributes.put(SubsystemConstants.SUBSYSTEM_CONTENT, BUNDLE_B + ',' + 
+        		APPLICATION_A + ";type=osgi.subsystem.application");
+        attributes.put(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_FEATURE);
+        createManifest(FEATURE_B + ".mf", attributes);
+    }
+    
+    @Test 
+    public void testSystemRepositoryBundlePreferredProvider() throws Exception {
+    	Subsystem root = getRootSubsystem();
+    	// Install bundle B providing capability b into the root subsystem's
+    	// region.
+    	Bundle bundleB = installBundleFromFile(BUNDLE_B, root);
+    	try {
+    		// Install application A containing content bundle A requiring 
+    		// capability b and dependency bundle B providing capability b.
+    		// Bundle B is not content but will become part of the local 
+    		// repository. The preferred provider is bundle B. Bundle B from the
+    		// system repository should be used. Bundle B from the local
+    		// repository should not be provisioned.
+    		Subsystem applicationA = installSubsystemFromFile(APPLICATION_A);
+    		uninstallSubsystemSilently(applicationA);
+    	}
+    	catch (SubsystemException e) {
+    		e.printStackTrace();
+    		fail("Subsystem should have installed");
+    	}
+    	finally {
+    		uninstallSilently(bundleB);
+    	}
+    }
+    
+    @Test
+    public void testSharedContentBundlePreferredProvider() throws Exception {
+    	// Install feature A containing bundle B and application A both in the
+    	// archive and as content into the root subsystem region. Bundle B 
+    	// provides capability b. Application A contains bundle A requiring 
+    	// capability b both in the archive and as content. Preferred provider 
+    	// bundle B is also included in the archive but not as content.
+    	Subsystem featureA = installSubsystemFromFile(FEATURE_A);
+    	try {
+    		// Install feature B having the same characteristics as feature A
+    		// described above into the root subsystem region. Bundle B will 
+    		// become shared content of features A and B. Shared content bundle
+    		// B from the system repository should be used as the preferred
+    		// provider. Bundle B from the local repository should not be
+    		// provisioned.
+    		Subsystem featureB = installSubsystemFromFile(FEATURE_B);
+    		uninstallSubsystemSilently(featureB);
+    	}
+    	catch (SubsystemException e) {
+    		e.printStackTrace();
+    		fail("Subsystem should have installed");
+    	}
+    	finally {
+    		uninstallSubsystemSilently(featureA);
+    	}
+    }
+}