FELIX-3963 Fix InventoryPrinter/ConfigurationPrinter reflection

- InventoryPrinter only accepted as a service implementing
  the API (using ServiceFactory and dynamic import fixes
  static dependency issues better)
- ConfigurationPrinter supported through reflection for
  backwards compatibility (only public method in the service
  object class itself)
- Removing test case checking for proper reflection support
  of the InventoryPrinter (not needed any longer)

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1461705 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterAdapter.java b/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterAdapter.java
index cc39692..dc8b501 100644
--- a/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterAdapter.java
+++ b/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterAdapter.java
@@ -39,42 +39,6 @@
 {
 
     /**
-     * The name of the method to look for in non-InventoryPrinter services.
-     *
-     * @see #PRINTER_SIGNATURE
-     */
-    private static final String PRINTER_METHOD = "print";
-
-    /**
-     * The signature of the {@link #PRINTER_METHOD} method to be called.
-     * This is similar to the
-     * {@link InventoryPrinter#print(PrinterMode, PrintWriter, boolean)} method
-     * where the first argument is the string value of the {@link PrinterMode}.
-     *
-     * @see InventoryPrinter#print(PrinterMode, PrintWriter, boolean)
-     */
-    private static final Class[] PRINTER_SIGNATURE = new Class[]
-        { String.class, PrintWriter.class, Boolean.TYPE };
-
-    /**
-     * The name of the method to look for in non-ZipAttachmentProvider services.
-     *
-     * @see #ATTACHMENT_SIGNATURE
-     */
-    private static final String ATTACHMENT_METHOD = "addAttachments";
-
-    /**
-     * The signature of the {@link #ATTACHMENT_METHOD} method to be called.
-     * This is similar to the
-     * {@link ZipAttachmentProvider#addAttachments(String, ZipOutputStream)}
-     * method.
-     *
-     * @see ZipAttachmentProvider#addAttachments(String, ZipOutputStream)
-     */
-    private static final Class[] ATTACHMENT_SIGNATURE = new Class[]
-        { String.class, ZipOutputStream.class };
-
-    /**
      * Formatter pattern to render the current time of inventory generation.
      */
     static final DateFormat DISPLAY_DATE_FORMAT = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG,
@@ -88,28 +52,9 @@
      * @return An adapter or <code>null</code> if the method is missing.
      */
     public static InventoryPrinterAdapter createAdapter(final InventoryPrinterDescription description,
-        final Object service)
+        final InventoryPrinter service)
     {
-
-        Method printMethod = null;
-        if (!(service instanceof InventoryPrinter))
-        {
-
-            // print(String, PrintWriter)
-            printMethod = ClassUtils.searchMethod(service.getClass(), PRINTER_METHOD, PRINTER_SIGNATURE);
-            if (printMethod == null)
-            {
-                return null;
-            }
-        }
-        Method attachmentMethod = null;
-        if (!(service instanceof ZipAttachmentProvider))
-        {
-
-            // addAttachments()
-            attachmentMethod = ClassUtils.searchMethod(service.getClass(), ATTACHMENT_METHOD, ATTACHMENT_SIGNATURE);
-        }
-        return new InventoryPrinterAdapter(description, service, printMethod, attachmentMethod);
+        return new InventoryPrinterAdapter(description, service);
     }
 
     /**
@@ -125,29 +70,21 @@
     };
 
     /** The Inventory printer service. */
-    private final Object printer;
+    private final InventoryPrinter printer;
 
     /** The printer description. */
     private final InventoryPrinterDescription description;
 
-    /** The method to use if printer does not implement the service interface. */
-    private final Method printMethod;
-
-    private final Method attachmentMethod;
-
     /** Service registration for the web console. */
     private ServiceRegistration registration;
 
     /**
      * Constructor.
      */
-    public InventoryPrinterAdapter(final InventoryPrinterDescription description, final Object printer,
-        final Method printMethod, final Method attachmentMethod)
+    public InventoryPrinterAdapter(final InventoryPrinterDescription description, final InventoryPrinter printer)
     {
         this.description = description;
         this.printer = printer;
-        this.printMethod = printMethod;
-        this.attachmentMethod = attachmentMethod;
     }
 
     public void registerConsole(final BundleContext context, final InventoryPrinterManagerImpl manager)
@@ -201,16 +138,10 @@
      */
     public void addAttachments(final String namePrefix, final ZipOutputStream zos) throws IOException
     {
-        // check if printer implements ZipAttachmentProvider
         if (printer instanceof ZipAttachmentProvider)
         {
             ((ZipAttachmentProvider) printer).addAttachments(namePrefix, zos);
         }
-        else if (this.attachmentMethod != null)
-        {
-            ClassUtils.invoke(this.printer, this.attachmentMethod, new Object[]
-                { namePrefix, zos });
-        }
     }
 
     /**
@@ -236,15 +167,7 @@
     {
         if (this.supports(mode))
         {
-            if (this.printer instanceof InventoryPrinter)
-            {
-                ((InventoryPrinter) this.printer).print(mode, printWriter, isZip);
-            }
-            else
-            {
-                ClassUtils.invoke(this.printer, this.printMethod, new Object[]
-                    { mode.toString(), printWriter, Boolean.valueOf(isZip) });
-            }
+            this.printer.print(mode, printWriter, isZip);
         }
     }
 
diff --git a/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterManagerImpl.java b/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterManagerImpl.java
index 9eee00e..9f20b36 100644
--- a/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterManagerImpl.java
+++ b/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterManagerImpl.java
@@ -78,9 +78,7 @@
     public InventoryPrinterManagerImpl(final BundleContext btx) throws InvalidSyntaxException
     {
         this.bundleContext = btx;
-        this.cfgPrinterTracker = new ServiceTracker(this.bundleContext, this.bundleContext.createFilter("(&("
-            + InventoryPrinter.CONFIG_PRINTER_MODES + "=*)" + "(" + InventoryPrinter.CONFIG_NAME + "=*)" + "("
-            + InventoryPrinter.CONFIG_TITLE + "=*))"), this);
+        this.cfgPrinterTracker = new ServiceTracker(this.bundleContext, InventoryPrinter.SERVICE, this);
         this.cfgPrinterTracker.open();
 
         final Dictionary props = new Hashtable();
@@ -126,8 +124,9 @@
         final Object obj = this.bundleContext.getService(reference);
         if (obj != null)
         {
-            this.addService(reference, obj);
+            this.addService(reference, (InventoryPrinter) obj);
         }
+
         return obj;
     }
 
@@ -138,10 +137,10 @@
     public void modifiedService(final ServiceReference reference, final Object service)
     {
         this.removeService(reference);
-        this.addService(reference, service);
+        this.addService(reference, (InventoryPrinter) service);
     }
 
-    private void addService(final ServiceReference reference, final Object obj)
+    private void addService(final ServiceReference reference, final InventoryPrinter obj)
     {
         final InventoryPrinterDescription desc = new InventoryPrinterDescription(reference);
 
diff --git a/inventory/src/main/java/org/apache/felix/inventory/impl/webconsole/ConfigurationPrinterAdapter.java b/inventory/src/main/java/org/apache/felix/inventory/impl/webconsole/ConfigurationPrinterAdapter.java
index fad6d6c..35279f2 100644
--- a/inventory/src/main/java/org/apache/felix/inventory/impl/webconsole/ConfigurationPrinterAdapter.java
+++ b/inventory/src/main/java/org/apache/felix/inventory/impl/webconsole/ConfigurationPrinterAdapter.java
@@ -5,9 +5,9 @@
  * 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.
@@ -18,6 +18,7 @@
 
 import java.io.PrintWriter;
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -25,7 +26,6 @@
 import java.util.Set;
 
 import org.apache.felix.inventory.PrinterMode;
-import org.apache.felix.inventory.impl.ClassUtils;
 import org.osgi.framework.ServiceReference;
 
 /**
@@ -86,12 +86,12 @@
             {
                 modes = ref.getProperty(ConsoleConstants.PROPERTY_MODES);
             }
-            final Method titleMethod = ClassUtils.searchMethod(service.getClass(), "getTitle", null);
+            final Method titleMethod = getMethod(service.getClass(), "getTitle", null);
             if (titleMethod == null)
             {
                 return null;
             }
-            title = (String) ClassUtils.invoke(service, titleMethod, null);
+            title = (String) invoke(service, titleMethod, null);
         }
         else
         {
@@ -103,7 +103,7 @@
         Method printMethod = null;
 
         // first: printConfiguration(PrintWriter, String)
-        final Method method2Params = ClassUtils.searchMethod(service.getClass(), "printConfiguration", new Class[]
+        final Method method2Params = getMethod(service.getClass(), "printConfiguration", new Class[]
             { PrintWriter.class, String.class });
         if (method2Params != null)
         {
@@ -114,7 +114,7 @@
         if (cfgPrinter == null)
         {
             // second: printConfiguration(PrintWriter)
-            final Method method1Params = ClassUtils.searchMethod(service.getClass(), "printConfiguration", new Class[]
+            final Method method1Params = getMethod(service.getClass(), "printConfiguration", new Class[]
                 { PrintWriter.class });
             if (method1Params != null)
             {
@@ -185,8 +185,8 @@
                 }
             }
 
-            return new ConfigurationPrinterAdapter(cfgPrinter, printMethod, ClassUtils.searchMethod(
-                cfgPrinter.getClass(), "getAttachments", new Class[]
+            return new ConfigurationPrinterAdapter(cfgPrinter, printMethod, getMethod(cfgPrinter.getClass(),
+                "getAttachments", new Class[]
                     { String.class }), title, (label instanceof String ? (String) label : null), modesArray,
                 !webUnescaped);
         }
@@ -249,12 +249,12 @@
     {
         if (printMethod.getParameterTypes().length > 1)
         {
-            ClassUtils.invoke(this.printer, this.printMethod, new Object[]
+            invoke(this.printer, this.printMethod, new Object[]
                 { pw, mode });
         }
         else
         {
-            ClassUtils.invoke(this.printer, this.printMethod, new Object[]
+            invoke(this.printer, this.printMethod, new Object[]
                 { pw });
         }
     }
@@ -265,7 +265,7 @@
         URL[] attachments = null;
         if (attachmentMethod != null)
         {
-            attachments = (URL[]) ClassUtils.invoke(printer, attachmentMethod, new Object[]
+            attachments = (URL[]) invoke(printer, attachmentMethod, new Object[]
                 { ConsoleConstants.MODE_ZIP });
         }
         return attachments;
@@ -278,4 +278,39 @@
     {
         return title + " (" + printer.getClass() + ")";
     }
+
+    private static Method getMethod(final Class clazz, final String mName, final Class[] params)
+    {
+        try
+        {
+            final Method m = clazz.getDeclaredMethod(mName, params);
+            if (Modifier.isPublic(m.getModifiers()))
+            {
+                return m;
+            }
+        }
+        catch (Throwable nsme)
+        {
+            // ignore, we catch Throwable above to not only catch
+            // NoSuchMethodException
+            // but also other ones like ClassDefNotFoundError etc.
+        }
+        return null;
+    }
+
+    /**
+     * Invoke the method on the printer with the arguments.
+     */
+    private static Object invoke(final Object obj, final Method m, final Object[] args)
+    {
+        try
+        {
+            return m.invoke(obj, args);
+        }
+        catch (final Throwable e)
+        {
+            // ignore
+        }
+        return null;
+    }
 }
diff --git a/inventory/src/test/java/org/apache/felix/inventory/impl/InventoryPrinterAdapterTest.java b/inventory/src/test/java/org/apache/felix/inventory/impl/InventoryPrinterAdapterTest.java
deleted file mode 100644
index 2639f9e..0000000
--- a/inventory/src/test/java/org/apache/felix/inventory/impl/InventoryPrinterAdapterTest.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * 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.inventory.impl;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.lang.reflect.Field;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.jar.JarOutputStream;
-import java.util.zip.ZipOutputStream;
-
-import junit.framework.TestCase;
-
-import org.apache.felix.inventory.InventoryPrinter;
-import org.apache.felix.inventory.PrinterMode;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.ServiceReference;
-
-public class InventoryPrinterAdapterTest extends TestCase
-{
-
-    public void test_validInventoryPrinter()
-    {
-        InventoryPrinterDescription ipd = new InventoryPrinterDescription(new TestServiceReference());
-        InventoryPrinterAdapter ipa = InventoryPrinterAdapter.createAdapter(ipd, new ValidInventoryPrinter());
-        TestCase.assertNotNull(ipa);
-        StringWriter w = new StringWriter();
-        ipa.print(PrinterMode.TEXT, new PrintWriter(w), false);
-        TestCase.assertEquals(w.toString(), PrinterMode.TEXT.name());
-    }
-
-    public void test_invalidInventoryPrinter()
-    {
-        InventoryPrinterDescription ipd = new InventoryPrinterDescription(new TestServiceReference());
-        InventoryPrinterAdapter ipa = InventoryPrinterAdapter.createAdapter(ipd, new InvalidInventoryPrinter());
-        TestCase.assertNull(ipa);
-    }
-
-    public void test_validZipAttachmentProvider() throws IOException
-    {
-        InventoryPrinterDescription ipd = new InventoryPrinterDescription(new TestServiceReference());
-        InventoryPrinterAdapter ipa = InventoryPrinterAdapter.createAdapter(ipd, new ValidZipAttachmentProvider());
-        TestCase.assertNotNull(ipa);
-
-        try
-        {
-            Field f = ipa.getClass().getDeclaredField("attachmentMethod");
-            f.setAccessible(true);
-            TestCase.assertNotNull(f.get(ipa));
-        }
-        catch (Exception e)
-        {
-            TestCase.fail(e.toString());
-        }
-    }
-
-    public void test_invalidZipAttachmentProvider() throws IOException
-    {
-        InventoryPrinterDescription ipd = new InventoryPrinterDescription(new TestServiceReference());
-
-        InventoryPrinterAdapter ipa = InventoryPrinterAdapter.createAdapter(ipd,
-            new InvalidZipAttachmentProvider_wrong_signature());
-        TestCase.assertNotNull(ipa);
-
-        try
-        {
-            Field f = ipa.getClass().getDeclaredField("attachmentMethod");
-            f.setAccessible(true);
-            TestCase.assertNull(f.get(ipa));
-        }
-        catch (Exception e)
-        {
-            TestCase.fail(e.toString());
-        }
-
-        InventoryPrinterAdapter ipa2 = InventoryPrinterAdapter.createAdapter(ipd,
-            new InvalidZipAttachmentProvider_no_print_method());
-        TestCase.assertNull(ipa2);
-    }
-
-    private static class ValidInventoryPrinter
-    {
-        private void print(String mode, PrintWriter w, boolean isZip)
-        {
-            w.print(mode);
-            w.flush();
-        }
-    }
-
-    private static class InvalidInventoryPrinter
-    {
-        private void print(String mode, PrintWriter w, Boolean isZip)
-        {
-            throw new IllegalStateException("Method not expected to be called");
-        }
-    }
-
-    private static class ValidZipAttachmentProvider
-    {
-        private void print(String mode, PrintWriter w, boolean isZip)
-        {
-            w.print(mode);
-            w.flush();
-        }
-
-        private void addAttachments(String prefix, ZipOutputStream out)
-        {
-        }
-    }
-
-    private static class InvalidZipAttachmentProvider_wrong_signature
-    {
-        private void print(String mode, PrintWriter w, boolean isZip)
-        {
-            w.print(mode);
-            w.flush();
-        }
-
-        private void addAttachments(String prefix, JarOutputStream out)
-        {
-            throw new IllegalStateException("Method not expected to be called");
-        }
-    }
-
-    private static class InvalidZipAttachmentProvider_no_print_method
-    {
-        private void addAttachments(String prefix, ZipOutputStream out)
-        {
-            throw new IllegalStateException("Method not expected to be called");
-        }
-    }
-
-    private static class TestServiceReference implements ServiceReference
-    {
-
-        private Map props;
-
-        {
-            props = new HashMap();
-            props.put(InventoryPrinter.CONFIG_PRINTER_MODES, new String[]
-                { PrinterMode.TEXT.name() });
-        }
-
-        public Object getProperty(String key)
-        {
-            return this.props.get(key);
-        }
-
-        public String[] getPropertyKeys()
-        {
-            return (String[]) this.props.keySet().toArray(new String[this.props.size()]);
-        }
-
-        public Bundle getBundle()
-        {
-            return null;
-        }
-
-        public Bundle[] getUsingBundles()
-        {
-            return null;
-        }
-
-        public boolean isAssignableTo(Bundle bundle, String className)
-        {
-            return false;
-        }
-
-        public int compareTo(Object reference)
-        {
-            return 0;
-        }
-    }
-}