Author: jwross
Date: Tue Feb  9 19:39:26 2016
New Revision: 1729443

URL: http://svn.apache.org/viewvc?rev=1729443&view=rev
Log:
[ARIES-1445] Bundles that are not direct dependencies of a subsystem can be 
removed while still in use

The resolve context will now return an empty map for getWirings(). This means 
that when computing dependencies, a "total" resolution will occur ensuring that 
all involved resources are
part of the resolution map. The wirings continue to be computed as before and 
used for purposes internal to the resolve context.

In pseudocode, the findProviders algorithm is:

If the requirement resource is already resolved, and the requirement is 
effective:=resolve, then:
     If the requirement resource is a fragment, and the requirement is payload, 
then:
          Get the requirement's resource.
          Get the resource's wiring.
          Get the required wires from the wiring for the osgi.wiring.host 
namespace.
          Process the provider of each wire as a bundle.

     Otherwise, process as a bundle.
          Get the requirement's namespace.
          Get the requirement's resource.
          Get the resource's wiring.
          Get the required wires from the wiring for the namespace.
          Return all matching capabilities.

     If no capabilities are found,
               and the namespace is osgi.wiring.package,
               and the requirement is mandatory,
               assume the requirer is the same as the provider (i.e. 
substitutable export):
          Get the requirement's namespace.
          Get the requirement's resource.
          Get the resource's wiring.
          Get the resource capabilities from the wiring for the namespace.
          Return all matching capabilities.

Otherwise, process the requirement as before.

The effective:=active requirements are processed as before because it doesn't 
matter which capability is returned to the resolver since the framework ignores 
these requirements and no
runtime wires exist.

The implementation includes support for handling fragments, but it would be 
nice at some point to have some dedicated tests.

(1) Ensure a payload requirement of an already resolved fragment is handled 
properly. The resolve context should return the matching wired capability from 
the required wires of each
host to which the fragment is attached.

(2) Ensure a non-payload requirement of an already resolved fragment is handled 
properly. The resolve context should return the matching wired capability from 
the required wires of the
fragment.

As a more general test, ensure that a multiple cardinality requirement of an 
already resolved resource is handled properly. The resolve context should 
return all matching wired
capabilities.

Added:
    
aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1445Test.java
Modified:
    
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResolveContext.java
    
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResource.java
    
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/UninstallAction.java
    
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Utils.java

Modified: 
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResolveContext.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResolveContext.java?rev=1729443&r1=1729442&r2=1729443&view=diff
==============================================================================
--- 
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResolveContext.java
 (original)
+++ 
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResolveContext.java
 Tue Feb  9 19:39:26 2016
@@ -34,18 +34,21 @@ import org.eclipse.equinox.region.Region
 import org.osgi.framework.BundleException;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.namespace.ExecutionEnvironmentNamespace;
+import org.osgi.framework.namespace.HostNamespace;
 import org.osgi.framework.namespace.IdentityNamespace;
 import org.osgi.framework.namespace.NativeNamespace;
+import org.osgi.framework.namespace.PackageNamespace;
 import org.osgi.framework.wiring.BundleRevision;
 import org.osgi.framework.wiring.BundleWiring;
+import org.osgi.namespace.service.ServiceNamespace;
 import org.osgi.resource.Capability;
 import org.osgi.resource.Namespace;
 import org.osgi.resource.Requirement;
 import org.osgi.resource.Resource;
+import org.osgi.resource.Wire;
 import org.osgi.resource.Wiring;
 import org.osgi.service.resolver.HostedCapability;
 import org.osgi.service.subsystem.Subsystem.State;
-import org.osgi.service.subsystem.SubsystemException;
 
 public class ResolveContext extends org.osgi.service.resolver.ResolveContext {
        private final Repository contentRepository;
@@ -94,44 +97,147 @@ public class ResolveContext extends org.
                        AccessController.doPrivileged(new 
StartAction(subsystem, subsystem, subsystem, Restriction.INSTALL_ONLY));
                }
        }
-
-       @Override
-       public List<Capability> findProviders(Requirement requirement) {
-               installDependenciesOfRequirerIfNecessary(requirement);
-               ArrayList<Capability> result = new ArrayList<Capability>();
+       
+       private boolean isResolved(Resource resource) {
+               return wirings.containsKey(resource);
+       }
+       
+       private boolean isProcessableAsFragment(Requirement requirement) {
+               Resource resource = requirement.getResource();
+               String namespace = requirement.getNamespace();
+               return Utils.isFragment(resource)
+                               && 
!(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE.equals(namespace)
+                                               || 
HostNamespace.HOST_NAMESPACE.equals(namespace));
+       }
+       
+       private void processAsFragment(Requirement requirement, 
List<Capability> capabilities) {
+               String namespace = requirement.getNamespace();
+               Resource fragment = requirement.getResource();
+               Wiring fragmentWiring = wirings.get(fragment);
+               List<Wire> fragmentWires = 
fragmentWiring.getRequiredResourceWires(HostNamespace.HOST_NAMESPACE);
+               for (Wire fragmentWire : fragmentWires) {
+                       Resource host = fragmentWire.getProvider();
+                       Wiring hostWiring = wirings.get(host);
+                       List<Wire> hostWires = 
hostWiring.getRequiredResourceWires(namespace);
+                       processWires(hostWires, requirement, capabilities);
+               }
+       }
+       
+       private void processWires(Collection<Wire> wires, Requirement 
requirement, List<Capability> capabilities) {
+               if (wires.isEmpty()) {
+                       handleNoWires(requirement, capabilities);
+                       return;
+               }
+               for (Wire wire : wires) {
+                       processWire(wire, requirement, capabilities);
+               }
+       }
+       
+       private void processWire(Wire wire, Requirement requirement, 
List<Capability> capabilities) {
+               Capability capability = wire.getCapability();
+               processCapability(capability, requirement, capabilities);
+       }
+       
+       private void processCapability(Capability capability, Requirement 
requirement, List<Capability> capabilities) {
+               if (ResourceHelper.matches(requirement, capability)) {
+                       capabilities.add(capability);
+               }
+       }
+       
+       private void processResourceCapabilities(Collection<Capability> 
resourceCapabilities, Requirement requirement, List<Capability> capabilities) {
+               for (Capability resourceCapability : resourceCapabilities) {
+                       processCapability(resourceCapability, requirement, 
capabilities);
+               }
+       }
+       
+       private void processAsBundle(Requirement requirement, List<Capability> 
capabilities) {
+               String namespace = requirement.getNamespace();
+               Resource bundle = requirement.getResource();
+               Wiring wiring = wirings.get(bundle);
+               List<Wire> wires = wiring.getRequiredResourceWires(namespace);
+               processWires(wires, requirement, capabilities);
+       }
+       
+       private void handleNoWires(Requirement requirement, List<Capability> 
capabilities) {
+               String namespace = requirement.getNamespace();
+               if (!ServiceNamespace.SERVICE_NAMESPACE.equals(namespace)) {
+                       return;
+               }
+               try {
+                       addDependenciesFromSystemRepository(requirement, 
capabilities);
+               }
+               catch (Exception e) {
+                       Utils.handleTrowable(e);
+               }
+       }
+       
+       private void processAsSubstitutableExport(Requirement requirement, 
List<Capability> capabilities) {
+               String namespace = requirement.getNamespace();
+               if (!PackageNamespace.PACKAGE_NAMESPACE.equals(namespace)) {
+                       return;
+               }
+               Resource resource = requirement.getResource();
+               Wiring wiring = wirings.get(resource);
+               List<Capability> resourceCapabilities = 
wiring.getResourceCapabilities(namespace);
+               processResourceCapabilities(resourceCapabilities, requirement, 
capabilities);
+       }
+       
+       private void processAlreadyResolvedResource(Resource resource, 
Requirement requirement, List<Capability> capabilities) {
+               if (isProcessableAsFragment(requirement)) {
+                       processAsFragment(requirement, capabilities);
+               }
+               else {
+                       processAsBundle(requirement, capabilities);
+               }
+               if (capabilities.isEmpty() && Utils.isMandatory(requirement)) {
+                       processAsSubstitutableExport(requirement, capabilities);
+               }
+       }
+       
+       private void processNewlyResolvedResource(Resource resource, 
Requirement requirement, List<Capability> capabilities) {
                try {
                        // Only check the system repository for osgi.ee and 
osgi.native
                        if 
(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE.equals(requirement.getNamespace())
                                        || 
NativeNamespace.NATIVE_NAMESPACE.equals(requirement.getNamespace())) {
-                               
addDependenciesFromSystemRepository(requirement, result);
+                               
addDependenciesFromSystemRepository(requirement, capabilities);
                        } else {
-                               
addDependenciesFromContentRepository(requirement, result);
-                               
addDependenciesFromPreferredProviderRepository(requirement, result);
-                               
addDependenciesFromSystemRepository(requirement, result);
-                               addDependenciesFromLocalRepository(requirement, 
result);
-                               if (result.isEmpty()) {
-                                       
addDependenciesFromRepositoryServiceRepositories(requirement, result);
+                               
addDependenciesFromContentRepository(requirement, capabilities);
+                               
addDependenciesFromPreferredProviderRepository(requirement, capabilities);
+                               
addDependenciesFromSystemRepository(requirement, capabilities);
+                               addDependenciesFromLocalRepository(requirement, 
capabilities);
+                               if (capabilities.isEmpty()) {
+                                       
addDependenciesFromRepositoryServiceRepositories(requirement, capabilities);
                                }
                        }
-                       if (result.isEmpty()) {
+                       if (capabilities.isEmpty()) {
                                // Is the requirement optional?
                                String resolution = 
requirement.getDirectives().get(Namespace.REQUIREMENT_RESOLUTION_DIRECTIVE);
                                if 
(Namespace.RESOLUTION_OPTIONAL.equals(resolution)) {
                                        // Yes, it's optional. Add a missing 
capability to ensure
                                        // it gets added to the sharing policy 
per the specification.
-                                       result.add(new 
MissingCapability(requirement));
+                                       capabilities.add(new 
MissingCapability(requirement));
                                }
                        }
                }
                catch (Throwable t) {
-                       if (t instanceof SubsystemException)
-                               throw (SubsystemException)t;
-                       if (t instanceof SecurityException)
-                               throw (SecurityException)t;
-                       throw new SubsystemException(t);
+                       Utils.handleTrowable(t);
+               }
+       }
+
+       @Override
+       public List<Capability> findProviders(Requirement requirement) {
+               ArrayList<Capability> capabilities = new 
ArrayList<Capability>();
+               Resource resource = requirement.getResource();
+               if (isResolved(resource)
+                               && Utils.isEffectiveResolve(requirement)) {
+                       processAlreadyResolvedResource(resource, requirement, 
capabilities);
+               }
+               else {
+                       installDependenciesOfRequirerIfNecessary(requirement);
+                       processNewlyResolvedResource(resource, requirement, 
capabilities);
                }
-               result.trimToSize();
-               return result;
+               capabilities.trimToSize();
+               return capabilities;
        }
 
        @Override
@@ -163,7 +269,7 @@ public class ResolveContext extends org.
 
        @Override
        public Map<Resource, Wiring> getWirings() {
-               return wirings;
+               return Collections.emptyMap();
        }
 
        private boolean addDependencies(Repository repository, Requirement 
requirement, List<Capability> capabilities, boolean validate) throws 
BundleException, IOException, InvalidSyntaxException, URISyntaxException {

Modified: 
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResource.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResource.java?rev=1729443&r1=1729442&r2=1729443&view=diff
==============================================================================
--- 
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResource.java
 (original)
+++ 
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResource.java
 Tue Feb  9 19:39:26 2016
@@ -294,15 +294,6 @@ public class SubsystemResource implement
                        sharedContent.add(resource);
        }
 
-       private void addDependency(Resource resource) {
-               if (resource == null)
-                       return;
-               if (isInstallable(resource))
-                       installableDependencies.add(resource);
-               else
-                       sharedDependencies.add(resource);
-       }
-
        private void addMissingResource(DeployedContentHeader.Clause resource) {
                missingResources.add(resource);
        }
@@ -383,9 +374,17 @@ public class SubsystemResource implement
                }
            }
        }
+       
+       private void addDependency(Resource resource) {
+               if (resource == null)
+                       return;
+               if (isInstallable(resource))
+                       installableDependencies.add(resource);
+               else
+                       sharedDependencies.add(resource);
+       }
 
        private void computeDependencies(SubsystemManifest manifest, 
Coordination coordination)  {
-               SubsystemContentHeader contentHeader = 
manifest.getSubsystemContentHeader();
                try {
                        // The following line is necessary in order to ensure 
that the
                        // export sharing policies of composites are in place 
for capability
@@ -393,36 +392,29 @@ public class SubsystemResource implement
                        
StartAction.setExportPolicyOfAllInstallingSubsystemsWithProvisionDependenciesResolve(coordination);
                        Map<Resource, List<Wire>> resolution = 
Activator.getInstance().getResolver().resolve(createResolveContext());
                        setImportIsolationPolicy(resolution);
-                       for (Map.Entry<Resource, List<Wire>> entry : 
resolution.entrySet()) {
-                               Resource key = entry.getKey();
-                               String type = 
ResourceHelper.getTypeAttribute(key);
-                               // Do not include synthetic resources in the 
dependencies.
-                               if 
(!Constants.ResourceTypeSynthesized.equals(type)
-                                               && 
!contentHeader.contains(key)) {
-                                       addDependency(key);
-                               }
-                               for (Wire wire : entry.getValue()) {
-                                       Resource provider = wire.getProvider();
-                                       type = 
ResourceHelper.getTypeAttribute(provider);
-                                       // Do not include synthetic resources 
in the dependencies.
-                                       if 
(!Constants.ResourceTypeSynthesized.equals(type)
-                                                       && 
!contentHeader.contains(provider)) {
-                                               addDependency(provider);
-                                       }
-                               }
-                       }
-               }
-               catch (ResolutionException e) {
-                       throw new SubsystemException(e);
+                       addDependencies(resolution);
                }
                catch (Exception e) {
-                       if (e instanceof SubsystemException) {
-                               throw (SubsystemException)e;
-                       }
-                       if (e instanceof SecurityException) {
-                               throw (SecurityException)e;
-                       }
-                       throw new SubsystemException(e);
+                       Utils.handleTrowable(e);
+               }
+       }
+       
+       private void addDependencies(Map<Resource, List<Wire>> resolution) {
+               for (Map.Entry<Resource, List<Wire>> entry : 
resolution.entrySet()) {
+                       addDependencies(entry, resolution);
+               }
+       }
+       
+       private void addDependencies(Map.Entry<Resource, List<Wire>> entry, 
Map<Resource, List<Wire>> resolution) {
+               addDependencies(entry.getKey(), entry, resolution);
+       }
+       
+       private void addDependencies(Resource resource, Map.Entry<Resource, 
List<Wire>> entry, Map<Resource, List<Wire>> resolution) {
+               String type = ResourceHelper.getTypeAttribute(resource);
+               SubsystemContentHeader contentHeader = 
getSubsystemManifest().getSubsystemContentHeader();
+               if (!Constants.ResourceTypeSynthesized.equals(type) // Do not 
include synthetic resources as dependencies.
+                               && !contentHeader.contains(resource)) { // Do 
not include content as dependencies.
+                       addDependency(resource);
                }
        }
 

Modified: 
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/UninstallAction.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/UninstallAction.java?rev=1729443&r1=1729442&r2=1729443&view=diff
==============================================================================
--- 
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/UninstallAction.java
 (original)
+++ 
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/UninstallAction.java
 Tue Feb  9 19:39:26 2016
@@ -29,8 +29,9 @@ public class UninstallAction extends Abs
                        return null;
                }
                try {
-                       // Acquire the global write lock to prevent all other 
operations until
-                       // the installation is complete. There is no need to 
hold any other locks.
+                       // Acquire the global write lock to prevent all other 
operations 
+                       // until the uninstall is complete. There is no need to 
hold any 
+                       // other locks.
                        LockingStrategy.writeLock();
                        try {
                                checkRoot();

Modified: 
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Utils.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Utils.java?rev=1729443&r1=1729442&r2=1729443&view=diff
==============================================================================
--- 
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Utils.java
 (original)
+++ 
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Utils.java
 Tue Feb  9 19:39:26 2016
@@ -14,6 +14,7 @@
 package org.apache.aries.subsystem.core.internal;
 
 import java.util.Collection;
+import java.util.Map;
 
 import org.apache.aries.subsystem.core.archive.DeploymentManifest;
 import org.apache.aries.subsystem.core.archive.ProvisionResourceHeader;
@@ -21,11 +22,14 @@ import org.apache.aries.subsystem.core.a
 import org.apache.aries.subsystem.core.archive.SubsystemManifest;
 import org.osgi.framework.namespace.IdentityNamespace;
 import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.resource.Namespace;
+import org.osgi.resource.Requirement;
 import org.osgi.resource.Resource;
 import org.osgi.service.coordinator.Coordination;
 import org.osgi.service.coordinator.CoordinationException;
 import org.osgi.service.subsystem.Subsystem;
 import org.osgi.service.subsystem.SubsystemConstants;
+import org.osgi.service.subsystem.SubsystemException;
 import org.osgi.service.subsystem.Subsystem.State;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -98,6 +102,16 @@ public class Utils {
                return -1;
        }
        
+       public static void handleTrowable(Throwable t) {
+               if (t instanceof SubsystemException) {
+                       throw (SubsystemException)t;
+               }
+               if (t instanceof SecurityException) {
+                       throw (SecurityException)t;
+               }
+               throw new SubsystemException(t);
+       }
+       
        public static void installResource(Resource resource, BasicSubsystem 
subsystem) {
                Coordination coordination = Utils.createCoordination(subsystem);
                try {
@@ -126,6 +140,23 @@ public class Utils {
                                IdentityNamespace.TYPE_FRAGMENT.equals(type);
        }
        
+       public static boolean isFragment(Resource resource) {
+               String type = ResourceHelper.getTypeAttribute(resource);
+               return IdentityNamespace.TYPE_FRAGMENT.equals(type);
+       }
+       
+       public static boolean isEffectiveResolve(Requirement requirement) {
+               Map<String, String> directives = requirement.getDirectives();
+               String value = 
directives.get(Namespace.REQUIREMENT_EFFECTIVE_DIRECTIVE);
+               return value == null || 
Namespace.EFFECTIVE_RESOLVE.equals(value);
+       }
+       
+       public static boolean isMandatory(Requirement requirement) {
+               Map<String, String> directives = requirement.getDirectives();
+               String value = 
directives.get(Namespace.REQUIREMENT_RESOLUTION_DIRECTIVE);
+               return value == null || 
Namespace.RESOLUTION_MANDATORY.equals(value);
+       }
+       
        /*
         * The Deployed-Content header in the deployment manifest is used to 
store
         * information about explicitly installed resources and provisioned

Added: 
aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1445Test.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1445Test.java?rev=1729443&view=auto
==============================================================================
--- 
aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1445Test.java
 (added)
+++ 
aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1445Test.java
 Tue Feb  9 19:39:26 2016
@@ -0,0 +1,218 @@
+/*
+ * 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.io.InputStream;
+
+import org.apache.aries.subsystem.itests.SubsystemTest;
+import org.apache.aries.subsystem.itests.util.BundleArchiveBuilder;
+import org.apache.aries.subsystem.itests.util.SubsystemArchiveBuilder;
+import org.apache.aries.subsystem.itests.util.TestCapability;
+import org.apache.aries.subsystem.itests.util.TestRepository;
+import org.apache.aries.subsystem.itests.util.TestRepositoryContent;
+import org.apache.aries.subsystem.itests.util.TestRequirement;
+import org.junit.Test;
+import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.Version;
+import org.osgi.framework.namespace.IdentityNamespace;
+import org.osgi.framework.namespace.PackageNamespace;
+import org.osgi.namespace.service.ServiceNamespace;
+import org.osgi.service.repository.Repository;
+import org.osgi.service.subsystem.Subsystem;
+import org.osgi.service.subsystem.SubsystemConstants;
+import org.osgi.service.subsystem.SubsystemException;
+
+public class Aries1445Test extends SubsystemTest {
+       @Test
+       public void testFeatureFeature() throws Exception {
+               test(SubsystemConstants.SUBSYSTEM_TYPE_FEATURE, 
SubsystemConstants.SUBSYSTEM_TYPE_FEATURE);
+       }
+       
+       @Test
+       public void testApplicationApplication() throws Exception {
+               test(SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, 
SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION);
+       }
+       
+       @Test
+       public void testCompositeComposite() throws Exception {
+               test(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE, 
SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE);
+       }
+       
+       @Test
+       public void testFeatureApplication() throws Exception {
+               test(SubsystemConstants.SUBSYSTEM_TYPE_FEATURE, 
SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION);
+       }
+       
+       @Test
+       public void testCompositeFeature() throws Exception {
+               test(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE, 
SubsystemConstants.SUBSYSTEM_TYPE_FEATURE);
+       }
+       
+    private void test(String type1, String type2) throws Exception {
+               serviceRegistrations.add(bundleContext.registerService(
+                               Repository.class,
+                               new TestRepository.Builder()
+                                       .resource(new 
TestRepositoryContent.Builder()
+                                               .capability(new 
TestCapability.Builder()
+                                                       
.namespace(IdentityNamespace.IDENTITY_NAMESPACE)
+                                                       .attribute(
+                                                                       
IdentityNamespace.IDENTITY_NAMESPACE, 
+                                                                       "b")
+                                                       .attribute(
+                                                                       
IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, 
+                                                                       
Version.emptyVersion)
+                                                       .attribute(
+                                                                       
IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE,
+                                                                       
IdentityNamespace.TYPE_BUNDLE))
+                                       .capability(new TestCapability.Builder()
+                                                       
.namespace(PackageNamespace.PACKAGE_NAMESPACE)
+                                                       .attribute(
+                                                                       
PackageNamespace.PACKAGE_NAMESPACE, 
+                                                                       
"b.package")
+                                                       .attribute(
+                                                                       
IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, 
+                                                                       
Version.emptyVersion))
+                                       .requirement(new 
TestRequirement.Builder()
+                                                       
.namespace(PackageNamespace.PACKAGE_NAMESPACE)
+                                                       .directive(
+                                                                       
PackageNamespace.REQUIREMENT_FILTER_DIRECTIVE,
+                                                                       
"(osgi.wiring.package=c.package)"))
+                                       .requirement(new 
TestRequirement.Builder()
+                                                       
.namespace(ServiceNamespace.SERVICE_NAMESPACE)
+                                                       .directive(
+                                                                       
ServiceNamespace.REQUIREMENT_FILTER_DIRECTIVE, 
+                                                                       
"(objectClass=foo.Bar)")
+                                                       .directive(
+                                                                       
ServiceNamespace.REQUIREMENT_EFFECTIVE_DIRECTIVE, 
+                                                                       
ServiceNamespace.EFFECTIVE_ACTIVE))
+                                       .content(new BundleArchiveBuilder()
+                                                       .symbolicName("b")
+                                                       
.exportPackage("b.package")
+                                                       
.importPackage("c.package")
+                                                       
.requireCapability("osgi.service;filter:=\"(objectClass=foo.Bar)\";effective:=active")
+                                                       .buildAsBytes())
+                                       .build())
+                               .resource(new TestRepositoryContent.Builder()
+                                               .capability(new 
TestCapability.Builder()
+                                                       
.namespace(IdentityNamespace.IDENTITY_NAMESPACE)
+                                                       .attribute(
+                                                                       
IdentityNamespace.IDENTITY_NAMESPACE, 
+                                                                       "c")
+                                                       .attribute(
+                                                                       
IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, 
+                                                                       
Version.emptyVersion)
+                                                       .attribute(
+                                                                       
IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE,
+                                                                       
IdentityNamespace.TYPE_BUNDLE))
+                                       .capability(new TestCapability.Builder()
+                                                       
.namespace(PackageNamespace.PACKAGE_NAMESPACE)
+                                                       .attribute(
+                                                                       
PackageNamespace.PACKAGE_NAMESPACE, 
+                                                                       
"c.package")
+                                                       .attribute(
+                                                                       
IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, 
+                                                                       
Version.emptyVersion))
+                                       .content(new BundleArchiveBuilder()
+                                                       .symbolicName("c")
+                                                       
.exportPackage("c.package")
+                                                       .buildAsBytes())
+                                       .build())
+                               .resource(new TestRepositoryContent.Builder()
+                                               .capability(new 
TestCapability.Builder()
+                                                       
.namespace(IdentityNamespace.IDENTITY_NAMESPACE)
+                                                       .attribute(
+                                                                       
IdentityNamespace.IDENTITY_NAMESPACE, 
+                                                                       "d")
+                                                       .attribute(
+                                                                       
IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, 
+                                                                       
Version.emptyVersion)
+                                                       .attribute(
+                                                                       
IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE,
+                                                                       
IdentityNamespace.TYPE_BUNDLE))
+                                       .capability(new TestCapability.Builder()
+                                                       
.namespace(ServiceNamespace.SERVICE_NAMESPACE)
+                                                       .attribute(
+                                                                       
Constants.OBJECTCLASS, 
+                                                                       
"foo.Bar")
+                                                       .attribute(
+                                                                       
IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, 
+                                                                       
Version.emptyVersion)
+                                                       .directive(
+                                                                       
ServiceNamespace.CAPABILITY_EFFECTIVE_DIRECTIVE, 
+                                                                       
ServiceNamespace.EFFECTIVE_ACTIVE))
+                                       .content(new BundleArchiveBuilder()
+                                                       .symbolicName("d")
+                                                       
.provideCapability("osgi.service;objectClass=foo.Bar;effective:=active")
+                                                       .buildAsBytes())
+                                       .build())
+                                       .build(),
+                null));
+               Subsystem root = getRootSubsystem();
+               Subsystem s1 = installSubsystem(
+                               root, 
+                               "s1", 
+                               buildSubsystem(root, "s1", type1));
+               uninstallableSubsystems.add(s1);
+               startSubsystem(s1);
+               stoppableSubsystems.add(s1);
+               Subsystem s2 = installSubsystem(
+                               root, 
+                               "s2", 
+                               buildSubsystem(root, "s2", type2));
+               uninstallableSubsystems.add(s2);
+               stopSubsystem(s1);
+               stoppableSubsystems.remove(s1);
+               uninstallSubsystem(s1);
+               uninstallableSubsystems.remove(s1);
+               getSystemBundleAsFrameworkWiring().refreshBundles(null, 
(FrameworkListener)null);
+               try {
+                       s2.start();
+                       stoppableSubsystems.add(s2);
+               }
+               catch (SubsystemException e) {
+                       e.printStackTrace();
+                       fail("Subsystem should have started");
+               }
+               // Test the effective:=active service capability and 
requirement. Bundle
+               // D should have had a reference count of 2 and not uninstalled 
as part
+               // of S1. Because effective:=active does not effect runtime 
resolution,
+               // we must ensure it is still a constituent of root.
+               assertConstituent(root, "d");
+    }
+       
+       private InputStream buildSubsystem(Subsystem parent, String 
symbolicName, String type) throws IOException {
+               SubsystemArchiveBuilder builder = new SubsystemArchiveBuilder();
+               builder.symbolicName(symbolicName);
+               builder.type(type);
+               if (SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE.equals(type)) {
+                       builder.importPackage("b.package");
+               }
+               builder.bundle(
+                               "a", 
+                               new BundleArchiveBuilder()
+                                               .symbolicName("a")
+                                               .importPackage("b.package")
+                                               .build());
+               return builder.build();
+       }
+}


Reply via email to