FELIX-3684 Add Http Service web console plugin (patch by Chetan Mehrotra, thanks alot)
  (plus fixed the http.api dependency to the latest release 2.2.0)
  (plus updated OSGi Core dependency to 4.2.0 I think this is reasonable)

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1391181 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/http/base/pom.xml b/http/base/pom.xml
index b27c5df..3ba340a 100644
--- a/http/base/pom.xml
+++ b/http/base/pom.xml
@@ -59,6 +59,7 @@
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.core</artifactId>
+            <version>4.2.0</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
@@ -69,7 +70,7 @@
         <dependency>
             <groupId>${pom.groupId}</groupId>
             <artifactId>org.apache.felix.http.api</artifactId>
-            <version>${pom.version}</version>
+            <version>2.2.0</version>
         </dependency>
     </dependencies>
 
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java b/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java
index 7abbedd..dfab10a 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java
@@ -23,6 +23,7 @@
 import org.apache.felix.http.api.ExtHttpService;
 import org.apache.felix.http.base.internal.dispatch.Dispatcher;
 import org.apache.felix.http.base.internal.handler.HandlerRegistry;
+import org.apache.felix.http.base.internal.handler.HttpServicePlugin;
 import org.apache.felix.http.base.internal.listener.HttpSessionAttributeListenerManager;
 import org.apache.felix.http.base.internal.listener.HttpSessionListenerManager;
 import org.apache.felix.http.base.internal.listener.ServletContextAttributeListenerManager;
@@ -65,6 +66,7 @@
     private final HttpSessionListenerManager sessionListener;
     private final HttpSessionAttributeListenerManager sessionAttributeListener;
     private final boolean sharedContextAttributes;
+    private final HttpServicePlugin plugin;
     private ServiceRegistration serviceReg;
 
     public HttpServiceController(BundleContext bundleContext)
@@ -79,6 +81,7 @@
         this.sessionListener = new HttpSessionListenerManager(bundleContext);
         this.sessionAttributeListener = new HttpSessionAttributeListenerManager(bundleContext);
         this.sharedContextAttributes = getBoolean(FELIX_HTTP_SHARED_SERVLET_CONTEXT_ATTRIBUTES);
+        this.plugin = new HttpServicePlugin(bundleContext,registry);
     }
 
     public Dispatcher getDispatcher()
@@ -128,6 +131,7 @@
         this.requestAttributeListener.open();
         this.sessionListener.open();
         this.sessionAttributeListener.open();
+        this.plugin.register();
 
         HttpServiceFactory factory = new HttpServiceFactory(servletContext, this.registry,
             this.contextAttributeListener, this.sharedContextAttributes);
@@ -146,6 +150,7 @@
         this.contextAttributeListener.close();
         this.requestListener.close();
         this.requestAttributeListener.close();
+        this.plugin.unregister();
 
         try {
             this.serviceReg.unregister();
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java
index 400fe45..33bee18 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java
@@ -93,4 +93,14 @@
     {
         return other.ranking - this.ranking;
     }
+
+    public int getRanking()
+    {
+        return ranking;
+    }
+
+    public String getPattern()
+    {
+        return regex.toString();
+    }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpServicePlugin.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpServicePlugin.java
new file mode 100644
index 0000000..d1d0aae
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpServicePlugin.java
@@ -0,0 +1,227 @@
+/*
+ * 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.http.base.internal.handler;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceRegistration;
+
+import javax.servlet.Servlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Properties;
+
+@SuppressWarnings("serial")
+public class HttpServicePlugin extends HttpServlet
+{
+
+    private final HandlerRegistry registry;
+    private final BundleContext context;
+
+    private ServiceRegistration serviceReg;
+
+    public HttpServicePlugin(BundleContext context, HandlerRegistry registry)
+    {
+        this.registry = registry;
+        this.context = context;
+    }
+
+    public void register()
+    {
+        Properties props = new Properties();
+        props.put(Constants.SERVICE_VENDOR, "Apache Software Foundation");
+        props.put(Constants.SERVICE_DESCRIPTION, "HTTP Service Web Console Plugin");
+        props.put("felix.webconsole.label", "httpservice");
+        props.put("felix.webconsole.title", "HTTP Service");
+        props.put("felix.webconsole.configprinter.modes", "always");
+        this.serviceReg = context.registerService(Servlet.class.getName(), this, props);
+    }
+
+    @Override
+    protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws IOException
+    {
+        getHtml(resp);
+    }
+
+    private void getHtml(HttpServletResponse resp) throws IOException
+    {
+        final PrintWriter pw = resp.getWriter();
+
+        printServletDetails(pw);
+        printFilterDetails(pw);
+
+    }
+
+    private void printFilterDetails(PrintWriter pw)
+    {
+        pw.println("<p class=\"statline ui-state-highlight\">${Registered Filter Services}</p>");
+
+        pw.println("<table class=\"nicetable\">");
+        pw.println("<thead><tr>");
+        pw.println("<th class=\"header\">${Pattern}</th>");
+        pw.println("<th class=\"header\">${Filter(Ranking)}</th>");
+        pw.println("<th class=\"header\">${Bundle}</th>");
+        pw.println("</tr></thead>");
+
+        FilterHandler[] filters = registry.getFilters();
+        Arrays.sort(filters);
+        String rowClass = "odd";
+        for (FilterHandler filter : filters)
+        {
+            pw.println("<tr class=\"" + rowClass + " ui-state-default\">");
+            pw.println("<td>" + filter.getPattern() + "</td>");
+            pw.println("<td>" + filter.getFilter().getClass().getName() + "(" + filter.getRanking() + ")" + "</td>");
+
+            printBundleDetails(pw, filter.getFilter().getClass());
+
+            if (rowClass.equals("odd"))
+            {
+                rowClass = "even";
+            }
+            else
+            {
+                rowClass = "odd";
+            }
+        }
+        pw.println("</table>");
+    }
+
+    private void printServletDetails(PrintWriter pw)
+    {
+        pw.println("<p class=\"statline ui-state-highlight\">${Registered Servlet Services}</p>");
+
+        pw.println("<table class=\"nicetable\">");
+        pw.println("<thead><tr>");
+        pw.println("<th class=\"header\">${Alias}</th>");
+        pw.println("<th class=\"header\">${Servlet}</th>");
+        pw.println("<th class=\"header\">${Bundle}</th>");
+        pw.println("</tr></thead>");
+
+        ServletHandler[] servlets = registry.getServlets();
+        String rowClass = "odd";
+        for (ServletHandler servlet : servlets)
+        {
+
+            pw.println("<tr class=\"" + rowClass + " ui-state-default\">");
+            pw.println("<td>" + servlet.getAlias() + "</td>");
+            pw.println("<td>" + servlet.getServlet().getClass().getName() + "</td>");
+
+            printBundleDetails(pw, servlet.getServlet().getClass());
+
+            pw.println("</tr>");
+            if (rowClass.equals("odd"))
+            {
+                rowClass = "even";
+            }
+            else
+            {
+                rowClass = "odd";
+            }
+        }
+        pw.println("</table>");
+    }
+
+    /**
+     * @see org.apache.felix.webconsole.ConfigurationPrinter#printConfiguration(java.io.PrintWriter)
+     */
+    public void printConfiguration(final PrintWriter pw)
+    {
+        pw.println("HTTP Service Details:");
+        pw.println();
+        pw.println("Registered Servlet Services");
+        ServletHandler[] servlets = registry.getServlets();
+        for (ServletHandler servlet : servlets)
+        {
+            pw.println("Alias : " + servlet.getAlias());
+
+            addSpace(pw, 1);
+            pw.println("Class  :" + servlet.getServlet().getClass().getName());
+            addSpace(pw, 1);
+            pw.println("Bundle :" + getBundleDetails(servlet.getServlet().getClass()));
+
+        }
+
+        pw.println();
+
+        pw.println("Registered Filter Services");
+        FilterHandler[] filters = registry.getFilters();
+        Arrays.sort(filters);
+        for (FilterHandler filter : filters)
+        {
+            pw.println("Pattern : " + filter.getPattern());
+
+            addSpace(pw, 1);
+            pw.println("Ranking :" + filter.getRanking());
+            addSpace(pw, 1);
+            pw.println("Class   :" + filter.getFilter().getClass().getName());
+            addSpace(pw, 1);
+            pw.println("Bundle  :" + getBundleDetails(filter.getFilter().getClass()));
+        }
+    }
+
+    public void unregister()
+    {
+        if (this.serviceReg != null)
+        {
+            this.serviceReg.unregister();
+        }
+    }
+
+    private void printBundleDetails(PrintWriter pw, Class<?> c)
+    {
+        Bundle b = getBundle(c);
+        pw.println("<td>");
+        if (b == null)
+        {
+            pw.print("UNKNOWN");
+        }
+        else
+        {
+            String details = b.getSymbolicName();
+            pw.print("<a href=\"${appRoot}/bundles/" + b.getBundleId() + "\">" + details + "</a>");
+        }
+        pw.println("</td>");
+    }
+
+    private String getBundleDetails(Class<?> c)
+    {
+        Bundle b = getBundle(c);
+        return (b == null) ? "UNKNOWN" : b.getSymbolicName();
+    }
+
+    private static void addSpace(PrintWriter pw, int count)
+    {
+        for (int i = 0; i < count; i++)
+        {
+            pw.print("  ");
+        }
+    }
+
+    private Bundle getBundle(Class<?> clazz)
+    {
+        return FrameworkUtil.getBundle(clazz);
+    }
+}