Fixed FELIX-2282 /Optimize Services Printer/
https://issues.apache.org/jira/browse/FELIX-2282

Also added some javadoc in OsgiManager and fixed spelling mistakes in the comments.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@934299 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/ServicesConfigurationPrinter.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/ServicesConfigurationPrinter.java
new file mode 100644
index 0000000..60f43c7
--- /dev/null
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/ServicesConfigurationPrinter.java
@@ -0,0 +1,142 @@
+/*

+ * 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.webconsole.internal.core;

+

+import java.io.PrintWriter;

+import java.text.MessageFormat;

+import java.util.Locale;

+

+import org.apache.felix.webconsole.internal.AbstractConfigurationPrinter;

+import org.apache.felix.webconsole.internal.Util;

+import org.osgi.framework.Bundle;

+import org.osgi.framework.Constants;

+import org.osgi.framework.InvalidSyntaxException;

+import org.osgi.framework.ServiceReference;

+

+/**

+ * ServicesConfigurationPrinter provides a configuration printer for inspecting the 

+ * registered services.

+ */

+public class ServicesConfigurationPrinter extends AbstractConfigurationPrinter implements Constants

+{

+    private static final String TITLE = "Services";

+

+    private static final MessageFormat INFO = new MessageFormat(

+        "Service {0} - {1} (pid: {2})");

+    private static final MessageFormat FROM = new MessageFormat(

+        "  from Bundle {0} - {1} ({2}), version {3}");

+    private static final MessageFormat USING = new MessageFormat(

+        "  Using Bundle {0} - {1} ({2}), version {3}");

+

+    // don't create empty reference array all the time, create it only once - it is immutable

+    private static final ServiceReference[] NO_REFS = new ServiceReference[0];

+

+    /**

+     * @see org.apache.felix.webconsole.ConfigurationPrinter#getTitle()

+     */

+    public final String getTitle()

+    {

+        return TITLE;

+    }

+

+    /**

+     * @see org.apache.felix.webconsole.ConfigurationPrinter#printConfiguration(java.io.PrintWriter)

+     */

+    public final void printConfiguration(PrintWriter pw)

+    {

+        final Object[] data = new Object[4]; // used as message formatter parameters

+        final ServiceReference refs[] = getServices();

+        pw.print("Status: ");

+        pw.println(ServicesServlet.getStatusLine(refs));

+

+        for (int i = 0; refs != null && i < refs.length; i++)

+        {

+            try

+            {

+                final Bundle bundle = refs[i].getBundle();

+                final Bundle[] usingBundles = refs[i].getUsingBundles();

+

+                pw.println();

+                pw.println(INFO.format(params(refs[i], data)));

+                pw.println(FROM.format(params(bundle, data)));

+

+                // print registration properties

+                String[] keys = refs[i].getPropertyKeys();

+                for (int j = 0; keys != null && j < keys.length; j++)

+                {

+                    final String key = keys[j];

+                    // skip common keys - already added above

+                    if (SERVICE_ID.equals(key) || OBJECTCLASS.equals(key)

+                        || SERVICE_PID.equals(key))

+                        continue;

+

+                    pw.print("    ");

+                    pw.print(key);

+                    pw.print(": ");

+                    pw.println(ServicesServlet.propertyAsString(refs[i], key));

+                }

+

+                // using bundles

+                for (int j = 0; usingBundles != null && j < usingBundles.length; j++)

+                {

+                    pw.println(USING.format(params(usingBundles[j], data)));

+                }

+            }

+            catch (Throwable t)

+            {

+                // a problem handling a service - ignore and continue with the next

+            }

+        }

+    }

+

+    private static final Object[] params(Bundle bundle, Object[] data)

+    {

+        data[0] = String.valueOf(bundle.getBundleId());

+        data[1] = Util.getName(bundle, Locale.ENGLISH);

+        data[2] = bundle.getSymbolicName();

+        data[3] = Util.getHeaderValue(bundle, Constants.BUNDLE_VERSION);

+        return data;

+    }

+

+    private static final Object[] params(ServiceReference ref, Object[] data)

+    {

+        data[0] = ServicesServlet.propertyAsString(ref, SERVICE_ID);

+        data[1] = ServicesServlet.propertyAsString(ref, OBJECTCLASS);

+        data[2] = ServicesServlet.propertyAsString(ref, SERVICE_PID);

+        data[3] = "";

+        return data;

+    }

+

+    private final ServiceReference[] getServices()

+    {

+        ServiceReference[] refs = null;

+        try

+        {

+            refs = getBundleContext().getAllServiceReferences(null, null);

+        }

+        catch (InvalidSyntaxException e)

+        {

+            // ignore

+        }

+

+        // no services or invalid filter syntax (unlikely)

+        return refs != null ? refs : NO_REFS;

+    }

+

+}

diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/ServicesServlet.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/ServicesServlet.java
index f8528da..9a56bb6 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/ServicesServlet.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/ServicesServlet.java
@@ -23,36 +23,30 @@
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.io.Writer;
-import java.text.MessageFormat;
 import java.util.Locale;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.felix.webconsole.ConfigurationPrinter;
 import org.apache.felix.webconsole.DefaultVariableResolver;
 import org.apache.felix.webconsole.SimpleWebConsolePlugin;
 import org.apache.felix.webconsole.WebConsoleConstants;
 import org.apache.felix.webconsole.WebConsoleUtil;
 import org.apache.felix.webconsole.internal.OsgiManagerPlugin;
 import org.apache.felix.webconsole.internal.Util;
-import org.json.JSONArray;
 import org.json.JSONException;
-import org.json.JSONObject;
 import org.json.JSONWriter;
 import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
 
 
 /**
  * ServicesServlet provides a plugin for inspecting the registered services.
  */
-public class ServicesServlet extends SimpleWebConsolePlugin implements ConfigurationPrinter, OsgiManagerPlugin
+public class ServicesServlet extends SimpleWebConsolePlugin implements OsgiManagerPlugin
 {
     // don't create empty reference array all the time, create it only once - it is immutable
     private static final ServiceReference[] NO_REFS = new ServiceReference[0];
@@ -109,8 +103,6 @@
         return ( RequestInfo ) request.getAttribute( ServicesServlet.class.getName() );
     }
 
-    private ServiceRegistration configurationPrinter;
-
     /** the label for the services plugin */
     public static final String LABEL = "services";
     private static final String TITLE = "%services.pluginTitle";
@@ -127,122 +119,6 @@
     }
 
 
-    /**
-     * @see org.apache.felix.webconsole.AbstractWebConsolePlugin#activate(org.osgi.framework.BundleContext)
-     */
-    public void activate( BundleContext bundleContext )
-    {
-        super.activate( bundleContext );
-        configurationPrinter = bundleContext.registerService( ConfigurationPrinter.SERVICE, this, null );
-    }
-
-
-    /**
-     * @see org.apache.felix.webconsole.SimpleWebConsolePlugin#deactivate()
-     */
-    public void deactivate()
-    {
-        if ( configurationPrinter != null )
-        {
-            configurationPrinter.unregister();
-            configurationPrinter = null;
-        }
-
-        super.deactivate();
-    }
-
-
-    /**
-     * @see org.apache.felix.webconsole.ConfigurationPrinter#printConfiguration(java.io.PrintWriter)
-     */
-    public void printConfiguration( PrintWriter pw )
-    {
-        try
-        {
-            StringWriter w = new StringWriter();
-            writeJSON( w, null, true, Locale.ENGLISH );
-            String jsonString = w.toString();
-            JSONObject json = new JSONObject( jsonString );
-
-            pw.println( "Status: " + json.get( "status" ) );
-            pw.println();
-
-            JSONArray data = json.getJSONArray( "data" );
-            for ( int i = 0; i < data.length(); i++ )
-            {
-                if ( !data.isNull( i ) )
-                {
-                    JSONObject service = data.getJSONObject( i );
-
-                    pw.println( MessageFormat.format( "Service {0} - {1} (pid: {2})", new Object[]
-                        { service.get( "id" ), service.get( "types" ), service.get( "pid" ) } ) );
-                    pw.println( MessageFormat.format( "  from Bundle {0} - {1} ({2}), version {3}", new Object[]
-                        { service.get( "bundleId" ), service.get( "bundleName" ), service.get( "bundleSymbolicName" ),
-                            service.get( "bundleVersion" ) } ) );
-
-                    JSONArray props = service.getJSONArray( "props" );
-                    for ( int pi = 0; pi < props.length(); pi++ )
-                    {
-                        if ( !props.isNull( pi ) )
-                        {
-                            JSONObject entry = props.getJSONObject( pi );
-
-                            pw.print( "    " + entry.get( "key" ) + ": " );
-
-                            Object entryValue = entry.get( "value" );
-                            if ( entryValue instanceof JSONArray )
-                            {
-                                pw.println();
-                                JSONArray entryArray = ( JSONArray ) entryValue;
-                                for ( int ei = 0; ei < entryArray.length(); ei++ )
-                                {
-                                    if ( !entryArray.isNull( ei ) )
-                                    {
-                                        pw.println( "        " + entryArray.get( ei ) );
-                                    }
-                                }
-                            }
-                            else
-                            {
-                                pw.println( entryValue );
-                            }
-                        }
-                    }
-
-                    JSONArray usingBundles = service.getJSONArray( "usingBundles" );
-                    for ( int ui = 0; ui < usingBundles.length(); ui++ )
-                    {
-                        if ( !usingBundles.isNull( ui ) )
-                        {
-                            JSONObject bundle = usingBundles.getJSONObject( ui );
-                            pw.println( MessageFormat.format( "  Using Bundle {0} - {1} ({2}), version {3}", new Object[]
-                                { bundle.get( "bundleId" ), bundle.get( "bundleName" ),
-                                    bundle.get( "bundleSymbolicName" ), bundle.get( "bundleVersion" ) } ) );
-                        }
-                    }
-
-                    pw.println();
-                }
-            }
-        }
-        catch ( Exception e )
-        {
-            log( "Problem rendering Bundle details for configuration status", e );
-        }
-    }
-
-
-    private static final void appendServiceInfoCount( final StringBuffer buf, String msg, int count )
-    {
-        buf.append( count );
-        buf.append( " service" );
-        if ( count != 1 )
-            buf.append( 's' );
-        buf.append( ' ' );
-        buf.append( msg );
-    }
-
-
     final ServiceReference getServiceById( String pathInfo )
     {
         // only use last part of the pathInfo
@@ -290,16 +166,21 @@
     }
 
 
-    private static final String getStatusLine( final ServiceReference[] services )
+    static final String getStatusLine( final ServiceReference[] services )
     {
+        final int count = services.length;
         final StringBuffer buffer = new StringBuffer();
         buffer.append( "Services information: " );
-        appendServiceInfoCount( buffer, "in total", services.length );
+        buffer.append( count );
+        buffer.append( " service" );
+        if ( count != 1 )
+            buffer.append( 's' );
+        buffer.append( " in total" );
         return buffer.toString();
     }
 
 
-    private String propertyAsString( ServiceReference ref, String name )
+    static final String propertyAsString( ServiceReference ref, String name )
     {
         Object value = ref.getProperty( name );
         if ( value instanceof Object[] )
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
index 0daf99d..9d2d45e 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
@@ -70,7 +70,7 @@
     private static final long serialVersionUID = 1L;
 
     /**
-     * Old name of the request attribute provding the root to the web console.
+     * Old name of the request attribute providing the root to the web console.
      * This attribute is no deprecated and replaced by
      * {@link WebConsoleConstants#ATTR_APP_ROOT}.
      *
@@ -79,7 +79,7 @@
     private static final String ATTR_APP_ROOT_OLD = OsgiManager.class.getName() + ".appRoot";
 
     /**
-     * Old name of the request attribute provding the mappings from label to
+     * Old name of the request attribute providing the mappings from label to
      * page title. This attribute is no deprecated and replaced by
      * {@link WebConsoleConstants#ATTR_LABEL_MAP}.
      *
@@ -141,6 +141,7 @@
             "org.apache.felix.webconsole.internal.compendium.LogServlet",
             "org.apache.felix.webconsole.internal.compendium.PreferencesConfigurationPrinter",
             "org.apache.felix.webconsole.internal.core.BundlesServlet",
+            "org.apache.felix.webconsole.internal.core.ServicesConfigurationPrinter",
             "org.apache.felix.webconsole.internal.core.ServicesServlet",
             "org.apache.felix.webconsole.internal.deppack.DepPackServlet",
             "org.apache.felix.webconsole.internal.misc.LicenseServlet",
@@ -240,6 +241,9 @@
 
     //---------- Servlet API
 
+    /**
+     * @see javax.servlet.GenericServlet#init()
+     */
     public void init()
     {
         // base class initialization not needed, since the GenericServlet.init
@@ -318,6 +322,9 @@
     }
 
 
+    /**
+     * @see javax.servlet.GenericServlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
+     */
     public void service( final ServletRequest req, final ServletResponse res ) throws ServletException, IOException
     {
         // don't really expect to be called within a non-HTTP environment
@@ -423,6 +430,9 @@
         return locale;
     }
 
+    /**
+     * @see javax.servlet.GenericServlet#destroy()
+     */
     public void destroy()
     {
         // base class destroy not needed, since the GenericServlet.destroy
@@ -479,7 +489,7 @@
      * Calls the <code>GenericServlet.log(String)</code> method if the
      * configured log level is less than or equal to the given <code>level</code>.
      * <p>
-     * Note, that the <code>level</code> paramter is only used to decide whether
+     * Note, that the <code>level</code> parameter is only used to decide whether
      * the <code>GenericServlet.log(String)</code> method is called or not. The
      * actual implementation of the <code>GenericServlet.log</code> method is
      * outside of the control of this method.
@@ -501,7 +511,7 @@
      * the configured log level is less than or equal to the given
      * <code>level</code>.
      * <p>
-     * Note, that the <code>level</code> paramter is only used to decide whether
+     * Note, that the <code>level</code> parameter is only used to decide whether
      * the <code>GenericServlet.log(String, Throwable)</code> method is called
      * or not. The actual implementation of the <code>GenericServlet.log</code>
      * method is outside of the control of this method.