Repository: karaf
Updated Branches:
  refs/heads/master b60231147 -> e164271c4


[KARAF-3026] Add a dependency="true" flag on feature dependencies
Improve the heuristic for sorting candidates based on mandatory resources

Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/e164271c
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/e164271c
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/e164271c

Branch: refs/heads/master
Commit: e164271c4a894b8b0d83c6c44741e44ff47f1605
Parents: b602311
Author: Guillaume Nodet <[email protected]>
Authored: Fri Jun 6 16:43:31 2014 +0200
Committer: Guillaume Nodet <[email protected]>
Committed: Fri Jun 6 16:43:31 2014 +0200

----------------------------------------------------------------------
 .../enterprise/src/main/feature/feature.xml     |  1 +
 .../org/apache/karaf/features/Dependency.java   |  2 +
 .../features/internal/model/Dependency.java     | 11 +++++
 .../internal/region/CandidateComparator.java    | 17 ++++++++
 .../features/internal/region/Subsystem.java     | 33 ++++++++-------
 .../region/SubsystemResolveContext.java         | 25 +++++++++++-
 .../internal/resolver/FeatureResource.java      |  4 +-
 .../internal/resolver/ResourceUtils.java        | 17 +++++++-
 .../karaf/features/karaf-features-1.3.0.xsd     |  1 +
 .../features/internal/region/SubsystemTest.java | 43 ++++++++++++++++++++
 .../karaf/features/internal/region/data5/a.mf   |  5 +++
 .../karaf/features/internal/region/data5/b.mf   |  5 +++
 .../karaf/features/internal/region/data5/c.mf   |  5 +++
 .../features/internal/region/data5/features.xml | 37 +++++++++++++++++
 .../karaf/features/internal/service/f07.xml     |  1 +
 15 files changed, 187 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/e164271c/assemblies/features/enterprise/src/main/feature/feature.xml
----------------------------------------------------------------------
diff --git a/assemblies/features/enterprise/src/main/feature/feature.xml 
b/assemblies/features/enterprise/src/main/feature/feature.xml
index d4b70cc..6c21fe3 100644
--- a/assemblies/features/enterprise/src/main/feature/feature.xml
+++ b/assemblies/features/enterprise/src/main/feature/feature.xml
@@ -189,6 +189,7 @@
 
     <feature name="jdbc" description="JDBC service and commands" 
version="${project.version}">
         <details>JDBC support providing service, commands, and MBean.</details>
+        <feature dependency="true">aries-blueprint</feature>
         <feature>transaction</feature>
         <bundle>mvn:commons-pool/commons-pool/${commons-pool.version}</bundle>
         <bundle>mvn:commons-dbcp/commons-dbcp/${commons-dbcp.version}</bundle>

http://git-wip-us.apache.org/repos/asf/karaf/blob/e164271c/features/core/src/main/java/org/apache/karaf/features/Dependency.java
----------------------------------------------------------------------
diff --git 
a/features/core/src/main/java/org/apache/karaf/features/Dependency.java 
b/features/core/src/main/java/org/apache/karaf/features/Dependency.java
index 421df19..13a4381 100644
--- a/features/core/src/main/java/org/apache/karaf/features/Dependency.java
+++ b/features/core/src/main/java/org/apache/karaf/features/Dependency.java
@@ -25,4 +25,6 @@ public interface Dependency {
 
     boolean isPrerequisite();
 
+    boolean isDependency();
+
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/e164271c/features/core/src/main/java/org/apache/karaf/features/internal/model/Dependency.java
----------------------------------------------------------------------
diff --git 
a/features/core/src/main/java/org/apache/karaf/features/internal/model/Dependency.java
 
b/features/core/src/main/java/org/apache/karaf/features/internal/model/Dependency.java
index 2a4d8dd..a0a3854 100644
--- 
a/features/core/src/main/java/org/apache/karaf/features/internal/model/Dependency.java
+++ 
b/features/core/src/main/java/org/apache/karaf/features/internal/model/Dependency.java
@@ -51,6 +51,8 @@ public class Dependency implements 
org.apache.karaf.features.Dependency {
     protected String version;
     @XmlAttribute
     protected boolean prerequisite;
+    @XmlAttribute
+    protected boolean dependency;
 
     /**
      * Feature name should be non empty string.
@@ -105,6 +107,15 @@ public class Dependency implements 
org.apache.karaf.features.Dependency {
         this.prerequisite = prerequisite;
     }
 
+    @Override
+    public boolean isDependency() {
+        return dependency;
+    }
+
+    public void setDependency(boolean dependency) {
+        this.dependency = dependency;
+    }
+
     public String toString() {
         return getName() + Feature.VERSION_SEPARATOR + getVersion();
     }

http://git-wip-us.apache.org/repos/asf/karaf/blob/e164271c/features/core/src/main/java/org/apache/karaf/features/internal/region/CandidateComparator.java
----------------------------------------------------------------------
diff --git 
a/features/core/src/main/java/org/apache/karaf/features/internal/region/CandidateComparator.java
 
b/features/core/src/main/java/org/apache/karaf/features/internal/region/CandidateComparator.java
index 35d6043..dfbfd05 100644
--- 
a/features/core/src/main/java/org/apache/karaf/features/internal/region/CandidateComparator.java
+++ 
b/features/core/src/main/java/org/apache/karaf/features/internal/region/CandidateComparator.java
@@ -17,6 +17,7 @@
 package org.apache.karaf.features.internal.region;
 
 import java.util.Comparator;
+import java.util.Set;
 
 import org.osgi.framework.Version;
 import org.osgi.framework.namespace.BundleNamespace;
@@ -24,8 +25,16 @@ import org.osgi.framework.namespace.IdentityNamespace;
 import org.osgi.framework.namespace.PackageNamespace;
 import org.osgi.framework.wiring.BundleCapability;
 import org.osgi.resource.Capability;
+import org.osgi.resource.Resource;
 
 public class CandidateComparator implements Comparator<Capability> {
+
+    private final Set<Resource> mandatory;
+
+    public CandidateComparator(Set<Resource> mandatory) {
+        this.mandatory = mandatory;
+    }
+
     public int compare(Capability cap1, Capability cap2) {
         int c = 0;
         // Always prefer system bundle
@@ -34,6 +43,14 @@ public class CandidateComparator implements 
Comparator<Capability> {
         } else if (!(cap1 instanceof BundleCapability) && cap2 instanceof 
BundleCapability) {
             c = 1;
         }
+        // Always prefer mandatory resources
+        if (c == 0) {
+            if (mandatory.contains(cap1.getResource()) && 
!mandatory.contains(cap2.getResource())) {
+                c = -1;
+            } else if (!mandatory.contains(cap1.getResource()) && 
mandatory.contains(cap2.getResource())) {
+                c = 1;
+            }
+        }
         // Compare revision capabilities.
         if ((c == 0) && 
cap1.getNamespace().equals(BundleNamespace.BUNDLE_NAMESPACE)) {
             c = ((Comparable<Object>) 
cap1.getAttributes().get(BundleNamespace.BUNDLE_NAMESPACE))

http://git-wip-us.apache.org/repos/asf/karaf/blob/e164271c/features/core/src/main/java/org/apache/karaf/features/internal/region/Subsystem.java
----------------------------------------------------------------------
diff --git 
a/features/core/src/main/java/org/apache/karaf/features/internal/region/Subsystem.java
 
b/features/core/src/main/java/org/apache/karaf/features/internal/region/Subsystem.java
index 30a789a..3318885 100644
--- 
a/features/core/src/main/java/org/apache/karaf/features/internal/region/Subsystem.java
+++ 
b/features/core/src/main/java/org/apache/karaf/features/internal/region/Subsystem.java
@@ -93,6 +93,7 @@ public class Subsystem extends ResourceImpl {
     private final Map<String, Set<String>> exportPolicy;
     private final List<Resource> installable = new ArrayList<>();
     private final Map<String, DependencyInfo> dependencies = new HashMap<>();
+    private final List<Requirement> dependentFeatures = new ArrayList<>();
 
     private final List<String> bundles = new ArrayList<>();
 
@@ -122,13 +123,10 @@ public class Subsystem extends ResourceImpl {
             this.exportPolicy = SHARE_ALL_POLICY;
         }
 
-        Map<String, String> dirs = new HashMap<>();
-        Map<String, Object> attrs = new HashMap<>();
-        attrs.put(IDENTITY_NAMESPACE, feature.getName());
-        attrs.put(CAPABILITY_TYPE_ATTRIBUTE, TYPE_FEATURE);
-        attrs.put(CAPABILITY_VERSION_ATTRIBUTE, new 
VersionRange(VersionTable.getVersion(feature.getVersion()), true));
-        Requirement requirement = new RequirementImpl(this, 
IDENTITY_NAMESPACE, dirs, attrs);
-        addRequirement(requirement);
+        addIdentityRequirement(this,
+                feature.getName(),
+                TYPE_FEATURE,
+                new 
VersionRange(VersionTable.getVersion(feature.getVersion()), true));
     }
 
     public Subsystem(String name, Subsystem parent, boolean 
acceptDependencies) {
@@ -191,13 +189,7 @@ public class Subsystem extends ResourceImpl {
         Subsystem as = new Subsystem(childName, this, acceptDependencies);
         children.add(as);
         // Add a requirement to force its resolution
-        Map<String, Object> attrs = new HashMap<>();
-        attrs.put(IDENTITY_NAMESPACE, childName);
-        attrs.put(CAPABILITY_TYPE_ATTRIBUTE, TYPE_SUBSYSTEM);
-        Requirement requirement = new RequirementImpl(this, IDENTITY_NAMESPACE,
-                Collections.<String, String>emptyMap(),
-                attrs);
-        addRequirement(requirement);
+        ResourceUtils.addIdentityRequirement(this, childName, TYPE_SUBSYSTEM, 
(VersionRange) null);
         // Add it to repo
         installable.add(as);
         return as;
@@ -207,8 +199,14 @@ public class Subsystem extends ResourceImpl {
         installable.add(resource);
     }
 
-    public void requireFeature(String name, String range) {
-        ResourceUtils.addIdentityRequirement(this, name, TYPE_FEATURE, range);
+    public void requireFeature(String name, String range, boolean mandatory) {
+        if (mandatory) {
+            ResourceUtils.addIdentityRequirement(this, name, TYPE_FEATURE, 
range);
+        } else {
+            ResourceImpl res = new ResourceImpl();
+            ResourceUtils.addIdentityRequirement(res, name, TYPE_FEATURE, 
range);
+            dependentFeatures.addAll(res.getRequirements(null));
+        }
     }
 
     public void require(String requirement) throws BundleException {
@@ -263,12 +261,13 @@ public class Subsystem extends ResourceImpl {
                 while (!ss.isAcceptDependencies()) {
                     ss = ss.getParent();
                 }
-                ss.requireFeature(dep.getName(), dep.getVersion());
+                ss.requireFeature(dep.getName(), dep.getVersion(), 
!dep.isDependency());
             }
         }
         List<Requirement> processed = new ArrayList<>();
         while (true) {
             List<Requirement> requirements = 
getRequirements(IDENTITY_NAMESPACE);
+            requirements.addAll(dependentFeatures);
             requirements.removeAll(processed);
             if (requirements.isEmpty()) {
                 break;

http://git-wip-us.apache.org/repos/asf/karaf/blob/e164271c/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolveContext.java
----------------------------------------------------------------------
diff --git 
a/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolveContext.java
 
b/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolveContext.java
index da435de..8b6fc6a 100644
--- 
a/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolveContext.java
+++ 
b/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolveContext.java
@@ -21,9 +21,11 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.felix.resolver.Util;
 import org.apache.karaf.features.internal.download.Downloader;
@@ -53,12 +55,14 @@ import static 
org.osgi.framework.Constants.RESOLUTION_DIRECTIVE;
 import static org.osgi.framework.Constants.RESOLUTION_OPTIONAL;
 import static 
org.osgi.framework.namespace.IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE;
 import static 
org.osgi.framework.namespace.IdentityNamespace.IDENTITY_NAMESPACE;
+import static org.osgi.resource.Namespace.REQUIREMENT_RESOLUTION_DIRECTIVE;
 
 public class SubsystemResolveContext extends ResolveContext {
 
     private final Subsystem root;
     private final RegionDigraph digraph;
-    private final CandidateComparator candidateComparator = new 
CandidateComparator();
+    private final Set<Resource> mandatory = new HashSet<>();
+    private final CandidateComparator candidateComparator = new 
CandidateComparator(mandatory);
 
     private final Map<Resource, Subsystem> resToSub = new HashMap<Resource, 
Subsystem>();
     private final Repository repository;
@@ -73,6 +77,25 @@ public class SubsystemResolveContext extends ResolveContext {
 
         prepare(root);
         repository = new BaseRepository(resToSub.keySet());
+
+        // Add a heuristic to sort capabilities :
+        //  if a capability comes from a resource which needs to be installed,
+        //  prefer that one over any capabilities from other resources
+        findMandatory(root);
+    }
+
+    void findMandatory(Resource res) {
+        if (mandatory.add(res)) {
+            for (Requirement req : res.getRequirements(null)) {
+                String resolution = 
req.getDirectives().get(REQUIREMENT_RESOLUTION_DIRECTIVE);
+                if (!RESOLUTION_OPTIONAL.equals(resolution)) {
+                    List<Capability> caps = findProviders(req);
+                    if (caps.size() == 1) {
+                        findMandatory(caps.get(0).getResource());
+                    }
+                }
+            }
+        }
     }
 
     void prepare(Subsystem subsystem) {

http://git-wip-us.apache.org/repos/asf/karaf/blob/e164271c/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
----------------------------------------------------------------------
diff --git 
a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
 
b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
index 15cfcc1..73cb7a1 100644
--- 
a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
+++ 
b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
@@ -80,7 +80,9 @@ public final class FeatureResource extends ResourceImpl {
             }
         }
         for (Dependency dep : feature.getDependencies()) {
-            addDependency(resource, dep, featureRange);
+            if (!dep.isDependency()) {
+                addDependency(resource, dep, featureRange);
+            }
         }
         for (org.apache.karaf.features.Capability cap : 
feature.getCapabilities()) {
             resource.addCapabilities(ResourceBuilder.parseCapability(resource, 
cap.getValue()));

http://git-wip-us.apache.org/repos/asf/karaf/blob/e164271c/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceUtils.java
----------------------------------------------------------------------
diff --git 
a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceUtils.java
 
b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceUtils.java
index 210c375..91ea5e1 100644
--- 
a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceUtils.java
+++ 
b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceUtils.java
@@ -81,8 +81,23 @@ public final class ResourceUtils {
     }
 
     public static void addIdentityRequirement(ResourceImpl resource, String 
name, String type, String range) {
+        addIdentityRequirement(resource, name, type, range, true);
+    }
+
+    public static void addIdentityRequirement(ResourceImpl resource, String 
name, String type, String range, boolean mandatory) {
+        addIdentityRequirement(resource, name, type, range != null ? new 
VersionRange(range) : null, mandatory);
+    }
+
+    public static void addIdentityRequirement(ResourceImpl resource, String 
name, String type, VersionRange range) {
+        addIdentityRequirement(resource, name, type, range, true);
+    }
+
+    public static void addIdentityRequirement(ResourceImpl resource, String 
name, String type, VersionRange range, boolean mandatory) {
         Map<String, String> dirs = new HashMap<>();
         Map<String, Object> attrs = new HashMap<>();
+        if (!mandatory) {
+            dirs.put(REQUIREMENT_RESOLUTION_DIRECTIVE, RESOLUTION_OPTIONAL);
+        }
         if (name != null) {
             attrs.put(IDENTITY_NAMESPACE, name);
         }
@@ -90,7 +105,7 @@ public final class ResourceUtils {
             attrs.put(CAPABILITY_TYPE_ATTRIBUTE, type);
         }
         if (range != null) {
-            attrs.put(CAPABILITY_VERSION_ATTRIBUTE, new VersionRange(range));
+            attrs.put(CAPABILITY_VERSION_ATTRIBUTE, range);
         }
         resource.addRequirement(new RequirementImpl(resource, 
IDENTITY_NAMESPACE, dirs, attrs));
     }

http://git-wip-us.apache.org/repos/asf/karaf/blob/e164271c/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.3.0.xsd
----------------------------------------------------------------------
diff --git 
a/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.3.0.xsd
 
b/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.3.0.xsd
index ef0f434..d145d7c 100644
--- 
a/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.3.0.xsd
+++ 
b/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.3.0.xsd
@@ -167,6 +167,7 @@ Dependency of feature.
             <xs:extension base="tns:featureName">
                 <xs:attribute name="version" type="xs:string" default="0.0.0" 
/>
                 <xs:attribute name="prerequisite" type="xs:boolean" 
default="false"/>
+                <xs:attribute name="dependency" type="xs:boolean" 
default="false"/>
             </xs:extension>
         </xs:simpleContent>
     </xs:complexType>

http://git-wip-us.apache.org/repos/asf/karaf/blob/e164271c/features/core/src/test/java/org/apache/karaf/features/internal/region/SubsystemTest.java
----------------------------------------------------------------------
diff --git 
a/features/core/src/test/java/org/apache/karaf/features/internal/region/SubsystemTest.java
 
b/features/core/src/test/java/org/apache/karaf/features/internal/region/SubsystemTest.java
index 11f9b0a..89adfae 100644
--- 
a/features/core/src/test/java/org/apache/karaf/features/internal/region/SubsystemTest.java
+++ 
b/features/core/src/test/java/org/apache/karaf/features/internal/region/SubsystemTest.java
@@ -182,6 +182,49 @@ public class SubsystemTest {
         verify(resolver, expected);
     }
 
+    @Test
+    public void testFeatureOptional() throws Exception {
+        RepositoryImpl repo = new 
RepositoryImpl(getClass().getResource("data5/features.xml").toURI());
+
+        Map<String, Set<String>> features = new HashMap<String, Set<String>>();
+        addToMapSet(features, "root", "f1");
+        Map<String, Set<String>> expected = new HashMap<String, Set<String>>();
+        addToMapSet(expected, "root", "a/1.0.0");
+        addToMapSet(expected, "root", "b/1.0.0");
+
+        SubsystemResolver resolver = new SubsystemResolver(new 
TestDownloadManager(getClass(), "data5"));
+        resolver.prepare(Arrays.asList(repo.getFeatures()),
+                features,
+                Collections.<String, Set<BundleRevision>>emptyMap());
+        resolver.resolve(Collections.<String>emptySet(),
+                FeaturesService.DEFAULT_FEATURE_RESOLUTION_RANGE,
+                null);
+
+        verify(resolver, expected);
+    }
+
+    @Test
+    public void testFeatureOptionalAlreadyProvided() throws Exception {
+        RepositoryImpl repo = new 
RepositoryImpl(getClass().getResource("data5/features.xml").toURI());
+
+        Map<String, Set<String>> features = new HashMap<String, Set<String>>();
+        addToMapSet(features, "root", "f1");
+        addToMapSet(features, "root", "f3");
+        Map<String, Set<String>> expected = new HashMap<String, Set<String>>();
+        addToMapSet(expected, "root", "a/1.0.0");
+        addToMapSet(expected, "root", "c/1.0.0");
+
+        SubsystemResolver resolver = new SubsystemResolver(new 
TestDownloadManager(getClass(), "data5"));
+        resolver.prepare(Arrays.asList(repo.getFeatures()),
+                features,
+                Collections.<String, Set<BundleRevision>>emptyMap());
+        resolver.resolve(Collections.<String>emptySet(),
+                FeaturesService.DEFAULT_FEATURE_RESOLUTION_RANGE,
+                null);
+
+        verify(resolver, expected);
+    }
+
     private void verify(SubsystemResolver resolver, Map<String, Set<String>> 
expected) {
         Map<String, Set<String>> mapping = getBundleNamesPerRegions(resolver);
         if (!expected.equals(mapping)) {

http://git-wip-us.apache.org/repos/asf/karaf/blob/e164271c/features/core/src/test/resources/org/apache/karaf/features/internal/region/data5/a.mf
----------------------------------------------------------------------
diff --git 
a/features/core/src/test/resources/org/apache/karaf/features/internal/region/data5/a.mf
 
b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data5/a.mf
new file mode 100644
index 0000000..20a7811
--- /dev/null
+++ 
b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data5/a.mf
@@ -0,0 +1,5 @@
+Manifest-Version: 1
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: a
+Bundle-Version: 1.0.0
+

http://git-wip-us.apache.org/repos/asf/karaf/blob/e164271c/features/core/src/test/resources/org/apache/karaf/features/internal/region/data5/b.mf
----------------------------------------------------------------------
diff --git 
a/features/core/src/test/resources/org/apache/karaf/features/internal/region/data5/b.mf
 
b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data5/b.mf
new file mode 100644
index 0000000..dc96158
--- /dev/null
+++ 
b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data5/b.mf
@@ -0,0 +1,5 @@
+Manifest-Version: 1
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: b
+Bundle-Version: 1.0.0
+

http://git-wip-us.apache.org/repos/asf/karaf/blob/e164271c/features/core/src/test/resources/org/apache/karaf/features/internal/region/data5/c.mf
----------------------------------------------------------------------
diff --git 
a/features/core/src/test/resources/org/apache/karaf/features/internal/region/data5/c.mf
 
b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data5/c.mf
new file mode 100644
index 0000000..8535efa
--- /dev/null
+++ 
b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data5/c.mf
@@ -0,0 +1,5 @@
+Manifest-Version: 1
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: c
+Bundle-Version: 1.0.0
+

http://git-wip-us.apache.org/repos/asf/karaf/blob/e164271c/features/core/src/test/resources/org/apache/karaf/features/internal/region/data5/features.xml
----------------------------------------------------------------------
diff --git 
a/features/core/src/test/resources/org/apache/karaf/features/internal/region/data5/features.xml
 
b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data5/features.xml
new file mode 100644
index 0000000..1cfff56
--- /dev/null
+++ 
b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data5/features.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+
+-->
+<features name="test" xmlns="http://karaf.apache.org/xmlns/features/v1.3.0";>
+
+    <feature name="f1">
+        <feature dependency="true">f2</feature>
+        <requirement>namespace;filter:="(namespace=foo)"</requirement>
+        <bundle>a</bundle>
+    </feature>
+
+    <feature name="f2">
+        <capability>namespace;namespace=foo</capability>
+        <bundle>b</bundle>
+    </feature>
+
+    <feature name="f3">
+        <capability>namespace;namespace=foo</capability>
+        <bundle>c</bundle>
+    </feature>
+
+</features>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/e164271c/features/core/src/test/resources/org/apache/karaf/features/internal/service/f07.xml
----------------------------------------------------------------------
diff --git 
a/features/core/src/test/resources/org/apache/karaf/features/internal/service/f07.xml
 
b/features/core/src/test/resources/org/apache/karaf/features/internal/service/f07.xml
index 8c59514..f32f938 100644
--- 
a/features/core/src/test/resources/org/apache/karaf/features/internal/service/f07.xml
+++ 
b/features/core/src/test/resources/org/apache/karaf/features/internal/service/f07.xml
@@ -17,6 +17,7 @@
 -->
 <features name="karaf" xmlns="http://karaf.apache.org/xmlns/features/v1.3.0";>
     <feature name="spring" version="2.5.6-SEC02">
+        <feature dependency="true">hidden</feature>
         <bundle 
dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.aopalliance/1.0_4</bundle>
         <bundle>mvn:org.springframework/spring-core/2.5.6.SEC02</bundle>
         <bundle>mvn:org.springframework/spring-beans/2.5.6.SEC02</bundle>

Reply via email to