SLING-5327 osgi-mock: Support OSGi R6 Component propert types for configuration

git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1716114 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index 7b7b28a..adf4ceb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -87,6 +87,12 @@
             <version>5.0.0</version>
             <scope>compile</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr</artifactId>
+            <version>2.0.2</version>
+            <scope>compile</scope>
+        </dependency>
 
         <dependency>
             <groupId>com.google.guava</groupId>
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java b/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java
index e05a15c..3ba8ad4 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java
@@ -18,19 +18,19 @@
  */
 package org.apache.sling.testing.mock.osgi;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.SortedSet;
 
-import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.felix.scr.impl.helper.Annotations;
 import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.FieldCollectionType;
 import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.OsgiMetadata;
 import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.Reference;
@@ -157,7 +157,13 @@
         }
         
         // 4. Component property type (annotation lass)
-        // TODO: implement
+        method = getMethod(targetClass, methodName, new Class<?>[] { Annotation.class });
+        if (method != null) {
+            invokeMethod(target, method, new Object[] { Annotations.toObject(method.getParameterTypes()[0],
+                    MapUtil.toMap(componentContext.getProperties()), 
+                    componentContext.getBundleContext().getBundle(), false) });
+            return true;
+        }
         
         // 5. int (deactivation only)
         if (allowIntegerArgument) {
@@ -179,8 +185,8 @@
         
         // 7. mixed arguments
         Class<?>[] mixedArgsAllowed = allowIntegerArgument ?
-                new Class<?>[] { ComponentContext.class, BundleContext.class, Map.class, int.class, Integer.class }
-                : new Class<?>[] { ComponentContext.class, BundleContext.class, Map.class };
+                new Class<?>[] { ComponentContext.class, BundleContext.class, Map.class, Annotation.class, int.class, Integer.class }
+                : new Class<?>[] { ComponentContext.class, BundleContext.class, Map.class, Annotation.class };
         method = getMethodWithAnyCombinationArgs(targetClass, methodName, mixedArgsAllowed);
         if (method != null) {
             Object[] args = new Object[method.getParameterTypes().length];
@@ -194,6 +200,11 @@
                 else if (method.getParameterTypes()[i] == Map.class) {
                     args[i] = MapUtil.toMap(componentContext.getProperties());
                 }
+                else if (method.getParameterTypes()[i].isAnnotation()) {
+                    args[i] = Annotations.toObject(method.getParameterTypes()[i],
+                            MapUtil.toMap(componentContext.getProperties()), 
+                            componentContext.getBundleContext().getBundle(), false);
+                }
                 else if (method.getParameterTypes()[i] == int.class || method.getParameterTypes()[i] == Integer.class) {
                     args[i] = 0;
                 }
@@ -215,9 +226,18 @@
     private static Method getMethod(Class clazz, String methodName, Class<?>[] types) {
         Method[] methods = clazz.getDeclaredMethods();
         for (Method method : methods) {
-            if (StringUtils.equals(method.getName(), methodName)
-                    && Arrays.equals(method.getParameterTypes(), types)) {
-                return method;
+            if (StringUtils.equals(method.getName(), methodName) && method.getParameterTypes().length==types.length) {
+                boolean foundMismatch = false;
+                for (int i=0; i<types.length; i++) {
+                    if (!((method.getParameterTypes()[i]==types[i]) 
+                            || (types[i]==Annotation.class && method.getParameterTypes()[i].isAnnotation()))) {
+                        foundMismatch = true;
+                        break;
+                    }
+                }
+                if (!foundMismatch) {
+                    return method;
+                }
             }
         }
         // not found? check super classes
@@ -235,7 +255,7 @@
                 boolean foundMismatch = false;
                 for (int i=0; i<types.length; i++) {
                     if (!method.getParameterTypes()[i].isAssignableFrom(types[i])) {
-                        foundMismatch = false;
+                        foundMismatch = true;
                         break;
                     }
                 }
@@ -256,12 +276,24 @@
         Method[] methods = clazz.getDeclaredMethods();
         for (Method method : methods) {
             if (StringUtils.equals(method.getName(), methodName) && method.getParameterTypes().length > 1) {
+                boolean foundMismatch = false;
                 for (Class<?> parameterType : method.getParameterTypes()) {
-                    if (!ArrayUtils.contains(types,  parameterType)) {
-                        return null;
+                    boolean foundAnyMatch = false;
+                    for (int i=0; i<types.length; i++) {
+                        if ((parameterType==types[i]) 
+                                || (types[i]==Annotation.class && parameterType.isAnnotation())) {
+                            foundAnyMatch = true;
+                            break;
+                        }
+                    }
+                    if (!foundAnyMatch) {
+                        foundMismatch = true;
+                        break;
                     }
                 }
-                return method;
+                if (!foundMismatch) {
+                    return method;
+                }
             }
         }
         // not found? check super classes
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtilActivateDeactivateTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtilActivateDeactivateTest.java
index d848fe2..6974c01 100644
--- a/src/test/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtilActivateDeactivateTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtilActivateDeactivateTest.java
@@ -84,6 +84,7 @@
         
         assertTrue(MockOsgi.activate(service, bundleContext, map));
         assertTrue(service.isActivated());
+        assertEquals(map, ImmutableMap.copyOf(service.getMap()));
         
         assertTrue(MockOsgi.deactivate(service, bundleContext, map));
         assertFalse(service.isActivated());
@@ -113,6 +114,25 @@
         assertTrue(MockOsgi.deactivate(service, bundleContext, map));
         assertFalse(service.isActivated());
     }
+    
+    @Test
+    public void testService7() {
+        Service7 service = new Service7();
+        
+        assertTrue(MockOsgi.activate(service, bundleContext, map));
+        assertTrue(service.isActivated());
+        assertSame(bundleContext, service.getComponentContext().getBundleContext());
+        assertSame(bundleContext, service.getBundleContext());
+        assertEquals(map, ImmutableMap.copyOf(service.getMap()));
+        
+        assertTrue(MockOsgi.deactivate(service, bundleContext, map));
+        assertFalse(service.isActivated());
+    }
+    
+    
+    public @interface ServiceConfig {
+        String prop1();
+    }
 
     @Component
     public static class Service1 {
@@ -202,10 +222,12 @@
     public static class Service4 {
         
         private boolean activated;
+        private Map<String, Object> map;
 
         @Activate
-        private void activate() {
+        private void activate(ServiceConfig config) {
             this.activated = true;
+            map = ImmutableMap.<String, Object>of("prop1", config.prop1());
         }
 
         @Deactivate
@@ -217,6 +239,10 @@
             return activated;
         }
 
+        public Map<String, Object> getMap() {
+            return map;
+        }
+        
     }
 
     @Component
@@ -282,4 +308,46 @@
 
     }
 
+    @Component
+    public static class Service7 {
+        
+        private boolean activated;
+        private ComponentContext componentContext;
+        private BundleContext bundleContext;
+        private Map<String,Object> map;
+
+        @Activate
+        private void activate(ComponentContext componentContext, ServiceConfig config, BundleContext bundleContext) {
+            this.activated = true;
+            this.componentContext = componentContext;
+            this.bundleContext = bundleContext;
+            this.map = ImmutableMap.<String, Object>of("prop1", config.prop1());;
+        }
+
+        @Deactivate
+        private void deactivate() {
+            this.activated = false;
+            this.componentContext = null;
+            this.bundleContext = null;
+            this.map = null;
+        }
+        
+        public boolean isActivated() {
+            return activated;
+        }
+
+        public ComponentContext getComponentContext() {
+            return componentContext;
+        }
+
+        public BundleContext getBundleContext() {
+            return bundleContext;
+        }
+
+        public Map<String, Object> getMap() {
+            return map;
+        }
+
+    }
+
 }
diff --git a/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.OsgiServiceUtilActivateDeactivateTest.xml b/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.OsgiServiceUtilActivateDeactivateTest.xml
index 61b4bc6..a869506 100644
--- a/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.OsgiServiceUtilActivateDeactivateTest.xml
+++ b/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.OsgiServiceUtilActivateDeactivateTest.xml
@@ -36,4 +36,7 @@
   <scr:component name="org.apache.sling.testing.mock.osgi.OsgiServiceUtilActivateDeactivateTest$Service6" activate="activate" deactivate="deactivate">
     <implementation class="org.apache.sling.testing.mock.osgi.OsgiServiceUtilActivateDeactivateTest$Service6"/>
   </scr:component>
+  <scr:component name="org.apache.sling.testing.mock.osgi.OsgiServiceUtilActivateDeactivateTest$Service7" activate="activate" deactivate="deactivate">
+    <implementation class="org.apache.sling.testing.mock.osgi.OsgiServiceUtilActivateDeactivateTest$Service7"/>
+  </scr:component>
 </components>