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/assembly/pom.xml b/karaf/assembly/pom.xml
index 333806b..84c6ebe 100644
--- a/karaf/assembly/pom.xml
+++ b/karaf/assembly/pom.xml
@@ -59,6 +59,18 @@
             <artifactId>org.apache.felix.karaf.deployer.features</artifactId>
         </dependency>
         <dependency>
+            <groupId>org.apache.felix.karaf.features</groupId>
+            <artifactId>org.apache.felix.karaf.features.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix.karaf.features</groupId>
+            <artifactId>org.apache.felix.karaf.features.command</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix.karaf.features</groupId>
+            <artifactId>org.apache.felix.karaf.features.management</artifactId>
+        </dependency>
+        <dependency>
             <groupId>org.apache.felix.karaf.gshell</groupId>
             <artifactId>org.apache.felix.karaf.gshell.console</artifactId>
         </dependency>
@@ -80,10 +92,6 @@
         </dependency>
         <dependency>
             <groupId>org.apache.felix.karaf.gshell</groupId>
-            <artifactId>org.apache.felix.karaf.gshell.features</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.felix.karaf.gshell</groupId>
             <artifactId>org.apache.felix.karaf.gshell.config</artifactId>
         </dependency>
         <dependency>
diff --git a/karaf/assembly/src/main/descriptors/unix-bin.xml b/karaf/assembly/src/main/descriptors/unix-bin.xml
index 2fffda8..e4093db 100644
--- a/karaf/assembly/src/main/descriptors/unix-bin.xml
+++ b/karaf/assembly/src/main/descriptors/unix-bin.xml
@@ -168,6 +168,17 @@
             <outputDirectory>/system</outputDirectory>
             <unpack>false</unpack>
             <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/apache/felix/karaf/features/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.apache.felix.karaf.features:org.apache.felix.karaf.features.core</include>
+                <include>org.apache.felix.karaf.features:org.apache.felix.karaf.features.command</include>
+                <include>org.apache.felix.karaf.features:org.apache.felix.karaf.features.management</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
             <outputFileNameMapping>org/apache/felix/karaf/deployer/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
             <includes>
                 <include>org.apache.felix.karaf.deployer:org.apache.felix.karaf.deployer.filemonitor</include>
@@ -186,7 +197,6 @@
                 <include>org.apache.felix.karaf.gshell:org.apache.felix.karaf.gshell.admin</include>
                 <include>org.apache.felix.karaf.gshell:org.apache.felix.karaf.gshell.osgi</include>
                 <include>org.apache.felix.karaf.gshell:org.apache.felix.karaf.gshell.log</include>
-                <include>org.apache.felix.karaf.gshell:org.apache.felix.karaf.gshell.features</include>
                 <include>org.apache.felix.karaf.gshell:org.apache.felix.karaf.gshell.config</include>
                 <include>org.apache.felix.karaf.gshell:org.apache.felix.karaf.gshell.packages</include>
                 <include>org.apache.felix.karaf.gshell:org.apache.felix.karaf.gshell.ssh</include>
diff --git a/karaf/assembly/src/main/descriptors/windows-bin.xml b/karaf/assembly/src/main/descriptors/windows-bin.xml
index 1241f3f..8039fba 100644
--- a/karaf/assembly/src/main/descriptors/windows-bin.xml
+++ b/karaf/assembly/src/main/descriptors/windows-bin.xml
@@ -160,6 +160,17 @@
             <outputDirectory>/system</outputDirectory>
             <unpack>false</unpack>
             <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/apache/felix/karaf/features/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.apache.felix.karaf.features:org.apache.felix.karaf.features.core</include>
+                <include>org.apache.felix.karaf.features:org.apache.felix.karaf.features.command</include>
+                <include>org.apache.felix.karaf.features:org.apache.felix.karaf.features.management</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
             <outputFileNameMapping>org/apache/felix/karaf/deployer/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
             <includes>
                 <include>org.apache.felix.karaf.deployer:org.apache.felix.karaf.deployer.filemonitor</include>
@@ -178,7 +189,6 @@
                 <include>org.apache.felix.karaf.gshell:org.apache.felix.karaf.gshell.admin</include>
                 <include>org.apache.felix.karaf.gshell:org.apache.felix.karaf.gshell.osgi</include>
                 <include>org.apache.felix.karaf.gshell:org.apache.felix.karaf.gshell.log</include>
-                <include>org.apache.felix.karaf.gshell:org.apache.felix.karaf.gshell.features</include>
                 <include>org.apache.felix.karaf.gshell:org.apache.felix.karaf.gshell.config</include>
                 <include>org.apache.felix.karaf.gshell:org.apache.felix.karaf.gshell.packages</include>
                 <include>org.apache.felix.karaf.gshell:org.apache.felix.karaf.gshell.ssh</include>
diff --git a/karaf/assembly/src/main/filtered-resources/etc/startup.properties b/karaf/assembly/src/main/filtered-resources/etc/startup.properties
index c7eb864..36f066b 100644
--- a/karaf/assembly/src/main/filtered-resources/etc/startup.properties
+++ b/karaf/assembly/src/main/filtered-resources/etc/startup.properties
@@ -43,7 +43,6 @@
 org/apache/felix/karaf/deployer/org.apache.felix.karaf.deployer.features/${pom.version}/org.apache.felix.karaf.deployer.features-${pom.version}.jar=30
 org/apache/felix/karaf/gshell/org.apache.felix.karaf.gshell.admin/${pom.version}/org.apache.felix.karaf.gshell.admin-${pom.version}.jar=30
 org/apache/felix/karaf/gshell/org.apache.felix.karaf.gshell.osgi/${pom.version}/org.apache.felix.karaf.gshell.osgi-${pom.version}.jar=30
-org/apache/felix/karaf/gshell/org.apache.felix.karaf.gshell.features/${pom.version}/org.apache.felix.karaf.gshell.features-${pom.version}.jar=30
 org/apache/felix/karaf/gshell/org.apache.felix.karaf.gshell.log/${pom.version}/org.apache.felix.karaf.gshell.log-${pom.version}.jar=30
 org/apache/felix/karaf/gshell/org.apache.felix.karaf.gshell.config/${pom.version}/org.apache.felix.karaf.gshell.config-${pom.version}.jar=30
 org/apache/felix/karaf/gshell/org.apache.felix.karaf.gshell.packages/${pom.version}/org.apache.felix.karaf.gshell.packages-${pom.version}.jar=30
@@ -51,6 +50,10 @@
 org/apache/felix/karaf/jaas/org.apache.felix.karaf.jaas.config/${pom.version}/org.apache.felix.karaf.jaas.config-${pom.version}.jar=30
 org/apache/felix/karaf/jaas/org.apache.felix.karaf.jaas.modules/${pom.version}/org.apache.felix.karaf.jaas.modules-${pom.version}.jar=30
 
+org/apache/felix/karaf/features/org.apache.felix.karaf.features.core/${pom.version}/org.apache.felix.karaf.features.core-${pom.version}.jar=30
+org/apache/felix/karaf/features/org.apache.felix.karaf.features.command/${pom.version}/org.apache.felix.karaf.features.command-${pom.version}.jar=30
+org/apache/felix/karaf/features/org.apache.felix.karaf.features.management/${pom.version}/org.apache.felix.karaf.features.management-${pom.version}.jar=30
+
 org/apache/felix/karaf/org.apache.felix.karaf.management/${pom.version}/org.apache.felix.karaf.management-${pom.version}.jar=30
 org/osgi/org.osgi.impl.bundle.jmx/${osgi.jmx.version}/org.osgi.impl.bundle.jmx-${osgi.jmx.version}.jar=30
 
diff --git a/karaf/deployer/features/pom.xml b/karaf/deployer/features/pom.xml
index 4c07b09..e759a21 100644
--- a/karaf/deployer/features/pom.xml
+++ b/karaf/deployer/features/pom.xml
@@ -46,8 +46,8 @@
             <artifactId>spring-osgi-core</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.apache.felix.karaf.gshell</groupId>
-            <artifactId>org.apache.felix.karaf.gshell.features</artifactId>
+            <groupId>org.apache.felix.karaf.features</groupId>
+            <artifactId>org.apache.felix.karaf.features.core</artifactId>
         </dependency>
         <dependency>
             <groupId>org.apache.felix.karaf.deployer</groupId>
diff --git a/karaf/deployer/features/src/main/java/org/apache/felix/karaf/deployer/features/FeatureDeploymentListener.java b/karaf/deployer/features/src/main/java/org/apache/felix/karaf/deployer/features/FeatureDeploymentListener.java
index 679e47f..706ede5 100644
--- a/karaf/deployer/features/src/main/java/org/apache/felix/karaf/deployer/features/FeatureDeploymentListener.java
+++ b/karaf/deployer/features/src/main/java/org/apache/felix/karaf/deployer/features/FeatureDeploymentListener.java
@@ -40,18 +40,15 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.felix.karaf.gshell.features.Feature;
-import org.apache.felix.karaf.gshell.features.FeaturesService;
-import org.apache.felix.karaf.gshell.features.Repository;
+import org.apache.felix.karaf.features.Feature;
+import org.apache.felix.karaf.features.FeaturesService;
+import org.apache.felix.karaf.features.Repository;
 import org.apache.felix.karaf.deployer.filemonitor.DeploymentListener;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleEvent;
 import org.osgi.framework.Constants;
 import org.osgi.framework.SynchronousBundleListener;
-import org.springframework.beans.factory.DisposableBean;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.osgi.context.BundleContextAware;
 
 /**
  * A deployment listener able to hot deploy a feature descriptor
diff --git a/karaf/deployer/features/src/main/resources/OSGI-INF/blueprint/features-deployer.xml b/karaf/deployer/features/src/main/resources/OSGI-INF/blueprint/features-deployer.xml
index 89e7825..474b993 100644
--- a/karaf/deployer/features/src/main/resources/OSGI-INF/blueprint/features-deployer.xml
+++ b/karaf/deployer/features/src/main/resources/OSGI-INF/blueprint/features-deployer.xml
@@ -28,7 +28,7 @@
           init-method="init" destroy-method="destroy" activation="lazy">
         <property name="bundleContext" ref="blueprintBundleContext"/>
         <property name="featuresService">
-            <reference interface="org.apache.felix.karaf.gshell.features.FeaturesService"/>
+            <reference interface="org.apache.felix.karaf.features.FeaturesService"/>
         </property>
     </bean>
 
diff --git a/karaf/gshell/gshell-features/pom.xml b/karaf/features/command/pom.xml
similarity index 89%
rename from karaf/gshell/gshell-features/pom.xml
rename to karaf/features/command/pom.xml
index 38363b8..ac6304e 100644
--- a/karaf/gshell/gshell-features/pom.xml
+++ b/karaf/features/command/pom.xml
@@ -22,20 +22,16 @@
     <modelVersion>4.0.0</modelVersion>
 
     <parent>
-        <groupId>org.apache.felix.karaf.gshell</groupId>
-        <artifactId>gshell</artifactId>
+        <groupId>org.apache.felix.karaf.features</groupId>
+        <artifactId>features</artifactId>
         <version>1.2.0-SNAPSHOT</version>
     </parent>
 
-    <groupId>org.apache.felix.karaf.gshell</groupId>
-    <artifactId>org.apache.felix.karaf.gshell.features</artifactId>
+    <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 :: GShell Features</name>
-
-    <description>
-        Provides Features in GShell
-    </description>
+    <name>Apache Felix Karaf :: Features Command</name>
 
     <dependencies>
         <dependency>
@@ -51,6 +47,11 @@
         </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>
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/AddUrlCommand.java b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/AddUrlCommand.java
similarity index 91%
rename from karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/AddUrlCommand.java
rename to karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/AddUrlCommand.java
index a4ee363..78c207d 100644
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/AddUrlCommand.java
+++ b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/AddUrlCommand.java
@@ -14,12 +14,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.karaf.gshell.features.commands;
+package org.apache.felix.karaf.features.command;
 
 import java.net.URI;
 import java.util.List;
 
-import org.apache.felix.karaf.gshell.features.FeaturesService;
+import org.apache.felix.karaf.features.FeaturesService;
 import org.apache.felix.gogo.commands.Argument;
 import org.apache.felix.gogo.commands.Command;
 
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/FeaturesCommandSupport.java b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/FeaturesCommandSupport.java
similarity index 93%
rename from karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/FeaturesCommandSupport.java
rename to karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/FeaturesCommandSupport.java
index 4f79be9..3014f35 100644
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/FeaturesCommandSupport.java
+++ b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/FeaturesCommandSupport.java
@@ -14,10 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.karaf.gshell.features.commands;
+package org.apache.felix.karaf.features.command;
 
-import org.apache.felix.karaf.gshell.features.FeaturesService;
 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 {
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/InstallFeatureCommand.java b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/InstallFeatureCommand.java
similarity index 91%
rename from karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/InstallFeatureCommand.java
rename to karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/InstallFeatureCommand.java
index 4a25b63..aff684d 100644
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/InstallFeatureCommand.java
+++ b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/InstallFeatureCommand.java
@@ -14,9 +14,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.karaf.gshell.features.commands;
+package org.apache.felix.karaf.features.command;
 
-import org.apache.felix.karaf.gshell.features.FeaturesService;
+import org.apache.felix.karaf.features.FeaturesService;
 import org.apache.felix.gogo.commands.Argument;
 import org.apache.felix.gogo.commands.Command;
 
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/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/ListUrlCommand.java b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/ListUrlCommand.java
similarity index 87%
rename from karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/ListUrlCommand.java
rename to karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/ListUrlCommand.java
index 10389b7..e9c5306 100644
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/ListUrlCommand.java
+++ b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/ListUrlCommand.java
@@ -14,10 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.karaf.gshell.features.commands;
+package org.apache.felix.karaf.features.command;
 
-import org.apache.felix.karaf.gshell.features.FeaturesService;
-import org.apache.felix.karaf.gshell.features.Repository;
+import org.apache.felix.karaf.features.FeaturesService;
+import org.apache.felix.karaf.features.Repository;
+
 
 public class ListUrlCommand extends FeaturesCommandSupport {
 
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/RefreshUrlCommand.java b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/RefreshUrlCommand.java
similarity index 90%
rename from karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/RefreshUrlCommand.java
rename to karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/RefreshUrlCommand.java
index 25fe4f4..45b400d 100644
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/RefreshUrlCommand.java
+++ b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/RefreshUrlCommand.java
@@ -14,16 +14,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.karaf.gshell.features.commands;
+package org.apache.felix.karaf.features.command;
 
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.felix.karaf.gshell.features.FeaturesService;
-import org.apache.felix.karaf.gshell.features.Repository;
 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 {
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/RemoveUrlCommand.java b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/RemoveUrlCommand.java
similarity index 91%
rename from karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/RemoveUrlCommand.java
rename to karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/RemoveUrlCommand.java
index 8157deb..17db749 100644
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/RemoveUrlCommand.java
+++ b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/RemoveUrlCommand.java
@@ -14,14 +14,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.karaf.gshell.features.commands;
+package org.apache.felix.karaf.features.command;
 
 import java.net.URI;
 import java.util.List;
 
-import org.apache.felix.karaf.gshell.features.FeaturesService;
 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 {
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/UninstallFeatureCommand.java b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/UninstallFeatureCommand.java
similarity index 92%
rename from karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/UninstallFeatureCommand.java
rename to karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/UninstallFeatureCommand.java
index b0c172e..229d43c 100644
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/UninstallFeatureCommand.java
+++ b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/UninstallFeatureCommand.java
@@ -14,11 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.karaf.gshell.features.commands;
+package org.apache.felix.karaf.features.command;
 
-import org.apache.felix.karaf.gshell.features.FeaturesService;
 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 {
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/completers/AvailableFeatureCompleter.java b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/completers/AvailableFeatureCompleter.java
similarity index 64%
rename from karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/completers/AvailableFeatureCompleter.java
rename to karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/completers/AvailableFeatureCompleter.java
index a9855df..0a826c6 100644
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/completers/AvailableFeatureCompleter.java
+++ b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/completers/AvailableFeatureCompleter.java
@@ -14,15 +14,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.karaf.gshell.features.completers;
+package org.apache.felix.karaf.features.command.completers;
 
-import java.util.Collection;
 import java.util.List;
 
-import org.apache.felix.karaf.gshell.features.management.ManagedFeature;
-import org.apache.felix.karaf.gshell.features.management.ManagedFeaturesRegistry;
 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.
@@ -32,22 +31,21 @@
  */
 public class AvailableFeatureCompleter implements Completer {
 
-    private ManagedFeaturesRegistry featuresRegistry;
-    private StringsCompleter delegate;
+    private FeaturesService featuresService;
 
-    public void setFeaturesRegistry(ManagedFeaturesRegistry featuresRegistry) {
-        this.featuresRegistry = featuresRegistry;
+    public void setFeaturesService(FeaturesService featuresService) {
+        this.featuresService = featuresService;
     }
 
     public int complete(final String buffer, final int cursor, final List candidates) {
-
-        Collection<ManagedFeature> features = featuresRegistry.getAvailableFeatures().values();
-        delegate = new StringsCompleter();
-
-        for (ManagedFeature feature : features) {
-            delegate.getStrings().add(feature.getName());
+        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/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/completers/FeatureRepositoryCompleter.java b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/completers/FeatureRepositoryCompleter.java
similarity index 67%
rename from karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/completers/FeatureRepositoryCompleter.java
rename to karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/completers/FeatureRepositoryCompleter.java
index 6c6f7be..80a8b79 100644
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/completers/FeatureRepositoryCompleter.java
+++ b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/completers/FeatureRepositoryCompleter.java
@@ -14,13 +14,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.karaf.gshell.features.completers;
+package org.apache.felix.karaf.features.command.completers;
 
 import java.util.List;
 
-import org.apache.felix.karaf.gshell.features.management.ManagedFeaturesRegistry;
 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.
@@ -31,14 +32,21 @@
 
 public class FeatureRepositoryCompleter implements Completer {
 
-    private ManagedFeaturesRegistry featuresRegistry;
+    private FeaturesService featuresService;
 
-    public void setFeaturesRegistry(ManagedFeaturesRegistry featuresRegistry) {
-        this.featuresRegistry = featuresRegistry;
+    public void setFeaturesService(FeaturesService featuresService) {
+        this.featuresService = featuresService;
     }
 
     public int complete(final String buffer, final int cursor, final List candidates) {
-        StringsCompleter delegate = new StringsCompleter(featuresRegistry.getRepositories().keySet());
+        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/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/completers/InstalledFeatureCompleter.java b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/completers/InstalledFeatureCompleter.java
similarity index 64%
rename from karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/completers/InstalledFeatureCompleter.java
rename to karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/completers/InstalledFeatureCompleter.java
index 8f03998..ba538c7 100644
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/completers/InstalledFeatureCompleter.java
+++ b/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/completers/InstalledFeatureCompleter.java
@@ -14,15 +14,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.karaf.gshell.features.completers;
+package org.apache.felix.karaf.features.command.completers;
 
-import java.util.Collection;
 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.gshell.features.management.ManagedFeature;
-import org.apache.felix.karaf.gshell.features.management.ManagedFeaturesRegistry;
+import org.apache.felix.karaf.features.FeaturesService;
+import org.apache.felix.karaf.features.Feature;
 
 /**
  * {@link jline.Completor} for installed features.
@@ -32,23 +31,22 @@
  */
 public class InstalledFeatureCompleter implements Completer {
 
-    private ManagedFeaturesRegistry featuresRegistry;
-    private StringsCompleter delegate;
+    private FeaturesService featuresService;
 
-    public void setFeaturesRegistry(ManagedFeaturesRegistry featuresRegistry) {
-        this.featuresRegistry = featuresRegistry;
+    public void setFeaturesService(FeaturesService featuresService) {
+        this.featuresService = featuresService;
     }
 
     public int complete(final String buffer, final int cursor, final List candidates) {
-        Collection<ManagedFeature> features = featuresRegistry.getInstalledFeatures().values();
-        delegate = new StringsCompleter();
-
-        for (ManagedFeature feature : features) {
-            delegate.getStrings().add(feature.getName());
+        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>
diff --git a/karaf/gshell/gshell-features/pom.xml b/karaf/features/core/pom.xml
similarity index 87%
copy from karaf/gshell/gshell-features/pom.xml
copy to karaf/features/core/pom.xml
index 38363b8..e7e03e7 100644
--- a/karaf/gshell/gshell-features/pom.xml
+++ b/karaf/features/core/pom.xml
@@ -22,20 +22,16 @@
     <modelVersion>4.0.0</modelVersion>
 
     <parent>
-        <groupId>org.apache.felix.karaf.gshell</groupId>
-        <artifactId>gshell</artifactId>
+        <groupId>org.apache.felix.karaf.features</groupId>
+        <artifactId>features</artifactId>
         <version>1.2.0-SNAPSHOT</version>
     </parent>
 
-    <groupId>org.apache.felix.karaf.gshell</groupId>
-    <artifactId>org.apache.felix.karaf.gshell.features</artifactId>
+    <groupId>org.apache.felix.karaf.features</groupId>
+    <artifactId>org.apache.felix.karaf.features.core</artifactId>
     <packaging>bundle</packaging>
     <version>1.2.0-SNAPSHOT</version>
-    <name>Apache Felix Karaf :: GShell Features</name>
-
-    <description>
-        Provides Features in GShell
-    </description>
+    <name>Apache Felix Karaf :: Features Core</name>
 
     <dependencies>
         <dependency>
@@ -95,7 +91,7 @@
                 <configuration>
                     <instructions>
                         <Bundle-SymbolicName>${artifactId}</Bundle-SymbolicName>
-                        <Export-Package>${pom.artifactId}*;version=${project.version}</Export-Package>
+                        <Export-Package>org.apache.felix.karaf.features;version=${project.version}</Export-Package>
                         <Import-Package>
                             javax.management,
                             javax.management.loading,
@@ -104,7 +100,7 @@
                             org.apache.felix.karaf.gshell.console,
                             *
                         </Import-Package>
-                        <Private-Package>!*</Private-Package>
+                        <Private-Package>org.apache.felix.karaf.features.internal</Private-Package>
                         <_versionpolicy>${bnd.version.policy}</_versionpolicy>
                     </instructions>
                 </configuration>
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/Feature.java b/karaf/features/core/src/main/java/org/apache/felix/karaf/features/Feature.java
similarity index 95%
rename from karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/Feature.java
rename to karaf/features/core/src/main/java/org/apache/felix/karaf/features/Feature.java
index e393dfa..6fc7f23 100644
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/Feature.java
+++ b/karaf/features/core/src/main/java/org/apache/felix/karaf/features/Feature.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.karaf.gshell.features;
+package org.apache.felix.karaf.features;
 
 import java.util.List;
 import java.util.Map;
diff --git a/karaf/features/core/src/main/java/org/apache/felix/karaf/features/FeatureEvent.java b/karaf/features/core/src/main/java/org/apache/felix/karaf/features/FeatureEvent.java
new file mode 100644
index 0000000..f368ff8
--- /dev/null
+++ b/karaf/features/core/src/main/java/org/apache/felix/karaf/features/FeatureEvent.java
@@ -0,0 +1,50 @@
+/*
+ * 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;
+
+import java.util.EventObject;
+
+public class FeatureEvent extends EventObject {
+
+    public static enum EventType {
+        FeatureInstalled,
+        FeatureUninstalled
+    }
+
+    private final EventType type;
+    private final Feature feature;
+    private final boolean replay;
+
+    public FeatureEvent(Feature feature, EventType type, boolean replay) {
+        super(feature);
+        this.type = type;
+        this.feature = feature;
+        this.replay = replay;
+    }
+
+    public EventType getType() {
+        return type;
+    }
+
+    public Feature getFeature() {
+        return feature;
+    }
+
+    public boolean isReplay() {
+        return replay;
+    }
+}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/Repository.java b/karaf/features/core/src/main/java/org/apache/felix/karaf/features/FeaturesListener.java
similarity index 75%
copy from karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/Repository.java
copy to karaf/features/core/src/main/java/org/apache/felix/karaf/features/FeaturesListener.java
index 8cede6a..1b54ed9 100644
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/Repository.java
+++ b/karaf/features/core/src/main/java/org/apache/felix/karaf/features/FeaturesListener.java
@@ -14,19 +14,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.karaf.gshell.features;
+package org.apache.felix.karaf.features;
 
-import java.net.URI;
+public interface FeaturesListener {
 
-/**
- * A repository of features.
- */
-public interface Repository {
+    void featureEvent(FeatureEvent event);
 
-    URI getURI();
-
-    URI[] getRepositories() throws Exception;
-
-    Feature[] getFeatures() throws Exception;
+    void repositoryEvent(RepositoryEvent event);
 
 }
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/FeaturesService.java b/karaf/features/core/src/main/java/org/apache/felix/karaf/features/FeaturesService.java
similarity index 90%
rename from karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/FeaturesService.java
rename to karaf/features/core/src/main/java/org/apache/felix/karaf/features/FeaturesService.java
index 0c5661c..de7c36a 100644
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/FeaturesService.java
+++ b/karaf/features/core/src/main/java/org/apache/felix/karaf/features/FeaturesService.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.karaf.gshell.features;
+package org.apache.felix.karaf.features;
 
 import java.net.URI;
 
@@ -37,8 +37,8 @@
     
     void uninstallFeature(String name, String version) throws Exception;
 
-    String[] listFeatures() throws Exception;
+    Feature[] listFeatures() throws Exception;
 
-    String[] listInstalledFeatures();
+    Feature[] listInstalledFeatures();
 
 }
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/Repository.java b/karaf/features/core/src/main/java/org/apache/felix/karaf/features/Repository.java
similarity index 95%
rename from karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/Repository.java
rename to karaf/features/core/src/main/java/org/apache/felix/karaf/features/Repository.java
index 8cede6a..25ffbad 100644
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/Repository.java
+++ b/karaf/features/core/src/main/java/org/apache/felix/karaf/features/Repository.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.karaf.gshell.features;
+package org.apache.felix.karaf.features;
 
 import java.net.URI;
 
diff --git a/karaf/features/core/src/main/java/org/apache/felix/karaf/features/RepositoryEvent.java b/karaf/features/core/src/main/java/org/apache/felix/karaf/features/RepositoryEvent.java
new file mode 100644
index 0000000..f62076a
--- /dev/null
+++ b/karaf/features/core/src/main/java/org/apache/felix/karaf/features/RepositoryEvent.java
@@ -0,0 +1,50 @@
+/*
+ * 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;
+
+import java.util.EventObject;
+
+public class RepositoryEvent extends EventObject {
+
+    public static enum EventType {
+        RepositoryAdded,
+        RepositoryRemoved,
+    }
+
+    private final EventType type;
+    private final Repository repository;
+    private final boolean replay;
+
+    public RepositoryEvent(Repository repository, EventType type, boolean replay) {
+        super(repository);
+        this.type = type;
+        this.repository = repository;
+        this.replay = replay;
+    }
+
+    public EventType getType() {
+        return type;
+    }
+
+    public Repository getRepository() {
+        return repository;
+    }
+
+    public boolean isReplay() {
+        return replay;
+    }
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/internal/FeatureImpl.java b/karaf/features/core/src/main/java/org/apache/felix/karaf/features/internal/FeatureImpl.java
similarity index 96%
rename from karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/internal/FeatureImpl.java
rename to karaf/features/core/src/main/java/org/apache/felix/karaf/features/internal/FeatureImpl.java
index ba206f4..0ae7c6b 100644
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/internal/FeatureImpl.java
+++ b/karaf/features/core/src/main/java/org/apache/felix/karaf/features/internal/FeatureImpl.java
@@ -14,14 +14,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.karaf.gshell.features.internal;
+package org.apache.felix.karaf.features.internal;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.felix.karaf.gshell.features.Feature;
+import org.apache.felix.karaf.features.Feature;
 
 /**
  * A feature
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/internal/FeaturesServiceImpl.java b/karaf/features/core/src/main/java/org/apache/felix/karaf/features/internal/FeaturesServiceImpl.java
similarity index 89%
rename from karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/internal/FeaturesServiceImpl.java
rename to karaf/features/core/src/main/java/org/apache/felix/karaf/features/internal/FeaturesServiceImpl.java
index 6f4fdd1..39a5e90 100644
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/internal/FeaturesServiceImpl.java
+++ b/karaf/features/core/src/main/java/org/apache/felix/karaf/features/internal/FeaturesServiceImpl.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.karaf.gshell.features.internal;
+package org.apache.felix.karaf.features.internal;
 
 import java.io.BufferedInputStream;
 import java.io.IOException;
@@ -31,15 +31,18 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.jar.JarInputStream;
 import java.util.jar.Manifest;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import org.apache.felix.karaf.gshell.features.Feature;
-import org.apache.felix.karaf.gshell.features.FeaturesRegistry;
-import org.apache.felix.karaf.gshell.features.FeaturesService;
-import org.apache.felix.karaf.gshell.features.Repository;
+import org.apache.felix.karaf.features.FeaturesService;
+import org.apache.felix.karaf.features.Feature;
+import org.apache.felix.karaf.features.Repository;
+import org.apache.felix.karaf.features.FeaturesListener;
+import org.apache.felix.karaf.features.FeatureEvent;
+import org.apache.felix.karaf.features.RepositoryEvent;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleException;
@@ -76,7 +79,7 @@
     private Map<Feature, Set<Long>> installed = new HashMap<Feature, Set<Long>>();
     private String boot;
     private boolean bootFeaturesInstalled;
-    private FeaturesRegistry featuresRegistry;
+    private List<FeaturesListener> listeners = new CopyOnWriteArrayList<FeaturesListener>();
 
     public BundleContext getBundleContext() {
         return bundleContext;
@@ -102,9 +105,18 @@
         this.preferences = preferences;
     }
 
-    public void setFeaturesServiceRegistry(FeaturesRegistry featuresRegistry) {
-        this.featuresRegistry = featuresRegistry;
-        this.featuresRegistry.setFeaturesService(this);
+    public void registerListener(FeaturesListener listener) {
+        listeners.add(listener);
+        for (Repository repository : listRepositories()) {
+            listener.repositoryEvent(new RepositoryEvent(repository, RepositoryEvent.EventType.RepositoryAdded, true));
+        }
+        for (Feature feature : listInstalledFeatures()) {
+            listener.featureEvent(new FeatureEvent(feature, FeatureEvent.EventType.FeatureInstalled, true));
+        }
+    }
+
+    public void unregisterListener(FeaturesListener listener) {
+        listeners.remove(listener);
     }
 
     public void setUrls(String uris) throws URISyntaxException {
@@ -129,7 +141,7 @@
     protected RepositoryImpl internalAddRepository(URI uri) throws Exception {
         RepositoryImpl repo = new RepositoryImpl(uri);
         repositories.put(uri, repo);
-        featuresRegistry.register(repo);
+        callListeners(new RepositoryEvent(repo, RepositoryEvent.EventType.RepositoryAdded, false));
         features = null;
         return repo;
     }
@@ -142,8 +154,8 @@
     }
 
     public void internalRemoveRepository(URI uri) {
-        featuresRegistry.unregister(repositories.get(uri));
-        repositories.remove(uri);
+        Repository repo = repositories.remove(uri);
+        callListeners(new RepositoryEvent(repo, RepositoryEvent.EventType.RepositoryRemoved, false));
         features = null;
     }
 
@@ -202,7 +214,7 @@
             bundleContext.getBundle(id).start();
         }
 
-        featuresRegistry.registerInstalled(f);
+        callListeners(new FeatureEvent(f, FeatureEvent.EventType.FeatureInstalled, false));
         installed.put(f, bundles);
         saveState();
     }
@@ -285,46 +297,23 @@
         for (long bundleId : bundles) {
             getBundleContext().getBundle(bundleId).uninstall();
         }
-        featuresRegistry.unregisterInstalled(feature);
+        callListeners(new FeatureEvent(feature, FeatureEvent.EventType.FeatureInstalled, false));
         saveState();
     }
 
-    public String[] listFeatures() throws Exception {
-        Collection<String> features = new ArrayList<String>();
+    public Feature[] listFeatures() throws Exception {
+        Collection<Feature> features = new ArrayList<Feature>();
         for (Map<String, Feature> featureWithDifferentVersion : getFeatures().values()) {
 			for (Feature f : featureWithDifferentVersion.values()) {
-				String installStatus = installed.containsKey(f) ? "installed  "
-						: "uninstalled";
-				String version = f.getVersion();
-				switch (version.length()) {
-				case 1:
-					version = "       " + version;
-				case 2:
-					version = "      " + version;
-				case 3:
-					version = "     " + version;
-				case 4:
-					version = "    " + version;
-				case 5:
-					version = "   " + version;
-				case 6:
-					version = "  " + version;
-				case 7:
-					version = " " + version;
-				}
-				features.add("[" + installStatus + "] " + " [" + version + "] "
-						+ f.getName());
-			}
-		}
-        return features.toArray(new String[features.size()]);
+                features.add(f);
+            }
+        }
+        return features.toArray(new Feature[features.size()]);
     }
 
-    public String[] listInstalledFeatures() {
-        List<String> result = new ArrayList<String>();
-        for (Feature feature : installed.keySet()) {
-            result.add(feature.getName());
-        }
-        return result.toArray(new String[result.size()]);
+    public Feature[] listInstalledFeatures() {
+        Set<Feature> result = installed.keySet();
+        return result.toArray(new Feature[result.size()]);
     }
 
     protected Feature getFeature(String name, String version) throws Exception {
@@ -470,7 +459,7 @@
                 }
                 installed = loadMap(prefs.node("features"));
                 for (Feature f : installed.keySet()) {
-                    featuresRegistry.registerInstalled(f);
+                    callListeners(new FeatureEvent(f, FeatureEvent.EventType.FeatureInstalled, true));
                 }
                 bootFeaturesInstalled = prefs.getBoolean("bootFeaturesInstalled", false);
                 return true;
@@ -537,6 +526,18 @@
         return set;
     }
 
+    protected void callListeners(FeatureEvent event) {
+        for (FeaturesListener listener : listeners) {
+            listener.featureEvent(event);
+        }
+    }
+
+    protected void callListeners(RepositoryEvent event) {
+        for (FeaturesListener listener : listeners) {
+            listener.repositoryEvent(event);
+        }
+    }
+
     static Pattern fuzzyVersion  = Pattern.compile("(\\d+)(\\.(\\d+)(\\.(\\d+))?)?([^a-zA-Z0-9](.*))?",
                                                    Pattern.DOTALL);
     static Pattern fuzzyModifier = Pattern.compile("(\\d+[.-])*(.*)",
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/internal/RepositoryImpl.java b/karaf/features/core/src/main/java/org/apache/felix/karaf/features/internal/RepositoryImpl.java
similarity index 97%
rename from karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/internal/RepositoryImpl.java
rename to karaf/features/core/src/main/java/org/apache/felix/karaf/features/internal/RepositoryImpl.java
index ffd6ce2..0d413c3 100644
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/internal/RepositoryImpl.java
+++ b/karaf/features/core/src/main/java/org/apache/felix/karaf/features/internal/RepositoryImpl.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.karaf.gshell.features.internal;
+package org.apache.felix.karaf.features.internal;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
@@ -38,8 +38,8 @@
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
-import org.apache.felix.karaf.gshell.features.Feature;
-import org.apache.felix.karaf.gshell.features.Repository;
+import org.apache.felix.karaf.features.Repository;
+import org.apache.felix.karaf.features.Feature;
 import org.xml.sax.SAXException;
 
 /**
diff --git a/karaf/features/core/src/main/resources/OSGI-INF/blueprint/gshell-features.xml b/karaf/features/core/src/main/resources/OSGI-INF/blueprint/gshell-features.xml
new file mode 100644
index 0000000..0d7e2c4
--- /dev/null
+++ b/karaf/features/core/src/main/resources/OSGI-INF/blueprint/gshell-features.xml
@@ -0,0 +1,53 @@
+<?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">
+
+    <ext:property-placeholder placeholder-prefix="$(" placeholder-suffix=")"/>
+
+    <ext:property-placeholder placeholder-prefix="$[" placeholder-suffix="]" ignore-missing-locations="true">
+        <ext:default-properties>
+            <ext:property name="featuresRepositories" value=""/>
+            <ext:property name="featuresBoot" value=""/>
+        </ext:default-properties>
+        <ext:location>file:$(karaf.home)/etc/org.apache.felix.karaf.features.cfg</ext:location>
+    </ext:property-placeholder>
+
+    <bean id="featuresService" class="org.apache.felix.karaf.features.internal.FeaturesServiceImpl" init-method="start" destroy-method="stop">
+        <property name="urls" value="$[featuresRepositories]" />
+        <property name="boot" value="$[featuresBoot]" />
+        <property name="configAdmin" ref="configAdmin" />
+        <property name="preferences" ref="preferences" />
+        <property name="bundleContext" ref="blueprintBundleContext" />
+    </bean>
+
+    <reference-list id="featuresListeners" interface="org.apache.felix.karaf.features.FeaturesListener" availability="optional">
+        <reference-listener ref="featuresService"
+                            bind-method="registerListener"
+                            unbind-method="unregisterListener" />
+    </reference-list>
+
+    <reference id="configAdmin" interface="org.osgi.service.cm.ConfigurationAdmin" />
+
+    <reference id="preferences" interface="org.osgi.service.prefs.PreferencesService" availability="optional"/>
+
+    <service ref="featuresService" interface="org.apache.felix.karaf.features.FeaturesService" />
+
+</blueprint>
diff --git a/karaf/gshell/gshell-features/src/test/java/org/apache/felix/karaf/gshell/features/FeatureTest.java b/karaf/features/core/src/test/java/org/apache/felix/karaf/features/FeatureTest.java
similarity index 91%
rename from karaf/gshell/gshell-features/src/test/java/org/apache/felix/karaf/gshell/features/FeatureTest.java
rename to karaf/features/core/src/test/java/org/apache/felix/karaf/features/FeatureTest.java
index 808307d..bd88118 100644
--- a/karaf/gshell/gshell-features/src/test/java/org/apache/felix/karaf/gshell/features/FeatureTest.java
+++ b/karaf/features/core/src/test/java/org/apache/felix/karaf/features/FeatureTest.java
@@ -14,10 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.karaf.gshell.features;
+package org.apache.felix.karaf.features;
 
 import junit.framework.TestCase;
-import org.apache.felix.karaf.gshell.features.internal.FeatureImpl;
+import org.apache.felix.karaf.features.internal.FeatureImpl;
 
 public class FeatureTest extends TestCase {
 	
diff --git a/karaf/gshell/gshell-features/src/test/java/org/apache/felix/karaf/gshell/features/FeaturesServiceTest.java b/karaf/features/core/src/test/java/org/apache/felix/karaf/features/FeaturesServiceTest.java
similarity index 93%
rename from karaf/gshell/gshell-features/src/test/java/org/apache/felix/karaf/gshell/features/FeaturesServiceTest.java
rename to karaf/features/core/src/test/java/org/apache/felix/karaf/features/FeaturesServiceTest.java
index d68bcda..0fcec78 100644
--- a/karaf/gshell/gshell-features/src/test/java/org/apache/felix/karaf/gshell/features/FeaturesServiceTest.java
+++ b/karaf/features/core/src/test/java/org/apache/felix/karaf/features/FeaturesServiceTest.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.karaf.gshell.features;
+package org.apache.felix.karaf.features;
 
 import java.io.File;
 import java.io.FileWriter;
@@ -23,9 +23,8 @@
 import java.net.URI;
 
 import junit.framework.TestCase;
-import org.apache.felix.karaf.gshell.features.internal.FeatureImpl;
-import org.apache.felix.karaf.gshell.features.internal.FeaturesServiceImpl;
-import org.apache.felix.karaf.gshell.features.management.ManagedFeaturesRegistry;
+import org.apache.felix.karaf.features.internal.FeaturesServiceImpl;
+import org.apache.felix.karaf.features.internal.FeatureImpl;
 import org.easymock.EasyMock;
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.isA;
@@ -64,7 +63,6 @@
         Preferences featuresNode = EasyMock.createMock(Preferences.class);
         BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
         Bundle installedBundle = EasyMock.createMock(Bundle.class);
-        FeaturesRegistry featuresRegistry = EasyMock.createNiceMock(FeaturesRegistry.class);
 
         expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
         expect(prefs.node("repositories")).andReturn(repositoriesNode);
@@ -75,14 +73,12 @@
         featuresNode.clear();
         prefs.putBoolean("bootFeaturesInstalled", false);
         prefs.flush();
-        featuresRegistry.register(isA(Repository.class));
 
-        replay(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle, featuresRegistry);
+        replay(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle);
 
         FeaturesServiceImpl svc = new FeaturesServiceImpl();
         svc.setPreferences(preferencesService);
         svc.setBundleContext(bundleContext);
-        svc.setFeaturesServiceRegistry(featuresRegistry);
         svc.addRepository(uri);
         
         Repository[] repositories = svc.listRepositories();
@@ -100,9 +96,9 @@
         assertEquals(1, features[0].getBundles().size());
         assertEquals(name, features[0].getBundles().get(0));
 
-        verify(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle, featuresRegistry);
+        verify(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle);
 
-        reset(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle, featuresRegistry);
+        reset(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle);
 
         expect(bundleContext.getBundles()).andReturn(new Bundle[0]);
         expect(bundleContext.installBundle(isA(String.class),
@@ -126,9 +122,9 @@
 
         svc.installFeature("f1");
         
-        String[] installed = svc.listInstalledFeatures();
+        Feature[] installed = svc.listInstalledFeatures();
         assertEquals(1, installed.length);
-        assertEquals("f1", installed[0]);
+        assertEquals("f1", installed[0].getName());
     }
 
     public void testUninstallFeature() throws Exception {
@@ -158,7 +154,6 @@
         Preferences featuresNode = EasyMock.createMock(Preferences.class);
         BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
         Bundle installedBundle = EasyMock.createMock(Bundle.class);
-        FeaturesRegistry featuresRegistry = EasyMock.createNiceMock(FeaturesRegistry.class);
 
         expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
         expect(prefs.node("repositories")).andReturn(repositoriesNode);
@@ -169,19 +164,17 @@
         featuresNode.clear();
         prefs.putBoolean("bootFeaturesInstalled", false);
         prefs.flush();
-        featuresRegistry.register(isA(Repository.class));
 
-        replay(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle, featuresRegistry);
+        replay(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle);
 
         FeaturesServiceImpl svc = new FeaturesServiceImpl();
         svc.setPreferences(preferencesService);
         svc.setBundleContext(bundleContext);
-        svc.setFeaturesServiceRegistry(featuresRegistry);
         svc.addRepository(uri);
         
-        verify(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle, featuresRegistry);
+        verify(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle);
 
-        reset(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle, featuresRegistry);
+        reset(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle);
 
         // Installs f1 and 0.1
         expect(bundleContext.getBundles()).andReturn(new Bundle[0]);
@@ -306,7 +299,6 @@
         Preferences featuresNode = EasyMock.createMock(Preferences.class);
         BundleContext bundleContext = EasyMock.createMock(BundleContext.class);        
         Bundle installedBundle = EasyMock.createMock(Bundle.class);        
-        FeaturesRegistry featuresRegistry = EasyMock.createNiceMock(FeaturesRegistry.class);
 
         expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
         expect(prefs.node("repositories")).andReturn(repositoriesNode);
@@ -318,8 +310,6 @@
         prefs.putBoolean("bootFeaturesInstalled", false);
         prefs.flush();
         
-        featuresRegistry.register(isA(Repository.class));
-        
         // SaveState for addRepository
         expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
         expect(prefs.node("repositories")).andReturn(repositoriesNode);
@@ -340,13 +330,12 @@
         featuresNode.clear();        
         prefs.putBoolean("bootFeaturesInstalled", false);
         prefs.flush();
-        replay(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle, featuresRegistry);
+        replay(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle);
 
         FeaturesServiceImpl svc = new FeaturesServiceImpl();
         svc.setPreferences(preferencesService);
         svc.setBundleContext(bundleContext);        
-        svc.setFeaturesServiceRegistry(featuresRegistry);
-        
+
         // Adds Repository
         svc.addRepository(uri);                                                     
         
@@ -387,7 +376,6 @@
         Preferences featuresNode = EasyMock.createMock(Preferences.class);
         BundleContext bundleContext = EasyMock.createMock(BundleContext.class);        
         Bundle installedBundle = EasyMock.createMock(Bundle.class);        
-        FeaturesRegistry featuresRegistry = EasyMock.createNiceMock(FeaturesRegistry.class);
 
         expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
         expect(prefs.node("repositories")).andReturn(repositoriesNode);
@@ -542,13 +530,12 @@
         prefs.putBoolean("bootFeaturesInstalled", false);
         prefs.flush();
 
-        replay(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle, featuresRegistry);
+        replay(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle);
 
         FeaturesServiceImpl svc = new FeaturesServiceImpl();
         svc.setPreferences(preferencesService);
         svc.setBundleContext(bundleContext);        
-        svc.setFeaturesServiceRegistry(featuresRegistry);                
-        svc.installAllFeatures(uri);                            
+        svc.installAllFeatures(uri);
         
         // Uninstalls features with versions.
         svc.uninstallAllFeatures(uri);    
@@ -589,7 +576,6 @@
         Preferences featuresNode = EasyMock.createMock(Preferences.class);
         BundleContext bundleContext = EasyMock.createMock(BundleContext.class);        
         Bundle installedBundle = EasyMock.createMock(Bundle.class);        
-        FeaturesRegistry featuresRegistry = EasyMock.createNiceMock(FeaturesRegistry.class);        
 
         // savestate from addRepository
         expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
@@ -681,12 +667,11 @@
         prefs.putBoolean("bootFeaturesInstalled", false);
         prefs.flush();                        
         
-        replay(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle, featuresRegistry);
+        replay(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle);
 
         FeaturesServiceImpl svc = new FeaturesServiceImpl();
         svc.setPreferences(preferencesService);
         svc.setBundleContext(bundleContext);        
-        svc.setFeaturesServiceRegistry(featuresRegistry);                
         svc.addRepository(uri);    
 
         svc.installFeature("f1", "0.1");
diff --git a/karaf/gshell/gshell-features/src/test/java/org/apache/felix/karaf/gshell/features/RepositoryTest.java b/karaf/features/core/src/test/java/org/apache/felix/karaf/features/RepositoryTest.java
similarity index 94%
rename from karaf/gshell/gshell-features/src/test/java/org/apache/felix/karaf/gshell/features/RepositoryTest.java
rename to karaf/features/core/src/test/java/org/apache/felix/karaf/features/RepositoryTest.java
index d18d00f..737acaf 100644
--- a/karaf/gshell/gshell-features/src/test/java/org/apache/felix/karaf/gshell/features/RepositoryTest.java
+++ b/karaf/features/core/src/test/java/org/apache/felix/karaf/features/RepositoryTest.java
@@ -14,13 +14,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.karaf.gshell.features;
+package org.apache.felix.karaf.features;
 
 import java.net.URI;
 
 import junit.framework.TestCase;
-import org.apache.felix.karaf.gshell.features.internal.FeatureImpl;
-import org.apache.felix.karaf.gshell.features.internal.RepositoryImpl;
+import org.apache.felix.karaf.features.internal.RepositoryImpl;
+import org.apache.felix.karaf.features.internal.FeatureImpl;
 
 
 public class RepositoryTest extends TestCase {
diff --git a/karaf/gshell/gshell-features/src/test/java/org/apache/felix/karaf/gshell/features/internal/FeaturesServiceImplTest.java b/karaf/features/core/src/test/java/org/apache/felix/karaf/features/internal/FeaturesServiceImplTest.java
similarity index 96%
rename from karaf/gshell/gshell-features/src/test/java/org/apache/felix/karaf/gshell/features/internal/FeaturesServiceImplTest.java
rename to karaf/features/core/src/test/java/org/apache/felix/karaf/features/internal/FeaturesServiceImplTest.java
index 89e86c4..8c8cb10 100644
--- a/karaf/gshell/gshell-features/src/test/java/org/apache/felix/karaf/gshell/features/internal/FeaturesServiceImplTest.java
+++ b/karaf/features/core/src/test/java/org/apache/felix/karaf/features/internal/FeaturesServiceImplTest.java
@@ -14,13 +14,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.karaf.gshell.features.internal;
+package org.apache.felix.karaf.features.internal;
 
 import java.util.HashMap;
 import java.util.Map;
 
 import junit.framework.TestCase;
-import org.apache.felix.karaf.gshell.features.Feature;
+import org.apache.felix.karaf.features.Feature;
 
 /**
  * Test cases for {@link FeaturesServiceImpl}
diff --git a/karaf/gshell/gshell-features/src/test/resources/org/apache/felix/karaf/gshell/features/repo1.xml b/karaf/features/core/src/test/resources/org/apache/felix/karaf/features/repo1.xml
similarity index 100%
rename from karaf/gshell/gshell-features/src/test/resources/org/apache/felix/karaf/gshell/features/repo1.xml
rename to karaf/features/core/src/test/resources/org/apache/felix/karaf/features/repo1.xml
diff --git a/karaf/gshell/gshell-features/pom.xml b/karaf/features/management/pom.xml
similarity index 83%
copy from karaf/gshell/gshell-features/pom.xml
copy to karaf/features/management/pom.xml
index 38363b8..6490511 100644
--- a/karaf/gshell/gshell-features/pom.xml
+++ b/karaf/features/management/pom.xml
@@ -22,20 +22,16 @@
     <modelVersion>4.0.0</modelVersion>
 
     <parent>
-        <groupId>org.apache.felix.karaf.gshell</groupId>
-        <artifactId>gshell</artifactId>
+        <groupId>org.apache.felix.karaf.features</groupId>
+        <artifactId>features</artifactId>
         <version>1.2.0-SNAPSHOT</version>
     </parent>
 
-    <groupId>org.apache.felix.karaf.gshell</groupId>
-    <artifactId>org.apache.felix.karaf.gshell.features</artifactId>
+    <groupId>org.apache.felix.karaf.features</groupId>
+    <artifactId>org.apache.felix.karaf.features.management</artifactId>
     <packaging>bundle</packaging>
     <version>1.2.0-SNAPSHOT</version>
-    <name>Apache Felix Karaf :: GShell Features</name>
-
-    <description>
-        Provides Features in GShell
-    </description>
+    <name>Apache Felix Karaf :: Features Management</name>
 
     <dependencies>
         <dependency>
@@ -51,6 +47,11 @@
         </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>
@@ -95,16 +96,19 @@
                 <configuration>
                     <instructions>
                         <Bundle-SymbolicName>${artifactId}</Bundle-SymbolicName>
-                        <Export-Package>${pom.artifactId}*;version=${project.version}</Export-Package>
+                        <Export-Package>
+                            ${artifactId}*;version=${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,
+                            !${artifactId}*,
                             *
                         </Import-Package>
-                        <Private-Package>!*</Private-Package>
+                        <Private-Package>org.apache.felix.karaf.features.management.internal</Private-Package>
                         <_versionpolicy>${bnd.version.policy}</_versionpolicy>
                     </instructions>
                 </configuration>
diff --git a/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/FeaturesServiceMBean.java b/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/FeaturesServiceMBean.java
new file mode 100644
index 0000000..dac88da
--- /dev/null
+++ b/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/FeaturesServiceMBean.java
@@ -0,0 +1,114 @@
+/*
+ * 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.management;
+
+import javax.management.openmbean.TabularData;
+
+public interface FeaturesServiceMBean {
+
+    TabularData getFeatures() throws Exception;
+
+    TabularData getRepositories() throws Exception;
+
+    void addRepository(String url) throws Exception;
+
+    void removeRepositroy(String url) throws Exception;
+
+    void installFeature(String name) throws Exception;
+
+    void installFeature(String name, String version) throws Exception;
+
+    void uninstallFeature(String name) throws Exception;
+
+    void uninstallFeature(String name, String version) throws Exception;
+
+    String FEATURE_NAME = "Name";
+
+    String FEATURE_VERSION = "Version";
+
+    String FEATURE_DEPENDENCIES = "Dependencies";
+
+    String FEATURE_BUNDLES = "Bundles";
+
+    String FEATURE_CONFIGURATIONS = "Configurations";
+
+    String FEATURE_INSTALLED = "Installed";
+
+    String FEATURE_CONFIG_PID = "Pid";
+    String FEATURE_CONFIG_ELEMENTS = "Elements";
+    String FEATURE_CONFIG_ELEMENT_KEY = "Key";
+    String FEATURE_CONFIG_ELEMENT_VALUE = "Value";
+
+    /**
+     * The type of the event which is emitted for features events
+     */
+    String FEATURE_EVENT_TYPE = "org.apache.felix.karaf.features.featureEvent";
+
+    String FEATURE_EVENT_EVENT_TYPE = "Type";
+
+    String FEATURE_EVENT_EVENT_TYPE_INSTALLED = "Installed";
+
+    String FEATURE_EVENT_EVENT_TYPE_UNINSTALLED = "Uninstalled";
+
+    /**
+     * The item names in the CompositeData representing a feature
+     */
+    String[] FEATURE = { FEATURE_NAME, FEATURE_VERSION, FEATURE_DEPENDENCIES, FEATURE_BUNDLES,
+                         FEATURE_CONFIGURATIONS, FEATURE_INSTALLED };
+
+    String[] FEATURE_IDENTIFIER = { FEATURE_NAME, FEATURE_VERSION };
+
+    String[] FEATURE_CONFIG = { FEATURE_CONFIG_PID, FEATURE_CONFIG_ELEMENTS };
+
+    String[] FEATURE_CONFIG_ELEMENT = { FEATURE_CONFIG_ELEMENT_KEY, FEATURE_CONFIG_ELEMENT_VALUE };
+
+    /**
+     * The item names in the CompositeData representing the event raised for
+     * feature events within the OSGi container by this bean
+     */
+    String[] FEATURE_EVENT = { FEATURE_NAME, FEATURE_VERSION, FEATURE_EVENT_EVENT_TYPE };
+
+
+    String REPOSITORY_URI = "Uri";
+
+    String REPOSITORY_REPOSITORIES = "Repositories";
+
+    String REPOSITORY_FEATURES = "Features";
+
+    /**
+     * The type of the event which is emitted for repositories events
+     */
+    String REPOSITORY_EVENT_TYPE = "org.apache.felix.karaf.features.repositoryEvent";
+
+    String REPOSITORY_EVENT_EVENT_TYPE = "Type";
+
+    String REPOSITORY_EVENT_EVENT_TYPE_ADDED = "Added";
+
+    String REPOSITORY_EVENT_EVENT_TYPE_REMOVED = "Removed";
+
+    /**
+     * The item names in the CompositeData representing a feature
+     */
+    String[] REPOSITORY = { REPOSITORY_URI,  REPOSITORY_REPOSITORIES, REPOSITORY_FEATURES };
+
+    /**
+     * The item names in the CompositeData representing the event raised for
+     * feature events within the OSGi container by this bean
+     */
+    String[] REPOSITORY_EVENT = { REPOSITORY_URI, REPOSITORY_EVENT_EVENT_TYPE };
+
+}
diff --git a/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxFeature.java b/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxFeature.java
new file mode 100644
index 0000000..f471282
--- /dev/null
+++ b/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxFeature.java
@@ -0,0 +1,259 @@
+/*
+ * 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.management.codec;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.TabularDataSupport;
+
+import org.apache.felix.karaf.features.Feature;
+import org.apache.felix.karaf.features.management.FeaturesServiceMBean;
+
+public class JmxFeature {
+
+    /**
+     * The CompositeType which represents a single feature
+     */
+    public final static CompositeType FEATURE;
+
+    /**
+     * The TabularType which represents a list of features
+     */
+    public final static TabularType FEATURE_TABLE;
+
+    public final static CompositeType FEATURE_IDENTIFIER;
+
+    public final static TabularType FEATURE_IDENTIFIER_TABLE;
+
+    public final static CompositeType FEATURE_CONFIG_ELEMENT;
+
+    public final static TabularType FEATURE_CONFIG_ELEMENT_TABLE;
+
+    public final static CompositeType FEATURE_CONFIG;
+
+    public final static TabularType FEATURE_CONFIG_TABLE;
+
+
+    private final CompositeData data;
+
+    public JmxFeature(Feature feature, boolean installed) {
+        try {
+            String[] itemNames = FeaturesServiceMBean.FEATURE;
+            Object[] itemValues = new Object[itemNames.length];
+            itemValues[0] = feature.getName();
+            itemValues[1] = feature.getVersion();
+            itemValues[2] = getFeatureIdentifierTable(feature.getDependencies());
+            itemValues[3] = feature.getBundles().toArray(new String[feature.getBundles().size()]);
+            itemValues[4]  = getConfigTable(feature.getConfigurations());
+            itemValues[5] = installed;
+            data = new CompositeDataSupport(FEATURE, itemNames, itemValues);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Cannot form feature open data", e);
+        }
+    }
+
+    public CompositeData asCompositeData() {
+        return data;
+    }
+
+    public static TabularData tableFrom(Collection<JmxFeature> features) {
+        TabularDataSupport table = new TabularDataSupport(FEATURE_TABLE);
+        for (JmxFeature feature : features) {
+            table.put(feature.asCompositeData());
+        }
+        return table;
+    }
+
+    static TabularData getFeatureIdentifierTable(List<Feature> features) throws OpenDataException {
+        TabularDataSupport table = new TabularDataSupport(FEATURE_IDENTIFIER_TABLE);
+        for (Feature feature : features) {
+            String[] itemNames = new String[] { FeaturesServiceMBean.FEATURE_NAME, FeaturesServiceMBean.FEATURE_VERSION };
+            Object[] itemValues = new Object[] { feature.getName(), feature.getVersion() };
+            CompositeData ident = new CompositeDataSupport(FEATURE_IDENTIFIER, itemNames, itemValues);
+            table.put(ident);
+        }
+        return table;
+    }
+
+    static TabularData getConfigTable(Map<String, Map<String, String>> configs) throws OpenDataException {
+        TabularDataSupport table = new TabularDataSupport(FEATURE_CONFIG_TABLE);
+        for (Map.Entry<String, Map<String, String>> entry : configs.entrySet()) {
+            String[] itemNames = FeaturesServiceMBean.FEATURE_CONFIG;
+            Object[] itemValues = new Object[2];
+            itemValues[0] = entry.getKey();
+            itemValues[1] = getConfigElementTable(entry.getValue());
+            CompositeData config = new CompositeDataSupport(FEATURE_CONFIG, itemNames, itemValues);
+            table.put(config);
+        }
+        return table;
+    }
+
+    static TabularData getConfigElementTable(Map<String, String> config) throws OpenDataException {
+        TabularDataSupport table = new TabularDataSupport(FEATURE_CONFIG_ELEMENT_TABLE);
+        for (Map.Entry<String, String> entry : config.entrySet()) {
+            String[] itemNames = FeaturesServiceMBean.FEATURE_CONFIG_ELEMENT;
+            Object[] itemValues = { entry.getKey(), entry.getValue() };
+            CompositeData element = new CompositeDataSupport(FEATURE_CONFIG_ELEMENT, itemNames, itemValues);
+            table.put(element);
+        }
+        return table;
+    }
+
+
+    static {
+        FEATURE_IDENTIFIER = createFeatureIdentifierType();
+        FEATURE_IDENTIFIER_TABLE = createFeatureIdentifierTableType();
+        FEATURE_CONFIG_ELEMENT = createFeatureConfigElementType();
+        FEATURE_CONFIG_ELEMENT_TABLE = createFeatureConfigElementTableType();
+        FEATURE_CONFIG = createFeatureConfigType();
+        FEATURE_CONFIG_TABLE = createFeatureConfigTableType();
+        FEATURE = createFeatureType();
+        FEATURE_TABLE = createFeatureTableType();
+    }
+
+    private static CompositeType createFeatureIdentifierType() {
+        try {
+            String description = "This type identify a Karaf features";
+            String[] itemNames = FeaturesServiceMBean.FEATURE_IDENTIFIER;
+            OpenType[] itemTypes = new OpenType[itemNames.length];
+            String[] itemDescriptions = new String[itemNames.length];
+            itemTypes[0] = SimpleType.STRING;
+            itemTypes[1] = SimpleType.STRING;
+
+            itemDescriptions[0] = "The id of the feature";
+            itemDescriptions[1] = "The version of the feature";
+
+            return new CompositeType("FeatureIdentifier", description, itemNames,
+                    itemDescriptions, itemTypes);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build featureIdentifier type", e);
+        }
+    }
+
+    private static TabularType createFeatureIdentifierTableType() {
+        try {
+            return new TabularType("Features", "The table of featureIdentifiers",
+                    FEATURE_IDENTIFIER, new String[] { FeaturesServiceMBean.FEATURE_NAME, FeaturesServiceMBean.FEATURE_VERSION });
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build featureIdentifier table type", e);
+        }
+    }
+
+    private static CompositeType createFeatureConfigElementType() {
+        try {
+            String description = "This type encapsulates Karaf feature config element";
+            String[] itemNames = FeaturesServiceMBean.FEATURE_CONFIG_ELEMENT;
+            OpenType[] itemTypes = new OpenType[itemNames.length];
+            String[] itemDescriptions = new String[itemNames.length];
+            itemTypes[0] = SimpleType.STRING;
+            itemTypes[1] = SimpleType.STRING;
+
+            itemDescriptions[0] = "The key";
+            itemDescriptions[1] = "The value";
+
+            return new CompositeType("ConfigElement", description, itemNames,
+                    itemDescriptions, itemTypes);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build configElement type", e);
+        }
+    }
+
+    private static TabularType createFeatureConfigElementTableType() {
+        try {
+            return new TabularType("ConfigElement", "The table of configurations elements",
+                    FEATURE_CONFIG_ELEMENT, new String[] { FeaturesServiceMBean.FEATURE_CONFIG_ELEMENT_KEY});
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build feature table type", e);
+        }
+    }
+
+    private static CompositeType createFeatureConfigType() {
+        try {
+            String description = "This type encapsulates Karaf feature config";
+            String[] itemNames = FeaturesServiceMBean.FEATURE_CONFIG;
+            OpenType[] itemTypes = new OpenType[itemNames.length];
+            String[] itemDescriptions = new String[itemNames.length];
+            itemTypes[0] = SimpleType.STRING;
+            itemTypes[1] = FEATURE_CONFIG_ELEMENT_TABLE;
+
+            itemDescriptions[0] = "The PID of the config";
+            itemDescriptions[1] = "The configuration elements";
+
+            return new CompositeType("Config", description, itemNames,
+                    itemDescriptions, itemTypes);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build configElement type", e);
+        }
+    }
+
+    private static TabularType createFeatureConfigTableType() {
+        try {
+            return new TabularType("Features", "The table of configurations",
+                    FEATURE_CONFIG, new String[] { FeaturesServiceMBean.FEATURE_CONFIG_PID});
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build feature table type", e);
+        }
+    }
+
+    private static CompositeType createFeatureType() {
+        try {
+            String description = "This type encapsulates Karaf features";
+            String[] itemNames = FeaturesServiceMBean.FEATURE;
+            OpenType[] itemTypes = new OpenType[itemNames.length];
+            String[] itemDescriptions = new String[itemNames.length];
+            itemTypes[0] = SimpleType.STRING;
+            itemTypes[1] = SimpleType.STRING;
+            itemTypes[2] = FEATURE_IDENTIFIER_TABLE;
+            itemTypes[3] = new ArrayType(1, SimpleType.STRING);
+            itemTypes[4] = FEATURE_CONFIG_TABLE;
+            itemTypes[5] = SimpleType.BOOLEAN;
+
+            itemDescriptions[0] = "The name of the feature";
+            itemDescriptions[1] = "The version of the feature";
+            itemDescriptions[2] = "The feature dependencies";
+            itemDescriptions[3] = "The feature bundles";
+            itemDescriptions[4] = "The feature configurations";
+            itemDescriptions[5] = "Whether the feature is installed";
+
+            return new CompositeType("Feature", description, itemNames,
+                    itemDescriptions, itemTypes);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build feature type", e);
+        }
+    }
+
+    private static TabularType createFeatureTableType() {
+        try {
+            return new TabularType("Features", "The table of all features",
+                    FEATURE, new String[] { FeaturesServiceMBean.FEATURE_NAME, FeaturesServiceMBean.FEATURE_VERSION });
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build feature table type", e);
+        }
+    }
+
+}
diff --git a/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxFeatureEvent.java b/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxFeatureEvent.java
new file mode 100644
index 0000000..03f024a
--- /dev/null
+++ b/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxFeatureEvent.java
@@ -0,0 +1,80 @@
+/*
+ * 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.management.codec;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+
+import org.apache.felix.karaf.features.FeatureEvent;
+import org.apache.felix.karaf.features.management.FeaturesServiceMBean;
+
+public class JmxFeatureEvent {
+
+    public static final CompositeType FEATURE_EVENT;
+
+    private final CompositeData data;
+
+    public JmxFeatureEvent(FeatureEvent event) {
+        try {
+            String[] itemNames = FeaturesServiceMBean.FEATURE_EVENT;
+            Object[] itemValues = new Object[itemNames.length];
+            itemValues[0] = event.getFeature().getName();
+            itemValues[1] = event.getFeature().getVersion();
+            switch (event.getType()) {
+                case FeatureInstalled:   itemValues[2] = FeaturesServiceMBean.FEATURE_EVENT_EVENT_TYPE_INSTALLED; break;
+                case FeatureUninstalled: itemValues[2] = FeaturesServiceMBean.FEATURE_EVENT_EVENT_TYPE_UNINSTALLED; break;
+                default: throw new IllegalStateException("Unsupported event type: " + event.getType());
+            }
+            data = new CompositeDataSupport(FEATURE_EVENT, itemNames, itemValues);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Cannot form feature event open data", e);
+        }
+    }
+
+    public CompositeData asCompositeData() {
+        return data;
+    }
+
+    static {
+        FEATURE_EVENT = createFeatureEventType();
+    }
+
+    private static CompositeType createFeatureEventType() {
+        try {
+            String description = "This type identify a Karaf feature event";
+            String[] itemNames = FeaturesServiceMBean.FEATURE_EVENT;
+            OpenType[] itemTypes = new OpenType[itemNames.length];
+            String[] itemDescriptions = new String[itemNames.length];
+            itemTypes[0] = SimpleType.STRING;
+            itemTypes[1] = SimpleType.STRING;
+            itemTypes[2] = SimpleType.STRING;
+
+            itemDescriptions[0] = "The id of the feature";
+            itemDescriptions[1] = "The version of the feature";
+            itemDescriptions[2] = "The type of the event";
+
+            return new CompositeType("FeatureEvent", description, itemNames,
+                    itemDescriptions, itemTypes);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build featureEvent type", e);
+        }
+    }
+}
diff --git a/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxRepository.java b/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxRepository.java
new file mode 100644
index 0000000..c2897a1
--- /dev/null
+++ b/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxRepository.java
@@ -0,0 +1,116 @@
+/*
+ * 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.management.codec;
+
+import java.util.Collection;
+import java.util.Arrays;
+import java.net.URI;
+
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.TabularType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularDataSupport;
+import javax.management.openmbean.CompositeDataSupport;
+
+import org.apache.felix.karaf.features.Repository;
+import org.apache.felix.karaf.features.management.FeaturesServiceMBean;
+
+public class JmxRepository {
+
+    public final static CompositeType REPOSITORY;
+
+    public final static TabularType REPOSITORY_TABLE;
+
+    private final CompositeData data;
+
+    public JmxRepository(Repository repository) {
+        try {
+            String[] itemNames = FeaturesServiceMBean.REPOSITORY;
+            Object[] itemValues = new Object[itemNames.length];
+            itemValues[0] = repository.getURI().toString();
+            itemValues[1] = toStringArray(repository.getRepositories());
+            itemValues[2] = JmxFeature.getFeatureIdentifierTable(Arrays.asList(repository.getFeatures()));
+            data = new CompositeDataSupport(REPOSITORY, itemNames, itemValues);
+        } catch (Exception e) {
+            throw new IllegalStateException("Cannot form repository open data", e);
+        }
+    }
+
+    public CompositeData asCompositeData() {
+        return data;
+    }
+
+    public static TabularData tableFrom(Collection<JmxRepository> repositories) {
+        TabularDataSupport table = new TabularDataSupport(REPOSITORY_TABLE);
+        for (JmxRepository repository : repositories) {
+            table.put(repository.asCompositeData());
+        }
+        return table;
+    }
+
+    private static String[] toStringArray(URI[] uris) {
+        if (uris == null) {
+            return null;
+        }
+        String[] res = new String[uris.length];
+        for (int i = 0; i < res.length; i++) {
+            res[i] = uris[i].toString();
+        }
+        return res;
+    }
+
+    static {
+        REPOSITORY = createRepositoryType();
+        REPOSITORY_TABLE = createRepositoryTableType();
+    }
+
+    private static CompositeType createRepositoryType() {
+        try {
+            String description = "This type identify a Karaf repository";
+            String[] itemNames = FeaturesServiceMBean.REPOSITORY;
+            OpenType[] itemTypes = new OpenType[itemNames.length];
+            String[] itemDescriptions = new String[itemNames.length];
+            itemTypes[0] = SimpleType.STRING;
+            itemTypes[1] = new ArrayType(1, SimpleType.STRING);
+            itemTypes[2] = JmxFeature.FEATURE_IDENTIFIER_TABLE;
+
+            itemDescriptions[0] = "The uri of the repository";
+            itemDescriptions[1] = "The dependent repositories";
+            itemDescriptions[2] = "The list of included features";
+
+            return new CompositeType("Repository", description, itemNames,
+                    itemDescriptions, itemTypes);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build repository type", e);
+        }
+    }
+
+    private static TabularType createRepositoryTableType() {
+        try {
+            return new TabularType("Features", "The table of repositories",
+                    REPOSITORY, new String[] { FeaturesServiceMBean.REPOSITORY_URI });
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build repository table type", e);
+        }
+    }
+
+}
diff --git a/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxRepositoryEvent.java b/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxRepositoryEvent.java
new file mode 100644
index 0000000..6e8954f
--- /dev/null
+++ b/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxRepositoryEvent.java
@@ -0,0 +1,77 @@
+/*
+ * 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.management.codec;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+
+import org.apache.felix.karaf.features.RepositoryEvent;
+import org.apache.felix.karaf.features.management.FeaturesServiceMBean;
+
+public class JmxRepositoryEvent {
+
+    public static final CompositeType REPOSITORY_EVENT;
+
+    private final CompositeData data;
+
+    public JmxRepositoryEvent(RepositoryEvent event) {
+        try {
+            String[] itemNames = FeaturesServiceMBean.REPOSITORY_EVENT;
+            Object[] itemValues = new Object[itemNames.length];
+            itemValues[0] = event.getRepository().getURI().toString();
+            switch (event.getType()) {
+                case RepositoryAdded:   itemValues[2] = FeaturesServiceMBean.REPOSITORY_EVENT_EVENT_TYPE_ADDED; break;
+                case RepositoryRemoved: itemValues[2] = FeaturesServiceMBean.REPOSITORY_EVENT_EVENT_TYPE_REMOVED; break;
+                default: throw new IllegalStateException("Unsupported event type: " + event.getType());
+            }
+            data = new CompositeDataSupport(REPOSITORY_EVENT, itemNames, itemValues);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Cannot form repository event open data", e);
+        }
+    }
+
+    public CompositeData asCompositeData() {
+        return data;
+    }
+
+    static {
+        REPOSITORY_EVENT = createRepositoryEventType();
+    }
+
+    private static CompositeType createRepositoryEventType() {
+        try {
+            String description = "This type identify a Karaf repository event";
+            String[] itemNames = FeaturesServiceMBean.REPOSITORY_EVENT;
+            OpenType[] itemTypes = new OpenType[itemNames.length];
+            String[] itemDescriptions = new String[itemNames.length];
+            itemTypes[0] = SimpleType.STRING;
+            itemTypes[1] = SimpleType.STRING;
+
+            itemDescriptions[0] = "The uri of the repository";
+            itemDescriptions[1] = "The type of event";
+
+            return new CompositeType("RepositoryEvent", description, itemNames,
+                    itemDescriptions, itemTypes);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build repositoryEvent type", e);
+        }
+    }
+}
\ No newline at end of file
diff --git a/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/internal/FeaturesServiceMBeanImpl.java b/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/internal/FeaturesServiceMBeanImpl.java
new file mode 100644
index 0000000..c7b37b4
--- /dev/null
+++ b/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/internal/FeaturesServiceMBeanImpl.java
@@ -0,0 +1,194 @@
+/*
+ * Licensed 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.management.internal;
+
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.net.URI;
+
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.ObjectName;
+import javax.management.Notification;
+import javax.management.openmbean.TabularData;
+
+import org.apache.felix.karaf.features.management.FeaturesServiceMBean;
+import org.apache.felix.karaf.features.management.codec.JmxFeature;
+import org.apache.felix.karaf.features.management.codec.JmxFeatureEvent;
+import org.apache.felix.karaf.features.management.codec.JmxRepository;
+import org.apache.felix.karaf.features.management.codec.JmxRepositoryEvent;
+import org.apache.felix.karaf.features.FeaturesListener;
+import org.apache.felix.karaf.features.FeatureEvent;
+import org.apache.felix.karaf.features.RepositoryEvent;
+import org.apache.felix.karaf.features.FeaturesService;
+import org.apache.felix.karaf.features.Feature;
+import org.apache.felix.karaf.features.Repository;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ *
+ */
+
+public class FeaturesServiceMBeanImpl extends NotificationBroadcasterSupport
+                                      implements MBeanRegistration, FeaturesServiceMBean {
+
+    private ServiceRegistration registration;
+
+    private BundleContext bundleContext;
+
+	private ObjectName objectName;
+
+	private volatile long sequenceNumber = 0;
+
+	private MBeanServer server;
+
+    private FeaturesService featuresService;
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see javax.management.MBeanRegistration#preRegister(javax.manamement.MBeanServer, javax.management.ObjectName)
+     */
+	public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception {
+		objectName = name;
+		this.server = server;
+		return name;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 *
+	 * @see javax.management.MBeanRegistration#postRegister(java.lang.Boolean)
+	 */
+	public void postRegister(Boolean registrationDone) {
+        registration = bundleContext.registerService(
+                            FeaturesListener.class.getName(),
+                            getFeaturesListener(),
+                            new Hashtable());
+	}
+
+	/*
+	 * (non-Javadoc)
+	 *
+	 * @see javax.management.MBeanRegistration#preDeregister()
+	 */
+	public void preDeregister() throws Exception {
+        registration.unregister();
+	}
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see javax.management.MBeanRegistration#postDeregister()
+     */
+    public void postDeregister() {
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.apache.felix.karaf.features.management.FeaturesServiceMBean#getFeatures()
+     */
+    public TabularData getFeatures() throws Exception {
+        try {
+            List<Feature> allFeatures = Arrays.asList(featuresService.listFeatures());
+            List<Feature> insFeatures = Arrays.asList(featuresService.listInstalledFeatures());
+            ArrayList<JmxFeature> features = new ArrayList<JmxFeature>();
+            for (Feature feature : allFeatures) {
+                features.add(new JmxFeature(feature, insFeatures.contains(feature)));
+            }
+            TabularData table = JmxFeature.tableFrom(features);
+            return table;
+        } catch (Throwable t) {
+            t.printStackTrace();
+            return null;
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.apache.felix.karaf.features.management.FeaturesServiceMBean#getRepositories()
+     */
+    public TabularData getRepositories() throws Exception {
+        try {
+            List<Repository> allRepositories = Arrays.asList(featuresService.listRepositories());
+            ArrayList<JmxRepository> repositories = new ArrayList<JmxRepository>();
+            for (Repository repository : allRepositories) {
+                repositories.add(new JmxRepository(repository));
+            }
+            TabularData table = JmxRepository.tableFrom(repositories);
+            return table;
+        } catch (Throwable t) {
+            t.printStackTrace();
+            return null;
+        }
+    }
+
+    public void addRepository(String uri) throws Exception {
+        featuresService.addRepository(new URI(uri));
+    }
+
+    public void removeRepositroy(String uri) throws Exception {
+        featuresService.removeRepository(new URI(uri));
+    }
+
+    public void installFeature(String name) throws Exception {
+        featuresService.installFeature(name);
+    }
+
+    public void installFeature(String name, String version) throws Exception {
+        featuresService.installFeature(name, version);
+    }
+
+    public void uninstallFeature(String name) throws Exception {
+        featuresService.uninstallFeature(name);
+    }
+
+    public void uninstallFeature(String name, String version) throws Exception {
+        featuresService.uninstallFeature(name, version);
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    public void setFeaturesService(FeaturesService featuresService) {
+        this.featuresService = featuresService;
+    }
+
+    public FeaturesListener getFeaturesListener() {
+        return new FeaturesListener() {
+            public void featureEvent(FeatureEvent event) {
+                if (!event.isReplay()) {
+                    Notification notification = new Notification(FEATURE_EVENT_TYPE, objectName, sequenceNumber++);
+                    notification.setUserData(new JmxFeatureEvent(event).asCompositeData());
+                    sendNotification(notification);
+                }
+            }
+            public void repositoryEvent(RepositoryEvent event) {
+                if (!event.isReplay()) {
+                    Notification notification = new Notification(REPOSITORY_EVENT_TYPE, objectName, sequenceNumber++);
+                    notification.setUserData(new JmxRepositoryEvent(event).asCompositeData());
+                    sendNotification(notification);
+                }
+            }
+        };
+    }
+
+}
\ No newline at end of file
diff --git a/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/internal/MBeanRegistrer.java b/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/internal/MBeanRegistrer.java
new file mode 100644
index 0000000..004ad00
--- /dev/null
+++ b/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/internal/MBeanRegistrer.java
@@ -0,0 +1,72 @@
+/*
+ * 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.management.internal;
+
+import java.util.Map;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.MBeanRegistrationException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.JMException;
+
+public class MBeanRegistrer {
+
+    private MBeanServer mbeanServer;
+
+    private Map<Object, String> mbeans;
+
+    public void setMbeans(Map<Object, String> mbeans) {
+        this.mbeans = mbeans;
+    }
+
+    public void registerMBeanServer(MBeanServer mbeanServer) throws JMException {
+        if (this.mbeanServer != mbeanServer) {
+            unregisterMBeans();
+        }
+        this.mbeanServer = mbeanServer;
+        registerMBeans();
+    }
+
+    public void unregisterMBeanServer(MBeanServer mbeanServer) throws JMException {
+        unregisterMBeans();
+        this.mbeanServer = null;
+    }
+
+    public void init() throws Exception {
+        registerMBeans();
+    }
+
+    protected void registerMBeans() throws JMException {
+        if (mbeanServer != null && mbeans != null) {
+            for (Map.Entry<Object, String> entry : mbeans.entrySet()) {
+                mbeanServer.registerMBean(entry.getKey(), new ObjectName(entry.getValue()));
+            }
+        }
+    }
+
+    protected void unregisterMBeans() throws JMException {
+        if (mbeanServer != null && mbeans != null) {
+            for (Map.Entry<Object, String> entry : mbeans.entrySet()) {
+                mbeanServer.unregisterMBean(new ObjectName(entry.getValue()));
+            }
+        }
+    }
+}
diff --git a/karaf/features/management/src/main/resources/OSGI-INF/blueprint/features-management.xml b/karaf/features/management/src/main/resources/OSGI-INF/blueprint/features-management.xml
new file mode 100644
index 0000000..98f1041
--- /dev/null
+++ b/karaf/features/management/src/main/resources/OSGI-INF/blueprint/features-management.xml
@@ -0,0 +1,50 @@
+<?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">
+
+    <reference id="featuresService" interface="org.apache.felix.karaf.features.FeaturesService" />
+
+    <reference id="mbeanServer" interface="javax.management.MBeanServer">
+        <reference-listener ref="mbeanRegister" bind-method="registerMBeanServer" unbind-method="unregisterMBeanServer" />
+    </reference>
+
+    <bean id="mbeanImpl" class="org.apache.felix.karaf.features.management.internal.FeaturesServiceMBeanImpl">
+        <property name="bundleContext" ref="blueprintBundleContext" />
+        <property name="featuresService" ref="featuresService" />
+    </bean>
+
+    <bean id="mbeanRegister" class="org.apache.felix.karaf.features.management.internal.MBeanRegistrer">
+        <property name="mbeans">
+            <map>
+                <entry>
+                    <key>
+                        <bean class="javax.management.StandardMBean">
+                            <argument ref="mbeanImpl" />
+                            <argument value="org.apache.felix.karaf.features.management.FeaturesServiceMBean"/>
+                        </bean>
+                    </key>
+                    <value>org.apache.felix.karaf:service=features</value>
+                </entry>
+            </map>
+        </property>
+    </bean>
+
+</blueprint>
diff --git a/karaf/features/pom.xml b/karaf/features/pom.xml
new file mode 100644
index 0000000..f9f15f1
--- /dev/null
+++ b/karaf/features/pom.xml
@@ -0,0 +1,42 @@
+<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</groupId>
+        <artifactId>karaf</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.felix.karaf.features</groupId>
+    <artifactId>features</artifactId>
+    <packaging>pom</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache Felix Karaf :: Features</name>
+
+    <modules>
+        <module>core</module>
+        <module>command</module>
+        <module>management</module>
+    </modules>
+
+</project>
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/FeaturesRegistry.java b/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/FeaturesRegistry.java
deleted file mode 100644
index b67c98c..0000000
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/FeaturesRegistry.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.gshell.features;
-
-/**
- * Main interface for a Feature Registry which tracks available and installed features.
- * Tracks features and repositories.
- */
-public interface FeaturesRegistry {
-
-    void setFeaturesService(FeaturesService service);
-
-    void register(Feature feature);
-
-    void unregister(Feature feature);
-
-    void registerInstalled(Feature feature);
-
-    void unregisterInstalled(Feature feature);
-
-    void register(Repository repository);
-
-    void unregister(Repository repository);
-}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/ListFeaturesCommand.java b/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/ListFeaturesCommand.java
deleted file mode 100644
index 9e2246d..0000000
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/commands/ListFeaturesCommand.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.gshell.features.commands;
-
-import org.apache.felix.karaf.gshell.features.FeaturesService;
-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 {
-        String[] features;
-        if (installed) {
-            features = admin.listInstalledFeatures();
-        } else {
-        	// Print column headers.
-        	System.out.println("  State          Version       Name");
-            features = admin.listFeatures();
-        }
-        if ((features != null) && (features.length > 0)) {
-            for (int i = 0; i < features.length; i++) {
-                System.out.println(features[i]);
-            }
-        } else {
-            if (installed) {
-                System.out.println("No features installed.");
-            } else {
-                System.out.println("No features available.");
-            }
-        }
-    }
-}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/DefaultNamingStrategy.java b/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/DefaultNamingStrategy.java
deleted file mode 100644
index 8902ed6..0000000
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/DefaultNamingStrategy.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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.gshell.features.management;
-
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
-
-import org.apache.felix.karaf.gshell.features.FeaturesRegistry;
-
-/**
- * Naming strategy for JMX MBeans.
- */
-public class DefaultNamingStrategy implements NamingStrategy {
-
-    private String jmxDomainName;
-
-    public String getJmxDomainName() {
-        return jmxDomainName;
-    }
-
-    public void setJmxDomainName(String jmxDomainName) {
-        this.jmxDomainName = jmxDomainName;
-    }
-
-    public ObjectName getObjectName(ManagedFeature feature) throws MalformedObjectNameException {
-        return getObjectName(feature, false);
-    }
-
-    public ObjectName getObjectName(ManagedFeature feature, boolean installed) throws MalformedObjectNameException {
-        StringBuffer sb = new StringBuffer();
-        sb.append(jmxDomainName).append(":Service=Features,");
-
-        if (installed) {
-            sb.append("Type=Installed,");
-        } else {
-            sb.append("Type=Available,");
-        }
-
-        sb.append("Name=").append(sanitize(feature.getName())).append(",")
-          .append("FeatureVersion=").append(sanitize(feature.getVersion()));
-
-        return new ObjectName(sb.toString());
-    }
-
-    public ObjectName getObjectName(ManagedRepository repository) throws MalformedObjectNameException {
-        return new ObjectName(jmxDomainName + ":" +
-                                    "Service=Features," +
-                                    "Type=Repositories," +
-                                    "Name=" + sanitize(repository.getUri().toString())); // + "," +
-    }
-
-    public ObjectName getObjectName(FeaturesRegistry featuresRegistry) throws MalformedObjectNameException {
-        return new ObjectName(jmxDomainName + ":" +
-                                    "Service=Features," +
-                                    "Name=FeaturesService");
-    }
-
-    private String sanitize(String in) {
-        String result = null;
-        if (in != null) {
-            result = in.replace(':', '_');
-            result = result.replace('/', '_');
-            result = result.replace('\\', '_');
-            result = result.replace('?', '_');
-            result = result.replace('=', '_');
-            result = result.replace(',', '_');
-        }
-        return result;
-    }
-}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/ManagedFeature.java b/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/ManagedFeature.java
deleted file mode 100644
index ed95215..0000000
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/ManagedFeature.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.gshell.features.management;
-
-import java.util.List;
-
-import org.apache.felix.karaf.gshell.features.Feature;
-import org.apache.felix.karaf.gshell.features.FeaturesService;
-
-/**
- * Managed Repository MBean
- */
-public class ManagedFeature implements ManagedFeatureMBean {
-    private Feature feature;
-    private FeaturesService featuresService;
-    private String id;
-
-    public ManagedFeature(Feature feature, FeaturesService featuresService) {
-        this.feature = feature;
-        id = feature.getName() + "-" + feature.getVersion();
-        this.featuresService = featuresService;
-    }
-
-    public String getId() {
-        return id;    
-    }
-
-    public String getName() {
-        return feature.getName();
-    }
-
-    public String getVersion() {
-        return feature.getVersion();
-    }
-
-    public List<Feature> getDependencies() {
-        return feature.getDependencies();
-    }
-
-    public List<String> getBundles() {
-        return feature.getBundles();
-    }
-
-    public void installFeature() throws Exception {
-        featuresService.installFeature(feature.getName(), feature.getVersion());
-    }
-
-    public void uninstallFeature() throws Exception {
-        featuresService.uninstallFeature(feature.getName(), feature.getVersion());
-    }
-
-}
-
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/ManagedFeatureMBean.java b/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/ManagedFeatureMBean.java
deleted file mode 100644
index 953dfad..0000000
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/ManagedFeatureMBean.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.gshell.features.management;
-
-import java.util.List;
-
-import org.apache.felix.karaf.gshell.features.Feature;
-
-public interface ManagedFeatureMBean {
-
-    String getId();
-
-    String getName();
-
-    String getVersion();
-
-    List<Feature> getDependencies();
-
-    List<String> getBundles();
-
-    void installFeature() throws Exception;
-
-    void uninstallFeature() throws Exception;
-
-}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/ManagedFeaturesRegistry.java b/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/ManagedFeaturesRegistry.java
deleted file mode 100644
index 77af08d..0000000
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/ManagedFeaturesRegistry.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * 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.gshell.features.management;
-
-import java.net.URI;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import javax.management.MBeanServer;
-
-import org.apache.felix.karaf.gshell.features.Feature;
-import org.apache.felix.karaf.gshell.features.FeaturesRegistry;
-import org.apache.felix.karaf.gshell.features.FeaturesService;
-import org.apache.felix.karaf.gshell.features.Repository;
-import org.slf4j.LoggerFactory;
-import org.slf4j.Logger;
-
-/**
- * The FeaturesServiceRegistry maintains the managed Features and Repositories
- * for JMX management.
- */
-public class ManagedFeaturesRegistry implements FeaturesRegistry, ManagedFeaturesRegistryMBean {
-
-    private static final transient Logger LOG = LoggerFactory.getLogger(ManagedFeaturesRegistry.class);
-
-    private NamingStrategy namingStrategy;
-    private ManagementAgent managementAgent;
-    private Map<String, ManagedFeature> availableFeatures;
-    private Map<String, ManagedFeature> installedFeatures;
-    private Map<String, ManagedRepository> repositories;
-    private boolean mbeanServerInitialized;
-    private FeaturesService featuresService;
-    private MBeanServer mbeanServer;
-
-    public void installFeature(String name) throws Exception {
-        featuresService.installFeature(name);
-    }
-
-    public void installFeature(String name, String version) throws Exception {
-        featuresService.installFeature(name, version);
-    }
-
-    public void installRepository(String repositoryUri) throws Exception {
-        featuresService.addRepository(new URI(repositoryUri));
-    }
-
-    public ManagedFeaturesRegistry() {
-        availableFeatures = new ConcurrentHashMap<String, ManagedFeature>();
-        installedFeatures = new ConcurrentHashMap<String, ManagedFeature>();
-        repositories = new ConcurrentHashMap<String, ManagedRepository>();
-    }
-
-    public Map<String, ManagedFeature> getAvailableFeatures() {
-        return availableFeatures;
-    }
-
-    public Map<String, ManagedFeature> getInstalledFeatures() {
-        return installedFeatures;
-    }
-
-    public Map<String, ManagedRepository> getRepositories() {
-        return repositories;
-    }
-
-    public void setFeaturesService(FeaturesService featuresService) {
-        this.featuresService = featuresService;
-    }
-
-    public void setNamingStrategy(NamingStrategy namingStrategy) {
-        this.namingStrategy = namingStrategy;
-    }
-
-    public void setManagementAgent(ManagementAgent managementAgent) {
-        this.managementAgent = managementAgent;
-    }
-
-    public void register(Feature feature) {
-        try {
-            ManagedFeature mf = new ManagedFeature(feature, featuresService);
-            availableFeatures.put(feature.getId(), mf);
-            if ( mbeanServerInitialized ) {
-                managementAgent.register(mf, namingStrategy.getObjectName(mf));
-            }
-        } catch (Exception e) {
-            LOG.warn("Unable to register managed feature: " + e, e);
-        }
-    }
-
-    public void unregister(Feature feature) {
-        try {
-            ManagedFeature mf = availableFeatures.remove(feature.getId());
-            if ( mbeanServerInitialized ) {
-                managementAgent.unregister(namingStrategy.getObjectName(mf));
-            }
-        } catch (Exception e) {
-            LOG.warn("Unable to unregister managed feature: " + e, e);
-        }
-    }
-
-    public void registerInstalled(Feature feature) {
-        try {
-            ManagedFeature mf = new ManagedFeature(feature, featuresService);
-            installedFeatures.put(feature.getId(), mf);
-            if ( mbeanServerInitialized ) {
-                managementAgent.register(mf, namingStrategy.getObjectName(mf, true));
-            }
-        } catch (Exception e) {
-            LOG.warn("Unable to register managed feature: " + e, e);
-        }
-    }
-
-    public void unregisterInstalled(Feature feature) {
-        try {
-            ManagedFeature mf = installedFeatures.remove(feature.getId());
-            if ( mbeanServerInitialized ) {
-                managementAgent.unregister(namingStrategy.getObjectName(mf, true));
-            }
-        } catch (Exception e) {
-            LOG.warn("Unable to unregister managed feature: " + e, e);
-        }
-    }
-
-    public void register(Repository repository) {
-        try {
-            ManagedRepository mr = new ManagedRepository(repository, featuresService);
-            repositories.put(repository.getURI().toString(), mr);
-
-            for (Feature f : repository.getFeatures()) {
-                // TODO: Associate the feature with the Repo?
-                register(f);
-            }
-
-            if ( mbeanServerInitialized ) {
-                managementAgent.register(mr, namingStrategy.getObjectName(mr));
-            }
-        } catch (Exception e) {
-            LOG.warn("Unable to register managed repository: " + e, e);
-        }
-    }
-
-    public void unregister(Repository repository) {
-        try {
-            ManagedRepository mr = repositories.remove(repository.getURI().toString());
-
-            for (Feature f : repository.getFeatures()) {
-                // TODO: Associate the feature with the Repo?
-                unregister(f);
-            }
-
-            if ( mbeanServerInitialized ) {
-                managementAgent.unregister(namingStrategy.getObjectName(mr));
-            }
-        } catch (Exception e) {
-            LOG.warn("Unable to unregister managed repository: " + e, e);
-        }
-    }
-
-    public void init() throws Exception {
-        if (managementAgent == null) {
-            throw new IllegalArgumentException("managementAgent must not be null");
-        }
-        if (namingStrategy == null) {
-            throw new IllegalArgumentException("namingStrategy must not be null");
-        }
-        if (mbeanServer != null) {
-            registerMBeanServer(mbeanServer, null);
-        }
-    }
-
-    public void registerMBeanServer(MBeanServer mbeanServer, Map props) throws Exception {
-        if (mbeanServer != null) {
-            this.mbeanServer = mbeanServer;
-        }
-        if (managementAgent == null) {
-            return;
-        }
-        mbeanServerInitialized = true;
-
-        managementAgent.register(this, namingStrategy.getObjectName(this));
-
-        for (ManagedRepository repository : repositories.values()) {
-            managementAgent.register(repository, namingStrategy.getObjectName(repository));
-        }
-
-        for (ManagedFeature feature : availableFeatures.values()) {
-            managementAgent.register(feature, namingStrategy.getObjectName(feature));
-        }
-
-        for (ManagedFeature feature : installedFeatures.values()) {
-            installedFeatures.put(feature.getId(), feature);
-            managementAgent.register(feature, namingStrategy.getObjectName(feature, true));
-        }
-    }
-
-    public void unregisterMBeanServer(MBeanServer mbeanServer, Map props) throws Exception {
-        // TODO
-    }
-
-    
-}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/ManagedFeaturesRegistryMBean.java b/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/ManagedFeaturesRegistryMBean.java
deleted file mode 100644
index a30b98f..0000000
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/ManagedFeaturesRegistryMBean.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * 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.gshell.features.management;
-
-public interface ManagedFeaturesRegistryMBean {
-
-    void installFeature(String name) throws Exception;
-
-    void installFeature(String name, String version) throws Exception;
-
-    void installRepository(String repositoryUri) throws Exception;
-
-}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/ManagedRepository.java b/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/ManagedRepository.java
deleted file mode 100644
index ddaa6b5..0000000
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/ManagedRepository.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.gshell.features.management;
-
-import java.net.URI;
-
-import org.apache.felix.karaf.gshell.features.Feature;
-import org.apache.felix.karaf.gshell.features.FeaturesService;
-import org.apache.felix.karaf.gshell.features.Repository;
-
-public class ManagedRepository implements ManagedRepositoryMBean {
-
-    private Repository repository;
-    private FeaturesService featuresService;
-
-    public ManagedRepository(Repository repository, FeaturesService featuresService) {
-        this.repository = repository;
-        this.featuresService = featuresService;
-    }
-
-    public URI getUri() {
-        return repository.getURI();
-    }
-
-    public URI[] getRepositories() throws Exception {
-        return repository.getRepositories();
-    }
-
-    public Feature[] getFeatures() throws Exception {
-        return repository.getFeatures();
-    }
-
-    public void removeRepository() throws Exception {
-        featuresService.removeRepository(repository.getURI());
-    }
-}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/ManagedRepositoryMBean.java b/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/ManagedRepositoryMBean.java
deleted file mode 100644
index ae2ae63..0000000
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/ManagedRepositoryMBean.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.gshell.features.management;
-
-import java.net.URI;
-
-import org.apache.felix.karaf.gshell.features.Feature;
-
-public interface ManagedRepositoryMBean {
-
-    URI getUri();
-
-    URI[] getRepositories() throws Exception;
-
-    Feature[] getFeatures() throws Exception;
-
-    void removeRepository() throws Exception;
-
-}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/ManagementAgent.java b/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/ManagementAgent.java
deleted file mode 100644
index 4275d09..0000000
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/ManagementAgent.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * 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.gshell.features.management;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.JMException;
-import javax.management.MBeanServer;
-import javax.management.NotCompliantMBeanException;
-import javax.management.ObjectInstance;
-import javax.management.ObjectName;
-
-import org.slf4j.LoggerFactory;
-import org.slf4j.Logger;
-
-/**
- * Management Agent that registers MBeans with JMX MBeanServer.
- */
-public class ManagementAgent {
-
-    private static final transient Logger LOG = LoggerFactory.getLogger(ManagementAgent.class);
-
-    private MBeanServer mbeanServer;
-    private Set<ObjectName> mbeans = new HashSet<ObjectName>();
-
-    public ManagementAgent() {
-    }
-
-    public MBeanServer getMbeanServer() {
-        return mbeanServer;
-    }
-
-    public void setMbeanServer(MBeanServer mbeanServer) {
-        this.mbeanServer = mbeanServer;
-    }
-
-    public void destroy() throws Exception {
-        // Using the array to hold the busMBeans to avoid the
-        // CurrentModificationException
-        Object[] mBeans = mbeans.toArray();
-        int caught = 0;
-        for (Object name : mBeans) {
-            mbeans.remove((ObjectName)name);
-            try {
-                unregister((ObjectName)name);
-            } catch (JMException jmex) {
-                LOG.info("Exception unregistering MBean", jmex);
-                caught++;
-            }
-        }
-        if (caught > 0) {
-            LOG.warn("A number of " + caught
-                     + " exceptions caught while unregistering MBeans during stop operation.  "
-                     + "See INFO log for details.");
-        }
-    }
-
-    public void register(Object obj, ObjectName name) throws JMException {
-        register(obj, name, false);
-    }
-
-    public void register(Object obj, ObjectName name, boolean forceRegistration) throws JMException {
-        /*
-        try {
-            registerMBeanWithServer(obj, name, forceRegistration);
-        } catch (NotCompliantMBeanException e) {
-            // If this is not a "normal" MBean, then try to deploy it using JMX
-            // annotations
-            ModelMBeanInfo mbi = assembler.getMBeanInfo(obj, name.toString());
-            RequiredModelMBean mbean = (RequiredModelMBean) mbeanServer.instantiate(RequiredModelMBean.class.getName());
-            mbean.setModelMBeanInfo(mbi);
-            try {
-                mbean.setManagedResource(obj, "ObjectReference");
-            } catch (InvalidTargetObjectTypeException itotex) {
-                throw new JMException(itotex.getMessage());
-            }
-            registerMBeanWithServer(mbean, name, forceRegistration);
-        }
-        */
-        registerMBeanWithServer(obj, name, forceRegistration);
-    }
-
-    public synchronized void unregister(ObjectName name) throws JMException {
-        if (mbeans.contains(name)) {
-            //check if this bean already get removed in destory method
-            mbeanServer.unregisterMBean(name);
-        }
-    }
-
-    private void registerMBeanWithServer(Object obj, ObjectName name, boolean forceRegistration) throws JMException {
-        ObjectInstance instance = null;
-        try {
-            instance = mbeanServer.registerMBean(obj, name);
-        } catch (InstanceAlreadyExistsException e) {
-            if (forceRegistration) {
-                mbeanServer.unregisterMBean(name);
-                instance = mbeanServer.registerMBean(obj, name);
-            } 
-        } catch (NotCompliantMBeanException e) {
-            throw e;
-        }
-
-        if (instance != null) {
-            mbeans.add(name);
-        }
-    }
-
-}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/NamingStrategy.java b/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/NamingStrategy.java
deleted file mode 100644
index 9b7ba47..0000000
--- a/karaf/gshell/gshell-features/src/main/java/org/apache/felix/karaf/gshell/features/management/NamingStrategy.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.gshell.features.management;
-
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
-
-import org.apache.felix.karaf.gshell.features.FeaturesRegistry;
-
-public interface NamingStrategy {
-
-    ObjectName getObjectName(ManagedFeature feature) throws MalformedObjectNameException;
-
-    ObjectName getObjectName(ManagedFeature feature, boolean installed) throws MalformedObjectNameException;
-
-    ObjectName getObjectName(ManagedRepository component) throws MalformedObjectNameException;
-
-    String getJmxDomainName();
-
-    ObjectName getObjectName(FeaturesRegistry features) throws MalformedObjectNameException;
-}
diff --git a/karaf/gshell/gshell-features/src/main/resources/OSGI-INF/blueprint/gshell-features.xml b/karaf/gshell/gshell-features/src/main/resources/OSGI-INF/blueprint/gshell-features.xml
deleted file mode 100644
index 7c784c0..0000000
--- a/karaf/gshell/gshell-features/src/main/resources/OSGI-INF/blueprint/gshell-features.xml
+++ /dev/null
@@ -1,112 +0,0 @@
-<?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">
-
-    <ext:property-placeholder placeholder-prefix="$(" placeholder-suffix=")"/>
-
-    <ext:property-placeholder placeholder-prefix="$[" placeholder-suffix="]" ignore-missing-locations="true">
-        <ext:default-properties>
-            <ext:property name="featuresRepositories" value=""/>
-            <ext:property name="featuresBoot" value=""/>
-        </ext:default-properties>
-        <ext:location>file:$(karaf.home)/etc/org.apache.felix.karaf.features.cfg</ext:location>
-    </ext:property-placeholder>
-
-    <command-bundle xmlns="http://felix.apache.org/karaf/xmlns/gshell/v1.0.0">
-        <command name="features/addUrl">
-            <action class="org.apache.felix.karaf.gshell.features.commands.AddUrlCommand"/>
-        </command>
-        <command name="features/listUrl">
-            <action class="org.apache.felix.karaf.gshell.features.commands.ListUrlCommand"/>
-        </command>
-        <command name="features/removeUrl">
-            <action class="org.apache.felix.karaf.gshell.features.commands.RemoveUrlCommand"/>
-            <completers>
-                <ref component-id="removeUrlCompleter" />
-            </completers>
-        </command>
-        <command name="features/refreshUrl">
-            <action class="org.apache.felix.karaf.gshell.features.commands.RefreshUrlCommand"/>
-        </command>
-        <command name="features/install">
-            <action class="org.apache.felix.karaf.gshell.features.commands.InstallFeatureCommand"/>
-            <completers>
-                <ref component-id="installFeatureCompleter" />
-            </completers>
-        </command>
-        <command name="features/uninstall">
-            <action class="org.apache.felix.karaf.gshell.features.commands.UninstallFeatureCommand"/>
-            <completers>
-                <ref component-id="uninstallFeatureCompleter" />
-            </completers>
-        </command>
-        <command name="features/list">
-            <action class="org.apache.felix.karaf.gshell.features.commands.ListFeaturesCommand"/>
-        </command>
-    </command-bundle>
-
-    <bean id="featuresService" class="org.apache.felix.karaf.gshell.features.internal.FeaturesServiceImpl" init-method="start" destroy-method="stop">
-        <property name="urls" value="$[featuresRepositories]" />
-        <property name="boot" value="$[featuresBoot]" />
-        <property name="configAdmin" ref="configAdmin" />
-        <property name="preferences" ref="preferences" />
-        <property name="featuresServiceRegistry" ref="featureServiceRegistry" />
-        <property name="bundleContext" ref="blueprintBundleContext" />
-    </bean>
-
-    <reference id="configAdmin" interface="org.osgi.service.cm.ConfigurationAdmin" />
-
-    <reference id="preferences" interface="org.osgi.service.prefs.PreferencesService" availability="optional"/>
-
-    <service ref="featuresService" interface="org.apache.felix.karaf.gshell.features.FeaturesService" />
-
-    <bean id="installFeatureCompleter" class="org.apache.felix.karaf.gshell.features.completers.AvailableFeatureCompleter">
-        <property name="featuresRegistry" ref="featureServiceRegistry" />
-    </bean>
-
-    <bean id="uninstallFeatureCompleter" class="org.apache.felix.karaf.gshell.features.completers.InstalledFeatureCompleter">
-        <property name="featuresRegistry" ref="featureServiceRegistry" />
-    </bean>
-
-    <bean id="removeUrlCompleter" class="org.apache.felix.karaf.gshell.features.completers.FeatureRepositoryCompleter">
-        <property name="featuresRegistry" ref="featureServiceRegistry" />
-    </bean>
-
-    <!-- Management -->
-
-    <bean id="namingStrategy" class="org.apache.felix.karaf.gshell.features.management.DefaultNamingStrategy">
-        <property name="jmxDomainName" value="org.apache.felix.karaf" />
-    </bean>
-
-    <bean id="managementAgent" class="org.apache.felix.karaf.gshell.features.management.ManagementAgent" destroy-method="destroy">
-        <property name="mbeanServer" ref="mbeanServer" />
-    </bean>
-
-    <bean id="featureServiceRegistry" class="org.apache.felix.karaf.gshell.features.management.ManagedFeaturesRegistry" init-method="init">
-        <property name="managementAgent" ref="managementAgent" />
-        <property name="namingStrategy" ref="namingStrategy" />
-    </bean>
-
-    <reference id="mbeanServer" interface="javax.management.MBeanServer" availability="optional">
-        <reference-listener ref="featureServiceRegistry" bind-method="registerMBeanServer" unbind-method="unregisterMBeanServer"/>
-    </reference>
-
-</blueprint>
diff --git a/karaf/gshell/pom.xml b/karaf/gshell/pom.xml
index bebd1eb..c98981c 100644
--- a/karaf/gshell/pom.xml
+++ b/karaf/gshell/pom.xml
@@ -37,7 +37,6 @@
         <module>gshell-console</module>
         <module>gshell-osgi</module>
         <module>gshell-admin</module>
-        <module>gshell-features</module>
         <module>gshell-obr</module>
         <module>gshell-wrapper</module>
         <module>gshell-log</module>
diff --git a/karaf/pom.xml b/karaf/pom.xml
index 5bdcf6e..fcff63a 100644
--- a/karaf/pom.xml
+++ b/karaf/pom.xml
@@ -36,6 +36,7 @@
 
     <modules>
         <module>main</module>
+        <module>features</module>
         <module>deployer</module>
         <module>gshell</module>
         <module>jaas</module>
@@ -247,6 +248,21 @@
                 <version>${pom.version}</version>
             </dependency> 
             <dependency>
+                <groupId>org.apache.felix.karaf.features</groupId>
+                <artifactId>org.apache.felix.karaf.features.core</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.felix.karaf.features</groupId>
+                <artifactId>org.apache.felix.karaf.features.command</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.felix.karaf.features</groupId>
+                <artifactId>org.apache.felix.karaf.features.management</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
                 <groupId>org.apache.felix.karaf.gshell</groupId>
                 <artifactId>org.apache.felix.karaf.gshell.core</artifactId>
                 <version>${pom.version}</version>
@@ -283,11 +299,6 @@
             </dependency>
             <dependency>
                 <groupId>org.apache.felix.karaf.gshell</groupId>
-                <artifactId>org.apache.felix.karaf.gshell.features</artifactId>
-                <version>${pom.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.felix.karaf.gshell</groupId>
                 <artifactId>org.apache.felix.karaf.gshell.config</artifactId>
                 <version>${pom.version}</version>
             </dependency>
diff --git a/karaf/webconsole/features/pom.xml b/karaf/webconsole/features/pom.xml
index 5910ace..02f60f9 100644
--- a/karaf/webconsole/features/pom.xml
+++ b/karaf/webconsole/features/pom.xml
@@ -61,8 +61,8 @@
       <scope>provided</scope>
     </dependency>
     <dependency>
-      <groupId>org.apache.felix.karaf.gshell</groupId>
-      <artifactId>org.apache.felix.karaf.gshell.features</artifactId>
+      <groupId>org.apache.felix.karaf.features</groupId>
+      <artifactId>org.apache.felix.karaf.features.core</artifactId>
     </dependency>
     <dependency>
       <groupId>org.apache.servicemix.bundles</groupId>
diff --git a/karaf/webconsole/features/src/main/java/org/apache/felix/karaf/webconsole/features/FeaturesPlugin.java b/karaf/webconsole/features/src/main/java/org/apache/felix/karaf/webconsole/features/FeaturesPlugin.java
index b4c9946..3778daa 100644
--- a/karaf/webconsole/features/src/main/java/org/apache/felix/karaf/webconsole/features/FeaturesPlugin.java
+++ b/karaf/webconsole/features/src/main/java/org/apache/felix/karaf/webconsole/features/FeaturesPlugin.java
@@ -24,6 +24,7 @@
 import java.net.URL;
 import java.util.Arrays;
 import java.util.Comparator;
+import java.util.List;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
@@ -31,9 +32,8 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.felix.karaf.gshell.features.FeaturesService;
-import org.apache.felix.karaf.gshell.features.Repository;
 import org.apache.felix.webconsole.AbstractWebConsolePlugin;
+import org.apache.felix.karaf.features.*;
 
 import org.json.JSONException;
 import org.json.JSONWriter;
@@ -404,10 +404,12 @@
             return features;
         }
 
-        String[] featureInfo = null;
+        List<org.apache.felix.karaf.features.Feature> allFeatures = null;
+        List<org.apache.felix.karaf.features.Feature> installedFeatures = null;
         try
         {
-            featureInfo = featuresService.listFeatures();
+            allFeatures = Arrays.asList(featuresService.listFeatures());
+            installedFeatures = Arrays.asList(featuresService.listInstalledFeatures());
         }
         catch ( Exception e )
         {
@@ -415,42 +417,20 @@
             return new Feature[0];
         }
 
-        features = new Feature[featureInfo.length];
-        for ( int i = 0; i < featureInfo.length; i++ )
+        features = new Feature[allFeatures.size()];
+        for ( int i = 0; i < features.length; i++ )
         {
-            String[] temp;
-            temp = getBracketedToken( featureInfo[i], 0 );
-            Feature.State state;
-            if ( "installed  ".equals( temp[0] ) )
+            Feature.State state = Feature.State.UNINSTALLED;
+            if ( installedFeatures.contains( allFeatures.get(i) ) )
             {
                 state = Feature.State.INSTALLED;
             }
-            else if ( "uninstalled".equals( temp[0] ) )
-            {
-                state = Feature.State.UNINSTALLED;
-            }
-            else
-            {
-                state = Feature.State.UNKNOWN;
-            }
-            temp = getBracketedToken( temp[1], 0 );
-            String version = temp[0];
-            features[i] = new Feature( temp[1].trim(), version, state );
+            features[i] = new Feature( allFeatures.get(i).getName(), allFeatures.get(i).getVersion(), state );
         }
         Arrays.sort( features, new FeatureComparator() );
         return features;
     }
 
-    private String[] getBracketedToken( String str, int startIndex )
-    {
-        int start = str.indexOf( '[', startIndex ) + 1;
-        int end = str.indexOf( ']', start );
-        String token = str.substring( start, end );
-        String remainder = str.substring( end + 1 );
-        return new String[]
-            { token, remainder };
-    }
-
 
     class FeatureComparator implements Comparator<Feature>
     {
diff --git a/karaf/webconsole/features/src/main/resources/OSGI-INF/blueprint/webconsole-features.xml b/karaf/webconsole/features/src/main/resources/OSGI-INF/blueprint/webconsole-features.xml
index 0cd5325..c79820b 100644
--- a/karaf/webconsole/features/src/main/resources/OSGI-INF/blueprint/webconsole-features.xml
+++ b/karaf/webconsole/features/src/main/resources/OSGI-INF/blueprint/webconsole-features.xml
@@ -20,7 +20,7 @@
 <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
            xmlns:cm="http://www.osgi.org/xmlns/blueprint-cm/v1.0.0">
 
-    <reference id="featuresService" interface="org.apache.felix.karaf.gshell.features.FeaturesService" />
+    <reference id="featuresService" interface="org.apache.felix.karaf.features.FeaturesService" />
 
     <bean id="featuresPlugin" class="org.apache.felix.karaf.webconsole.features.FeaturesPlugin" init-method="start" destroy-method="stop">
         <property name="featuresService" ref="featuresService" />