You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by io...@apache.org on 2012/09/16 15:58:38 UTC

svn commit: r1385270 - in /karaf/trunk: assemblies/features/standard/src/main/feature/ features/command/src/main/java/org/apache/karaf/features/command/ features/core/src/main/java/org/apache/karaf/features/ features/core/src/main/java/org/apache/karaf...

Author: iocanel
Date: Sun Sep 16 13:58:37 2012
New Revision: 1385270

URL: http://svn.apache.org/viewvc?rev=1385270&view=rev
Log:
[KARAF-1718] Added support for conditional features.

Added:
    karaf/trunk/features/core/src/main/java/org/apache/karaf/features/Conditional.java
    karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/Conditional.java
    karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/Content.java
    karaf/trunk/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.2.0.xsd
    karaf/trunk/features/core/src/test/java/org/apache/karaf/features/ConditionalTest.java
    karaf/trunk/features/core/src/test/resources/org/apache/karaf/features/internal/f06.xml
      - copied, changed from r1384857, karaf/trunk/features/core/src/test/resources/org/apache/karaf/features/repo1.xml
    karaf/trunk/itests/src/test/java/org/apache/karaf/itests/ConditionalFeaturesTest.java
Modified:
    karaf/trunk/assemblies/features/standard/src/main/feature/feature.xml
    karaf/trunk/features/command/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java
    karaf/trunk/features/core/src/main/java/org/apache/karaf/features/Feature.java
    karaf/trunk/features/core/src/main/java/org/apache/karaf/features/FeaturesNamespaces.java
    karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/FeatureValidationUtil.java
    karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/FeaturesServiceImpl.java
    karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/RepositoryImpl.java
    karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/Feature.java
    karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
    karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/package-info.java
    karaf/trunk/features/core/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java
    karaf/trunk/features/core/src/test/java/org/apache/karaf/features/internal/FeaturesValidationTest.java
    karaf/trunk/features/core/src/test/resources/org/apache/karaf/features/repo1.xml
    karaf/trunk/webconsole/features/src/main/java/org/apache/karaf/webconsole/features/ExtendedFeature.java

Modified: karaf/trunk/assemblies/features/standard/src/main/feature/feature.xml
URL: http://svn.apache.org/viewvc/karaf/trunk/assemblies/features/standard/src/main/feature/feature.xml?rev=1385270&r1=1385269&r2=1385270&view=diff
==============================================================================
--- karaf/trunk/assemblies/features/standard/src/main/feature/feature.xml (original)
+++ karaf/trunk/assemblies/features/standard/src/main/feature/feature.xml Sun Sep 16 13:58:37 2012
@@ -16,7 +16,7 @@
       See the License for the specific language governing permissions and
       limitations under the License.
 -->
-<features name="standard-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.0.0">
+<features name="standard-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0">
 
     <feature name="standard" description="Karaf standard feature" version="${project.version}">
         <bundle start-level="30">mvn:org.apache.karaf.shell/org.apache.karaf.shell.console/${project.version}</bundle>
@@ -33,6 +33,13 @@
         <bundle start-level="30">mvn:org.apache.karaf.log/org.apache.karaf.log.command/${project.version}</bundle>
         <bundle start-level="30">mvn:org.apache.karaf.service/org.apache.karaf.service.core/${project.version}</bundle>
         <bundle start-level="30">mvn:org.apache.karaf.service/org.apache.karaf.service.command/${project.version}</bundle>
+        <conditional>
+            <condition>webconsole</condition>
+            <bundle start-level="30">mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.instance/${project.version}</bundle>
+            <bundle start-level="30">mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.features/${project.version}</bundle>
+            <bundle start-level="30">mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.gogo/${project.version}</bundle>
+            <bundle start-level="30">mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.http/${project.version}</bundle>
+        </conditional>
     </feature>
 
     <feature name="aries-annotation" description="Aries Annotations" version="${project.version}">
@@ -136,7 +143,7 @@
         <bundle start-level="30">mvn:org.apache.karaf.deployer/org.apache.karaf.deployer.kar/${project.version}</bundle>
     </feature>
 
-    <feature name="webconsole-base" description="Base support of the Karaf WebConsole" version="${project.version}" resolver="(obr)">
+    <feature name="webconsole" description="Base support of the Karaf WebConsole" version="${project.version}" resolver="(obr)">
         <config name="org.apache.karaf.webconsole">
             realm=karaf
         </config>
@@ -144,15 +151,12 @@
         <bundle start-level="30">mvn:org.apache.felix/org.apache.felix.metatype/${felix.metatype.version}</bundle>
         <bundle start-level="30">mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.branding/${project.version}</bundle>
         <bundle start-level="30">mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.console/${project.version}</bundle>
-    </feature>
+        <!-- Normally this should be part of the eventadmin feature. This is a workaround to a console error. -->
+        <conditional>
+            <condition>eventadmin</condition>
+            <bundle start-level="30">mvn:org.apache.felix/org.apache.felix.webconsole.plugins.event/${felix.eventadmin-plugin.version}</bundle>
+        </conditional>
 
-    <feature name="webconsole" description="Karaf WebConsole for administration and monitoring" version="${project.version}" resolver="(obr)">
-        <feature version="${project.version}">webconsole-base</feature>
-        <bundle start-level="30">mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.instance/${project.version}</bundle>
-        <bundle start-level="30">mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.features/${project.version}</bundle>
-        <bundle start-level="30">mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.gogo/${project.version}</bundle>
-        <bundle start-level="30">mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.http/${project.version}</bundle>
-		<bundle start-level="30">mvn:org.apache.felix/org.apache.felix.webconsole.plugins.event/${felix.eventadmin-plugin.version}</bundle>
     </feature>
 
     <feature name="ssh" description="Provide a SSHd server on Karaf" version="${project.version}">
@@ -196,7 +200,10 @@
         <bundle dependency="true" start-level="30">mvn:org.apache.felix/org.apache.felix.metatype/${felix.metatype.version}</bundle>
         <bundle dependency="true" start-level="30">mvn:org.apache.felix/org.apache.felix.scr/${felix.scr.version}</bundle>
         <bundle start-level="30">mvn:org.apache.karaf.scr/org.apache.karaf.scr.command/${project.version}</bundle>
-        <bundle start-level="30">mvn:org.apache.karaf.scr/org.apache.karaf.scr.management/${project.version}</bundle>
+        <conditional>
+            <condition>management</condition>
+            <bundle start-level="30">mvn:org.apache.karaf.scr/org.apache.karaf.scr.management/${project.version}</bundle>
+        </conditional>
     </feature>
 
 </features>

Modified: karaf/trunk/features/command/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java
URL: http://svn.apache.org/viewvc/karaf/trunk/features/command/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java?rev=1385270&r1=1385269&r2=1385270&view=diff
==============================================================================
--- karaf/trunk/features/command/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java (original)
+++ karaf/trunk/features/command/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java Sun Sep 16 13:58:37 2012
@@ -16,9 +16,14 @@
  */
 package org.apache.karaf.features.command;
 
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
+import org.apache.karaf.features.Conditional;
 import org.apache.karaf.shell.commands.Argument;
 import org.apache.karaf.shell.commands.Command;
 import org.apache.karaf.shell.commands.Option;
@@ -32,6 +37,8 @@ import org.apache.karaf.features.Feature
 public class InfoFeatureCommand extends FeaturesCommandSupport {
 
     private static final String INDENT = "  ";
+    private static final String FEATURE_CONTENT = "Feature";
+    private static final String CONDITIONAL_CONTENT = "Conditional(%s)";
 
 	@Argument(index = 0, name = "name", description = "The name of the feature", required = true, multiValued = false)
     private String name;
@@ -48,6 +55,9 @@ public class InfoFeatureCommand extends 
     @Option(name = "-b", aliases={"--bundle"}, description="Display bundles info", required = false, multiValued = false)
     private boolean bundle;
 
+    @Option(name = "--conditional", description="Display conditional info", required = false, multiValued = false)
+    private boolean conditional;
+
     @Option(name = "-t", aliases={"--tree"}, description="Display feature tree", required = false, multiValued = false)
     private boolean tree;
 
@@ -66,10 +76,11 @@ public class InfoFeatureCommand extends 
         }
 
         // default behavior
-        if (!config && !dependency && !bundle) {
+        if (!config && !dependency && !bundle && !conditional) {
             config = true;
             dependency = true;
             bundle = true;
+            conditional = true;
         }
 
         System.out.println("Feature " + feature.getName() + " " + feature.getVersion());
@@ -84,16 +95,20 @@ public class InfoFeatureCommand extends 
         }
 
         if (config) {
-            displayConfigInformation(feature);
-            displayConfigFileInformation(feature);
+            displayConfigInformation(feature, FEATURE_CONTENT);
+            displayConfigFileInformation(feature, FEATURE_CONTENT);
         }
 
         if (dependency) {
-            displayDependencyInformation(feature);
+            displayDependencyInformation(feature, FEATURE_CONTENT);
         }
 
         if (bundle) {
-            displayBundleInformation(feature);
+            displayBundleInformation(feature, FEATURE_CONTENT);
+        }
+
+        if(conditional) {
+           displayConditionalInfo(feature);
         }
 
         if (tree) {
@@ -116,12 +131,12 @@ public class InfoFeatureCommand extends 
 		}
 	}
 
-	private void displayBundleInformation(Feature feature) {
+	private void displayBundleInformation(Feature feature, String contentType) {
         List<BundleInfo> bundleInfos = feature.getBundles();
         if (bundleInfos.isEmpty()) {
-            System.out.println("Feature has no bundles.");
+            System.out.println(contentType + " has no bundles.");
         } else {
-            System.out.println("Feature contains followed bundles:");
+            System.out.println(contentType + " contains followed bundles:");
             for (BundleInfo featureBundle : bundleInfos) {
                 int startLevel = featureBundle.getStartLevel();
                 StringBuilder sb = new StringBuilder();
@@ -134,36 +149,36 @@ public class InfoFeatureCommand extends 
         }
     }
 
-    private void displayDependencyInformation(Feature feature) {
+    private void displayDependencyInformation(Feature feature, String contentType) {
         List<Dependency> dependencies = feature.getDependencies();
         if (dependencies.isEmpty()) {
-            System.out.println("Feature has no dependencies.");
+            System.out.println(contentType + " has no dependencies.");
         } else {
-            System.out.println("Feature depends on:");
+            System.out.println(contentType + " depends on:");
             for (Dependency featureDependency : dependencies) {
                 System.out.println(INDENT + featureDependency.getName() + " " + featureDependency.getVersion());
             }
         }
     }
 
-    private void displayConfigInformation(Feature feature) {
+    private void displayConfigInformation(Feature feature, String contentType) {
         Map<String, Map<String, String>> configurations = feature.getConfigurations();
         if (configurations.isEmpty()) {
-            System.out.println("Feature has no configuration");
+            System.out.println(contentType + " has no configuration");
         } else {
-            System.out.println("Feature configuration:");
+            System.out.println(contentType + " configuration:");
             for (String name : configurations.keySet()) {
                 System.out.println(INDENT + name);
             }
         }
     }
     
-    private void displayConfigFileInformation(Feature feature) {
+    private void displayConfigFileInformation(Feature feature, String contentType) {
     	List<ConfigFileInfo> configurationFiles = feature.getConfigurationFiles();
     	if (configurationFiles.isEmpty()) {
-    		System.out.println("Feature has no configuration files");
+    		System.out.println(contentType + " has no configuration files");
     	} else {
-    		System.out.println("Feature configuration files: ");
+    		System.out.println(contentType + " configuration files: ");
     		for (ConfigFileInfo configFileInfo : configurationFiles) {
 				System.out.println(INDENT + configFileInfo.getFinalname());
 			}
@@ -193,9 +208,23 @@ public class InfoFeatureCommand extends 
 
         if (resolved != null) {
             if (bundle) {
+                List<String> bundleLocation = new LinkedList<String>();
                 List<BundleInfo> bundles = resolved.getBundles();
-                for (int i = 0, j = bundles.size(); i < j; i++) {
-                    System.out.println(prefix + " " + (i+1 == j ? "\\" : "+") + " " + bundles.get(i).getLocation());
+                for (BundleInfo bundleInfo : bundles) {
+                    bundleLocation.add(bundleInfo.getLocation());
+                }
+
+                if (conditional) {
+                    for (Conditional cond : resolved.getConditional()) {
+                        List<? extends Dependency> condition = cond.getCondition();
+                        List<BundleInfo> conditionalBundles = cond.getBundles();
+                        for (BundleInfo bundleInfo : conditionalBundles) {
+                            bundleLocation.add(bundleInfo.getLocation() + "(condition:"+condition+")");
+                        }
+                    }
+                }
+                for (int i = 0, j = bundleLocation.size(); i < j; i++) {
+                    System.out.println(prefix + " " + (i + 1 == j ? "\\" : "+") + " " + bundleLocation.get(i));
                 }
             }
             prefix += "   ";
@@ -204,9 +233,57 @@ public class InfoFeatureCommand extends 
                 Dependency toDisplay =  dependencies.get(i);
                 unresolved += displayFeatureTree(admin, toDisplay.getName(), toDisplay.getVersion(), prefix +1);
             }
+
+            if (conditional) {
+                for (Conditional cond : resolved.getConditional()) {
+                    List<Dependency> conditionDependencies = cond.getDependencies();
+                    for (int i = 0, j = conditionDependencies.size(); i < j; i++) {
+                        Dependency toDisplay =  dependencies.get(i);
+                        unresolved += displayFeatureTree(admin, toDisplay.getName(), toDisplay.getVersion(), prefix +1);
+                    }
+                }
+            }
         }
 
         return unresolved;
     }
 
+    private void displayConditionalInfo(Feature feature) {
+        List<? extends Conditional> conditionals = feature.getConditional();
+        if (conditionals.isEmpty()) {
+            System.out.println("Feature has no conditionals.");
+        } else {
+            System.out.println("Feature contains followed conditionals:");
+            for (Conditional featureConditional : conditionals) {
+                String conditionDescription = getConditionDescription(featureConditional);
+                Feature wrappedConditional = featureConditional.asFeature(feature.getName(), feature.getVersion());
+                if (config) {
+                    displayConfigInformation(wrappedConditional, String.format(CONDITIONAL_CONTENT, conditionDescription));
+                    displayConfigFileInformation(wrappedConditional, String.format(CONDITIONAL_CONTENT, conditionDescription));
+                }
+
+                if (dependency) {
+                    displayDependencyInformation(wrappedConditional, String.format(CONDITIONAL_CONTENT, conditionDescription));
+                }
+
+                if (bundle) {
+                    displayBundleInformation(wrappedConditional, String.format(CONDITIONAL_CONTENT, conditionDescription));
+                }
+            }
+        }
+    }
+
+    private String getConditionDescription(Conditional cond) {
+        StringBuffer sb = new StringBuffer();
+        Iterator<? extends Dependency> di = cond.getCondition().iterator();
+        while (di.hasNext()) {
+            Dependency dep = di.next();
+            sb.append(dep.getName()).append("/").append(dep.getVersion());
+            if (di.hasNext()) {
+                sb.append(" ");
+            }
+        }
+        return sb.toString();
+    }
+
 }

Added: karaf/trunk/features/core/src/main/java/org/apache/karaf/features/Conditional.java
URL: http://svn.apache.org/viewvc/karaf/trunk/features/core/src/main/java/org/apache/karaf/features/Conditional.java?rev=1385270&view=auto
==============================================================================
--- karaf/trunk/features/core/src/main/java/org/apache/karaf/features/Conditional.java (added)
+++ karaf/trunk/features/core/src/main/java/org/apache/karaf/features/Conditional.java Sun Sep 16 13:58:37 2012
@@ -0,0 +1,19 @@
+package org.apache.karaf.features;
+
+import java.util.List;
+import java.util.Map;
+
+public interface Conditional {
+
+    List<? extends Dependency> getCondition();
+
+    List<Dependency> getDependencies();
+
+    List<BundleInfo> getBundles();
+
+    Map<String, Map<String, String>> getConfigurations();
+
+    List<ConfigFileInfo> getConfigurationFiles();
+
+    Feature asFeature(String name, String version);
+}

Modified: karaf/trunk/features/core/src/main/java/org/apache/karaf/features/Feature.java
URL: http://svn.apache.org/viewvc/karaf/trunk/features/core/src/main/java/org/apache/karaf/features/Feature.java?rev=1385270&r1=1385269&r2=1385270&view=diff
==============================================================================
--- karaf/trunk/features/core/src/main/java/org/apache/karaf/features/Feature.java (original)
+++ karaf/trunk/features/core/src/main/java/org/apache/karaf/features/Feature.java Sun Sep 16 13:58:37 2012
@@ -49,6 +49,8 @@ public interface Feature {
     Map<String, Map<String, String>> getConfigurations();
 
     List<ConfigFileInfo> getConfigurationFiles();
+
+    List<? extends Conditional> getConditional();
     
     int getStartLevel();
 

Modified: karaf/trunk/features/core/src/main/java/org/apache/karaf/features/FeaturesNamespaces.java
URL: http://svn.apache.org/viewvc/karaf/trunk/features/core/src/main/java/org/apache/karaf/features/FeaturesNamespaces.java?rev=1385270&r1=1385269&r2=1385270&view=diff
==============================================================================
--- karaf/trunk/features/core/src/main/java/org/apache/karaf/features/FeaturesNamespaces.java (original)
+++ karaf/trunk/features/core/src/main/java/org/apache/karaf/features/FeaturesNamespaces.java Sun Sep 16 13:58:37 2012
@@ -25,12 +25,14 @@ public interface FeaturesNamespaces {
     String URI_0_0_0 = "";
     String URI_1_0_0 = "http://karaf.apache.org/xmlns/features/v1.0.0";
     String URI_1_1_0 = "http://karaf.apache.org/xmlns/features/v1.1.0";
+    String URI_1_2_0 = "http://karaf.apache.org/xmlns/features/v1.2.0";
 
-    String URI_CURRENT = URI_1_1_0;
+    String URI_CURRENT = URI_1_2_0;
 
     QName FEATURES_0_0_0 = new QName("features");
     QName FEATURES_1_0_0 = new QName(URI_1_0_0, "features");
     QName FEATURES_1_1_0 = new QName(URI_1_1_0, "features");
+    QName FEATURES_1_2_0 = new QName(URI_1_2_0, "features");
 
     QName FEATURES_CURRENT = FEATURES_1_1_0;
 

Modified: karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/FeatureValidationUtil.java
URL: http://svn.apache.org/viewvc/karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/FeatureValidationUtil.java?rev=1385270&r1=1385269&r2=1385270&view=diff
==============================================================================
--- karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/FeatureValidationUtil.java (original)
+++ karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/FeatureValidationUtil.java Sun Sep 16 13:58:37 2012
@@ -40,6 +40,10 @@ import org.xml.sax.SAXException;
  */
 public class FeatureValidationUtil {
 
+    public static final QName FEATURES_0_0 = new QName("features");
+    public static final QName FEATURES_1_0 = new QName("http://karaf.apache.org/xmlns/features/v1.0.0", "features");
+    public static final QName FEATURES_1_1 = new QName("http://karaf.apache.org/xmlns/features/v1.1.0", "features");
+    public static final QName FEATURES_1_2 = new QName("http://karaf.apache.org/xmlns/features/v1.2.0", "features");
     private static final Logger LOGGER = LoggerFactory.getLogger(FeatureValidationUtil.class);
 
     /**
@@ -60,7 +64,10 @@ public class FeatureValidationUtil {
             validate(doc, "/org/apache/karaf/features/karaf-features-1.0.0.xsd");
         } else if (FeaturesNamespaces.FEATURES_1_1_0.equals(name)) {
             validate(doc, "/org/apache/karaf/features/karaf-features-1.1.0.xsd");
-        } else {
+        } else if (FeaturesNamespaces.FEATURES_1_2_0.equals(name)) {
+            validate(doc, "/org/apache/karaf/features/karaf-features-1.2.0.xsd");
+        }
+        else {
             throw new IllegalArgumentException("Unrecognized root element: " + name);
         }
     }

Modified: karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/FeaturesServiceImpl.java
URL: http://svn.apache.org/viewvc/karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/FeaturesServiceImpl.java?rev=1385270&r1=1385269&r2=1385270&view=diff
==============================================================================
--- karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/FeaturesServiceImpl.java (original)
+++ karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/FeaturesServiceImpl.java Sun Sep 16 13:58:37 2012
@@ -59,6 +59,7 @@ import org.apache.felix.utils.manifest.P
 import org.apache.felix.utils.version.VersionRange;
 import org.apache.felix.utils.version.VersionTable;
 import org.apache.karaf.features.BundleInfo;
+import org.apache.karaf.features.Conditional;
 import org.apache.karaf.features.ConfigFileInfo;
 import org.apache.karaf.features.Dependency;
 import org.apache.karaf.features.Feature;
@@ -429,6 +430,20 @@ public class FeaturesServiceImpl impleme
                 InstallationState s = new InstallationState();
             	try {
                     doInstallFeature(s, f, verbose);
+                    doInstallFeatureConditionals(s, f, verbose);
+                    state.bundleInfos.putAll(s.bundleInfos);
+                    state.bundles.addAll(s.bundles);
+                    state.features.putAll(s.features);
+                    state.installed.addAll(s.installed);
+
+                    //Check if current feature satisfies the conditionals of existing features
+                    for (Feature installedFeautre : listInstalledFeatures()) {
+                        for (Conditional conditional : installedFeautre.getConditional()) {
+                            if (dependenciesSatisfied(conditional.getCondition(), state)) {
+                                doInstallFeatureConditionals(s, installedFeautre, verbose);
+                            }
+                        }
+                    }
                     state.bundleInfos.putAll(s.bundleInfos);
                     state.bundles.addAll(s.bundles);
                     state.features.putAll(s.features);
@@ -473,6 +488,7 @@ public class FeaturesServiceImpl impleme
             }
             // Start all bundles
             for (Bundle b : state.bundles) {
+                LOGGER.info("Starting bundle: {}", b.getSymbolicName());
                 startBundle(state, b);
             }
             // Clean up for batch
@@ -567,7 +583,7 @@ public class FeaturesServiceImpl impleme
 
     protected static class InstallationState {
         final Set<Bundle> installed = new HashSet<Bundle>();
-        final List<Bundle> bundles = new ArrayList<Bundle>();
+        final Set<Bundle> bundles = new HashSet<Bundle>();
         final Map<Long, BundleInfo> bundleInfos = new HashMap<Long, BundleInfo>();
         final Map<Feature, Set<Long>> features = new HashMap<Feature, Set<Long>>();
     }
@@ -600,34 +616,25 @@ public class FeaturesServiceImpl impleme
         state.features.put(feature, bundles);
     }
 
-    private void installFeatureDependency(Dependency dependency, InstallationState state, boolean verbose)
-            throws Exception {
-        VersionRange range = org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION.equals(dependency.getVersion())
-                    ? VersionRange.ANY_VERSION : new VersionRange(dependency.getVersion(), true, true);
-        Feature fi = null;
-        for (Feature f : installed.keySet()) {
-            if (f.getName().equals(dependency.getName())) {
-                Version v = VersionTable.getVersion(f.getVersion());
-                if (range.contains(v)) {
-                    if (fi == null || VersionTable.getVersion(fi.getVersion()).compareTo(v) < 0) {
-                        fi = f;
-                    }
-                }
-            }
-        }
-        if (fi == null) {
-            Map<String, Feature> avail = getFeatures().get(dependency.getName());
-            if (avail != null) {
-                for (Feature f : avail.values()) {
-                    Version v = VersionTable.getVersion(f.getVersion());
-                    if (range.contains(v)) {
-                        if (fi == null || VersionTable.getVersion(fi.getVersion()).compareTo(v) < 0) {
-                            fi = f;
-                        }
-                    }
-                }
+    protected void doInstallFeatureConditionals(InstallationState state, Feature feature,  boolean verbose) throws Exception {
+        InstallationState failure = new InstallationState();
+        //Check conditions of the current feature.
+        for (Conditional conditional : feature.getConditional()) {
+
+            if (dependenciesSatisfied(conditional.getCondition(), state)) {
+                InstallationState s = new InstallationState();
+                doInstallFeature(s, conditional.asFeature(feature.getName(), feature.getVersion()), verbose);
+                state.bundleInfos.putAll(s.bundleInfos);
+                state.bundles.addAll(s.bundles);
+                state.features.putAll(s.features);
+                state.installed.addAll(s.installed);
             }
         }
+    }
+
+    private void installFeatureDependency(Dependency dependency, InstallationState state, boolean verbose)
+            throws Exception {
+        Feature fi = getFeatureForDependency(dependency);
         if (fi == null) {
             throw new Exception("No feature named '" + dependency.getName()
                     + "' with version '" + dependency.getVersion() + "' available");
@@ -986,6 +993,12 @@ public class FeaturesServiceImpl impleme
         // and remove all those who will still be in use.
         // This gives this list of bundles to uninstall.
         Set<Long> bundles = installed.remove(feature);
+
+        //Also remove bundles installed as conditionals
+        for (Conditional conditional : feature.getConditional()) {
+            bundles.addAll(installed.remove(conditional.asFeature(feature.getName(),feature.getVersion())));
+        }
+
         for (Set<Long> b : installed.values()) {
             bundles.removeAll(b);
         }
@@ -1459,6 +1472,60 @@ public class FeaturesServiceImpl impleme
     }
 
     /**
+     * Returns the {@link Feature} that matches the {@link Dependency}.
+     * @param dependency
+     * @return
+     * @throws Exception
+     */
+    private Feature getFeatureForDependency(Dependency dependency) throws Exception {
+        VersionRange range = org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION.equals(dependency.getVersion())
+                ? VersionRange.ANY_VERSION : new VersionRange(dependency.getVersion(), true, true);
+        Feature fi = null;
+        for (Feature f : installed.keySet()) {
+            if (f.getName().equals(dependency.getName())) {
+                Version v = VersionTable.getVersion(f.getVersion());
+                if (range.contains(v)) {
+                    if (fi == null || VersionTable.getVersion(fi.getVersion()).compareTo(v) < 0) {
+                        fi = f;
+                    }
+                }
+            }
+        }
+        if (fi == null) {
+            Map<String, Feature> avail = getFeatures().get(dependency.getName());
+            if (avail != null) {
+                for (Feature f : avail.values()) {
+                    Version v = VersionTable.getVersion(f.getVersion());
+                    if (range.contains(v)) {
+                        if (fi == null || VersionTable.getVersion(fi.getVersion()).compareTo(v) < 0) {
+                            fi = f;
+                        }
+                    }
+                }
+            }
+        }
+        return fi;
+    }
+
+    /**
+     * Estimates if the {@link List} of {@link Dependency} is satisfied.
+     * The method will look into {@link Feature}s that are already installed or now being installed (if {@link InstallationState} is provided (not null)).
+     * @param dependencies
+     * @param state
+     * @return
+     */
+    private boolean dependenciesSatisfied(List<? extends Dependency> dependencies, InstallationState state) throws Exception {
+       boolean satisfied = true;
+       for (Dependency dep : dependencies) {
+           Feature f = getFeatureForDependency(dep);
+           if (f != null && !isInstalled(f) && (state != null && !state.features.keySet().contains(f))) {
+               satisfied = false;
+           }
+       }
+       return satisfied;
+    }
+
+    /**
      * Will wait for the {@link URLStreamHandlerService} service for the specified protocol to be registered.
      * @param protocol
      */

Modified: karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/RepositoryImpl.java?rev=1385270&r1=1385269&r2=1385270&view=diff
==============================================================================
--- karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/RepositoryImpl.java (original)
+++ karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/RepositoryImpl.java Sun Sep 16 13:58:37 2012
@@ -16,30 +16,15 @@
  */
 package org.apache.karaf.features.internal;
 
-import org.apache.karaf.features.ConfigFileInfo;
-import org.apache.karaf.features.Feature;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.List;
 import org.apache.karaf.features.Repository;
 import org.apache.karaf.features.internal.model.Features;
 import org.apache.karaf.features.internal.model.JaxbUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URLConnection;
-import java.util.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 /**
  * The repository implementation.
@@ -105,3 +90,4 @@ public class RepositoryImpl implements R
     }
 
 }
+

Added: karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/Conditional.java
URL: http://svn.apache.org/viewvc/karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/Conditional.java?rev=1385270&view=auto
==============================================================================
--- karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/Conditional.java (added)
+++ karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/Conditional.java Sun Sep 16 13:58:37 2012
@@ -0,0 +1,56 @@
+package org.apache.karaf.features.internal.model;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.karaf.features.Feature;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "conditional", propOrder = {
+        "condition",
+        "config",
+        "configfile",
+        "feature",
+        "bundle"
+})
+public class Conditional extends Content implements org.apache.karaf.features.Conditional {
+
+    @XmlElement(name = "condition")
+    protected List<Dependency> condition;
+
+    public List<Dependency> getCondition() {
+        if (condition == null) {
+            this.condition = new ArrayList<Dependency>();
+        }
+        return condition;
+    }
+
+    @Override
+    public Feature asFeature(String name, String version) {
+        String conditionName = name + "-condition-" + getConditionId().replaceAll("[^A-Za-z0-9 ]", "_");
+        org.apache.karaf.features.internal.model.Feature f = new org.apache.karaf.features.internal.model.Feature(conditionName, version);
+        f.getBundle().addAll(getBundle());
+        f.getConfig().addAll(getConfig());
+        f.getConfigfile().addAll(getConfigfile());
+        f.getFeature().addAll(getFeature());
+        return f;
+    }
+
+    private String getConditionId() {
+        StringBuffer sb = new StringBuffer();
+        Iterator<Dependency> di = getCondition().iterator();
+        while (di.hasNext()) {
+            Dependency dependency = di.next();
+            sb.append(dependency.getName() + "_" + dependency.getVersion());
+            if (di.hasNext()) {
+                sb.append("_");
+            }
+        }
+        return sb.toString();
+    }
+}

Added: karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/Content.java
URL: http://svn.apache.org/viewvc/karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/Content.java?rev=1385270&view=auto
==============================================================================
--- karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/Content.java (added)
+++ karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/Content.java Sun Sep 16 13:58:37 2012
@@ -0,0 +1,182 @@
+package org.apache.karaf.features.internal.model;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.xml.bind.annotation.XmlTransient;
+import org.apache.karaf.features.BundleInfo;
+import org.apache.karaf.features.ConfigFileInfo;
+
+@XmlTransient
+public class Content {
+
+    protected List<Config> config;
+    protected List<ConfigFile> configfile;
+    protected List<Dependency> feature;
+    protected List<Bundle> bundle;
+
+    /**
+     * Gets the value of the config property.
+     * <p/>
+     * <p/>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the config property.
+     * <p/>
+     * <p/>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getConfig().add(newItem);
+     * </pre>
+     * <p/>
+     * <p/>
+     * <p/>
+     * Objects of the following type(s) are allowed in the list
+     * {@link Config }
+     */
+    public List<Config> getConfig() {
+        if (config == null) {
+            config = new ArrayList<Config>();
+        }
+        return this.config;
+    }
+
+    /**
+     * Gets the value of the configfile property.
+     * <p/>
+     * <p/>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the configfile property.
+     * <p/>
+     * <p/>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getConfigfile().add(newItem);
+     * </pre>
+     * <p/>
+     * <p/>
+     * <p/>
+     * Objects of the following type(s) are allowed in the list
+     * {@link ConfigFile }
+     */
+    public List<ConfigFile> getConfigfile() {
+        if (configfile == null) {
+            configfile = new ArrayList<ConfigFile>();
+        }
+        return this.configfile;
+    }
+
+    /**
+     * Gets the value of the feature property.
+     * <p/>
+     * <p/>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the feature property.
+     * <p/>
+     * <p/>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getFeature().add(newItem);
+     * </pre>
+     * <p/>
+     * <p/>
+     * <p/>
+     * Objects of the following type(s) are allowed in the list
+     * {@link Dependency }
+     */
+    public List<Dependency> getFeature() {
+        if (feature == null) {
+            feature = new ArrayList<Dependency>();
+        }
+        return this.feature;
+    }
+
+    /**
+     * Gets the value of the bundle property.
+     * <p/>
+     * <p/>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the bundle property.
+     * <p/>
+     * <p/>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getBundle().add(newItem);
+     * </pre>
+     * <p/>
+     * <p/>
+     * <p/>
+     * Objects of the following type(s) are allowed in the list
+     * {@link Bundle }
+     */
+    public List<Bundle> getBundle() {
+        if (bundle == null) {
+            bundle = new ArrayList<Bundle>();
+        }
+        return this.bundle;
+    }
+
+    public List<org.apache.karaf.features.Dependency> getDependencies() {
+        return Collections.<org.apache.karaf.features.Dependency>unmodifiableList(getFeature());
+    }
+
+    public List<BundleInfo> getBundles() {
+        return Collections.<BundleInfo>unmodifiableList(getBundle());
+    }
+
+    public Map<String, Map<String, String>> getConfigurations() {
+        Map<String, Map<String, String>> result = new HashMap<String, Map<String, String>>();
+        for (Config config : getConfig()) {
+            String name = config.getName();
+            StringReader propStream = new StringReader(config.getValue());
+            Properties props = new Properties();
+            try {
+                props.load(propStream);
+            } catch (IOException e) {
+                //ignore??
+            }
+            interpolation(props);
+            Map<String, String> propMap = new HashMap<String, String>();
+            for (Map.Entry<Object, Object> entry : props.entrySet()) {
+                propMap.put((String) entry.getKey(), (String) entry.getValue());
+            }
+            result.put(name, propMap);
+        }
+        return result;
+    }
+
+    public List<ConfigFileInfo> getConfigurationFiles() {
+        return Collections.<ConfigFileInfo>unmodifiableList(getConfigfile());
+    }
+
+    protected void interpolation(Properties properties) {
+        for (Enumeration e = properties.propertyNames(); e.hasMoreElements(); ) {
+            String key = (String) e.nextElement();
+            String val = properties.getProperty(key);
+            Matcher matcher = Pattern.compile("\\$\\{([^}]+)\\}").matcher(val);
+            while (matcher.find()) {
+                String rep = System.getProperty(matcher.group(1));
+                if (rep != null) {
+                    val = val.replace(matcher.group(0), rep);
+                    matcher.reset(val);
+                }
+            }
+            properties.put(key, val);
+        }
+    }
+}

Modified: karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/Feature.java
URL: http://svn.apache.org/viewvc/karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/Feature.java?rev=1385270&r1=1385269&r2=1385270&view=diff
==============================================================================
--- karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/Feature.java (original)
+++ karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/Feature.java Sun Sep 16 13:58:37 2012
@@ -19,14 +19,9 @@
 
 package org.apache.karaf.features.internal.model;
 
-import java.io.IOException;
-import java.io.StringReader;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Enumeration;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.Properties;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -36,9 +31,6 @@ import javax.xml.bind.annotation.XmlAcce
 import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlType;
 
-import org.apache.karaf.features.BundleInfo;
-import org.apache.karaf.features.ConfigFileInfo;
-
 
 /**
  * 
@@ -77,18 +69,15 @@ import org.apache.karaf.features.ConfigF
     "config",
     "configfile",
     "feature",
-    "bundle"
+    "bundle",
+    "conditional"
 })
-public class Feature implements org.apache.karaf.features.Feature {
+public class Feature extends Content implements org.apache.karaf.features.Feature {
     public static String SPLIT_FOR_NAME_AND_VERSION = "_split_for_name_and_version_";
     public static String DEFAULT_VERSION = "0.0.0";
 
 
     protected String details;
-    protected List<Config> config;
-    protected List<ConfigFile> configfile;
-    protected List<Dependency> feature;
-    protected List<Bundle> bundle;
     @XmlAttribute(required = true)
     protected String name;
     @XmlAttribute
@@ -103,6 +92,7 @@ public class Feature implements org.apac
     protected Integer startLevel;
     @XmlAttribute
     protected String region;
+    protected List<Conditional> conditional;
 
     public Feature() {
     }
@@ -130,121 +120,6 @@ public class Feature implements org.apac
 
     }
 
-    /**
-     * Gets the value of the config property.
-     * 
-     * <p>
-     * This accessor method returns a reference to the live list,
-     * not a snapshot. Therefore any modification you make to the
-     * returned list will be present inside the JAXB object.
-     * This is why there is not a <CODE>set</CODE> method for the config property.
-     * 
-     * <p>
-     * For example, to add a new item, do as follows:
-     * <pre>
-     *    getConfig().add(newItem);
-     * </pre>
-     * 
-     * 
-     * <p>
-     * Objects of the following type(s) are allowed in the list
-     * {@link Config }
-     * 
-     * 
-     */
-    public List<Config> getConfig() {
-        if (config == null) {
-            config = new ArrayList<Config>();
-        }
-        return this.config;
-    }
-
-    /**
-     * Gets the value of the configfile property.
-     * 
-     * <p>
-     * This accessor method returns a reference to the live list,
-     * not a snapshot. Therefore any modification you make to the
-     * returned list will be present inside the JAXB object.
-     * This is why there is not a <CODE>set</CODE> method for the configfile property.
-     * 
-     * <p>
-     * For example, to add a new item, do as follows:
-     * <pre>
-     *    getConfigfile().add(newItem);
-     * </pre>
-     * 
-     * 
-     * <p>
-     * Objects of the following type(s) are allowed in the list
-     * {@link ConfigFile }
-     * 
-     * 
-     */
-    public List<ConfigFile> getConfigfile() {
-        if (configfile == null) {
-            configfile = new ArrayList<ConfigFile>();
-        }
-        return this.configfile;
-    }
-
-    /**
-     * Gets the value of the feature property.
-     * 
-     * <p>
-     * This accessor method returns a reference to the live list,
-     * not a snapshot. Therefore any modification you make to the
-     * returned list will be present inside the JAXB object.
-     * This is why there is not a <CODE>set</CODE> method for the feature property.
-     * 
-     * <p>
-     * For example, to add a new item, do as follows:
-     * <pre>
-     *    getFeature().add(newItem);
-     * </pre>
-     * 
-     * 
-     * <p>
-     * Objects of the following type(s) are allowed in the list
-     * {@link Dependency }
-     * 
-     * 
-     */
-    public List<Dependency> getFeature() {
-        if (feature == null) {
-            feature = new ArrayList<Dependency>();
-        }
-        return this.feature;
-    }
-
-    /**
-     * Gets the value of the bundle property.
-     * 
-     * <p>
-     * This accessor method returns a reference to the live list,
-     * not a snapshot. Therefore any modification you make to the
-     * returned list will be present inside the JAXB object.
-     * This is why there is not a <CODE>set</CODE> method for the bundle property.
-     * 
-     * <p>
-     * For example, to add a new item, do as follows:
-     * <pre>
-     *    getBundle().add(newItem);
-     * </pre>
-     * 
-     * 
-     * <p>
-     * Objects of the following type(s) are allowed in the list
-     * {@link Bundle }
-     * 
-     * 
-     */
-    public List<Bundle> getBundle() {
-        if (bundle == null) {
-            bundle = new ArrayList<Bundle>();
-        }
-        return this.bundle;
-    }
 
     public String getId() {
         return getName() + "-" + getVersion();
@@ -362,39 +237,6 @@ public class Feature implements org.apac
         this.install = install;
     }
 
-    public List<org.apache.karaf.features.Dependency> getDependencies() {
-        return Collections.<org.apache.karaf.features.Dependency>unmodifiableList(getFeature());
-    }
-
-    public List<BundleInfo> getBundles() {
-        return Collections.<BundleInfo>unmodifiableList(getBundle());
-    }
-
-    public Map<String, Map<String, String>> getConfigurations() {
-        Map<String, Map<String, String>> result = new HashMap<String, Map<String, String>>();
-        for (Config config: getConfig()) {
-            String name = config.getName();
-            StringReader propStream = new StringReader(config.getValue());
-            Properties props = new Properties();
-            try {
-                props.load(propStream);
-            } catch (IOException e) {
-                //ignore??
-            }
-            interpolation(props);
-            Map<String, String> propMap = new HashMap<String, String>();
-            for (Map.Entry<Object, Object> entry: props.entrySet()) {
-                propMap.put((String)entry.getKey(), (String)entry.getValue());
-            }
-            result.put(name, propMap);
-        }
-        return result;
-    }
-
-    public List<ConfigFileInfo> getConfigurationFiles() {
-        return Collections.<ConfigFileInfo>unmodifiableList(getConfigfile());
-    }
-
     /**
      * Sets the value of the resolver property.
      * 
@@ -440,6 +282,33 @@ public class Feature implements org.apac
         this.region = region;
     }
 
+    /**
+     * Gets the value of the conditional property.
+     * <p/>
+     * <p/>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the feature property.
+     * <p/>
+     * <p/>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getConditionals().add(newItem);
+     * </pre>
+     * <p/>
+     * <p/>
+     * <p/>
+     * Objects of the following type(s) are allowed in the list
+     * {@link Dependency }
+     */
+    public List<Conditional> getConditional() {
+        if (conditional == null) {
+            conditional = new ArrayList<Conditional>();
+        }
+        return this.conditional;
+    }
+
     public String toString() {
     	String ret = getName() + SPLIT_FOR_NAME_AND_VERSION + getVersion();
     	return ret;

Modified: karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
URL: http://svn.apache.org/viewvc/karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java?rev=1385270&r1=1385269&r2=1385270&view=diff
==============================================================================
--- karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java (original)
+++ karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java Sun Sep 16 13:58:37 2012
@@ -119,10 +119,10 @@ public class JaxbUtil {
 
     /**
      * Provides an empty inputsource for the entity resolver.
-     * Converts all elements with empty namespace to the features namespace to make old feature files 
+     * Converts all elements to the features namespace to make old feature files
      * compatible to the new format
      */
-    public static class NoSourceAndNamespaceFilter extends XMLFilterImpl {
+    public static class NoSourceAndNamespaceFilter extends XMLFilterImpl {        
         private static final InputSource EMPTY_INPUT_SOURCE = new InputSource(new ByteArrayInputStream(new byte[0]));
 
         public NoSourceAndNamespaceFilter(XMLReader xmlReader) {

Modified: karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/package-info.java
URL: http://svn.apache.org/viewvc/karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/package-info.java?rev=1385270&r1=1385269&r2=1385270&view=diff
==============================================================================
--- karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/package-info.java (original)
+++ karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/package-info.java Sun Sep 16 13:58:37 2012
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-@javax.xml.bind.annotation.XmlSchema(namespace = FeaturesNamespaces.URI_CURRENT, elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
+@javax.xml.bind.annotation.XmlSchema(namespace = "http://karaf.apache.org/xmlns/features/v1.2.0", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
 package org.apache.karaf.features.internal.model;
 
 import org.apache.karaf.features.FeaturesNamespaces;
\ No newline at end of file

Added: karaf/trunk/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.2.0.xsd
URL: http://svn.apache.org/viewvc/karaf/trunk/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.2.0.xsd?rev=1385270&view=auto
==============================================================================
--- karaf/trunk/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.2.0.xsd (added)
+++ karaf/trunk/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.2.0.xsd Sun Sep 16 13:58:37 2012
@@ -0,0 +1,254 @@
+<?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.
+
+-->
+<xs:schema elementFormDefault="qualified"
+    targetNamespace="http://karaf.apache.org/xmlns/features/v1.2.0"
+    xmlns:tns="http://karaf.apache.org/xmlns/features/v1.2.0"
+    xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+    <xs:annotation>
+        <xs:documentation><![CDATA[
+Karaf features mechanism. For documentation please visit the
+<a href="http://karaf.apache.org/">Karaf website</a>.
+        ]]></xs:documentation>
+    </xs:annotation>
+
+    <xs:complexType name="features">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Root element of Feature definition. It contains an required attribute for
+designating from which repository this feature should be loaded. The Karaf
+shell will show the repository name when displaying information about the feature.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="repository" type="xs:anyURI">
+                <xs:annotation>
+                    <xs:documentation><![CDATA[
+Additional repositories where dependencies are stored.
+                    ]]></xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="feature" type="tns:feature">
+                <xs:annotation>
+                    <xs:documentation><![CDATA[
+Feature definition.
+                    ]]></xs:documentation>
+                </xs:annotation>
+            </xs:element>
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string" use="required"/>
+    </xs:complexType>
+
+    <xs:complexType name="feature">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Definition of the Feature.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="details" minOccurs="0" type="xs:string">
+                <xs:annotation>
+                    <xs:documentation><![CDATA[
+The help text shown for this feature when using feature:info console command.
+                    ]]>
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="config" type="tns:config" />
+            <xs:element name="configfile" type="tns:configFile" />
+            <xs:element name="feature" type="tns:dependency" />
+            <xs:element name="bundle" type="tns:bundle" />
+            <xs:element name="conditional" type="tns:conditional" />
+        </xs:choice>
+        <xs:attribute name="name" type="tns:featureName" use="required" />
+        <xs:attribute name="version" type="xs:string" default="0.0.0" />
+        <xs:attribute name="description" type="xs:string" />
+        <xs:attribute name="resolver" type="tns:resolver">
+            <xs:annotation>
+                <xs:documentation><![CDATA[
+Optional alternative resolver to use for determining the list of bundles to install for a given feature.
+                ]]>
+                </xs:documentation>
+            </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="install" type="tns:install">
+            <xs:annotation>
+                <xs:documentation><![CDATA[
+Marks if the feaute will be automatically started when thrown to the deploy folder.
+                ]]>
+                </xs:documentation>
+            </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="start-level" type="xs:int">
+             <xs:annotation>
+                <xs:documentation><![CDATA[
+Set this attribute to have an OSGi start level for this feature different
+from the default start level defined in Karaf's config.properties.
+                ]]>
+                </xs:documentation>
+             </xs:annotation>
+         </xs:attribute>
+    </xs:complexType>
+
+    <xs:complexType name="conditional">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Definition of the Conditional.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="config" type="tns:config" />
+            <xs:element name="configfile" type="tns:configFile" />
+            <xs:element name="feature" type="tns:dependency" />
+            <xs:element name="bundle" type="tns:bundle" />
+            <xs:element name="condition" type="tns:dependency" minOccurs="0" maxOccurs="1" />
+        </xs:choice>
+    </xs:complexType>
+
+
+    <xs:complexType name="bundle">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Deployable element to install.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="xs:anyURI">
+                <xs:attribute name="start-level" type="xs:int">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+Set this attribute to have an OSGi start level for this bundle different
+from the default start level defined in the Karaf's config.properties.
+                        ]]>
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+                <xs:attribute name="start" type="xs:boolean" default="true">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+If false, leaves bundle in resolved state rather than the default active state.
+                        ]]>
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+                <xs:attribute name="dependency" type="xs:boolean">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+Mark this bundle as a dependency for the resolver.
+                        ]]>
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="dependency">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Dependency of feature.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="tns:featureName">
+                <xs:attribute name="version" type="xs:string" default="0.0.0" />
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="config">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Configuration entries which should be created during feature installation. This
+configuration may be used with OSGi Configuration Admin. The element content is
+read in as a properties file.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute name="name" type="xs:string" use="required" />
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="configFile">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Additional configuration files which should be created during feature installation.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="xs:anyURI">
+                <xs:attribute name="finalname" type="xs:string" use="required">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+The final destination path and name for the configuration file.
+                        ]]></xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+                <xs:attribute name="override" type="xs:boolean">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+If the configFile already exists at the finalname location, whether or not to replace it.
+                        ]]></xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:simpleType name="featureName">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Feature name should be non empty string.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:minLength value="1" />
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="resolver">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Resolver to use. Karaf will look for OSGi service which have following properties:
+objectClass: org.apache.karaf.features.Resolver
+name: the value
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:minLength value="1" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="install">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Installation mode. Can be either manual or auto. Specifies whether the feature should be automatically installed when
+dropped inside the deploy folder. Note: This attribute doesn't affect feature descriptors that are installed from the
+command line or as part of the org.apache.karaf.features.cfg.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:minLength value="1" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:element name="features" type="tns:features" />
+
+</xs:schema>

Added: karaf/trunk/features/core/src/test/java/org/apache/karaf/features/ConditionalTest.java
URL: http://svn.apache.org/viewvc/karaf/trunk/features/core/src/test/java/org/apache/karaf/features/ConditionalTest.java?rev=1385270&view=auto
==============================================================================
--- karaf/trunk/features/core/src/test/java/org/apache/karaf/features/ConditionalTest.java (added)
+++ karaf/trunk/features/core/src/test/java/org/apache/karaf/features/ConditionalTest.java Sun Sep 16 13:58:37 2012
@@ -0,0 +1,48 @@
+/*
+ * 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.karaf.features;
+
+import java.net.URI;
+import junit.framework.TestCase;
+import org.apache.karaf.features.internal.RepositoryImpl;
+
+
+public class ConditionalTest extends TestCase {
+
+    public void testLoad() throws Exception {
+        RepositoryImpl r = new RepositoryImpl(getClass().getResource("internal/f06.xml").toURI());
+        // Check repo
+        Feature[] features = r.getFeatures();
+        assertNotNull(features);
+        assertEquals(1, features.length);
+        Feature feature = features[0];
+
+        assertNotNull(feature.getConditional());
+        assertEquals(1,feature.getConditional().size());
+
+        Conditional conditional = feature.getConditional().get(0);
+        assertNotNull(conditional.getCondition());
+        assertEquals(1,conditional.getCondition().size());
+        Dependency dependency = conditional.getCondition().get(0);
+        assertNotNull(dependency);
+        assertEquals(dependency.getName(),"http");
+        assertNotNull(conditional.getBundles());
+        assertEquals(1, feature.getConditional().get(0).getBundles().size());
+
+        String wrapperName = "my6/1.5.3-beta-3".replaceAll("[^A-Za-z0-9 ]", "_");
+    }
+}

Modified: karaf/trunk/features/core/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java
URL: http://svn.apache.org/viewvc/karaf/trunk/features/core/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java?rev=1385270&r1=1385269&r2=1385270&view=diff
==============================================================================
--- karaf/trunk/features/core/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java (original)
+++ karaf/trunk/features/core/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java Sun Sep 16 13:58:37 2012
@@ -103,6 +103,7 @@ public class FeaturesServiceTest extends
         reset(bundleContext, installedBundle);
 
         expect(bundleContext.createFilter(EasyMock.<String>anyObject())).andReturn(null).anyTimes();
+        expect(installedBundle.getSymbolicName()).andReturn(name).anyTimes();
         expect(bundleContext.getBundles()).andReturn(new Bundle[0]);
         expect(bundleContext.installBundle(isA(String.class),
                                            isA(InputStream.class))).andReturn(installedBundle);
@@ -160,6 +161,7 @@ public class FeaturesServiceTest extends
 
         // Installs f1 and 0.1
         expect(bundleContext.createFilter(EasyMock.<String>anyObject())).andReturn(null).anyTimes();
+        expect(installedBundle.getSymbolicName()).andReturn(name).anyTimes();
         expect(bundleContext.getBundles()).andReturn(new Bundle[0]);
         expect(bundleContext.installBundle(isA(String.class),
                                            isA(InputStream.class))).andReturn(installedBundle);
@@ -297,6 +299,7 @@ public class FeaturesServiceTest extends
 
         // Then installs f1
         expect(bundleContext.createFilter(EasyMock.<String>anyObject())).andReturn(null).anyTimes();
+        expect(installedBundle.getSymbolicName()).andReturn(name).anyTimes();
         expect(bundleContext.getBundles()).andReturn(new Bundle[0]);
         expect(bundleContext.installBundle(isA(String.class),
                                            isA(InputStream.class))).andReturn(installedBundle);
@@ -566,6 +569,7 @@ public class FeaturesServiceTest extends
 
         // uninstalls first feature name = f2, version = 0.1
         expect(bundleContext.createFilter(EasyMock.<String>anyObject())).andReturn(null).anyTimes();
+        expect(installedBundle.getSymbolicName()).andReturn("mybundle").anyTimes();
         expect(bundleContext.getBundle(12345)).andReturn(installedBundle);
         installedBundle.uninstall();
 
@@ -618,6 +622,8 @@ public class FeaturesServiceTest extends
         installedBundle2.start();
 
         expect(bundleContext.getDataFile(EasyMock.<String>anyObject())).andReturn(dataFile).anyTimes();
+        expect(installedBundle1.getSymbolicName()).andReturn("bundle1").anyTimes();
+        expect(installedBundle2.getSymbolicName()).andReturn("bundle2").anyTimes();
 
         replay(bundleContext, installedBundle1, installedBundle2);
 
@@ -661,6 +667,7 @@ public class FeaturesServiceTest extends
         expect(installedBundle1.getBundleId()).andReturn(12345L);
         expect(installedBundle1.getBundleId()).andReturn(12345L);
         expect(installedBundle1.getBundleId()).andReturn(12345L);
+        expect(installedBundle1.getSymbolicName()).andReturn("bundle1").anyTimes();
         installedBundle1.uninstall();
 
         expect(bundleContext.getBundles()).andReturn(new Bundle[0]);
@@ -669,6 +676,7 @@ public class FeaturesServiceTest extends
         expect(installedBundle2.getBundleId()).andReturn(54321L);
         expect(installedBundle2.getBundleId()).andReturn(54321L);
         expect(installedBundle2.getHeaders()).andReturn(new Hashtable()).anyTimes();
+        expect(installedBundle2.getSymbolicName()).andReturn("bundle2").anyTimes();
         installedBundle2.start();
 
         expect(bundleContext.getDataFile(EasyMock.<String>anyObject())).andReturn(dataFile).anyTimes();

Modified: karaf/trunk/features/core/src/test/java/org/apache/karaf/features/internal/FeaturesValidationTest.java
URL: http://svn.apache.org/viewvc/karaf/trunk/features/core/src/test/java/org/apache/karaf/features/internal/FeaturesValidationTest.java?rev=1385270&r1=1385269&r2=1385270&view=diff
==============================================================================
--- karaf/trunk/features/core/src/test/java/org/apache/karaf/features/internal/FeaturesValidationTest.java (original)
+++ karaf/trunk/features/core/src/test/java/org/apache/karaf/features/internal/FeaturesValidationTest.java Sun Sep 16 13:58:37 2012
@@ -44,6 +44,11 @@ public class FeaturesValidationTest {
 
     @Test
     public void testNs12() throws Exception {
+        FeatureValidationUtil.validate(getClass().getResource("f06.xml").toURI());
+    }
+
+    @Test
+    public void testNs13() throws Exception {
         try {
             FeatureValidationUtil.validate(getClass().getResource("f05.xml").toURI());
             fail("Validation should have failed");

Copied: karaf/trunk/features/core/src/test/resources/org/apache/karaf/features/internal/f06.xml (from r1384857, karaf/trunk/features/core/src/test/resources/org/apache/karaf/features/repo1.xml)
URL: http://svn.apache.org/viewvc/karaf/trunk/features/core/src/test/resources/org/apache/karaf/features/internal/f06.xml?p2=karaf/trunk/features/core/src/test/resources/org/apache/karaf/features/internal/f06.xml&p1=karaf/trunk/features/core/src/test/resources/org/apache/karaf/features/repo1.xml&r1=1384857&r2=1385270&rev=1385270&view=diff
==============================================================================
--- karaf/trunk/features/core/src/test/resources/org/apache/karaf/features/repo1.xml (original)
+++ karaf/trunk/features/core/src/test/resources/org/apache/karaf/features/internal/f06.xml Sun Sep 16 13:58:37 2012
@@ -15,21 +15,18 @@
     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.0.0">
-    <repository>urn:r1</repository>
-    <feature name="f1" region="foo">
-        <config name="c1">
-            k=v
-        </config>
-        <bundle>b1</bundle>
-        <bundle>b2</bundle>
-    </feature>
-    <feature name="f2">
-        <feature>f1</feature>
-        <bundle>b3</bundle>
-    </feature>
-    <feature name="f3">
-    	<configfile finalname="cf1" override="true">cfloc</configfile>
-    	<bundle>b4</bundle> 
+<features name="karaf" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0">
+    <feature name="spring" version="2.5.6.SEC02" resolver="(obr)">
+        <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>
+        <bundle>mvn:org.springframework/spring-aop/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-context/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-context-support/2.5.6.SEC02</bundle>
+        <conditional>
+            <condition>http</condition>
+            <bundle>mvn:org.springframework/spring-web/2.5.6.SEC02</bundle>
+        </conditional>
     </feature>
 </features>
+

Modified: karaf/trunk/features/core/src/test/resources/org/apache/karaf/features/repo1.xml
URL: http://svn.apache.org/viewvc/karaf/trunk/features/core/src/test/resources/org/apache/karaf/features/repo1.xml?rev=1385270&r1=1385269&r2=1385270&view=diff
==============================================================================
--- karaf/trunk/features/core/src/test/resources/org/apache/karaf/features/repo1.xml (original)
+++ karaf/trunk/features/core/src/test/resources/org/apache/karaf/features/repo1.xml Sun Sep 16 13:58:37 2012
@@ -15,7 +15,7 @@
     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.0.0">
+<features name="test" xmlns="http://karaf.apache.org/xmlns/features/v1.1.0">
     <repository>urn:r1</repository>
     <feature name="f1" region="foo">
         <config name="c1">

Added: karaf/trunk/itests/src/test/java/org/apache/karaf/itests/ConditionalFeaturesTest.java
URL: http://svn.apache.org/viewvc/karaf/trunk/itests/src/test/java/org/apache/karaf/itests/ConditionalFeaturesTest.java?rev=1385270&view=auto
==============================================================================
--- karaf/trunk/itests/src/test/java/org/apache/karaf/itests/ConditionalFeaturesTest.java (added)
+++ karaf/trunk/itests/src/test/java/org/apache/karaf/itests/ConditionalFeaturesTest.java Sun Sep 16 13:58:37 2012
@@ -0,0 +1,112 @@
+/*
+ * 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.karaf.itests;
+
+import javax.inject.Inject;
+import junit.framework.Assert;
+import org.apache.felix.service.command.CommandProcessor;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.tooling.exam.options.configs.FeaturesCfg;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.TestProbeBuilder;
+import org.ops4j.pax.exam.junit.Configuration;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.ops4j.pax.exam.junit.ProbeBuilder;
+import org.ops4j.pax.exam.util.Filter;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.blueprint.container.BlueprintContainer;
+
+
+import static org.apache.karaf.tooling.exam.options.KarafDistributionOption.editConfigurationFileExtend;
+import static org.apache.karaf.tooling.exam.options.KarafDistributionOption.karafDistributionConfiguration;
+import static org.junit.Assert.assertNotNull;
+import static org.ops4j.pax.exam.CoreOptions.maven;
+
+@RunWith(JUnit4TestRunner.class)
+public class ConditionalFeaturesTest {
+
+    @Inject
+    private CommandProcessor cp;
+
+    @Inject
+    private FeaturesService featuresService;
+
+    @Inject
+    private BundleContext bundleContext;
+
+    @ProbeBuilder
+    public TestProbeBuilder probeConfiguration(TestProbeBuilder probe) {
+        probe.setHeader(Constants.DYNAMICIMPORT_PACKAGE, "*,org.apache.felix.service.*;status=provisional");
+        return probe;
+    }
+
+    @Configuration
+    public Option[] config() {
+        return new Option[]{
+            karafDistributionConfiguration().frameworkUrl(
+                maven().groupId("org.apache.karaf").artifactId("apache-karaf").type("zip")
+                    .versionAsInProject())};
+    }
+
+    @Test
+    public void testScr() throws Exception {
+        //Remove management and install scr
+        featuresService.uninstallFeature("management");
+        featuresService.installFeature("scr");
+        Assert.assertFalse(isBundleInstalled("org.apache.karaf.scr.management"));
+
+        //Add management back
+        featuresService.installFeature("management");
+        Assert.assertTrue(isBundleInstalled("org.apache.karaf.scr.management"));
+    }
+
+    @Test
+    public void testWebconsole() throws Exception {
+        featuresService.installFeature("webconsole");
+
+        Assert.assertTrue(isBundleInstalled("org.apache.karaf.webconsole.features"));
+        Assert.assertTrue(isBundleInstalled("org.apache.karaf.webconsole.instance"));
+        Assert.assertTrue(isBundleInstalled("org.apache.karaf.webconsole.gogo"));
+        Assert.assertTrue(isBundleInstalled("org.apache.karaf.webconsole.http"));
+
+        Assert.assertFalse(isBundleInstalled("org.apache.felix.webconsole.plugins.event"));
+
+        //Add eventadmin
+        try {
+            featuresService.installFeature("eventadmin");
+        } catch (Exception ex) {
+          //ignore as the eventadmin activator might throw an error.
+        }
+        Assert.assertTrue(isBundleInstalled("org.apache.felix.webconsole.plugins.event"));
+    }
+
+
+
+    private boolean isBundleInstalled(String symbolicName) {
+        for (Bundle bundle : bundleContext.getBundles()) {
+            if (bundle.getSymbolicName().equals(symbolicName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}

Modified: karaf/trunk/webconsole/features/src/main/java/org/apache/karaf/webconsole/features/ExtendedFeature.java
URL: http://svn.apache.org/viewvc/karaf/trunk/webconsole/features/src/main/java/org/apache/karaf/webconsole/features/ExtendedFeature.java?rev=1385270&r1=1385269&r2=1385270&view=diff
==============================================================================
--- karaf/trunk/webconsole/features/src/main/java/org/apache/karaf/webconsole/features/ExtendedFeature.java (original)
+++ karaf/trunk/webconsole/features/src/main/java/org/apache/karaf/webconsole/features/ExtendedFeature.java Sun Sep 16 13:58:37 2012
@@ -21,6 +21,7 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.karaf.features.BundleInfo;
+import org.apache.karaf.features.Conditional;
 import org.apache.karaf.features.ConfigFileInfo;
 import org.apache.karaf.features.Dependency;
 import org.apache.karaf.features.Feature;
@@ -81,7 +82,12 @@ public class ExtendedFeature implements 
     public List<ConfigFileInfo> getConfigurationFiles() {
 		return this.feature.getConfigurationFiles();
 	}
-    
+
+    @Override
+    public List<? extends Conditional> getConditional() {
+        return this.feature.getConditional();
+    }
+
     public List<Dependency> getDependencies()
     {
         return this.feature.getDependencies();