FELIX-5023 : Web Console plugin is missing function to enable component descriptions

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1700717 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole-plugins/ds/changelog.txt b/webconsole-plugins/ds/changelog.txt
index d007bd8..03eb901 100755
--- a/webconsole-plugins/ds/changelog.txt
+++ b/webconsole-plugins/ds/changelog.txt
@@ -4,6 +4,7 @@
     * [FELIX-4998] - Declarative Service plugin might provide JSON format support for Inventory Printer
 ** Bug
     * [FELIX-5005] - BundleInfoProvider should work with null being passed as appRoot
+    * [FELIX-5023] - Web Console plugin is missing function to enable component descriptions
 
 
 Changes from 1.0.0 to 2.0.0
diff --git a/webconsole-plugins/ds/src/main/java/org/apache/felix/webconsole/plugins/ds/internal/ComponentConfigurationPrinter.java b/webconsole-plugins/ds/src/main/java/org/apache/felix/webconsole/plugins/ds/internal/ComponentConfigurationPrinter.java
index 2744a29..b0639b2 100644
--- a/webconsole-plugins/ds/src/main/java/org/apache/felix/webconsole/plugins/ds/internal/ComponentConfigurationPrinter.java
+++ b/webconsole-plugins/ds/src/main/java/org/apache/felix/webconsole/plugins/ds/internal/ComponentConfigurationPrinter.java
@@ -63,17 +63,17 @@
      */
     public void print(PrintWriter pw, Format format, boolean isZip)
     {
-        final List<ComponentDescriptionDTO> descriptions = new ArrayList<ComponentDescriptionDTO>();
+        final List<ComponentDescriptionDTO> disabled = new ArrayList<ComponentDescriptionDTO>();
         final List<ComponentConfigurationDTO> configurations = new ArrayList<ComponentConfigurationDTO>();
 
         final Collection<ComponentDescriptionDTO> descs = scrService.getComponentDescriptionDTOs();
         for(final ComponentDescriptionDTO d : descs)
         {
-            for(final ComponentConfigurationDTO cfg : scrService.getComponentConfigurationDTOs(d))
+            if ( !scrService.isComponentEnabled(d) )
             {
-                configurations.add(cfg);
+                disabled.add(d);
             }
-            descriptions.add(d);
+            configurations.addAll(scrService.getComponentConfigurationDTOs(d));
         }
         Collections.sort(configurations, Util.COMPONENT_COMPARATOR);
 
@@ -81,7 +81,7 @@
         {
             try
             {
-                printComponentsJson(pw, configurations, isZip);
+                printComponentsJson(pw, disabled, configurations, isZip);
             }
             catch (JSONException t)
             {
@@ -90,11 +90,12 @@
         }
         else
         {
-            printComponentsText(pw, configurations);
+            printComponentsText(pw, disabled, configurations);
         }
     }
 
     private final void printComponentsJson(final PrintWriter pw,
+        final List<ComponentDescriptionDTO> disabled,
         final List<ComponentConfigurationDTO> configurations,
         final boolean details) throws JSONException
     {
@@ -102,26 +103,42 @@
         jw.object();
         jw.key("components"); //$NON-NLS-1$
         jw.array();
-        
-        // render components
+
+        // render disabled descriptions
+        for(final ComponentDescriptionDTO cd : disabled)
+        {
+            plugin.disabledComponent(jw, cd);
+        }
+        // render configurations
         for (final ComponentConfigurationDTO cfg : configurations)
         {
             plugin.component(jw, cfg, details);
         }
-        
+
         jw.endArray();
         jw.endObject();
     }
 
     private static final void printComponentsText(final PrintWriter pw,
+            final List<ComponentDescriptionDTO> disabled,
             final List<ComponentConfigurationDTO> configurations)
     {
+        if ( !disabled.isEmpty())
+        {
+            pw.println("Disabled components:");
+        }
+        for(final ComponentDescriptionDTO cd : disabled)
+        {
+            disabledComponent(pw, cd);
+        }
+
         if (configurations.size() == 0)
         {
-            pw.println("Status: No Components Registered");
+            pw.println("Status: No Component Configurations");
         }
         else
         {
+            pw.println("Component Configurations:");
             // order components by id
             TreeMap<Long, ComponentConfigurationDTO> componentMap = new TreeMap<Long, ComponentConfigurationDTO>();
             for(final ComponentConfigurationDTO cfg : configurations)
@@ -159,6 +176,19 @@
         pw.println();
     }
 
+    private static final void disabledComponent(PrintWriter pw, final ComponentDescriptionDTO cfg)
+    {
+
+        pw.print(cfg.name);
+
+        pw.println("  Bundle" + cfg.bundle.symbolicName + " ("
+            + cfg.bundle.id + ")");
+        pw.println("  DefaultState="
+            + (cfg.defaultEnabled ? "enabled" : "disabled"));
+        pw.println("  Activation=" + (cfg.immediate ? "immediate" : "delayed"));
+        pw.println();
+    }
+
     private static void listServices(PrintWriter pw, final ComponentConfigurationDTO cfg)
     {
         String[] services = cfg.description.serviceInterfaces;
diff --git a/webconsole-plugins/ds/src/main/java/org/apache/felix/webconsole/plugins/ds/internal/InfoProvider.java b/webconsole-plugins/ds/src/main/java/org/apache/felix/webconsole/plugins/ds/internal/InfoProvider.java
index 5744430..9094ccf 100644
--- a/webconsole-plugins/ds/src/main/java/org/apache/felix/webconsole/plugins/ds/internal/InfoProvider.java
+++ b/webconsole-plugins/ds/src/main/java/org/apache/felix/webconsole/plugins/ds/internal/InfoProvider.java
@@ -64,17 +64,17 @@
     */

     public BundleInfo[] getBundleInfo(Bundle bundle, String webConsoleRoot, Locale locale)

     {

-        final List<ComponentDescriptionDTO> descriptions = new ArrayList<ComponentDescriptionDTO>();

+        final List<ComponentDescriptionDTO> disabled = new ArrayList<ComponentDescriptionDTO>();

         final List<ComponentConfigurationDTO> configurations = new ArrayList<ComponentConfigurationDTO>();

 

         final Collection<ComponentDescriptionDTO> descs = scrService.getComponentDescriptionDTOs(bundle);

         for(final ComponentDescriptionDTO d : descs)

         {

-            for(final ComponentConfigurationDTO cfg : scrService.getComponentConfigurationDTOs(d))

+            if ( !scrService.isComponentEnabled(d))

             {

-                configurations.add(cfg);

+                disabled.add(d);

             }

-            descriptions.add(d);

+            configurations.addAll(scrService.getComponentConfigurationDTOs(d));

         }

         Collections.sort(configurations, Util.COMPONENT_COMPARATOR);

 

@@ -83,8 +83,13 @@
             return NO_INFO;

         }

 

-        BundleInfo[] ret = new BundleInfo[configurations.size()];

+        BundleInfo[] ret = new BundleInfo[configurations.size() + disabled.size()];

         int i=0;

+        for (final ComponentDescriptionDTO cfg : disabled)

+        {

+            ret[i] = toInfo(cfg, webConsoleRoot, locale);

+            i++;

+        }

         for (final ComponentConfigurationDTO cfg : configurations)

         {

             ret[i] = toInfo(cfg, webConsoleRoot, locale);

@@ -93,6 +98,24 @@
         return ret;

     }

 

+    private BundleInfo toInfo(final ComponentDescriptionDTO cfg, String webConsoleRoot, Locale locale)

+    {

+        final ResourceBundle bundle = localization.getResourceBundle(locale);

+        final String state = "disabled";

+        final String name = cfg.name;

+        final String descr = bundle.getString("info.descr"); //$NON-NLS-1$;

+        String key = bundle.getString("info.key"); //$NON-NLS-1$;

+        // Component #{0} {1}, state {2}

+        key = MessageFormat.format(key, new Object[] { "", //$NON-NLS-1$

+                name,

+                state

+        });

+        return new BundleInfo(key,

+                (webConsoleRoot == null ? "" : webConsoleRoot) + "/components", //$NON-NLS-1$

+                BundleInfoType.LINK,

+                descr);

+    }

+

     private BundleInfo toInfo(final ComponentConfigurationDTO cfg, String webConsoleRoot, Locale locale)

     {

         final ResourceBundle bundle = localization.getResourceBundle(locale);

@@ -101,9 +124,9 @@
         final String descr = bundle.getString("info.descr"); //$NON-NLS-1$;

         String key = bundle.getString("info.key"); //$NON-NLS-1$;

         // Component #{0} {1}, state {2}

-        key = MessageFormat.format(key, new Object[] { String.valueOf(cfg.id), //

-                name != null ? name : "", //$NON-NLS-1$

-                state, //

+        key = MessageFormat.format(key, new Object[] { String.valueOf(cfg.id),

+                name,

+                state

         });

         return new BundleInfo(key, (webConsoleRoot == null ? "" : webConsoleRoot) + "/components/" + cfg.id, //$NON-NLS-1$

             BundleInfoType.LINK, descr);

diff --git a/webconsole-plugins/ds/src/main/java/org/apache/felix/webconsole/plugins/ds/internal/WebConsolePlugin.java b/webconsole-plugins/ds/src/main/java/org/apache/felix/webconsole/plugins/ds/internal/WebConsolePlugin.java
index 3d14ba5..f084529 100644
--- a/webconsole-plugins/ds/src/main/java/org/apache/felix/webconsole/plugins/ds/internal/WebConsolePlugin.java
+++ b/webconsole-plugins/ds/src/main/java/org/apache/felix/webconsole/plugins/ds/internal/WebConsolePlugin.java
@@ -51,6 +51,7 @@
 import org.osgi.service.component.runtime.dto.SatisfiedReferenceDTO;
 import org.osgi.service.metatype.MetaTypeInformation;
 import org.osgi.service.metatype.MetaTypeService;
+import org.osgi.util.promise.Promise;
 
 /**
  * ComponentsServlet provides a plugin for managing Service Components Runtime.
@@ -95,6 +96,21 @@
         return CATEGORY;
     }
 
+    private void wait(final Promise<Void> p )
+    {
+        while ( !p.isDone() )
+        {
+            try
+            {
+                Thread.sleep(5);
+            }
+            catch (final InterruptedException e)
+            {
+                Thread.currentThread().interrupt();
+            }
+        }
+    }
+
     /**
      * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
      */
@@ -102,25 +118,43 @@
     protected void doPost(HttpServletRequest request, HttpServletResponse response)
         throws IOException
     {
-        final RequestInfo reqInfo = new RequestInfo(request);
+        final String op = request.getParameter(OPERATION);
+        RequestInfo reqInfo = new RequestInfo(request, true);
         if (reqInfo.component == null && reqInfo.componentRequested)
         {
-            response.sendError(404);
-            return;
+            boolean found = false;
+            if (OPERATION_ENABLE.equals(op))
+            {
+                final String name = reqInfo.name;
+                for(final ComponentDescriptionDTO cd : reqInfo.disabled)
+                {
+                    if ( name.equals(cd.name) )
+                    {
+                        wait(getScrService().enableComponent(cd));
+                        reqInfo = new RequestInfo(request, false);
+                        found = true;
+                        break;
+                    }
+                }
+            }
+            if ( !found )
+            {
+                response.sendError(404);
+                return;
+            }
         }
-        if (!reqInfo.componentRequested)
+        else
         {
-            response.sendError(500);
-            return;
-        }
-        String op = request.getParameter(OPERATION);
-        if (OPERATION_ENABLE.equals(op))
-        {
-            getScrService().enableComponent(reqInfo.component.description);
-        }
-        else if (OPERATION_DISABLE.equals(op))
-        {
-            getScrService().disableComponent(reqInfo.component.description);
+            if (!reqInfo.componentRequested)
+            {
+                response.sendError(500);
+                return;
+            }
+            if (OPERATION_DISABLE.equals(op))
+            {
+                wait(getScrService().disableComponent(reqInfo.component.description));
+                reqInfo = new RequestInfo(request, false);
+            }
         }
 
         final PrintWriter pw = response.getWriter();
@@ -140,7 +174,7 @@
         // don't process if this is request to load a resource
         if (!path.startsWith(RES))
         {
-            final RequestInfo reqInfo = new RequestInfo(request);
+            final RequestInfo reqInfo = new RequestInfo(request, true);
             if (reqInfo.component == null && reqInfo.componentRequested)
             {
                 response.sendError(404);
@@ -191,32 +225,17 @@
         {
             jw.object();
 
+            jw.key("status"); //$NON-NLS-1$
             final ServiceComponentRuntime scrService = getScrService();
             if (scrService == null)
             {
-                jw.key("status"); //$NON-NLS-1$
                 jw.value(-1);
             }
             else
             {
-                if (info.configurations.size() == 0)
+                jw.value(info.configurations.size());
+                if ( !info.configurations.isEmpty())
                 {
-                    jw.key("status"); //$NON-NLS-1$
-                    jw.value(0);
-                }
-                else
-                {
-                    final StringBuffer buffer = new StringBuffer();
-                    buffer.append(info.configurations.size());
-                    buffer.append(" component"); //$NON-NLS-1$
-                    if (info.configurations.size() != 1)
-                    {
-                        buffer.append('s');
-                    }
-                    buffer.append(" installed."); //$NON-NLS-1$
-                    jw.key("status"); //$NON-NLS-1$
-                    jw.value(info.configurations.size());
-
                     // render components
                     jw.key("data"); //$NON-NLS-1$
                     jw.array();
@@ -226,6 +245,10 @@
                     }
                     else
                     {
+                        for( final ComponentDescriptionDTO cd : info.disabled )
+                        {
+                            disabledComponent(jw, cd);
+                        }
                         for (final ComponentConfigurationDTO cfg : info.configurations)
                         {
                             component(jw, cfg, false);
@@ -243,6 +266,41 @@
         }
     }
 
+    void disabledComponent(final JSONWriter jw, final ComponentDescriptionDTO component)
+    throws JSONException
+    {
+        final String name = component.name;
+
+        jw.object();
+
+        // component information
+        jw.key("id"); //$NON-NLS-1$
+        jw.value("");
+        jw.key("name"); //$NON-NLS-1$
+        jw.value(name);
+        jw.key("state"); //$NON-NLS-1$
+        jw.value("disabled"); //$NON-NLS-1$
+        jw.key("stateRaw"); //$NON-NLS-1$
+        jw.value(-1);
+
+        if ( component.configurationPid != null && component.configurationPid.length > 0 )
+        {
+            final String pid;
+            if ( component.configurationPid.length == 1 )
+            {
+                pid = component.configurationPid[0];
+            }
+            else
+            {
+                pid = Arrays.toString(component.configurationPid);
+            }
+            jw.key("pid"); //$NON-NLS-1$
+            jw.value(pid);
+        }
+
+        jw.endObject();
+    }
+
     void component(JSONWriter jw, ComponentConfigurationDTO component, boolean details)
         throws JSONException
     {
@@ -546,8 +604,10 @@
         public final ServiceComponentRuntime scrService;
         public final List<ComponentDescriptionDTO> descriptions = new ArrayList<ComponentDescriptionDTO>();
         public final List<ComponentConfigurationDTO> configurations = new ArrayList<ComponentConfigurationDTO>();
+        public final List<ComponentDescriptionDTO> disabled = new ArrayList<ComponentDescriptionDTO>();
+        public final String name;
 
-        protected RequestInfo(final HttpServletRequest request)
+        protected RequestInfo(final HttpServletRequest request, final boolean checkPathInfo)
         {
             this.scrService = getScrService();
             if ( scrService != null )
@@ -555,11 +615,12 @@
                 final Collection<ComponentDescriptionDTO> descs = scrService.getComponentDescriptionDTOs();
                 for(final ComponentDescriptionDTO d : descs)
                 {
-                    for(final ComponentConfigurationDTO cfg : scrService.getComponentConfigurationDTOs(d))
-                    {
-                        configurations.add(cfg);
-                    }
                     descriptions.add(d);
+                    if ( !scrService.isComponentEnabled(d) )
+                    {
+                        disabled.add(d);
+                    }
+                    configurations.addAll(scrService.getComponentConfigurationDTOs(d));
                 }
                 Collections.sort(configurations, Util.COMPONENT_COMPARATOR);
             }
@@ -579,7 +640,7 @@
                 extension = "html"; //$NON-NLS-1$
             }
 
-            if (info.length() > 1 && info.startsWith("/")) //$NON-NLS-1$
+            if (checkPathInfo && info.length() > 1 && info.startsWith("/")) //$NON-NLS-1$
             {
                 this.componentRequested = true;
                 info = info.substring(1);
@@ -595,6 +656,7 @@
                 this.componentRequested = false;
                 this.component = null;
             }
+            this.name = info;
 
             request.setAttribute(WebConsolePlugin.this.getClass().getName(), this);
         }
diff --git a/webconsole-plugins/ds/src/main/resources/res/plugin.js b/webconsole-plugins/ds/src/main/resources/res/plugin.js
index d1fa357..2bb2519 100644
--- a/webconsole-plugins/ds/src/main/resources/res/plugin.js
+++ b/webconsole-plugins/ds/src/main/resources/res/plugin.js
@@ -62,8 +62,8 @@
 	_.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(idPath, 'enable') });
+	if ( dataEntry.stateRaw == -1 ) { // disabled or disabling
+		_.find('li:eq(0)').removeClass('ui-helper-hidden').click(function() { changeDataEntryState(dataEntry.name, 'enable') });
 	} else {
 		_.find('li:eq(1)').removeClass('ui-helper-hidden').click(function() { changeDataEntryState(idPath, 'disable') });
 	}