You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2014/06/06 17:35:37 UTC
git commit: [KARAF-3026] Add a dependency="true" flag on feature
dependencies Improve the heuristic for sorting candidates based on mandatory
resources
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 <gn...@gmail.com>
Authored: Fri Jun 6 16:43:31 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
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>