You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by gn...@apache.org on 2009/08/07 11:55:55 UTC

svn commit: r801925 [2/2] - in /felix/trunk/karaf: ./ assembly/ assembly/src/main/descriptors/ assembly/src/main/filtered-resources/etc/ deployer/features/ deployer/features/src/main/java/org/apache/felix/karaf/deployer/features/ deployer/features/src/...

Copied: felix/trunk/karaf/features/core/src/test/java/org/apache/felix/karaf/features/FeaturesServiceTest.java (from r801923, felix/trunk/karaf/gshell/gshell-features/src/test/java/org/apache/felix/karaf/gshell/features/FeaturesServiceTest.java)
URL: http://svn.apache.org/viewvc/felix/trunk/karaf/features/core/src/test/java/org/apache/felix/karaf/features/FeaturesServiceTest.java?p2=felix/trunk/karaf/features/core/src/test/java/org/apache/felix/karaf/features/FeaturesServiceTest.java&p1=felix/trunk/karaf/gshell/gshell-features/src/test/java/org/apache/felix/karaf/gshell/features/FeaturesServiceTest.java&r1=801923&r2=801925&rev=801925&view=diff
==============================================================================
--- felix/trunk/karaf/gshell/gshell-features/src/test/java/org/apache/felix/karaf/gshell/features/FeaturesServiceTest.java (original)
+++ felix/trunk/karaf/features/core/src/test/java/org/apache/felix/karaf/features/FeaturesServiceTest.java Fri Aug  7 09:55:51 2009
@@ -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");

Copied: felix/trunk/karaf/features/core/src/test/java/org/apache/felix/karaf/features/RepositoryTest.java (from r801923, felix/trunk/karaf/gshell/gshell-features/src/test/java/org/apache/felix/karaf/gshell/features/RepositoryTest.java)
URL: http://svn.apache.org/viewvc/felix/trunk/karaf/features/core/src/test/java/org/apache/felix/karaf/features/RepositoryTest.java?p2=felix/trunk/karaf/features/core/src/test/java/org/apache/felix/karaf/features/RepositoryTest.java&p1=felix/trunk/karaf/gshell/gshell-features/src/test/java/org/apache/felix/karaf/gshell/features/RepositoryTest.java&r1=801923&r2=801925&rev=801925&view=diff
==============================================================================
--- felix/trunk/karaf/gshell/gshell-features/src/test/java/org/apache/felix/karaf/gshell/features/RepositoryTest.java (original)
+++ felix/trunk/karaf/features/core/src/test/java/org/apache/felix/karaf/features/RepositoryTest.java Fri Aug  7 09:55:51 2009
@@ -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 {

Copied: felix/trunk/karaf/features/core/src/test/java/org/apache/felix/karaf/features/internal/FeaturesServiceImplTest.java (from r801923, felix/trunk/karaf/gshell/gshell-features/src/test/java/org/apache/felix/karaf/gshell/features/internal/FeaturesServiceImplTest.java)
URL: http://svn.apache.org/viewvc/felix/trunk/karaf/features/core/src/test/java/org/apache/felix/karaf/features/internal/FeaturesServiceImplTest.java?p2=felix/trunk/karaf/features/core/src/test/java/org/apache/felix/karaf/features/internal/FeaturesServiceImplTest.java&p1=felix/trunk/karaf/gshell/gshell-features/src/test/java/org/apache/felix/karaf/gshell/features/internal/FeaturesServiceImplTest.java&r1=801923&r2=801925&rev=801925&view=diff
==============================================================================
--- felix/trunk/karaf/gshell/gshell-features/src/test/java/org/apache/felix/karaf/gshell/features/internal/FeaturesServiceImplTest.java (original)
+++ felix/trunk/karaf/features/core/src/test/java/org/apache/felix/karaf/features/internal/FeaturesServiceImplTest.java Fri Aug  7 09:55:51 2009
@@ -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}

Copied: felix/trunk/karaf/features/core/src/test/resources/org/apache/felix/karaf/features/repo1.xml (from r801923, felix/trunk/karaf/gshell/gshell-features/src/test/resources/org/apache/felix/karaf/gshell/features/repo1.xml)
URL: http://svn.apache.org/viewvc/felix/trunk/karaf/features/core/src/test/resources/org/apache/felix/karaf/features/repo1.xml?p2=felix/trunk/karaf/features/core/src/test/resources/org/apache/felix/karaf/features/repo1.xml&p1=felix/trunk/karaf/gshell/gshell-features/src/test/resources/org/apache/felix/karaf/gshell/features/repo1.xml&r1=801923&r2=801925&rev=801925&view=diff
==============================================================================
    (empty)

Copied: felix/trunk/karaf/features/management/pom.xml (from r801923, felix/trunk/karaf/gshell/gshell-features/pom.xml)
URL: http://svn.apache.org/viewvc/felix/trunk/karaf/features/management/pom.xml?p2=felix/trunk/karaf/features/management/pom.xml&p1=felix/trunk/karaf/gshell/gshell-features/pom.xml&r1=801923&r2=801925&rev=801925&view=diff
==============================================================================
--- felix/trunk/karaf/gshell/gshell-features/pom.xml (original)
+++ felix/trunk/karaf/features/management/pom.xml Fri Aug  7 09:55:51 2009
@@ -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>

Added: felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/FeaturesServiceMBean.java
URL: http://svn.apache.org/viewvc/felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/FeaturesServiceMBean.java?rev=801925&view=auto
==============================================================================
--- felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/FeaturesServiceMBean.java (added)
+++ felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/FeaturesServiceMBean.java Fri Aug  7 09:55:51 2009
@@ -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 };
+
+}

Added: felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxFeature.java
URL: http://svn.apache.org/viewvc/felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxFeature.java?rev=801925&view=auto
==============================================================================
--- felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxFeature.java (added)
+++ felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxFeature.java Fri Aug  7 09:55:51 2009
@@ -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);
+        }
+    }
+
+}

Added: felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxFeatureEvent.java
URL: http://svn.apache.org/viewvc/felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxFeatureEvent.java?rev=801925&view=auto
==============================================================================
--- felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxFeatureEvent.java (added)
+++ felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxFeatureEvent.java Fri Aug  7 09:55:51 2009
@@ -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);
+        }
+    }
+}

Added: felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxRepository.java
URL: http://svn.apache.org/viewvc/felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxRepository.java?rev=801925&view=auto
==============================================================================
--- felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxRepository.java (added)
+++ felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxRepository.java Fri Aug  7 09:55:51 2009
@@ -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);
+        }
+    }
+
+}

Added: felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxRepositoryEvent.java
URL: http://svn.apache.org/viewvc/felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxRepositoryEvent.java?rev=801925&view=auto
==============================================================================
--- felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxRepositoryEvent.java (added)
+++ felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/codec/JmxRepositoryEvent.java Fri Aug  7 09:55:51 2009
@@ -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

Added: felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/internal/FeaturesServiceMBeanImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/internal/FeaturesServiceMBeanImpl.java?rev=801925&view=auto
==============================================================================
--- felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/internal/FeaturesServiceMBeanImpl.java (added)
+++ felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/internal/FeaturesServiceMBeanImpl.java Fri Aug  7 09:55:51 2009
@@ -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

Added: felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/internal/MBeanRegistrer.java
URL: http://svn.apache.org/viewvc/felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/internal/MBeanRegistrer.java?rev=801925&view=auto
==============================================================================
--- felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/internal/MBeanRegistrer.java (added)
+++ felix/trunk/karaf/features/management/src/main/java/org/apache/felix/karaf/features/management/internal/MBeanRegistrer.java Fri Aug  7 09:55:51 2009
@@ -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()));
+            }
+        }
+    }
+}

Copied: felix/trunk/karaf/features/management/src/main/resources/OSGI-INF/blueprint/features-management.xml (from r801923, felix/trunk/karaf/webconsole/features/src/main/resources/OSGI-INF/blueprint/webconsole-features.xml)
URL: http://svn.apache.org/viewvc/felix/trunk/karaf/features/management/src/main/resources/OSGI-INF/blueprint/features-management.xml?p2=felix/trunk/karaf/features/management/src/main/resources/OSGI-INF/blueprint/features-management.xml&p1=felix/trunk/karaf/webconsole/features/src/main/resources/OSGI-INF/blueprint/webconsole-features.xml&r1=801923&r2=801925&rev=801925&view=diff
==============================================================================
--- felix/trunk/karaf/webconsole/features/src/main/resources/OSGI-INF/blueprint/webconsole-features.xml (original)
+++ felix/trunk/karaf/features/management/src/main/resources/OSGI-INF/blueprint/features-management.xml Fri Aug  7 09:55:51 2009
@@ -18,19 +18,33 @@
 
 -->
 <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
-           xmlns:cm="http://www.osgi.org/xmlns/blueprint-cm/v1.0.0">
+           xmlns:ext="http://geronimo.apache.org/blueprint/xmlns/blueprint-ext/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" />
+    <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>
 
-    <service ref="featuresPlugin" interface="javax.servlet.Servlet" >
-        <service-properties>
-            <entry key="felix.webconsole.label" value="features"/>
-        </service-properties>
-    </service>
+    <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>

Copied: felix/trunk/karaf/features/pom.xml (from r801923, felix/trunk/karaf/gshell/pom.xml)
URL: http://svn.apache.org/viewvc/felix/trunk/karaf/features/pom.xml?p2=felix/trunk/karaf/features/pom.xml&p1=felix/trunk/karaf/gshell/pom.xml&r1=801923&r2=801925&rev=801925&view=diff
==============================================================================
--- felix/trunk/karaf/gshell/pom.xml (original)
+++ felix/trunk/karaf/features/pom.xml Fri Aug  7 09:55:51 2009
@@ -27,24 +27,16 @@
         <version>1.2.0-SNAPSHOT</version>
     </parent>
 
-    <groupId>org.apache.felix.karaf.gshell</groupId>
-    <artifactId>gshell</artifactId>
+    <groupId>org.apache.felix.karaf.features</groupId>
+    <artifactId>features</artifactId>
     <packaging>pom</packaging>
     <version>1.2.0-SNAPSHOT</version>
-    <name>Apache Felix Karaf :: GShell</name>
+    <name>Apache Felix Karaf :: Features</name>
 
     <modules>
-        <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>
-        <module>gshell-config</module>
-        <module>gshell-packages</module>
-        <module>gshell-ssh</module>
-        <module>gshell-commands</module>
+        <module>core</module>
+        <module>command</module>
+        <module>management</module>
     </modules>
 
 </project>

Modified: felix/trunk/karaf/gshell/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/karaf/gshell/pom.xml?rev=801925&r1=801924&r2=801925&view=diff
==============================================================================
--- felix/trunk/karaf/gshell/pom.xml (original)
+++ felix/trunk/karaf/gshell/pom.xml Fri Aug  7 09:55:51 2009
@@ -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>

Modified: felix/trunk/karaf/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/karaf/pom.xml?rev=801925&r1=801924&r2=801925&view=diff
==============================================================================
--- felix/trunk/karaf/pom.xml (original)
+++ felix/trunk/karaf/pom.xml Fri Aug  7 09:55:51 2009
@@ -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>

Modified: felix/trunk/karaf/webconsole/features/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/karaf/webconsole/features/pom.xml?rev=801925&r1=801924&r2=801925&view=diff
==============================================================================
--- felix/trunk/karaf/webconsole/features/pom.xml (original)
+++ felix/trunk/karaf/webconsole/features/pom.xml Fri Aug  7 09:55:51 2009
@@ -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>

Modified: felix/trunk/karaf/webconsole/features/src/main/java/org/apache/felix/karaf/webconsole/features/FeaturesPlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/karaf/webconsole/features/src/main/java/org/apache/felix/karaf/webconsole/features/FeaturesPlugin.java?rev=801925&r1=801924&r2=801925&view=diff
==============================================================================
--- felix/trunk/karaf/webconsole/features/src/main/java/org/apache/felix/karaf/webconsole/features/FeaturesPlugin.java (original)
+++ felix/trunk/karaf/webconsole/features/src/main/java/org/apache/felix/karaf/webconsole/features/FeaturesPlugin.java Fri Aug  7 09:55:51 2009
@@ -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>
     {

Modified: felix/trunk/karaf/webconsole/features/src/main/resources/OSGI-INF/blueprint/webconsole-features.xml
URL: http://svn.apache.org/viewvc/felix/trunk/karaf/webconsole/features/src/main/resources/OSGI-INF/blueprint/webconsole-features.xml?rev=801925&r1=801924&r2=801925&view=diff
==============================================================================
--- felix/trunk/karaf/webconsole/features/src/main/resources/OSGI-INF/blueprint/webconsole-features.xml (original)
+++ felix/trunk/karaf/webconsole/features/src/main/resources/OSGI-INF/blueprint/webconsole-features.xml Fri Aug  7 09:55:51 2009
@@ -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" />