FELIX-1457: refactor features management layer
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@801925 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/karaf/features/command/pom.xml b/karaf/features/command/pom.xml
new file mode 100644
index 0000000..ac6304e
--- /dev/null
+++ b/karaf/features/command/pom.xml
@@ -0,0 +1,115 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <!--
+
+ 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.
+ -->
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix.karaf.features</groupId>
+ <artifactId>features</artifactId>
+ <version>1.2.0-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.apache.felix.karaf.features</groupId>
+ <artifactId>org.apache.felix.karaf.features.command</artifactId>
+ <packaging>bundle</packaging>
+ <version>1.2.0-SNAPSHOT</version>
+ <name>Apache Felix Karaf :: Features Command</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix.karaf.features</groupId>
+ <artifactId>org.apache.felix.karaf.features.core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.bundlerepository</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix.karaf.gshell</groupId>
+ <artifactId>org.apache.felix.karaf.gshell.console</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix.karaf.gshell</groupId>
+ <artifactId>org.apache.felix.karaf.gshell.obr</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework.osgi</groupId>
+ <artifactId>spring-osgi-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.bundles</groupId>
+ <artifactId>org.apache.servicemix.bundles.junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymock</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-jdk14</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${artifactId}</Bundle-SymbolicName>
+ <Export-Package>${pom.artifactId}*;version=${project.version}</Export-Package>
+ <Import-Package>
+ javax.management,
+ javax.management.loading,
+ org.osgi.service.command,
+ org.apache.felix.gogo.commands,
+ org.apache.felix.karaf.gshell.console,
+ *
+ </Import-Package>
+ <Private-Package>!*</Private-Package>
+ <_versionpolicy>${bnd.version.policy}</_versionpolicy>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/AddUrlCommand.java b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/AddUrlCommand.java
new file mode 100644
index 0000000..78c207d
--- /dev/null
+++ b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/AddUrlCommand.java
@@ -0,0 +1,37 @@
+/*
+ * 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.felix.karaf.features.command;
+
+import java.net.URI;
+import java.util.List;
+
+import org.apache.felix.karaf.features.FeaturesService;
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.felix.gogo.commands.Command;
+
+@Command(scope = "features", name = "addUrl", description = "Add a list of repository URLs to the features service.")
+public class AddUrlCommand extends FeaturesCommandSupport {
+
+ @Argument(required = true, multiValued = true, description = "Repository URLs")
+ List<String> urls;
+
+ protected void doExecute(FeaturesService admin) throws Exception {
+ for (String url : urls) {
+ admin.addRepository(new URI(url));
+ }
+ }
+}
diff --git a/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/FeaturesCommandSupport.java b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/FeaturesCommandSupport.java
new file mode 100644
index 0000000..3014f35
--- /dev/null
+++ b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/FeaturesCommandSupport.java
@@ -0,0 +1,49 @@
+/*
+ * 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.felix.karaf.features.command;
+
+import org.apache.felix.karaf.gshell.console.OsgiCommandSupport;
+import org.apache.felix.karaf.features.FeaturesService;
+import org.osgi.framework.ServiceReference;
+
+public abstract class FeaturesCommandSupport extends OsgiCommandSupport {
+
+ protected Object doExecute() throws Exception {
+ // Get repository admin service.
+ ServiceReference ref = getBundleContext().getServiceReference(FeaturesService.class.getName());
+ if (ref == null) {
+ System.out.println("FeaturesService service is unavailable.");
+ return null;
+ }
+ try {
+ FeaturesService admin = (FeaturesService) getBundleContext().getService(ref);
+ if (admin == null) {
+ System.out.println("FeaturesService service is unavailable.");
+ return null;
+ }
+
+ doExecute(admin);
+ }
+ finally {
+ getBundleContext().ungetService(ref);
+ }
+ return null;
+ }
+
+ protected abstract void doExecute(FeaturesService admin) throws Exception;
+
+}
diff --git a/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/InstallFeatureCommand.java b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/InstallFeatureCommand.java
new file mode 100644
index 0000000..aff684d
--- /dev/null
+++ b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/InstallFeatureCommand.java
@@ -0,0 +1,38 @@
+/*
+ * 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.felix.karaf.features.command;
+
+import org.apache.felix.karaf.features.FeaturesService;
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.felix.gogo.commands.Command;
+
+@Command(scope = "features", name = "install", description = "Install a feature.")
+public class InstallFeatureCommand extends FeaturesCommandSupport {
+
+ @Argument(required = true, description = "The name of the feature")
+ String name;
+ @Argument(description = "The version of the feature", index = 1)
+ String version;
+
+ protected void doExecute(FeaturesService admin) throws Exception {
+ if (version != null && version.length() > 0) {
+ admin.installFeature(name, version);
+ } else {
+ admin.installFeature(name);
+ }
+ }
+}
diff --git a/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/ListFeaturesCommand.java b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/ListFeaturesCommand.java
new file mode 100644
index 0000000..33e942b
--- /dev/null
+++ b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/ListFeaturesCommand.java
@@ -0,0 +1,82 @@
+/*
+ * 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.felix.karaf.features.command;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.felix.karaf.features.FeaturesService;
+import org.apache.felix.karaf.features.Feature;
+import org.apache.felix.gogo.commands.Option;
+import org.apache.felix.gogo.commands.Command;
+
+@Command(scope = "features", name = "list", description = "List existing features.")
+public class ListFeaturesCommand extends FeaturesCommandSupport {
+
+ @Option(name = "-i", aliases={"--installed"}, description="Display the list of installed features")
+ boolean installed;
+
+ protected void doExecute(FeaturesService admin) throws Exception {
+ List<Feature> features;
+ List<Feature> installedFeatures;
+ if (installed) {
+ features = Arrays.asList(admin.listInstalledFeatures());
+ installedFeatures = features;
+ if (features == null || features.size() == 0) {
+ System.out.println("No features installed.");
+ return;
+ }
+ } else {
+ features = Arrays.asList(admin.listFeatures());
+ installedFeatures = Arrays.asList(admin.listInstalledFeatures());
+ if (features == null || features.size() == 0) {
+ System.out.println("No features available.");
+ return;
+ }
+ }
+ int maxVersionSize = 7;
+ for (Feature feature : features) {
+ maxVersionSize = Math.max(maxVersionSize, feature.getVersion().length());
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append(" State Version ");
+ for (int i = 7; i < maxVersionSize; i++) {
+ sb.append(" ");
+ }
+ sb.append("Name");
+ System.out.println(sb.toString());
+ for (Feature feature : features) {
+ sb.setLength(0);
+ sb.append("[");
+ if (installedFeatures.contains(feature)) {
+ sb.append("installed ");
+ } else {
+ sb.append("uninstalled");
+ }
+ sb.append("] [");
+ String v = feature.getVersion();
+ sb.append(v);
+ for (int i = v.length(); i < maxVersionSize; i++) {
+ sb.append(" ");
+ }
+ sb.append("] ");
+ sb.append(feature.getName());
+ System.out.println(sb.toString());
+ }
+ }
+
+}
diff --git a/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/ListUrlCommand.java b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/ListUrlCommand.java
new file mode 100644
index 0000000..e9c5306
--- /dev/null
+++ b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/ListUrlCommand.java
@@ -0,0 +1,35 @@
+/*
+ * 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.felix.karaf.features.command;
+
+import org.apache.felix.karaf.features.FeaturesService;
+import org.apache.felix.karaf.features.Repository;
+
+
+public class ListUrlCommand extends FeaturesCommandSupport {
+
+ protected void doExecute(FeaturesService admin) throws Exception {
+ Repository[] repos = admin.listRepositories();
+ if ((repos != null) && (repos.length > 0)) {
+ for (int i = 0; i < repos.length; i++) {
+ System.out.println(repos[i].getURI());
+ }
+ } else {
+ System.out.println("No repository URLs are set.");
+ }
+ }
+}
diff --git a/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/RefreshUrlCommand.java b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/RefreshUrlCommand.java
new file mode 100644
index 0000000..45b400d
--- /dev/null
+++ b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/RefreshUrlCommand.java
@@ -0,0 +1,47 @@
+/*
+ * 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.felix.karaf.features.command;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.felix.gogo.commands.Command;
+import org.apache.felix.karaf.features.FeaturesService;
+import org.apache.felix.karaf.features.Repository;
+
+@Command(scope = "features", name = "refreshUrl", description = "Reload the repositories to obtain a fresh list of features.")
+public class RefreshUrlCommand extends FeaturesCommandSupport {
+
+ @Argument(required = false, multiValued = true, description = "Repository URLs (leave empty for all)")
+ List<String> urls;
+
+ protected void doExecute(FeaturesService admin) throws Exception {
+ if (urls == null || urls.isEmpty()) {
+ urls = new ArrayList<String>();
+ for (Repository repo : admin.listRepositories()) {
+ urls.add(repo.getURI().toString());
+ }
+ }
+ for (String strUri : urls) {
+ URI uri = new URI(strUri);
+ admin.removeRepository(uri);
+ admin.addRepository(uri);
+ }
+ }
+}
diff --git a/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/RemoveUrlCommand.java b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/RemoveUrlCommand.java
new file mode 100644
index 0000000..17db749
--- /dev/null
+++ b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/RemoveUrlCommand.java
@@ -0,0 +1,37 @@
+/*
+ * 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.felix.karaf.features.command;
+
+import java.net.URI;
+import java.util.List;
+
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.felix.gogo.commands.Command;
+import org.apache.felix.karaf.features.FeaturesService;
+
+@Command(scope = "features", name = "removeUrl", description = "Remove a list of repository URLs from the features service.")
+public class RemoveUrlCommand extends FeaturesCommandSupport {
+
+ @Argument(required = true, multiValued = true, description = "Repository URLs")
+ List<String> urls;
+
+ protected void doExecute(FeaturesService admin) throws Exception {
+ for (String url : urls) {
+ admin.removeRepository(new URI(url));
+ }
+ }
+}
diff --git a/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/UninstallFeatureCommand.java b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/UninstallFeatureCommand.java
new file mode 100644
index 0000000..229d43c
--- /dev/null
+++ b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/UninstallFeatureCommand.java
@@ -0,0 +1,38 @@
+/*
+ * 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.felix.karaf.features.command;
+
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.felix.gogo.commands.Command;
+import org.apache.felix.karaf.features.FeaturesService;
+
+@Command(scope = "features", name = "uninstall", description = "Uninstall a feature.")
+public class UninstallFeatureCommand extends FeaturesCommandSupport {
+
+ @Argument(required = true, description = "The name of the feature")
+ String name;
+ @Argument(description = "The version of the feature", index = 1)
+ String version;
+
+ protected void doExecute(FeaturesService admin) throws Exception {
+ if (version != null && version.length() > 0) {
+ admin.uninstallFeature(name, version);
+ } else {
+ admin.uninstallFeature(name );
+ }
+ }
+}
diff --git a/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/completers/AvailableFeatureCompleter.java b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/completers/AvailableFeatureCompleter.java
new file mode 100644
index 0000000..0a826c6
--- /dev/null
+++ b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/completers/AvailableFeatureCompleter.java
@@ -0,0 +1,53 @@
+/*
+ * 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.felix.karaf.features.command.completers;
+
+import java.util.List;
+
+import org.apache.felix.karaf.gshell.console.completer.StringsCompleter;
+import org.apache.felix.karaf.gshell.console.Completer;
+import org.apache.felix.karaf.features.FeaturesService;
+import org.apache.felix.karaf.features.Feature;
+
+/**
+ * {@link jline.Completor} for available features.
+ *
+ * Displays a list of available features from installed repositories.
+ *
+ */
+public class AvailableFeatureCompleter implements Completer {
+
+ private FeaturesService featuresService;
+
+ public void setFeaturesService(FeaturesService featuresService) {
+ this.featuresService = featuresService;
+ }
+
+ public int complete(final String buffer, final int cursor, final List candidates) {
+ StringsCompleter delegate = new StringsCompleter();
+ try {
+ for (Feature feature : featuresService.listFeatures()) {
+ delegate.getStrings().add(feature.getName());
+ }
+ } catch (Exception e) {
+ // Ignore
+ }
+ return delegate.complete(buffer, cursor, candidates);
+ }
+
+
+}
diff --git a/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/completers/FeatureRepositoryCompleter.java b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/completers/FeatureRepositoryCompleter.java
new file mode 100644
index 0000000..80a8b79
--- /dev/null
+++ b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/completers/FeatureRepositoryCompleter.java
@@ -0,0 +1,53 @@
+/*
+ * 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.felix.karaf.features.command.completers;
+
+import java.util.List;
+
+import org.apache.felix.karaf.gshell.console.completer.StringsCompleter;
+import org.apache.felix.karaf.gshell.console.Completer;
+import org.apache.felix.karaf.features.FeaturesService;
+import org.apache.felix.karaf.features.Repository;
+
+/**
+ * {@link jline.Completor} for Feature Repository URLs.
+ *
+ * Displays a list of currently installed Feature repositories.
+ *
+ */
+
+public class FeatureRepositoryCompleter implements Completer {
+
+ private FeaturesService featuresService;
+
+ public void setFeaturesService(FeaturesService featuresService) {
+ this.featuresService = featuresService;
+ }
+
+ public int complete(final String buffer, final int cursor, final List candidates) {
+ StringsCompleter delegate = new StringsCompleter();
+ try {
+ for (Repository repository : featuresService.listRepositories()) {
+ delegate.getStrings().add(repository.getURI().toString());
+ }
+ } catch (Exception e) {
+ // Ignore
+ }
+ return delegate.complete(buffer, cursor, candidates);
+ }
+
+}
diff --git a/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/completers/InstalledFeatureCompleter.java b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/completers/InstalledFeatureCompleter.java
new file mode 100644
index 0000000..ba538c7
--- /dev/null
+++ b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/completers/InstalledFeatureCompleter.java
@@ -0,0 +1,52 @@
+/*
+ * 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.felix.karaf.features.command.completers;
+
+import java.util.List;
+
+import org.apache.felix.karaf.gshell.console.Completer;
+import org.apache.felix.karaf.gshell.console.completer.StringsCompleter;
+import org.apache.felix.karaf.features.FeaturesService;
+import org.apache.felix.karaf.features.Feature;
+
+/**
+ * {@link jline.Completor} for installed features.
+ *
+ * Displays a list of currently installed features.
+ *
+ */
+public class InstalledFeatureCompleter implements Completer {
+
+ private FeaturesService featuresService;
+
+ public void setFeaturesService(FeaturesService featuresService) {
+ this.featuresService = featuresService;
+ }
+
+ public int complete(final String buffer, final int cursor, final List candidates) {
+ StringsCompleter delegate = new StringsCompleter();
+ try {
+ for (Feature feature : featuresService.listInstalledFeatures()) {
+ delegate.getStrings().add(feature.getName());
+ }
+ } catch (Exception e) {
+ // Ignore
+ }
+ return delegate.complete(buffer, cursor, candidates);
+ }
+
+}
diff --git a/karaf/features/command/src/main/resources/OSGI-INF/blueprint/features-command.xml b/karaf/features/command/src/main/resources/OSGI-INF/blueprint/features-command.xml
new file mode 100644
index 0000000..1ebb11e
--- /dev/null
+++ b/karaf/features/command/src/main/resources/OSGI-INF/blueprint/features-command.xml
@@ -0,0 +1,70 @@
+<?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.
+
+-->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ xmlns:ext="http://geronimo.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0">
+
+ <command-bundle xmlns="http://felix.apache.org/karaf/xmlns/gshell/v1.0.0">
+ <command name="features/addUrl">
+ <action class="org.apache.felix.karaf.features.command.AddUrlCommand"/>
+ </command>
+ <command name="features/listUrl">
+ <action class="org.apache.felix.karaf.features.command.ListUrlCommand"/>
+ </command>
+ <command name="features/removeUrl">
+ <action class="org.apache.felix.karaf.features.command.RemoveUrlCommand"/>
+ <completers>
+ <ref component-id="removeUrlCompleter" />
+ </completers>
+ </command>
+ <command name="features/refreshUrl">
+ <action class="org.apache.felix.karaf.features.command.RefreshUrlCommand"/>
+ </command>
+ <command name="features/install">
+ <action class="org.apache.felix.karaf.features.command.InstallFeatureCommand"/>
+ <completers>
+ <ref component-id="installFeatureCompleter" />
+ </completers>
+ </command>
+ <command name="features/uninstall">
+ <action class="org.apache.felix.karaf.features.command.UninstallFeatureCommand"/>
+ <completers>
+ <ref component-id="uninstallFeatureCompleter" />
+ </completers>
+ </command>
+ <command name="features/list">
+ <action class="org.apache.felix.karaf.features.command.ListFeaturesCommand"/>
+ </command>
+ </command-bundle>
+
+ <reference id="featuresService" interface="org.apache.felix.karaf.features.FeaturesService" />
+
+ <bean id="installFeatureCompleter" class="org.apache.felix.karaf.features.command.completers.AvailableFeatureCompleter">
+ <property name="featuresService" ref="featuresService" />
+ </bean>
+
+ <bean id="uninstallFeatureCompleter" class="org.apache.felix.karaf.features.command.completers.InstalledFeatureCompleter">
+ <property name="featuresService" ref="featuresService" />
+ </bean>
+
+ <bean id="removeUrlCompleter" class="org.apache.felix.karaf.features.command.completers.FeatureRepositoryCompleter">
+ <property name="featuresService" ref="featuresService" />
+ </bean>
+
+</blueprint>