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();