You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by jb...@apache.org on 2012/11/07 12:09:07 UTC

svn commit: r1406547 - in /karaf/cellar/branches/cellar-2.2.x: bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/ management/src/main/java/org/apache/karaf/cellar/management/internal/

Author: jbonofre
Date: Wed Nov  7 11:09:07 2012
New Revision: 1406547

URL: http://svn.apache.org/viewvc?rev=1406547&view=rev
Log:
[KARAF-2004] Add support of Cellar bundles selector

Added:
    karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/BundleCommandSupport.java
Modified:
    karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/ListBundleCommand.java
    karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/StartBundleCommand.java
    karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/StopBundleCommand.java
    karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/UninstallBundleCommand.java
    karaf/cellar/branches/cellar-2.2.x/management/src/main/java/org/apache/karaf/cellar/management/internal/CellarBundleMBeanImpl.java

Added: karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/BundleCommandSupport.java
URL: http://svn.apache.org/viewvc/karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/BundleCommandSupport.java?rev=1406547&view=auto
==============================================================================
--- karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/BundleCommandSupport.java (added)
+++ karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/BundleCommandSupport.java Wed Nov  7 11:09:07 2012
@@ -0,0 +1,74 @@
+/*
+ * 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.karaf.cellar.bundle.shell;
+
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.karaf.cellar.bundle.BundleState;
+import org.apache.karaf.cellar.core.shell.CellarCommandSupport;
+
+import java.util.Map;
+
+public abstract class BundleCommandSupport extends CellarCommandSupport {
+
+    @Argument(index = 0, name = "group", description = "The cluster group name.", required = true, multiValued = false)
+    String groupName;
+
+    @Argument(index = 1, name = "id", description = "The bundle ID or symbolic name.", required = true, multiValued = false)
+    String name;
+
+    @Argument(index = 2, name = "version", description = "The bundle version.", required = false, multiValued = false)
+    String version;
+
+    protected abstract Object doExecute() throws Exception;
+
+    /**
+     * Bundle selector.
+     *
+     * @return the bundle key is the distributed bundle map.
+     */
+    protected String selector(Map<String, BundleState> distributedBundles) {
+        String key = null;
+        if (version == null) {
+            // looking for bundle using ID
+            int id = -1;
+            try {
+                id = Integer.parseInt(name);
+                int index = 0;
+                for (String bundle : distributedBundles.keySet()) {
+                    if (index == id) {
+                        key = bundle;
+                        break;
+                    }
+                    index++;
+                }
+            } catch (NumberFormatException nfe) {
+                // ignore
+            }
+            if (id == -1) {
+                // looking for bundle using only the name
+                for (String bundle : distributedBundles.keySet()) {
+                    if (bundle.startsWith(name)) {
+                        key = bundle;
+                        break;
+                    }
+                }
+            }
+        } else {
+            // looking for the bundle using name and version
+            key = name + "/" + version;
+        }
+        return key;
+    }
+
+}

Modified: karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/ListBundleCommand.java
URL: http://svn.apache.org/viewvc/karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/ListBundleCommand.java?rev=1406547&r1=1406546&r2=1406547&view=diff
==============================================================================
--- karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/ListBundleCommand.java (original)
+++ karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/ListBundleCommand.java Wed Nov  7 11:09:07 2012
@@ -28,8 +28,8 @@ import java.util.Map;
 @Command(scope = "cluster", name = "bundle-list", description = "List the bundles assigned to a cluster group.")
 public class ListBundleCommand extends CellarCommandSupport {
 
-    protected static final String HEADER_FORMAT = " %-11s  %s";
-    protected static final String OUTPUT_FORMAT = "[%-11s] %s";
+    protected static final String HEADER_FORMAT = " %-4s   %-11s  %s";
+    protected static final String OUTPUT_FORMAT = "[%-4s] [%-11s] %s";
 
     @Argument(index = 0, name = "group", description = "The cluster group name.", required = true, multiValued = false)
     String groupName;
@@ -53,7 +53,8 @@ public class ListBundleCommand extends C
             Map<String, BundleState> bundles = clusterManager.getMap(Constants.BUNDLE_MAP + Configurations.SEPARATOR + groupName);
             if (bundles != null && !bundles.isEmpty()) {
                 System.out.println(String.format("Bundles for cluster group " + groupName));
-                System.out.println(String.format(HEADER_FORMAT, "State", "Name"));
+                System.out.println(String.format(HEADER_FORMAT, "ID", "State", "Name"));
+                int id = 0;
                 for (String bundle : bundles.keySet()) {
                     String[] tokens = bundle.split("/");
                     String name = null;
@@ -94,10 +95,11 @@ public class ListBundleCommand extends C
                             break;
                     }
                     if (showLoc) {
-                        System.out.println(String.format(OUTPUT_FORMAT, status, state.getLocation()));
+                        System.out.println(String.format(OUTPUT_FORMAT, id, status, state.getLocation()));
                     } else {
-                        System.out.println(String.format(OUTPUT_FORMAT, status, name + " (" + version + ")"));
+                        System.out.println(String.format(OUTPUT_FORMAT, id, status, name + " (" + version + ")"));
                     }
+                    id++;
                 }
             } else {
                 System.err.println("No bundles found for cluster group " + groupName);

Modified: karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/StartBundleCommand.java
URL: http://svn.apache.org/viewvc/karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/StartBundleCommand.java?rev=1406547&r1=1406546&r2=1406547&view=diff
==============================================================================
--- karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/StartBundleCommand.java (original)
+++ karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/StartBundleCommand.java Wed Nov  7 11:09:07 2012
@@ -30,16 +30,7 @@ import org.osgi.framework.BundleEvent;
 import java.util.Map;
 
 @Command(scope = "cluster", name = "bundle-start", description = "Start a bundle assigned to a cluster group.")
-public class StartBundleCommand extends CellarCommandSupport {
-
-    @Argument(index = 0, name = "group", description = "The cluster group name.", required = true, multiValued = false)
-    String groupName;
-
-    @Argument(index = 1, name = "name", description = "The bundle symbolic name.", required = true, multiValued = false)
-    String name;
-
-    @Argument(index = 2, name = "version", description = "The bundle version.", required = true, multiValued = false)
-    String version;
+public class StartBundleCommand extends BundleCommandSupport {
 
     private EventProducer eventProducer;
 
@@ -63,11 +54,19 @@ public class StartBundleCommand extends 
         Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
 
         String location;
+        String key = null;
         try {
-            Map<String, BundleState> bundles = clusterManager.getMap(Constants.BUNDLE_MAP + Configurations.SEPARATOR + groupName);
-            BundleState state = bundles.get(name + "/" + version);
+            Map<String, BundleState> distributedBundles = clusterManager.getMap(Constants.BUNDLE_MAP + Configurations.SEPARATOR + groupName);
+
+            key = selector(distributedBundles);
+
+            if (key == null) {
+                System.err.println("Bundle " + key + " not found in cluster group " + groupName);
+            }
+
+            BundleState state = distributedBundles.get(key);
             if (state == null) {
-                System.err.println("Bundle " + name + "/" + version + " not found in cluster group " + groupName);
+                System.err.println("Bundle " + key + " not found in cluster group " + groupName);
                 return null;
             }
             location = state.getLocation();
@@ -83,13 +82,14 @@ public class StartBundleCommand extends 
             }
 
             state.setStatus(BundleEvent.STARTED);
-            bundles.put(name + "/" + version, state);
+            distributedBundles.put(key, state);
         } finally {
             Thread.currentThread().setContextClassLoader(originalClassLoader);
         }
 
         // broadcast the cluster event
-        RemoteBundleEvent event = new RemoteBundleEvent(name, version, location, BundleEvent.STARTED);
+        String[] split = key.split("/");
+        RemoteBundleEvent event = new RemoteBundleEvent(split[0], split[1], location, BundleEvent.STARTED);
         event.setSourceGroup(group);
         eventProducer.produce(event);
 

Modified: karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/StopBundleCommand.java
URL: http://svn.apache.org/viewvc/karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/StopBundleCommand.java?rev=1406547&r1=1406546&r2=1406547&view=diff
==============================================================================
--- karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/StopBundleCommand.java (original)
+++ karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/StopBundleCommand.java Wed Nov  7 11:09:07 2012
@@ -30,17 +30,7 @@ import org.osgi.framework.BundleEvent;
 import java.util.Map;
 
 @Command(scope = "cluster", name = "bundle-stop", description = "Stop a bundle assigned to a cluster group.")
-public class StopBundleCommand extends CellarCommandSupport {
-
-    @Argument(index = 0, name = "group", description = "The cluster group name.", required = true, multiValued = false)
-    String groupName;
-
-    @Argument(index = 1, name = "name", description = "The bundle symbolic name.", required = true, multiValued = false)
-    String name;
-
-    @Argument(index = 2, name = "version", description = "The bundle version.", required = true, multiValued = false)
-    String version;
-
+public class StopBundleCommand extends BundleCommandSupport {
     private EventProducer eventProducer;
 
     @Override
@@ -63,11 +53,20 @@ public class StopBundleCommand extends C
         Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
 
         String location;
+        String key = null;
         try {
-            Map<String, BundleState> bundles = clusterManager.getMap(Constants.BUNDLE_MAP + Configurations.SEPARATOR + groupName);
-            BundleState state = bundles.get(name + "/" + version);
+            Map<String, BundleState> distributedBundles = clusterManager.getMap(Constants.BUNDLE_MAP + Configurations.SEPARATOR + groupName);
+
+            key = selector(distributedBundles);
+
+            if (key == null) {
+                System.err.println("Bundle " + key + " not found in cluster group " + groupName);
+                return null;
+            }
+
+            BundleState state = distributedBundles.get(key);
             if (state == null) {
-                System.err.println("Bundle " + name + "/" + version + " not found in cluster group " + groupName);
+                System.err.println("Bundle " + key + " not found in cluster group " + groupName);
                 return null;
             }
             state.setStatus(BundleEvent.STOPPED);
@@ -83,13 +82,14 @@ public class StopBundleCommand extends C
                 return null;
             }
 
-            bundles.put(name + "/" + version, state);
+            distributedBundles.put(key, state);
         } finally {
             Thread.currentThread().setContextClassLoader(originalClassLoader);
         }
 
         // broadcast the cluster event
-        RemoteBundleEvent event = new RemoteBundleEvent(name, version, location, BundleEvent.STOPPED);
+        String[] split = key.split("/");
+        RemoteBundleEvent event = new RemoteBundleEvent(split[0], split[1], location, BundleEvent.STOPPED);
         event.setSourceGroup(group);
         eventProducer.produce(event);
 

Modified: karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/UninstallBundleCommand.java
URL: http://svn.apache.org/viewvc/karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/UninstallBundleCommand.java?rev=1406547&r1=1406546&r2=1406547&view=diff
==============================================================================
--- karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/UninstallBundleCommand.java (original)
+++ karaf/cellar/branches/cellar-2.2.x/bundle/src/main/java/org/apache/karaf/cellar/bundle/shell/UninstallBundleCommand.java Wed Nov  7 11:09:07 2012
@@ -30,16 +30,7 @@ import org.osgi.framework.BundleEvent;
 import java.util.Map;
 
 @Command(scope = "cluster", name = "bundle-uninstall", description = "Uninstall a bundle assigned to a cluster group.")
-public class UninstallBundleCommand extends CellarCommandSupport {
-
-    @Argument(index = 0, name = "group", description = "The cluster group name.", required = true, multiValued = false)
-    String groupName;
-
-    @Argument(index = 1, name = "name", description = "The bundle symbolic name.", required = true, multiValued = false)
-    String name;
-
-    @Argument(index = 2, name = "version", description = "The bundle version.", required = true, multiValued = false)
-    String version;
+public class UninstallBundleCommand extends BundleCommandSupport {
 
     private EventProducer eventProducer;
 
@@ -63,11 +54,20 @@ public class UninstallBundleCommand exte
         Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
 
         String location;
+        String key = null;
         try {
-            Map<String, BundleState> bundles = clusterManager.getMap(Constants.BUNDLE_MAP + Configurations.SEPARATOR + groupName);
-            BundleState state = bundles.get(name + "/" + version);
+            Map<String, BundleState> distributedBundles = clusterManager.getMap(Constants.BUNDLE_MAP + Configurations.SEPARATOR + groupName);
+
+            key = selector(distributedBundles);
+
+            if (key == null) {
+                System.err.println("Bundle " + key + " not found in cluster group " + groupName);
+                return null;
+            }
+
+            BundleState state = distributedBundles.get(key);
             if (state == null) {
-                System.err.println("Bundle " + name + "/" + version + " not found in cluster group " + groupName);
+                System.err.println("Bundle " + key + " not found in cluster group " + groupName);
                 return null;
             }
             location = state.getLocation();
@@ -82,13 +82,14 @@ public class UninstallBundleCommand exte
                 return null;
             }
 
-            bundles.remove(name + "/" + version);
+            distributedBundles.remove(key);
         } finally {
             Thread.currentThread().setContextClassLoader(originalClassLoader);
         }
 
         // broadcast the cluster event
-        RemoteBundleEvent event = new RemoteBundleEvent(name, version, location, BundleEvent.UNINSTALLED);
+        String[] split = key.split("/");
+        RemoteBundleEvent event = new RemoteBundleEvent(split[0], split[1], location, BundleEvent.UNINSTALLED);
         event.setSourceGroup(group);
         eventProducer.produce(event);
 

Modified: karaf/cellar/branches/cellar-2.2.x/management/src/main/java/org/apache/karaf/cellar/management/internal/CellarBundleMBeanImpl.java
URL: http://svn.apache.org/viewvc/karaf/cellar/branches/cellar-2.2.x/management/src/main/java/org/apache/karaf/cellar/management/internal/CellarBundleMBeanImpl.java?rev=1406547&r1=1406546&r2=1406547&view=diff
==============================================================================
--- karaf/cellar/branches/cellar-2.2.x/management/src/main/java/org/apache/karaf/cellar/management/internal/CellarBundleMBeanImpl.java (original)
+++ karaf/cellar/branches/cellar-2.2.x/management/src/main/java/org/apache/karaf/cellar/management/internal/CellarBundleMBeanImpl.java Wed Nov  7 11:09:07 2012
@@ -142,13 +142,23 @@ public class CellarBundleMBeanImpl exten
         // update the cluster map
         ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
         Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
+
+        String key = null;
+        String location = null;
         try {
-            Map<String, BundleState> bundles = clusterManager.getMap(Constants.BUNDLE_MAP + Configurations.SEPARATOR + groupName);
-            BundleState state = bundles.get(symbolicName + "/" + version);
+            Map<String, BundleState> distributedBundles = clusterManager.getMap(Constants.BUNDLE_MAP + Configurations.SEPARATOR + groupName);
+
+            key = selector(symbolicName, version, distributedBundles);
+
+            if (key == null) {
+                throw new IllegalArgumentException("Bundle " + key + " is not found in cluster group " + groupName);
+            }
+
+            BundleState state = distributedBundles.get(key);
             if (state == null) {
-                throw new IllegalArgumentException("Bundle " + symbolicName + "/" + version + " is not found in cluster group " + groupName);
+                throw new IllegalArgumentException("Bundle " + key + " is not found in cluster group " + groupName);
             }
-            String location = state.getLocation();
+            location = state.getLocation();
 
             // check if the bundle location is allowed outbound
             CellarSupport support = new CellarSupport();
@@ -159,13 +169,14 @@ public class CellarBundleMBeanImpl exten
                 throw new IllegalArgumentException("Bundle location " + location + " is blocked outbound");
             }
 
-            bundles.remove(symbolicName + "/" + version);
+            distributedBundles.remove(key);
         } finally {
             Thread.currentThread().setContextClassLoader(originalClassLoader);
         }
 
         // broadcast the event
-        RemoteBundleEvent event = new RemoteBundleEvent(symbolicName, version, null, BundleEvent.UNINSTALLED);
+        String[] split = key.split("/");
+        RemoteBundleEvent event = new RemoteBundleEvent(split[0], split[1], location, BundleEvent.UNINSTALLED);
         event.setSourceGroup(group);
         eventProducer.produce(event);
     }
@@ -185,13 +196,22 @@ public class CellarBundleMBeanImpl exten
         // update the cluster map
         ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
         Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
+        String key = null;
+        String location = null;
         try {
-            Map<String, BundleState> bundles = clusterManager.getMap(Constants.BUNDLE_MAP + Configurations.SEPARATOR + groupName);
-            BundleState state = bundles.get(symbolicName + "/" + version);
+            Map<String, BundleState> distributedBundles = clusterManager.getMap(Constants.BUNDLE_MAP + Configurations.SEPARATOR + groupName);
+
+            key = selector(symbolicName, version, distributedBundles);
+
+            if (key == null) {
+                throw new IllegalStateException("Bundle " + key + " not found in cluster group " + groupName);
+            }
+
+            BundleState state = distributedBundles.get(key);
             if (state == null) {
-                throw new IllegalStateException("Bundle " + symbolicName + "/" + version + " not found in cluster group " + groupName);
+                throw new IllegalStateException("Bundle " + key + " not found in cluster group " + groupName);
             }
-            String location = state.getLocation();
+            location = state.getLocation();
 
             // check if the bundle location is allowed
             CellarSupport support = new CellarSupport();
@@ -203,13 +223,14 @@ public class CellarBundleMBeanImpl exten
             }
 
             state.setStatus(BundleEvent.STARTED);
-            bundles.put(symbolicName + "/" + version, state);
+            distributedBundles.put(key, state);
         } finally {
             Thread.currentThread().setContextClassLoader(originalClassLoader);
         }
 
         // broadcast the event
-        RemoteBundleEvent event = new RemoteBundleEvent(symbolicName, version, null, BundleEvent.STARTED);
+        String[] split = key.split("/");
+        RemoteBundleEvent event = new RemoteBundleEvent(split[0], split[1], location, BundleEvent.STARTED);
         event.setSourceGroup(group);
         eventProducer.produce(event);
     }
@@ -229,13 +250,22 @@ public class CellarBundleMBeanImpl exten
         // update the cluster map
         ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
         Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
+        String key = null;
+        String location = null;
         try {
-            Map<String, BundleState> bundles = clusterManager.getMap(Constants.BUNDLE_MAP + Configurations.SEPARATOR + groupName);
-            BundleState state = bundles.get(symbolicName + "/" + version);
+            Map<String, BundleState> distributedBundles = clusterManager.getMap(Constants.BUNDLE_MAP + Configurations.SEPARATOR + groupName);
+
+            key = selector(symbolicName, version, distributedBundles);
+
+            if (key == null) {
+                throw new IllegalStateException("Bundle " + key + " not found in cluster group " + groupName);
+            }
+
+            BundleState state = distributedBundles.get(key);
             if (state == null) {
-                throw new IllegalStateException("Bundle " + symbolicName + "/" + version + " not found in cluster group " + groupName);
+                throw new IllegalStateException("Bundle " + key + " not found in cluster group " + groupName);
             }
-            String location = state.getLocation();
+            location = state.getLocation();
 
             // check if the bundle location is allowed
             CellarSupport support = new CellarSupport();
@@ -247,23 +277,23 @@ public class CellarBundleMBeanImpl exten
             }
 
             state.setStatus(BundleEvent.STOPPED);
-            bundles.put(symbolicName + "/" + version, state);
+            distributedBundles.put(key, state);
         } finally {
             Thread.currentThread().setContextClassLoader(originalClassLoader);
         }
 
         // broadcast the event
-        RemoteBundleEvent event = new RemoteBundleEvent(symbolicName, version, null, BundleEvent.STOPPED);
-        event.setForce(true);
+        String[] split = key.split("/");
+        RemoteBundleEvent event = new RemoteBundleEvent(split[0], split[1], location, BundleEvent.STOPPED);
         event.setSourceGroup(group);
         eventProducer.produce(event);
     }
 
     public TabularData getBundles(String groupName) throws Exception {
         CompositeType compositeType = new CompositeType("Bundle", "Karaf Cellar bundle",
-                new String[]{"name", "version", "status", "location"},
-                new String[]{"Name of the bundle", "Version of the bundle", "Current status of the bundle", "Location of the bundle"},
-                new OpenType[]{SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING});
+                new String[]{"id", "name", "version", "status", "location"},
+                new String[]{"ID of the bundle", "Name of the bundle", "Version of the bundle", "Current status of the bundle", "Location of the bundle"},
+                new OpenType[]{SimpleType.INTEGER, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING});
         TabularType tableType = new TabularType("Bundles", "Table of all KarafCellar bundles", compositeType,
                 new String[]{"name", "version"});
         TabularData table = new TabularDataSupport(tableType);
@@ -272,6 +302,7 @@ public class CellarBundleMBeanImpl exten
         Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
         try {
             Map<String, BundleState> bundles = clusterManager.getMap(Constants.BUNDLE_MAP + Configurations.SEPARATOR + groupName);
+            int id = 0;
             for (String bundle : bundles.keySet()) {
                 String[] tokens = bundle.split("/");
                 String name = tokens[0];
@@ -305,9 +336,10 @@ public class CellarBundleMBeanImpl exten
                         break;
                 }
                 CompositeData data = new CompositeDataSupport(compositeType,
-                        new String[]{"name", "version", "status", "location"},
-                        new Object[]{name, version, status, state.getLocation()});
+                        new String[]{"id", "name", "version", "status", "location"},
+                        new Object[]{id, name, version, status, state.getLocation()});
                 table.put(data);
+                id++;
             }
         } finally {
             Thread.currentThread().setContextClassLoader(originalClassLoader);
@@ -315,4 +347,43 @@ public class CellarBundleMBeanImpl exten
         return table;
     }
 
+    /**
+     * Bundle selector.
+     *
+     * @return the bundle key is the distributed bundle map.
+     */
+    private String selector(String name, String version, Map<String, BundleState> distributedBundles) {
+        String key = null;
+        if (version == null || version.trim().isEmpty()) {
+            // looking for bundle using ID
+            int id = -1;
+            try {
+                id = Integer.parseInt(name);
+                int index = 0;
+                for (String bundle : distributedBundles.keySet()) {
+                    if (index == id) {
+                        key = bundle;
+                        break;
+                    }
+                    index++;
+                }
+            } catch (NumberFormatException nfe) {
+                // ignore
+            }
+            if (id == -1) {
+                // looking for bundle using only the name
+                for (String bundle : distributedBundles.keySet()) {
+                    if (bundle.startsWith(name)) {
+                        key = bundle;
+                        break;
+                    }
+                }
+            }
+        } else {
+            // looking for the bundle using name and version
+            key = name + "/" + version;
+        }
+        return key;
+    }
+
 }