FELIX-2288 Add support for components whose component ID is not assigned. Instead of the component ID a combination of the component name and the service.pid property assigned to the component is used. If the service.pid property is not assigned to the component, just the component name is used.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@981795 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ComponentsServlet.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ComponentsServlet.java
index 1481b25..4baaf05 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ComponentsServlet.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ComponentsServlet.java
@@ -508,60 +508,121 @@
         public final Component component;
         public final boolean componentRequested;
 
-        protected long getComponentId( final String componentIdPar )
-        {
-            try
-            {
-                return Long.parseLong( componentIdPar );
-            }
-            catch ( NumberFormatException nfe )
-            {
-                // TODO: log
-            }
-
-            // no bundleId or wrong format
-            return -1;
-        }
 
         protected RequestInfo( final HttpServletRequest request )
         {
             String info = request.getPathInfo();
             // remove label and starting slash
-            info = info.substring(getLabel().length() + 1);
+            info = info.substring( getLabel().length() + 1 );
 
             // get extension
-            if ( info.endsWith(".json") )
+            if ( info.endsWith( ".json" ) )
             {
                 extension = "json";
-                info = info.substring(0, info.length() - 5);
+                info = info.substring( 0, info.length() - 5 );
             }
             else
             {
                 extension = "html";
             }
 
-            long componentId = getComponentId(info.substring(info.lastIndexOf('/') + 1));
-            if ( componentId == -1 )
+            if ( info.length() > 0 && info.startsWith( "/" ) )
             {
-                componentRequested = false;
-                component = null;
+                this.componentRequested = true;
+                info = info.substring( 1 );
+                Component component = getComponentId( info );
+                if ( component == null )
+                {
+                    component = getComponentByName( info );
+                }
+                this.component = component;
             }
             else
             {
-                componentRequested = true;
+                this.componentRequested = false;
+                this.component = null;
+            }
+
+            request.setAttribute( ComponentsServlet.this.getClass().getName(), this );
+        }
+
+
+        protected Component getComponentId( final String componentIdPar )
+        {
+            final ScrService scrService = getScrService();
+            if ( scrService != null )
+            {
+                try
+                {
+                    final long componentId = Long.parseLong( componentIdPar );
+                    return scrService.getComponent( componentId );
+                }
+                catch ( NumberFormatException nfe )
+                {
+                    // don't care
+                }
+            }
+
+            return null;
+        }
+
+
+        protected Component getComponentByName( final String names )
+        {
+            if ( names.length() > 0 )
+            {
                 final ScrService scrService = getScrService();
                 if ( scrService != null )
                 {
-                    component = scrService.getComponent( componentId );
-                }
-                else
-                {
-                    component = null;
+
+                    final int slash = names.lastIndexOf( '/' );
+                    final String componentName;
+                    final String pid;
+                    if ( slash > 0 )
+                    {
+                        componentName = names.substring( 0, slash );
+                        pid = names.substring( slash + 1 );
+                    }
+                    else
+                    {
+                        componentName = names;
+                        pid = null;
+                    }
+
+                    Component[] components;
+                    try
+                    {
+                        components = scrService.getComponents( componentName );
+                    }
+                    catch ( Throwable t )
+                    {
+                        // not implemented in the used API versio
+                        components = null;
+                    }
+
+                    if ( components != null )
+                    {
+                        if ( pid != null )
+                        {
+                            for ( int i = 0; i < components.length; i++ )
+                            {
+                                Component component = components[i];
+                                if ( pid.equals( component.getProperties().get( Constants.SERVICE_PID ) ) )
+                                {
+                                    return component;
+                                }
+                            }
+                        }
+                        else if ( components.length > 0 )
+                        {
+                            return components[0];
+                        }
+                    }
                 }
             }
-            request.setAttribute(ComponentsServlet.class.getName(), this);
-        }
 
+            return null;
+        }
     }
 
     static RequestInfo getRequestInfo(final HttpServletRequest request)
diff --git a/webconsole/src/main/resources/res/ui/components.js b/webconsole/src/main/resources/res/ui/components.js
index b0d084c..c1432e8 100644
--- a/webconsole/src/main/resources/res/ui/components.js
+++ b/webconsole/src/main/resources/res/ui/components.js
@@ -38,24 +38,35 @@
 	}
 }
 
-function entry( /* Object */ dataEntry ) {
-	var id = dataEntry.id;
-	var name = dataEntry.name;
+function getEntryId(/* Object */ dataEntry) {
+    var id = dataEntry.id;
+    if (id < 0) {
+        id = dataEntry.name;
+        if (dataEntry.pid) {
+            id += "/" + dataEntry.pid;
+        }
+    }
+    return id;
+}
 
-	var _ = tableEntryTemplate.clone().appendTo(tableBody).attr('id', 'entry' + dataEntry.id);
+function entry( /* Object */ dataEntry ) {
+	var idPath = getEntryId(dataEntry);
+	var id = idPath.replace(/[./-]/g, "_");
+	var name = dataEntry.name;
+	var _ = tableEntryTemplate.clone().appendTo(tableBody).attr('id', 'entry' + id);
 
 	_.find('.bIcon').attr('id', 'img' + id).click(function() {
-		showDetails(id);
-	}).after(drawDetails ? name : ('<a href="' + window.location.pathname + '/' + id + '">' + name + '</a>'));
+		showDetails(idPath);
+	}).after(drawDetails ? name : ('<a href="' + pluginRoot + '/' + idPath + '">' + name + '</a>'));
 
-	_.find('td:eq(0)').text( id );
+	_.find('td:eq(0)').text( dataEntry.id );
 	_.find('td:eq(2)').text( dataEntry.state );
 
 	// setup buttons
 	if ( dataEntry.stateRaw == 1 || dataEntry.stateRaw == 1024 ) { // disabled or disabling
-		_.find('li:eq(0)').removeClass('ui-helper-hidden').click(function() { changeDataEntryState(id, 'enable') });
+		_.find('li:eq(0)').removeClass('ui-helper-hidden').click(function() { changeDataEntryState(idPath, 'enable') });
 	} else {
-		_.find('li:eq(1)').removeClass('ui-helper-hidden').click(function() { changeDataEntryState(id, 'disable') });
+		_.find('li:eq(1)').removeClass('ui-helper-hidden').click(function() { changeDataEntryState(idPath, 'disable') });
 	}
 	if ( dataEntry.configurable ) _.find('li:eq(2)').removeClass('ui-helper-hidden').click(function() { // configure
 		changeDataEntryState(dataEntry.pid, 'configure');
@@ -85,6 +96,7 @@
 }
 
 function hideDetails( id ) {
+	var __test__ = $("#img" + id);
 	$("#img" + id).each(function() {
 		$("#pluginInlineDetails").remove();
 		$(this).
@@ -98,9 +110,11 @@
 
 function renderDetails( data ) {
 	data = data.data[0];
+	var id = getEntryId(data).replace(/[./-]/g, "_");
 	$("#pluginInlineDetails").remove();
-	$("#entry" + data.id + " > td").eq(1).append("<div id='pluginInlineDetails'/>");
-	$("#img" + data.id).each(function() {
+	var __test__ = $("#entry" + id);
+	$("#entry" + id + " > td").eq(1).append("<div id='pluginInlineDetails'/>");
+	$("#img" + id).each(function() {
 		if ( drawDetails ) {
 			var ref = window.location.pathname;
 			ref = ref.substring(0, ref.lastIndexOf('/'));
@@ -116,7 +130,7 @@
 				removeClass('ui-icon-triangle-1-e').//right
 				addClass('ui-icon-triangle-1-s').//down
 				attr("title", "Hide Details").
-				unbind('click').click(function() {hideDetails(data.id)});
+				unbind('click').click(function() {hideDetails(id)});
 		}
 	});
 	$("#pluginInlineDetails").append("<table border='0'><tbody></tbody></table>");