FELIX-2649 : Support for configuration printers without requiring them to implement the interface

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1021352 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleConstants.java b/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleConstants.java
index a8590e0..e08f4d0 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleConstants.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleConstants.java
@@ -19,6 +19,7 @@
 package org.apache.felix.webconsole;
 
 import java.util.Locale;
+import java.util.Map;
 
 /**
  * WebConsoleConstants provides some common constants that are used by plugin
@@ -63,6 +64,20 @@
     public static final String PLUGIN_TITLE = "felix.webconsole.title";
 
     /**
+     * The property marking a service as a configuration printer.
+     * This can be any service having either a printConfiguration(PrintWriter)
+     * or printConfiguration(PrintWriter, String) method - this is according
+     * to the ConfigurationPrinter and ModeAwareConfigurationPrinter
+     * interfaces.
+     *
+     * If a service has a {@link #PLUGIN_LABEL}, {@link #PLUGIN_TITLE} and
+     * this property, it is treated as a configuration printer servce.
+     *
+     * @since 3.1.4
+     */
+    public static final String CONFIG_PRINTER_MODES = "felix.webconsole.configprinter.modes";
+
+    /**
      * The name of the service registration properties providing references
      * to addition CSS files that should be loaded when rendering the header
      * for a registered plugin.
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ConfigurationPrinterAdapter.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ConfigurationPrinterAdapter.java
new file mode 100644
index 0000000..7be7e32
--- /dev/null
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ConfigurationPrinterAdapter.java
@@ -0,0 +1,77 @@
+/*
+ * 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.misc;
+
+
+import java.io.PrintWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.apache.felix.webconsole.ConfigurationPrinter;
+
+
+/**
+ * Adapter for a service acting as configuration printer.
+ */
+public class ConfigurationPrinterAdapter implements ConfigurationPrinter
+{
+
+    private final Object service;
+
+    private final String title;
+
+    private final Method printMethod;
+
+    public ConfigurationPrinterAdapter(final Object service,
+            final String title,
+            final Method printMethod)
+    {
+        this.title = title;
+        this.service = service;
+        this.printMethod = printMethod;
+    }
+
+    public String getTitle()
+    {
+        return this.title;
+    }
+
+    protected void invoke(final Object[] args)
+    {
+        try
+        {
+            printMethod.invoke(service, args);
+        }
+        catch (IllegalArgumentException e)
+        {
+            // ignore
+        }
+        catch (IllegalAccessException e)
+        {
+            // ignore
+        }
+        catch (InvocationTargetException e)
+        {
+            // ignore
+        }
+    }
+
+    public void printConfiguration(final PrintWriter printWriter)
+    {
+        invoke(new Object[] {printWriter});
+    }
+}
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ConfigurationRender.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ConfigurationRender.java
index e8611dd..2a1a316 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ConfigurationRender.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ConfigurationRender.java
@@ -18,6 +18,7 @@
 
 
 import java.io.*;
+import java.lang.reflect.Method;
 import java.net.URL;
 import java.text.*;
 import java.util.*;
@@ -31,8 +32,7 @@
 import org.apache.felix.webconsole.*;
 import org.apache.felix.webconsole.internal.OsgiManagerPlugin;
 import org.apache.felix.webconsole.internal.i18n.ResourceBundleManager;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.ServiceReference;
+import org.osgi.framework.*;
 import org.osgi.util.tracker.ServiceTracker;
 
 
@@ -280,11 +280,23 @@
     }
 
 
-    private final ArrayList getConfigurationPrinters()
+    private final synchronized List getConfigurationPrinters()
     {
         if ( cfgPrinterTracker == null )
         {
-            cfgPrinterTracker = new ServiceTracker( getBundleContext(), ConfigurationPrinter.SERVICE, null );
+            try
+            {
+                cfgPrinterTracker = new ServiceTracker( getBundleContext(),
+                        getBundleContext().createFilter("(|(" + Constants.OBJECTCLASS + "=" + ConfigurationPrinter.class.getName() + ")" +
+                                "(&(" + WebConsoleConstants.PLUGIN_LABEL + "=*)(&("
+                                + WebConsoleConstants.PLUGIN_TITLE + "=*)("
+                                + WebConsoleConstants.CONFIG_PRINTER_MODES + "=*))))"),
+                        null );
+            }
+            catch (InvalidSyntaxException e)
+            {
+                // ignore
+            }
             cfgPrinterTracker.open();
             cfgPrinterTrackerCount = -1;
         }
@@ -297,10 +309,56 @@
             {
                 for ( int i = 0; i < refs.length; i++ )
                 {
-                    ConfigurationPrinter cfgPrinter = ( ConfigurationPrinter ) cfgPrinterTracker.getService( refs[i] );
-                    addConfigurationPrinter( cp, cfgPrinter, refs[i].getBundle(), refs[i]
-                        .getProperty( WebConsoleConstants.PLUGIN_LABEL ), refs[i]
-                        .getProperty( ConfigurationPrinter.PROPERTY_MODES ) );
+                    final ServiceReference ref = refs[i];
+                    final Object service = cfgPrinterTracker.getService( ref );
+                    if ( service != null )
+                    {
+                        if ( service instanceof ConfigurationPrinter )
+                        {
+                            final ConfigurationPrinter cfgPrinter = (ConfigurationPrinter) service;
+                            addConfigurationPrinter( cp, cfgPrinter, refs[i].getBundle(),
+                                    ref.getProperty( WebConsoleConstants.PLUGIN_LABEL ),
+                                    ref.getProperty( ConfigurationPrinter.PROPERTY_MODES ) );
+                        }
+                        else
+                        {
+                            ConfigurationPrinter cfgPrinter = null;
+                            // first: printConfiguration(PrintWriter, String)
+                            try
+                            {
+                                final Method method = service.getClass().getDeclaredMethod("printConfiguration",
+                                        new Class[] {PrintWriter.class, String.class});
+                                cfgPrinter = new ModeAwareConfigurationPrinterAdapter(service,
+                                        (String)ref.getProperty(  WebConsoleConstants.PLUGIN_TITLE ), method);
+                            }
+                            catch (NoSuchMethodException nsme)
+                            {
+                                // ignore
+                            }
+                            if ( cfgPrinter == null )
+                            {
+                                // second: printConfiguration(PrintWriter)
+                                try
+                                {
+                                   final Method method = service.getClass().getDeclaredMethod("printConfiguration",
+                                           new Class[] {PrintWriter.class});
+                                   cfgPrinter = new ConfigurationPrinterAdapter(service,
+                                           (String)ref.getProperty(  WebConsoleConstants.PLUGIN_TITLE ), method);
+                                }
+                                catch (NoSuchMethodException nsme)
+                                {
+                                    // ignore
+                                }
+                            }
+
+                            if ( cfgPrinter != null )
+                            {
+                                addConfigurationPrinter( cp, cfgPrinter, ref.getBundle(),
+                                        ref.getProperty( WebConsoleConstants.PLUGIN_LABEL ),
+                                        ref.getProperty( WebConsoleConstants.CONFIG_PRINTER_MODES ) );
+                            }
+                        }
+                    }
                 }
             }
             configurationPrinters = new ArrayList(cp.values());
@@ -311,28 +369,28 @@
     }
 
 
-    private final void addConfigurationPrinter( final SortedMap printers, final ConfigurationPrinter cfgPrinter,
-        final Bundle provider, final Object labelProperty, final Object mode )
+    private final void addConfigurationPrinter( final SortedMap printers,
+            final ConfigurationPrinter cfgPrinter,
+            final Bundle provider,
+            final Object labelProperty,
+            final Object mode )
     {
-        if ( cfgPrinter != null )
+        final String title = getTitle( cfgPrinter.getTitle(), provider );
+        String sortKey = title;
+        if ( printers.containsKey( sortKey ) )
         {
-            final String title = getTitle( cfgPrinter.getTitle(), provider );
-            String sortKey = title;
-            if ( printers.containsKey( sortKey ) )
+            int idx = -1;
+            String idxTitle;
+            do
             {
-                int idx = -1;
-                String idxTitle;
-                do
-                {
-                    idx++;
-                    idxTitle = sortKey + idx;
-                }
-                while ( printers.containsKey( idxTitle ) );
-                sortKey = idxTitle;
+                idx++;
+                idxTitle = sortKey + idx;
             }
-            String label = ( labelProperty instanceof String ) ? ( String ) labelProperty : sortKey;
-            printers.put( sortKey, new PrinterDesc( cfgPrinter, title, label, mode ) );
+            while ( printers.containsKey( idxTitle ) );
+            sortKey = idxTitle;
         }
+        String label = ( labelProperty instanceof String ) ? ( String ) labelProperty : sortKey;
+        printers.put( sortKey, new PrinterDesc( cfgPrinter, title, label, mode ) );
     }
 
 
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ModeAwareConfigurationPrinterAdapter.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ModeAwareConfigurationPrinterAdapter.java
new file mode 100644
index 0000000..21eba00
--- /dev/null
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ModeAwareConfigurationPrinterAdapter.java
@@ -0,0 +1,50 @@
+/*
+ * 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.misc;
+
+
+import java.io.PrintWriter;
+import java.lang.reflect.Method;
+
+import org.apache.felix.webconsole.ConfigurationPrinter;
+import org.apache.felix.webconsole.ModeAwareConfigurationPrinter;
+
+
+/**
+ * Adapter for a service acting as mode aware configuration printer.
+ */
+public class ModeAwareConfigurationPrinterAdapter
+    extends ConfigurationPrinterAdapter
+    implements ModeAwareConfigurationPrinter
+{
+    public ModeAwareConfigurationPrinterAdapter(final Object service,
+            final String title,
+            final Method printMethod)
+    {
+        super(service, title, printMethod);
+    }
+
+    public void printConfiguration(final PrintWriter printWriter)
+    {
+        printConfiguration(printWriter, ConfigurationPrinter.MODE_ALWAYS);
+    }
+
+    public void printConfiguration(final PrintWriter printWriter, final String mode)
+    {
+        invoke(new Object[] {printWriter, mode});
+    }
+}