You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 10:18:22 UTC

[sling-org-apache-sling-testing-osgi-mock] annotated tag org.apache.sling.testing.osgi-mock-1.1.0 created (now e64940a)

This is an automated email from the ASF dual-hosted git repository.

rombert pushed a change to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git.


      at e64940a  (tag)
 tagging 69c8b9c9f3551396eb2a9e91b8f58b2d7cc6df10 (commit)
      by Stefan Seifert
      on Tue Dec 9 23:02:14 2014 +0000

- Log -----------------------------------------------------------------
org.apache.sling.testing.osgi-mock-1.1.0
-----------------------------------------------------------------------

This annotated tag includes the following new commits:

     new e5ba840  SLING-4042 Donate sling-mock, jcr-mock, osgi-mock implementation
     new e1ee5ad  svn:ignore
     new 8d20817  SLING-4042 move all mock projects to mocks/ subdirectory
     new ad838b2  SLING-4042 add missing package-info files
     new 740687d  SLING-4042 make sure dependency injection is continued even if not all injections succeeded, and report root cause of invocation target exceptions
     new 7e5bc2d  SLING-4042 add README files
     new 21a5152  add/update SCM urls
     new 74be83a  [maven-release-plugin] prepare release org.apache.sling.testing.osgi-mock-1.0.0
     new d794a37  [maven-release-plugin] prepare for next development iteration
     new 0a80e0c  SLING-4090 Define package versions for Sling Mock, JCR Mock, OSGi Mock
     new 59f74f6  SLING-4142 MockOsgi: Activate/Deactivate method does not support different signatures
     new a822c76  SLING-4162 Introduce "OsgiContext" junit rule for OSGi and OsgiContextImpl
     new b30dd56  SLING-4162 fix javadoc
     new c40b2dd  SLING-4163 OSGi Mock: Reference bind/unbind method picking order
     new abe8b21  fix some javadoc copy&paste errors and formatting
     new 7c2b519  SLING-4166 OSGi Mock: Support for "modified" SCR lifecycle method
     new 4d131cd  SLING-4166 update package version
     new 907c7df  SLING-4165 OSGi Mock: Fail-fast when calling methods requiring SCR metadata and this is not present
     new 5538cda  SLING-4201 MockOsgi.activate()/deactivate()/modified() should fail fast if method is declared but can't be found
     new 50112aa  SLING-4202 OSGi Mock: Fail-fast when mandatory references cannot be injected
     new 70f5447  fix some javadoc errors/warnings
     new d7f336c  [maven-release-plugin] prepare release org.apache.sling.testing.osgi-mock-1.1.0
     new 69c8b9c  [maven-release-plugin]  copy for tag org.apache.sling.testing.osgi-mock-1.1.0

The 23 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


-- 
To stop receiving notification emails like this one, please contact
['"commits@sling.apache.org" <co...@sling.apache.org>'].

[sling-org-apache-sling-testing-osgi-mock] 02/23: svn:ignore

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit e1ee5adbce15e7be195d7769d035c9e29b6dbf6a
Author: Bertrand Delacretaz <bd...@apache.org>
AuthorDate: Mon Oct 13 13:23:53 2014 +0000

    svn:ignore
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/osgi-mock@1631387 13f79535-47bb-0310-9956-ffa450edef68

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 20/23: SLING-4202 OSGi Mock: Fail-fast when mandatory references cannot be injected

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 50112aaddc782b1710a018d177e455007f3532fa
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Wed Nov 26 22:17:39 2014 +0000

    SLING-4202 OSGi Mock: Fail-fast when mandatory references cannot be injected
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1641954 13f79535-47bb-0310-9956-ffa450edef68
---
 .../apache/sling/testing/mock/osgi/MockOsgi.java   |  2 +-
 .../testing/mock/osgi/ReflectionServiceUtil.java   | 35 +++++++++-------------
 .../mock/osgi/context/OsgiContextImplTest.java     | 10 +++++++
 3 files changed, 25 insertions(+), 22 deletions(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java
index d6e1b71..82448e4 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java
@@ -108,7 +108,7 @@ public final class MockOsgi {
      * is thrown.
      * @param target Service instance
      * @param bundleContext Bundle context from which services are fetched to inject.
-     * @return true if all dependencies could be injected
+     * @return true if all dependencies could be injected, false if the service has no dependencies.
      */
     public static boolean injectServices(Object target, BundleContext bundleContext) {
         return ReflectionServiceUtil.injectServices(target, bundleContext);
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java b/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
index 4056ce4..77d5e08 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
@@ -34,8 +34,6 @@ import org.osgi.framework.BundleContext;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.component.ComponentContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 
 /**
@@ -43,8 +41,6 @@ import org.w3c.dom.Document;
  */
 final class ReflectionServiceUtil {
 
-    private static final Logger log = LoggerFactory.getLogger(ReflectionServiceUtil.class);
-
     private ReflectionServiceUtil() {
         // static methods only
     }
@@ -261,7 +257,7 @@ final class ReflectionServiceUtil {
      * multiple references.
      * @param target Service instance
      * @param bundleContext Bundle context from which services are fetched to inject.
-     * @return true if all dependencies could be injected
+     * @return true if all dependencies could be injected, false if the service has no dependencies.
      */
     public static boolean injectServices(Object target, BundleContext bundleContext) {
 
@@ -273,17 +269,18 @@ final class ReflectionServiceUtil {
             throw new NoScrMetadataException(targetClass);
         }
         List<Reference> references = OsgiMetadataUtil.getReferences(targetClass, metadata);
+        if (references.isEmpty()) {
+            return false;
+        }
 
         // try to inject services
-        boolean allInjected = true;
         for (Reference reference : references) {
-            boolean injectSuccess = injectServiceReference(reference, target, bundleContext);
-            allInjected = allInjected && injectSuccess;
+            injectServiceReference(reference, target, bundleContext);
         }
-        return allInjected;
+        return true;
     }
 
-    private static boolean injectServiceReference(Reference reference, Object target, BundleContext bundleContext) {
+    private static void injectServiceReference(Reference reference, Object target, BundleContext bundleContext) {
         Class<?> targetClass = target.getClass();
 
         // get reference type
@@ -302,18 +299,14 @@ final class ReflectionServiceUtil {
             boolean isOptional = (reference.getCardinality() == ReferenceCardinality.OPTIONAL_UNARY || reference
                     .getCardinality() == ReferenceCardinality.OPTIONAL_MULTIPLE);
             if (!isOptional) {
-                log.warn("Unable to inject mandatory reference '{}' for class {}", reference.getName(),
-                        targetClass.getName());
+                throw new RuntimeException("Unable to inject mandatory reference '" + reference.getName() + "' for class " + targetClass.getName());
             }
-            return isOptional;
         }
 
         // multiple references found? check if reference is not multiple
         if (matchingServices.size() > 1
                 && (reference.getCardinality() == ReferenceCardinality.MANDATORY_UNARY || reference.getCardinality() == ReferenceCardinality.OPTIONAL_UNARY)) {
-            log.warn("Multiple matches found for unary reference '{}' for class {}", reference.getName(),
-                    targetClass.getName());
-            return false;
+            throw new RuntimeException("Multiple matches found for unary reference '" + reference.getName() + "' for class "+ targetClass.getName());
         }
 
         // try to invoke bind method
@@ -326,7 +319,7 @@ final class ReflectionServiceUtil {
                 for (ServiceInfo matchingService : matchingServices) {
                     invokeMethod(target, bindMethod, new Object[] { matchingService.getServiceReference() });
                 }
-                return true;
+                return;
             }
             
             // 2. assignable from service instance
@@ -341,7 +334,7 @@ final class ReflectionServiceUtil {
                 for (ServiceInfo matchingService : matchingServices) {
                     invokeMethod(target, bindMethod, new Object[] { matchingService.getServiceInstance() });
                 }
-                return true;
+                return;
             }
             
             // 3. assignable from service instance plus map
@@ -350,12 +343,12 @@ final class ReflectionServiceUtil {
                 for (ServiceInfo matchingService : matchingServices) {
                     invokeMethod(target, bindMethod, new Object[] { matchingService.getServiceInstance(), matchingService.getServiceConfig() });
                 }
-                return true;
+                return;
             }
         }
 
-        log.warn("Bind method not found for reference '{}' for class {}", reference.getName(), targetClass.getName());
-        return false;
+        throw new RuntimeException("Bind method with name " + bindMethodName + " not found "
+                + "for reference '" + reference.getName() + "' for class {}" +  targetClass.getName());
     }
 
     private static List<ServiceInfo> getMatchingServices(Class<?> type, BundleContext bundleContext) {
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImplTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImplTest.java
index 19c5a5b..35eecbb 100644
--- a/src/test/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImplTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImplTest.java
@@ -21,6 +21,7 @@ package org.apache.sling.testing.mock.osgi.context;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
 
 import java.util.HashMap;
 import java.util.HashSet;
@@ -29,6 +30,8 @@ import java.util.Set;
 
 import org.apache.sling.testing.mock.osgi.NoScrMetadataException;
 import org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest;
+import org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest.ServiceInterface1;
+import org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest.ServiceInterface2;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -92,6 +95,13 @@ public class OsgiContextImplTest {
 
     @Test
     public void testRegisterInjectActivate() {
+        context.registerService(ServiceInterface1.class, mock(ServiceInterface1.class));
+        context.registerService(ServiceInterface2.class, mock(ServiceInterface2.class));
+        context.registerInjectActivateService(new ReflectionServiceUtilTest.Service3());
+    }
+
+    @Test(expected=RuntimeException.class)
+    public void testRegisterInjectActivate_RefrenceMissing() {
         context.registerInjectActivateService(new ReflectionServiceUtilTest.Service3());
     }
 

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 23/23: [maven-release-plugin] copy for tag org.apache.sling.testing.osgi-mock-1.1.0

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 69c8b9c9f3551396eb2a9e91b8f58b2d7cc6df10
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Tue Dec 9 23:02:14 2014 +0000

    [maven-release-plugin]  copy for tag org.apache.sling.testing.osgi-mock-1.1.0
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.testing.osgi-mock-1.1.0@1644222 13f79535-47bb-0310-9956-ffa450edef68

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 16/23: SLING-4166 OSGi Mock: Support for "modified" SCR lifecycle method

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 7c2b51939974634ede6007737962ba9cf1db5e57
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Fri Nov 14 17:16:11 2014 +0000

    SLING-4166 OSGi Mock: Support for "modified" SCR lifecycle method
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1639705 13f79535-47bb-0310-9956-ffa450edef68
---
 .../apache/sling/testing/mock/osgi/MockOsgi.java   | 36 ++++++++++++++++++++-
 .../sling/testing/mock/osgi/OsgiMetadataUtil.java  | 19 +++++------
 .../testing/mock/osgi/ReflectionServiceUtil.java   | 31 +++++++++++++++---
 .../mock/osgi/ReflectionServiceUtilTest.java       | 37 +++++++++++++++++++++-
 ...testing.mock.osgi.ReflectionServiceUtilTest.xml |  2 +-
 5 files changed, 109 insertions(+), 16 deletions(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java
index bffb7b3..395f2c6 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java
@@ -19,6 +19,8 @@
 package org.apache.sling.testing.mock.osgi;
 
 import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Map;
 
@@ -226,8 +228,40 @@ public final class MockOsgi {
         return deactivate(target, bundleContext, toDictionary(properties));
     }
 
-    private static Dictionary<String, Object> toDictionary(Map<String, Object> map) {
+    /**
+     * Simulate configuration modification of service instance. Invokes the @Modified annotated method.
+     * @param target Service instance.
+     * @param bundleContext Bundle context
+     * @param properties Properties
+     * @return true if modified method was called. False if it failed.
+     */
+    public static boolean modified(Object target, BundleContext bundleContext, Dictionary<String, Object> properties) {
+        return modified(target, bundleContext, toMap(properties));
+    }
+
+    /**
+     * Simulate configuration modification of service instance. Invokes the @Modified annotated method.
+     * @param target Service instance.
+     * @param bundleContext Bundle context
+     * @param properties Properties
+     * @return true if modified method was called. False if it failed.
+     */
+    public static boolean modified(Object target, BundleContext bundleContext, Map<String, Object> properties) {
+        return ReflectionServiceUtil.modified(target, bundleContext, properties);
+    }
+    
+    static Dictionary<String, Object> toDictionary(Map<String, Object> map) {
         return new Hashtable<String, Object>(map);
     }
 
+    static Map<String, Object> toMap(Dictionary<String, Object> dictionary) {
+        Map<String,Object> map = new HashMap<String, Object>();
+        Enumeration<String> keys = dictionary.keys();
+        while (keys.hasMoreElements()) {
+            String key = keys.nextElement();
+            map.put(key, dictionary.get(key));
+        }
+        return map;
+    }
+
 }
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtil.java b/src/main/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtil.java
index da8bca0..a1b7a0a 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtil.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtil.java
@@ -178,22 +178,23 @@ final class OsgiMetadataUtil {
     }
 
     public static String getActivateMethodName(Class clazz, Document metadata) {
-        if (metadata != null) {
-            String query = "/components/component[@name='" + clazz.getName() + "']";
-            Node node = queryNode(metadata, query);
-            if (node != null) {
-                return getAttributeValue(node, "activate");
-            }
-        }
-        return null;
+        return getLifecycleMethodName(clazz, metadata, "activate");
     }
 
     public static String getDeactivateMethodName(Class clazz, Document metadata) {
+        return getLifecycleMethodName(clazz, metadata, "deactivate");
+    }
+
+    public static String getModifiedMethodName(Class clazz, Document metadata) {
+        return getLifecycleMethodName(clazz, metadata, "modified");
+    }
+
+    private static String getLifecycleMethodName(Class clazz, Document metadata, String methodName) {
         if (metadata != null) {
             String query = "/components/component[@name='" + clazz.getName() + "']";
             Node node = queryNode(metadata, query);
             if (node != null) {
-                return getAttributeValue(node, "deactivate");
+                return getAttributeValue(node, methodName);
             }
         }
         return null;
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java b/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
index fa75ebf..8269501 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
@@ -53,8 +53,7 @@ final class ReflectionServiceUtil {
      * Simulate activation or deactivation of OSGi service instance.
      * @param target Service instance.
      * @param componentContext Component context
-     * @return true if activation method was called. False if such a method did
-     *         not exist.
+     * @return true if activation/deactivation method was called. False if it failed.
      */
     public static boolean activateDeactivate(Object target, ComponentContext componentContext, boolean activate) {
         Class<?> targetClass = target.getClass();
@@ -71,7 +70,7 @@ final class ReflectionServiceUtil {
             return false;
         }
 
-        // try to find matchin activate/deactivate method and execute it
+        // try to find matching activate/deactivate method and execute it
         
         // 1. componentContext
         Method method = getMethod(targetClass, methodName, new Class<?>[] { ComponentContext.class });
@@ -143,7 +142,31 @@ final class ReflectionServiceUtil {
             return true;
         }
         
-        log.warn("Method {}(ComponentContext) not found in class {}", methodName, targetClass.getName());
+        log.warn("Method {} not found in class {}", methodName, targetClass.getName());
+        return false;
+    }
+
+    /**
+     * Simulate modification of configuration of OSGi service instance.
+     * @param target Service instance.
+     * @param properties Updated configuration
+     * @return true if modified method was called. False if it failed.
+     */
+    public static boolean modified(Object target, BundleContext bundleContext, Map<String,Object> properties) {
+        Class<?> targetClass = target.getClass();
+
+        // get method name for activation/deactivation from osgi metadata
+        Document metadata = OsgiMetadataUtil.getMetadata(targetClass);
+        String methodName = OsgiMetadataUtil.getModifiedMethodName(targetClass, metadata);
+        
+        // try to find matching modified method and execute it
+        Method method = getMethod(targetClass, methodName, new Class<?>[] { Map.class });
+        if (method != null) {
+            invokeMethod(target, method, new Object[] { properties });
+            return true;
+        }
+        
+        log.warn("Method {} not found in class {}", methodName, targetClass.getName());
         return false;
     }
 
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtilTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtilTest.java
index 6fd4ec2..37e5c49 100644
--- a/src/test/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtilTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtilTest.java
@@ -45,6 +45,9 @@ import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Modified;
+
+import com.google.common.collect.ImmutableMap;
 
 public class ReflectionServiceUtilTest {
 
@@ -85,12 +88,32 @@ public class ReflectionServiceUtilTest {
         List<Map<String, Object>> reference3Configs = service3.getReference3Configs();
         assertEquals(1, reference3Configs.size());
         assertEquals(200, reference3Configs.get(0).get(Constants.SERVICE_RANKING));
-
+        
         assertTrue(MockOsgi.deactivate(service3));
         assertNull(service3.getComponentContext());
     }
 
     @Test
+    public void testService3_Config() {
+        BundleContext bundleContext = MockOsgi.newBundleContext();
+        
+        Map<String,Object> initialProperites = ImmutableMap.<String, Object>of("prop1", "value1");
+
+        Service3 service3 = new Service3();
+        MockOsgi.activate(service3, bundleContext, initialProperites);
+        assertEquals(initialProperites, service3.getConfig());
+        
+        Map<String,Object> newProperties = ImmutableMap.<String, Object>of("prop2", "value2");
+        MockOsgi.modified(service3, bundleContext, newProperties);
+        assertEquals(newProperties, service3.getConfig());
+
+        newProperties = ImmutableMap.<String, Object>of("prop3", "value3");
+        Dictionary<String,Object> newPropertiesDictonary = new Hashtable<String,Object>(newProperties);
+        MockOsgi.modified(service3, bundleContext, newPropertiesDictonary);
+        assertEquals(newProperties, service3.getConfig());
+    }
+    
+    @Test
     public void testService4() {
         Service4 service4 = new Service4();
 
@@ -144,16 +167,24 @@ public class ReflectionServiceUtilTest {
         private List<Map<String, Object>> reference3Configs = new ArrayList<Map<String, Object>>();
 
         private ComponentContext componentContext;
+        private Map<String, Object> config;
 
+        @SuppressWarnings("unchecked")
         @Activate
         private void activate(ComponentContext ctx) {
             this.componentContext = ctx;
+            this.config = MockOsgi.toMap(ctx.getProperties());
         }
 
         @Deactivate
         private void deactivate(ComponentContext ctx) {
             this.componentContext = null;
         }
+        
+        @Modified
+        private void modified(Map<String,Object> newConfig) {
+            this.config = newConfig;
+        }
 
         public ServiceInterface1 getReference1() {
             return this.reference1;
@@ -178,6 +209,10 @@ public class ReflectionServiceUtilTest {
         public ComponentContext getComponentContext() {
             return this.componentContext;
         }
+        
+        public Map<String, Object> getConfig() {
+            return config;
+        }
 
         protected void bindReference1(ServiceInterface1 service) {
             reference1 = service;
diff --git a/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest.xml b/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest.xml
index 923b90f..202dc40 100644
--- a/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest.xml
+++ b/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest.xml
@@ -17,7 +17,7 @@
     <property name="service.ranking" type="Integer" value="200"/>
     <property name="service.pid" value="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service2"/>
   </scr:component>
-  <scr:component name="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service3" activate="activate" deactivate="deactivate">
+  <scr:component name="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service3" activate="activate" deactivate="deactivate" modified="modified">
     <implementation class="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service3"/>
     <property name="service.pid" value="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service3"/>
     <reference name="reference2" interface="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$ServiceInterface2" cardinality="1..n" policy="static" bind="bindReference2" unbind="unbindReference2"/>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 09/23: [maven-release-plugin] prepare for next development iteration

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit d794a379295203b6d4eccccda041417966a67030
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Fri Oct 17 08:17:42 2014 +0000

    [maven-release-plugin] prepare for next development iteration
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1632499 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/pom.xml b/pom.xml
index d50758c..83f3930 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@
     </parent>
 
     <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
-    <version>1.0.0</version>
+    <version>1.0.1-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
     <name>Apache Sling Testing OSGi Mock</name>
@@ -39,9 +39,9 @@
     </properties>
 
     <scm>
-        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/tags/org.apache.sling.testing.osgi-mock-1.0.0</connection>
-        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.testing.osgi-mock-1.0.0</developerConnection>
-        <url>http://svn.apache.org/viewvc/sling/tags/org.apache.sling.testing.osgi-mock-1.0.0</url>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/trunk/testing/mocks/osgi-mock</url>
     </scm>
 
     <dependencies>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 08/23: [maven-release-plugin] prepare release org.apache.sling.testing.osgi-mock-1.0.0

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 74be83a1b3688bbcc077e6058ea135d5aeeb8932
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Fri Oct 17 08:17:37 2014 +0000

    [maven-release-plugin] prepare release org.apache.sling.testing.osgi-mock-1.0.0
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1632497 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/pom.xml b/pom.xml
index 4083ee6..d50758c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@
     </parent>
 
     <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
-    <version>1.0.0-SNAPSHOT</version>
+    <version>1.0.0</version>
     <packaging>bundle</packaging>
 
     <name>Apache Sling Testing OSGi Mock</name>
@@ -39,9 +39,9 @@
     </properties>
 
     <scm>
-        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock</connection>
-        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock</developerConnection>
-        <url>http://svn.apache.org/viewvc/sling/trunk/testing/mocks/osgi-mock</url>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/tags/org.apache.sling.testing.osgi-mock-1.0.0</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.testing.osgi-mock-1.0.0</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/tags/org.apache.sling.testing.osgi-mock-1.0.0</url>
     </scm>
 
     <dependencies>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 01/23: SLING-4042 Donate sling-mock, jcr-mock, osgi-mock implementation

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit e5ba840d79da4de23084251e3d5ce06e04c5973a
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Mon Oct 13 11:54:39 2014 +0000

    SLING-4042 Donate sling-mock, jcr-mock, osgi-mock implementation
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/osgi-mock@1631356 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                                            | 119 ++++++++
 .../apache/sling/testing/mock/osgi/MockBundle.java | 182 +++++++++++++
 .../sling/testing/mock/osgi/MockBundleContext.java | 220 +++++++++++++++
 .../testing/mock/osgi/MockComponentContext.java    |  98 +++++++
 .../apache/sling/testing/mock/osgi/MockFilter.java |  46 ++++
 .../sling/testing/mock/osgi/MockLogService.java    |  87 ++++++
 .../apache/sling/testing/mock/osgi/MockOsgi.java   | 250 +++++++++++++++++
 .../testing/mock/osgi/MockServiceReference.java    | 131 +++++++++
 .../testing/mock/osgi/MockServiceRegistration.java | 105 +++++++
 .../sling/testing/mock/osgi/OsgiMetadataUtil.java  | 278 +++++++++++++++++++
 .../testing/mock/osgi/ReflectionServiceUtil.java   | 301 +++++++++++++++++++++
 src/main/resources/simplelogger.properties         |  18 ++
 src/site/markdown/index.md                         |  35 +++
 src/site/markdown/usage.md                         |  59 ++++
 .../testing/mock/osgi/MockBundleContextTest.java   | 159 +++++++++++
 .../sling/testing/mock/osgi/MockBundleTest.java    |  60 ++++
 .../mock/osgi/MockComponentContextTest.java        |  84 ++++++
 .../sling/testing/mock/osgi/MockFilterTest.java    |  46 ++++
 .../testing/mock/osgi/MockLogServiceTest.java      |  70 +++++
 .../mock/osgi/MockServiceReferenceTest.java        |  81 ++++++
 .../testing/mock/osgi/OsgiMetadataUtilTest.java    |  93 +++++++
 .../mock/osgi/ReflectionServiceUtilTest.java       | 226 ++++++++++++++++
 .../sling/testing/mock/osgi/package-info.java      |  23 ++
 src/test/resources/META-INF/test.txt               |   1 +
 ...ling.testing.mock.osgi.OsgiMetadataUtilTest.xml |  14 +
 ...testing.mock.osgi.ReflectionServiceUtilTest.xml |  32 +++
 src/test/resources/simplelogger.properties         |  18 ++
 27 files changed, 2836 insertions(+)

diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..708d885
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>sling</artifactId>
+        <version>22</version>
+        <relativePath>../../parent/pom.xml</relativePath>
+    </parent>
+
+    <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
+    <version>1.0.0-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <name>Apache Sling Testing OSGi Mock</name>
+    <description>Mock implementation of selected OSGi APIs.</description>
+
+    <properties>
+        <sling.java.version>6</sling.java.version>
+    </properties>
+
+    <dependencies>
+  
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.annotations</artifactId>
+            <scope>compile</scope>
+        </dependency>
+    
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>compile</scope>
+        </dependency>
+    
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>15.0</version>
+            <scope>compile</scope>
+        </dependency>
+  
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.0.1</version>
+            <scope>compile</scope>
+        </dependency>
+    
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <scope>compile</scope>
+        </dependency>
+    
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <version>1.9.5</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+  
+    <build>
+        <plugins>
+    
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+            </plugin>
+      
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-scr-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>generate-scr-scrdescriptor</id>
+                        <goals>
+                            <goal>scr</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+    
+        </plugins>
+    </build>
+  
+</project>
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockBundle.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockBundle.java
new file mode 100644
index 0000000..6c1f22e
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockBundle.java
@@ -0,0 +1,182 @@
+/*
+ * 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.sling.testing.mock.osgi;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Version;
+
+/**
+ * Mock {@link Bundle} implementation.
+ */
+class MockBundle implements Bundle {
+
+    private static volatile long bundleCounter;
+
+    private final long bundleId;
+    private final BundleContext bundleContext;
+
+    /**
+     * Constructor
+     */
+    public MockBundle(BundleContext bundleContext) {
+        this.bundleId = ++bundleCounter;
+        this.bundleContext = bundleContext;
+    }
+
+    @Override
+    public long getBundleId() {
+        return this.bundleId;
+    }
+
+    @Override
+    public BundleContext getBundleContext() {
+        return this.bundleContext;
+    }
+
+    @Override
+    public URL getEntry(final String name) {
+        // try to load resource from classpath
+        return getClass().getResource(name);
+    }
+
+    @Override
+    public int getState() {
+        return Bundle.ACTIVE;
+    }
+
+    // --- unsupported operations ---
+    @Override
+    public Enumeration<?> findEntries(final String path, final String filePattern, final boolean recurse) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Enumeration<?> getEntryPaths(final String path) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Dictionary<?, ?> getHeaders() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Dictionary<?, ?> getHeaders(final String locale) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public long getLastModified() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getLocation() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ServiceReference[] getRegisteredServices() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public URL getResource(final String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Enumeration<?> getResources(final String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ServiceReference[] getServicesInUse() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getSymbolicName() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean hasPermission(final Object permission) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Class<?> loadClass(final String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void start() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void stop() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void uninstall() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void update() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void update(final InputStream inputStream) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void start(final int options) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void stop(final int options) {
+        throw new UnsupportedOperationException();
+    }
+
+    // this is part of org.osgi 4.2.0
+    public Map getSignerCertificates(final int signersType) {
+        throw new UnsupportedOperationException();
+    }
+
+    // this is part of org.osgi 4.2.0
+    public Version getVersion() {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockBundleContext.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockBundleContext.java
new file mode 100644
index 0000000..cbaa13d
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockBundleContext.java
@@ -0,0 +1,220 @@
+/*
+ * 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.sling.testing.mock.osgi;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.commons.lang3.StringUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Mock {@link BundleContext} implementation.
+ */
+class MockBundleContext implements BundleContext {
+
+    private final MockBundle bundle;
+    private final List<MockServiceRegistration> registeredServices = new ArrayList<MockServiceRegistration>();
+    private final List<ServiceListener> serviceListeners = new ArrayList<ServiceListener>();
+    private final List<BundleListener> bundleListeners = new ArrayList<BundleListener>();
+
+    public MockBundleContext() {
+        this.bundle = new MockBundle(this);
+    }
+
+    @Override
+    public Bundle getBundle() {
+        return this.bundle;
+    }
+
+    @Override
+    public Filter createFilter(final String s) {
+        // return filter that denies all
+        return new MockFilter();
+    }
+
+    @Override
+    public ServiceRegistration registerService(final String clazz, final Object service, final Dictionary properties) {
+        String[] clazzes;
+        if (StringUtils.isBlank(clazz)) {
+            clazzes = new String[0];
+        } else {
+            clazzes = new String[] { clazz };
+        }
+        return registerService(clazzes, service, properties);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public ServiceRegistration registerService(final String[] clazzes, final Object service, final Dictionary properties) {
+        MockServiceRegistration registration = new MockServiceRegistration(this.bundle, clazzes, service, properties);
+        this.registeredServices.add(registration);
+        notifyServiceListeners(ServiceEvent.REGISTERED, registration.getReference());
+        return registration;
+    }
+
+    @Override
+    public ServiceReference getServiceReference(final String clazz) {
+        ServiceReference[] serviceRefs = getServiceReferences(clazz, null);
+        if (serviceRefs != null && serviceRefs.length > 0) {
+            return serviceRefs[0];
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public ServiceReference[] getServiceReferences(final String clazz, final String filter) {
+        Set<ServiceReference> result = new TreeSet<ServiceReference>();
+        for (MockServiceRegistration serviceRegistration : this.registeredServices) {
+            if (serviceRegistration.matches(clazz, filter)) {
+                result.add(serviceRegistration.getReference());
+            }
+        }
+        if (result.isEmpty()) {
+            return null;
+        } else {
+            return result.toArray(new ServiceReference[result.size()]);
+        }
+    }
+
+    @Override
+    public ServiceReference[] getAllServiceReferences(final String clazz, final String filter) {
+        // for now just do the same as getServiceReferences
+        return getServiceReferences(clazz, filter);
+    }
+
+    @Override
+    public Object getService(final ServiceReference serviceReference) {
+        return ((MockServiceReference) serviceReference).getService();
+    }
+
+    @Override
+    public boolean ungetService(final ServiceReference serviceReference) {
+        // do nothing for now
+        return false;
+    }
+
+    @Override
+    public void addServiceListener(final ServiceListener serviceListener) {
+        addServiceListener(serviceListener, null);
+    }
+
+    @Override
+    public void addServiceListener(final ServiceListener serviceListener, final String s) {
+        if (!serviceListeners.contains(serviceListener)) {
+            serviceListeners.add(serviceListener);
+        }
+    }
+
+    @Override
+    public void removeServiceListener(final ServiceListener serviceListener) {
+        serviceListeners.remove(serviceListener);
+    }
+
+    private void notifyServiceListeners(int eventType, ServiceReference serviceReference) {
+        final ServiceEvent event = new ServiceEvent(eventType, serviceReference);
+        for (ServiceListener serviceListener : serviceListeners) {
+            serviceListener.serviceChanged(event);
+        }
+    }
+
+    @Override
+    public void addBundleListener(final BundleListener bundleListener) {
+        if (!bundleListeners.contains(bundleListener)) {
+            bundleListeners.add(bundleListener);
+        }
+    }
+
+    @Override
+    public void removeBundleListener(final BundleListener bundleListener) {
+        bundleListeners.remove(bundleListener);
+    }
+
+    void sendBundleEvent(BundleEvent bundleEvent) {
+        for (BundleListener bundleListener : bundleListeners) {
+            bundleListener.bundleChanged(bundleEvent);
+        }
+    }
+
+    @Override
+    public void addFrameworkListener(final FrameworkListener frameworkListener) {
+        // accept method, but ignore it
+    }
+
+    @Override
+    public void removeFrameworkListener(final FrameworkListener frameworkListener) {
+        // accept method, but ignore it
+    }
+
+    Object locateService(final String name, final ServiceReference reference) {
+        for (MockServiceRegistration serviceRegistration : this.registeredServices) {
+            if (serviceRegistration.getReference() == reference) {
+                return serviceRegistration.getService();
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Bundle[] getBundles() {
+        return new Bundle[0];
+    }
+
+    // --- unsupported operations ---
+    @Override
+    public String getProperty(final String s) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Bundle installBundle(final String s) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Bundle installBundle(final String s, final InputStream inputStream) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Bundle getBundle(final long l) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public File getDataFile(final String s) {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockComponentContext.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockComponentContext.java
new file mode 100644
index 0000000..cf70b1d
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockComponentContext.java
@@ -0,0 +1,98 @@
+/*
+ * 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.sling.testing.mock.osgi;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.ComponentInstance;
+
+/**
+ * Mock {@link ComponentContext} implementation.
+ */
+class MockComponentContext implements ComponentContext {
+
+    private final MockBundleContext bundleContext;
+    private final Dictionary<String, Object> properties;
+
+    public MockComponentContext(final MockBundleContext mockBundleContext) {
+        this(mockBundleContext, new Hashtable<String, Object>());
+    }
+
+    public MockComponentContext(final MockBundleContext mockBundleContext, final Dictionary<String, Object> properties) {
+        this.bundleContext = mockBundleContext;
+        this.properties = properties;
+    }
+
+    @Override
+    public Dictionary<String, Object> getProperties() {
+        return this.properties;
+    }
+
+    @Override
+    public Object locateService(final String name, final ServiceReference reference) {
+        return this.bundleContext.locateService(name, reference);
+    }
+
+    @Override
+    public BundleContext getBundleContext() {
+        return this.bundleContext;
+    }
+
+    @Override
+    public void disableComponent(final String name) {
+        // allow calling, but ignore
+    }
+
+    @Override
+    public void enableComponent(final String name) {
+        // allow calling, but ignore
+    }
+
+    // --- unsupported operations ---
+    @Override
+    public ComponentInstance getComponentInstance() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ServiceReference getServiceReference() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Bundle getUsingBundle() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Object locateService(final String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Object[] locateServices(final String name) {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockFilter.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockFilter.java
new file mode 100644
index 0000000..b0f585c
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockFilter.java
@@ -0,0 +1,46 @@
+/*
+ * 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.sling.testing.mock.osgi;
+
+import java.util.Dictionary;
+
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Mock {@link Filter} implementation.
+ */
+class MockFilter implements Filter {
+
+    @Override
+    public boolean match(final ServiceReference reference) {
+        return false;
+    }
+
+    @Override
+    public boolean match(final Dictionary dictionary) {
+        return false;
+    }
+
+    @Override
+    public boolean matchCase(final Dictionary dictionary) {
+        return false;
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockLogService.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockLogService.java
new file mode 100644
index 0000000..28d1433
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockLogService.java
@@ -0,0 +1,87 @@
+/*
+ * 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.sling.testing.mock.osgi;
+
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Mock {@link LogService} implementation.
+ */
+class MockLogService implements LogService {
+
+    private final Logger log;
+
+    public MockLogService(final Class<?> loggerContext) {
+        this.log = LoggerFactory.getLogger(loggerContext);
+    }
+
+    @Override
+    public void log(final int level, final String message) {
+        switch (level) {
+        case LogService.LOG_ERROR:
+            this.log.error(message);
+            break;
+        case LogService.LOG_WARNING:
+            this.log.warn(message);
+            break;
+        case LogService.LOG_INFO:
+            this.log.info(message);
+            break;
+        case LogService.LOG_DEBUG:
+            this.log.debug(message);
+            break;
+        default:
+            throw new IllegalArgumentException("Invalid log level: " + level);
+        }
+    }
+
+    @Override
+    public void log(final int level, final String message, final Throwable exception) {
+        switch (level) {
+        case LogService.LOG_ERROR:
+            this.log.error(message, exception);
+            break;
+        case LogService.LOG_WARNING:
+            this.log.warn(message, exception);
+            break;
+        case LogService.LOG_INFO:
+            this.log.info(message, exception);
+            break;
+        case LogService.LOG_DEBUG:
+            this.log.debug(message, exception);
+            break;
+        default:
+            throw new IllegalArgumentException("Invalid log level: " + level);
+        }
+    }
+
+    @Override
+    public void log(final ServiceReference sr, final int level, final String message) {
+        log(level, message);
+    }
+
+    @Override
+    public void log(final ServiceReference sr, final int level, final String message, final Throwable exception) {
+        log(level, message, exception);
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java
new file mode 100644
index 0000000..fd65fe1
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java
@@ -0,0 +1,250 @@
+/*
+ * 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.sling.testing.mock.osgi;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.log.LogService;
+
+/**
+ * Factory for mock OSGi objects.
+ */
+public final class MockOsgi {
+
+    private MockOsgi() {
+        // static methods only
+    }
+
+    /**
+     * @return Mocked {@link BundleContext} instance
+     */
+    public static BundleContext newBundleContext() {
+        return new MockBundleContext();
+    }
+
+    /**
+     * Simulates a bundle event on the given bundle context (that is forwarded
+     * to registered bundle listeners).
+     * @param bundleContext Bundle context
+     * @param bundleEvent Bundle event
+     */
+    public static void sendBundleEvent(BundleContext bundleContext, BundleEvent bundleEvent) {
+        ((MockBundleContext) bundleContext).sendBundleEvent(bundleEvent);
+    }
+
+    /**
+     * @return Mocked {@link ComponentContext} instance
+     */
+    public static ComponentContext newComponentContext() {
+        return new MockComponentContext((MockBundleContext) newBundleContext());
+    }
+
+    /**
+     * @param properties Properties
+     * @return Mocked {@link ComponentContext} instance
+     */
+    public static ComponentContext newComponentContext(Dictionary<String, Object> properties) {
+        return newComponentContext(newBundleContext(), properties);
+    }
+
+    /**
+     * @param properties Properties
+     * @return Mocked {@link ComponentContext} instance
+     */
+    public static ComponentContext newComponentContext(Map<String, Object> properties) {
+        return newComponentContext(toDictionary(properties));
+    }
+
+    /**
+     * @param bundleContext Bundle context
+     * @param properties Properties
+     * @return Mocked {@link ComponentContext} instance
+     */
+    public static ComponentContext newComponentContext(BundleContext bundleContext,
+            Dictionary<String, Object> properties) {
+        return new MockComponentContext((MockBundleContext) bundleContext, properties);
+    }
+
+    /**
+     * @param bundleContext Bundle context
+     * @param properties Properties
+     * @return Mocked {@link ComponentContext} instance
+     */
+    public static ComponentContext newComponentContext(BundleContext bundleContext, Map<String, Object> properties) {
+        return newComponentContext(bundleContext, toDictionary(properties));
+    }
+
+    /**
+     * @param loggerContext Context class for logging
+     * @return Mocked {@link LogService} instance
+     */
+    public static LogService newLogService(final Class<?> loggerContext) {
+        return new MockLogService(loggerContext);
+    }
+
+    /**
+     * Simulate OSGi service dependency injection. Injects direct references and
+     * multiple references. If a some references could not be injected no error
+     * is thrown.
+     * @param target Service instance
+     * @param bundleContext Bundle context from which services are fetched to inject.
+     * @return true if all dependencies could be injected
+     */
+    public static boolean injectServices(Object target, BundleContext bundleContext) {
+        return ReflectionServiceUtil.injectServices(target, bundleContext);
+    }
+
+    /**
+     * Simulate activation of service instance. Invokes the @Activate annotated
+     * method.
+     * @param target Service instance.
+     * @return true if activation method was called. False if such a method did
+     *         not exist.
+     */
+    public static boolean activate(Object target) {
+        ComponentContext componentContext = newComponentContext();
+        return ReflectionServiceUtil.activateDeactivate(target, componentContext, true);
+    }
+
+    /**
+     * Simulate activation of service instance. Invokes the @Activate annotated
+     * method.
+     * @param target Service instance.
+     * @param properties Properties
+     * @return true if activation method was called. False if such a method did
+     *         not exist.
+     */
+    public static boolean activate(Object target, Dictionary<String, Object> properties) {
+        ComponentContext componentContext = newComponentContext(properties);
+        return ReflectionServiceUtil.activateDeactivate(target, componentContext, true);
+    }
+
+    /**
+     * Simulate activation of service instance. Invokes the @Activate annotated
+     * method.
+     * @param target Service instance.
+     * @param properties Properties
+     * @return true if activation method was called. False if such a method did
+     *         not exist.
+     */
+    public static boolean activate(Object target, Map<String, Object> properties) {
+        return activate(target, toDictionary(properties));
+    }
+
+    /**
+     * Simulate activation of service instance. Invokes the @Activate annotated
+     * method.
+     * @param target Service instance.
+     * @param bundleContext Bundle context
+     * @param properties Properties
+     * @return true if activation method was called. False if such a method did
+     *         not exist.
+     */
+    public static boolean activate(Object target, BundleContext bundleContext, Dictionary<String, Object> properties) {
+        ComponentContext componentContext = newComponentContext(bundleContext, properties);
+        return ReflectionServiceUtil.activateDeactivate(target, componentContext, true);
+    }
+
+    /**
+     * Simulate activation of service instance. Invokes the @Activate annotated
+     * method.
+     * @param target Service instance.
+     * @param bundleContext Bundle context
+     * @param properties Properties
+     * @return true if activation method was called. False if such a method did
+     *         not exist.
+     */
+    public static boolean activate(Object target, BundleContext bundleContext, Map<String, Object> properties) {
+        return activate(target, bundleContext, toDictionary(properties));
+    }
+
+    /**
+     * Simulate deactivation of service instance. Invokes the @Activate
+     * annotated method.
+     * @param target Service instance.
+     * @return true if deactivation method was called. False if such a method
+     *         did not exist.
+     */
+    public static boolean deactivate(Object target) {
+        ComponentContext componentContext = newComponentContext();
+        return ReflectionServiceUtil.activateDeactivate(target, componentContext, false);
+    }
+
+    /**
+     * Simulate deactivation of service instance. Invokes the @Activate
+     * annotated method.
+     * @param target Service instance.
+     * @param properties Properties
+     * @return true if deactivation method was called. False if such a method
+     *         did not exist.
+     */
+    public static boolean deactivate(Object target, Dictionary<String, Object> properties) {
+        ComponentContext componentContext = newComponentContext(properties);
+        return ReflectionServiceUtil.activateDeactivate(target, componentContext, false);
+    }
+
+    /**
+     * Simulate deactivation of service instance. Invokes the @Activate
+     * annotated method.
+     * @param target Service instance.
+     * @param properties Properties
+     * @return true if deactivation method was called. False if such a method
+     *         did not exist.
+     */
+    public static boolean deactivate(Object target, Map<String, Object> properties) {
+        return deactivate(target, toDictionary(properties));
+    }
+
+    /**
+     * Simulate deactivation of service instance. Invokes the @Activate
+     * annotated method.
+     * @param target Service instance.
+     * @param bundleContext Bundle context
+     * @param properties Properties
+     * @return true if deactivation method was called. False if such a method
+     *         did not exist.
+     */
+    public static boolean deactivate(Object target, BundleContext bundleContext, Dictionary<String, Object> properties) {
+        ComponentContext componentContext = newComponentContext(bundleContext, properties);
+        return ReflectionServiceUtil.activateDeactivate(target, componentContext, false);
+    }
+
+    /**
+     * Simulate activation of service instance. Invokes the @Activate annotated
+     * method.
+     * @param target Service instance.
+     * @param bundleContext Bundle context
+     * @param properties Properties
+     * @return true if activation method was called. False if such a method did
+     *         not exist.
+     */
+    public static boolean deactivate(Object target, BundleContext bundleContext, Map<String, Object> properties) {
+        return deactivate(target, bundleContext, toDictionary(properties));
+    }
+
+    private static Dictionary<String, Object> toDictionary(Map<String, Object> map) {
+        return new Hashtable<String, Object>(map);
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceReference.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceReference.java
new file mode 100644
index 0000000..c7568be
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceReference.java
@@ -0,0 +1,131 @@
+/*
+ * 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.sling.testing.mock.osgi;
+
+import java.util.Collections;
+import java.util.Dictionary;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Mock {@link ServiceReference} implementation.
+ */
+class MockServiceReference implements ServiceReference {
+
+    private final Bundle bundle;
+    private final MockServiceRegistration serviceRegistration;
+
+    public MockServiceReference(final Bundle bundle, final MockServiceRegistration serviceRegistration) {
+        this.bundle = bundle;
+        this.serviceRegistration = serviceRegistration;
+    }
+
+    @Override
+    public Bundle getBundle() {
+        return this.bundle;
+    }
+
+    /**
+     * Set service reference property
+     * @param key Key
+     * @param value Value
+     */
+    public void setProperty(final String key, final Object value) {
+        this.serviceRegistration.getProperties().put(key, value);
+    }
+
+    @Override
+    public Object getProperty(final String key) {
+        return this.serviceRegistration.getProperties().get(key);
+    }
+
+    @Override
+    public String[] getPropertyKeys() {
+        Dictionary<String, Object> props = this.serviceRegistration.getProperties();
+        return Collections.list(props.keys()).toArray(new String[props.size()]);
+    }
+
+    @Override
+    public int hashCode() {
+        return ((Long) getServiceId()).hashCode();
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (!(obj instanceof MockServiceReference)) {
+            return false;
+        }
+        return ((Long) getServiceId()).equals(((MockServiceReference) obj).getServiceId());
+    }
+
+    @Override
+    public int compareTo(final Object obj) {
+        if (!(obj instanceof MockServiceReference)) {
+            return 0;
+        }
+        // sort by decreasing by service ranking, and secondary increasing by
+        // service id
+        Integer serviceRanking = getServiceRanking();
+        Integer otherServiceRanking = ((MockServiceReference) obj).getServiceRanking();
+        int serviceRankingCompare = otherServiceRanking.compareTo(serviceRanking);
+        if (serviceRankingCompare == 0) {
+            Long serviceId = getServiceId();
+            Long otherServiceId = ((MockServiceReference) obj).getServiceId();
+            return serviceId.compareTo(otherServiceId);
+        } else {
+            return serviceRankingCompare;
+        }
+    }
+
+    long getServiceId() {
+        Number serviceID = (Number) getProperty(Constants.SERVICE_ID);
+        if (serviceID != null) {
+            return serviceID.longValue();
+        } else {
+            return 0L;
+        }
+    }
+
+    int getServiceRanking() {
+        Number serviceRanking = (Number) getProperty(Constants.SERVICE_RANKING);
+        if (serviceRanking != null) {
+            return serviceRanking.intValue();
+        } else {
+            return 0;
+        }
+    }
+
+    Object getService() {
+        return this.serviceRegistration.getService();
+    }
+
+    // --- unsupported operations ---
+    @Override
+    public Bundle[] getUsingBundles() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isAssignableTo(final Bundle otherBundle, final String className) {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceRegistration.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceRegistration.java
new file mode 100644
index 0000000..a3bdaf5
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceRegistration.java
@@ -0,0 +1,105 @@
+/*
+ * 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.sling.testing.mock.osgi;
+
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.w3c.dom.Document;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Mock {@link ServiceRegistration} implementation.
+ */
+class MockServiceRegistration implements ServiceRegistration {
+
+    private static volatile long serviceCounter;
+
+    private final Set<String> clazzes;
+    private final Object service;
+    private Dictionary<String, Object> properties;
+    private final ServiceReference serviceReference;
+
+    @SuppressWarnings("unchecked")
+    public MockServiceRegistration(final Bundle bundle, final String[] clazzes, final Object service,
+            final Dictionary<String, Object> properties) {
+        this.clazzes = new HashSet<String>(ImmutableList.copyOf(clazzes));
+        this.service = service;
+        this.properties = properties != null ? properties : new Hashtable();
+        this.properties.put(Constants.SERVICE_ID, ++serviceCounter);
+        this.serviceReference = new MockServiceReference(bundle, this);
+        readOsgiMetadata();
+    }
+
+    @Override
+    public ServiceReference getReference() {
+        return this.serviceReference;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void setProperties(final Dictionary properties) {
+        this.properties = properties;
+    }
+
+    @Override
+    public void unregister() {
+        // do nothing for now
+    }
+
+    Dictionary<String, Object> getProperties() {
+        return this.properties;
+    }
+
+    boolean matches(final String clazz, final String filter) {
+        // ignore filter for now
+        return this.clazzes.contains(clazz);
+    }
+
+    Object getService() {
+        return this.service;
+    }
+
+    /**
+     * Try to read OSGI-metadata from /OSGI-INF and read all implemented
+     * interfaces and service properties
+     */
+    private void readOsgiMetadata() {
+        Class<?> serviceClass = service.getClass();
+        Document doc = OsgiMetadataUtil.getMetadata(serviceClass);
+
+        // add service interfaces from OSGi metadata
+        clazzes.addAll(OsgiMetadataUtil.getServiceInterfaces(serviceClass, doc));
+
+        // add properties from OSGi metadata
+        Map<String, Object> props = OsgiMetadataUtil.getProperties(serviceClass, doc);
+        for (Map.Entry<String, Object> entry : props.entrySet()) {
+            properties.put(entry.getKey(), entry.getValue());
+        }
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtil.java b/src/main/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtil.java
new file mode 100644
index 0000000..da8bca0
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtil.java
@@ -0,0 +1,278 @@
+/*
+ * 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.sling.testing.mock.osgi;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+
+/**
+ * Helper methods to parse OSGi metadata.
+ */
+final class OsgiMetadataUtil {
+
+    private static final Logger log = LoggerFactory.getLogger(OsgiMetadataUtil.class);
+
+    private static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY;
+    static {
+        DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
+        DOCUMENT_BUILDER_FACTORY.setNamespaceAware(true);
+    }
+
+    private static final XPathFactory XPATH_FACTORY = XPathFactory.newInstance();
+
+    private static final BiMap<String, String> NAMESPACES = HashBiMap.create();
+    static {
+        NAMESPACES.put("scr", "http://www.osgi.org/xmlns/scr/v1.1.0");
+    }
+
+    private OsgiMetadataUtil() {
+        // static methods only
+    }
+
+    private static final NamespaceContext NAMESPACE_CONTEXT = new NamespaceContext() {
+        @Override
+        public String getNamespaceURI(String prefix) {
+            return NAMESPACES.get(prefix);
+        }
+
+        @Override
+        public String getPrefix(String namespaceURI) {
+            return NAMESPACES.inverse().get(namespaceURI);
+        }
+
+        @Override
+        public Iterator getPrefixes(String namespaceURI) {
+            return NAMESPACES.keySet().iterator();
+        }
+    };
+
+    /**
+     * Try to read OSGI-metadata from /OSGI-INF and read all implemented
+     * interfaces and service properties
+     * @param clazz OSGi service implementation class
+     * @return Metadata document or null
+     */
+    public static Document getMetadata(Class clazz) {
+        String metadataPath = "/OSGI-INF/" + StringUtils.substringBefore(clazz.getName(), "$") + ".xml";
+        InputStream metadataStream = clazz.getResourceAsStream(metadataPath);
+        if (metadataStream == null) {
+            log.debug("No OSGi metadata found at {}", metadataPath);
+            return null;
+        }
+        try {
+            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+            return documentBuilder.parse(metadataStream);
+        } catch (ParserConfigurationException ex) {
+            throw new RuntimeException("Unable to read classpath resource: " + metadataPath, ex);
+        } catch (SAXException ex) {
+            throw new RuntimeException("Unable to read classpath resource: " + metadataPath, ex);
+        } catch (IOException ex) {
+            throw new RuntimeException("Unable to read classpath resource: " + metadataPath, ex);
+        } finally {
+            try {
+                metadataStream.close();
+            } catch (IOException ex) {
+                // ignore
+            }
+        }
+    }
+
+    public static Set<String> getServiceInterfaces(Class clazz, Document metadata) {
+        Set<String> serviceInterfaces = new HashSet<String>();
+        if (metadata != null) {
+            String query = "/components/component[@name='" + clazz.getName() + "']/service/provide[@interface!='']";
+            NodeList nodes = queryNodes(metadata, query);
+            if (nodes != null) {
+                for (int i = 0; i < nodes.getLength(); i++) {
+                    Node node = nodes.item(i);
+                    String serviceInterface = getAttributeValue(node, "interface");
+                    if (StringUtils.isNotBlank(serviceInterface)) {
+                        serviceInterfaces.add(serviceInterface);
+                    }
+                }
+            }
+        }
+        return serviceInterfaces;
+    }
+
+    public static Map<String, Object> getProperties(Class clazz, Document metadata) {
+        Map<String, Object> props = new HashMap<String, Object>();
+        if (metadata != null) {
+            String query = "/components/component[@name='" + clazz.getName() + "']/property[@name!='' and @value!='']";
+            NodeList nodes = queryNodes(metadata, query);
+            if (nodes != null) {
+                for (int i = 0; i < nodes.getLength(); i++) {
+                    Node node = nodes.item(i);
+                    String name = getAttributeValue(node, "name");
+                    String value = getAttributeValue(node, "value");
+                    String type = getAttributeValue(node, "type");
+                    if (StringUtils.equals("Integer", type)) {
+                        props.put(name, Integer.parseInt(value));
+                    } else {
+                        props.put(name, value);
+                    }
+                }
+            }
+        }
+        return props;
+    }
+
+    public static List<Reference> getReferences(Class clazz, Document metadata) {
+        List<Reference> references = new ArrayList<Reference>();
+        if (metadata != null) {
+            String query = "/components/component[@name='" + clazz.getName() + "']/reference[@name!='']";
+            NodeList nodes = queryNodes(metadata, query);
+            if (nodes != null) {
+                for (int i = 0; i < nodes.getLength(); i++) {
+                    Node node = nodes.item(i);
+                    references.add(new Reference(node));
+                }
+            }
+        }
+        return references;
+    }
+
+    public static String getActivateMethodName(Class clazz, Document metadata) {
+        if (metadata != null) {
+            String query = "/components/component[@name='" + clazz.getName() + "']";
+            Node node = queryNode(metadata, query);
+            if (node != null) {
+                return getAttributeValue(node, "activate");
+            }
+        }
+        return null;
+    }
+
+    public static String getDeactivateMethodName(Class clazz, Document metadata) {
+        if (metadata != null) {
+            String query = "/components/component[@name='" + clazz.getName() + "']";
+            Node node = queryNode(metadata, query);
+            if (node != null) {
+                return getAttributeValue(node, "deactivate");
+            }
+        }
+        return null;
+    }
+
+    private static NodeList queryNodes(Document metadata, String xpathQuery) {
+        try {
+            XPath xpath = XPATH_FACTORY.newXPath();
+            xpath.setNamespaceContext(NAMESPACE_CONTEXT);
+            return (NodeList) xpath.evaluate(xpathQuery, metadata, XPathConstants.NODESET);
+        } catch (XPathExpressionException ex) {
+            throw new RuntimeException("Error evaluating XPath: " + xpathQuery, ex);
+        }
+    }
+
+    private static Node queryNode(Document metadata, String xpathQuery) {
+        try {
+            XPath xpath = XPATH_FACTORY.newXPath();
+            xpath.setNamespaceContext(NAMESPACE_CONTEXT);
+            return (Node) xpath.evaluate(xpathQuery, metadata, XPathConstants.NODE);
+        } catch (XPathExpressionException ex) {
+            throw new RuntimeException("Error evaluating XPath: " + xpathQuery, ex);
+        }
+    }
+
+    private static String getAttributeValue(Node node, String attributeName) {
+        Node namedItem = node.getAttributes().getNamedItem(attributeName);
+        if (namedItem != null) {
+            return namedItem.getNodeValue();
+        } else {
+            return null;
+        }
+    }
+
+    public static class Reference {
+
+        private final String name;
+        private final String interfaceType;
+        private final ReferenceCardinality cardinality;
+        private final String bind;
+        private final String unbind;
+
+        public Reference(Node node) {
+            this.name = getAttributeValue(node, "name");
+            this.interfaceType = getAttributeValue(node, "interface");
+            this.cardinality = toCardinality(getAttributeValue(node, "cardinality"));
+            this.bind = getAttributeValue(node, "bind");
+            this.unbind = getAttributeValue(node, "unbind");
+        }
+
+        private ReferenceCardinality toCardinality(String value) {
+            for (ReferenceCardinality item : ReferenceCardinality.values()) {
+                if (StringUtils.equals(item.getCardinalityString(), value)) {
+                    return item;
+                }
+            }
+            return ReferenceCardinality.MANDATORY_UNARY;
+        }
+
+        public String getName() {
+            return this.name;
+        }
+
+        public String getInterfaceType() {
+            return this.interfaceType;
+        }
+
+        public ReferenceCardinality getCardinality() {
+            return this.cardinality;
+        }
+
+        public String getBind() {
+            return this.bind;
+        }
+
+        public String getUnbind() {
+            return this.unbind;
+        }
+
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java b/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
new file mode 100644
index 0000000..aa338a3
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
@@ -0,0 +1,301 @@
+/*
+ * 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.sling.testing.mock.osgi;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.Reference;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+
+/**
+ * Helper methods to inject dependencies and activate services via reflection.
+ */
+final class ReflectionServiceUtil {
+
+    private static final Logger log = LoggerFactory.getLogger(ReflectionServiceUtil.class);
+
+    private ReflectionServiceUtil() {
+        // static methods only
+    }
+
+    /**
+     * Simulate activation or deactivation of OSGi service instance.
+     * @param target Service instance.
+     * @param componentContext Component context
+     * @return true if activation method was called. False if such a method did
+     *         not exist.
+     */
+    public static boolean activateDeactivate(Object target, ComponentContext componentContext, boolean activate) {
+        Class<?> targetClass = target.getClass();
+
+        // get method name for activation/deactivation from osgi metadata
+        Document metadata = OsgiMetadataUtil.getMetadata(targetClass);
+        String methodName;
+        if (activate) {
+            methodName = OsgiMetadataUtil.getActivateMethodName(targetClass, metadata);
+        } else {
+            methodName = OsgiMetadataUtil.getDeactivateMethodName(targetClass, metadata);
+        }
+        if (StringUtils.isEmpty(methodName)) {
+            return false;
+        }
+
+        // if method is defined try to execute it
+        Method method = getMethod(targetClass, methodName, new Class<?>[] { ComponentContext.class }, activate);
+        if (method != null) {
+            try {
+                method.setAccessible(true);
+                method.invoke(target, componentContext);
+                return true;
+            } catch (IllegalAccessException ex) {
+                throw new RuntimeException("Unable to invoke activate/deactivate method for class "
+                        + targetClass.getName(), ex);
+            } catch (IllegalArgumentException ex) {
+                throw new RuntimeException("Unable to invoke activate/deactivate method for class "
+                        + targetClass.getName(), ex);
+            } catch (InvocationTargetException ex) {
+                throw new RuntimeException("Unable to invoke activate/deactivate method for class "
+                        + targetClass.getName(), ex);
+            }
+        }
+        log.warn("Method {}(ComponentContext) not found in class {}", methodName, targetClass.getName());
+        return false;
+    }
+
+    private static Method getMethod(Class clazz, String methodName, Class<?>[] signature, boolean activate) {
+        Method[] methods = clazz.getDeclaredMethods();
+        for (Method method : methods) {
+            if (StringUtils.equals(method.getName(), methodName)
+                    && Arrays.equals(method.getParameterTypes(), signature)) {
+                return method;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Simulate OSGi service dependency injection. Injects direct references and
+     * multiple references.
+     * @param target Service instance
+     * @param bundleContext Bundle context from which services are fetched to inject.
+     * @return true if all dependencies could be injected
+     */
+    public static boolean injectServices(Object target, BundleContext bundleContext) {
+
+        // collect all declared reference annotations on class and field level
+        Class<?> targetClass = target.getClass();
+        List<Reference> references = getReferences(targetClass);
+
+        // try to inject services
+        boolean allInjected = true;
+        for (Reference reference : references) {
+            allInjected = allInjected && injectServiceReference(reference, target, bundleContext);
+        }
+        return allInjected;
+    }
+
+    private static List<Reference> getReferences(Class clazz) {
+        Document metadata = OsgiMetadataUtil.getMetadata(clazz);
+        return OsgiMetadataUtil.getReferences(clazz, metadata);
+    }
+
+    private static boolean injectServiceReference(Reference reference, Object target, BundleContext bundleContext) {
+        Class<?> targetClass = target.getClass();
+
+        // get reference type
+        Class<?> type;
+        try {
+            type = Class.forName(reference.getInterfaceType());
+        } catch (ClassNotFoundException ex) {
+            throw new RuntimeException("Unable to instantiate reference type: " + reference.getInterfaceType(), ex);
+        }
+
+        // get matching service references
+        List<ServiceInfo> matchingServices = getMatchingServices(type, bundleContext);
+
+        // no references found? check if reference was optional
+        if (matchingServices.isEmpty()) {
+            boolean isOptional = (reference.getCardinality() == ReferenceCardinality.OPTIONAL_UNARY || reference
+                    .getCardinality() == ReferenceCardinality.OPTIONAL_MULTIPLE);
+            if (!isOptional) {
+                log.warn("Unable to inject mandatory reference '{}' for class {}", reference.getName(),
+                        targetClass.getName());
+            }
+            return isOptional;
+        }
+
+        // multiple references found? check if reference is not multiple
+        if (matchingServices.size() > 1
+                && (reference.getCardinality() == ReferenceCardinality.MANDATORY_UNARY || reference.getCardinality() == ReferenceCardinality.OPTIONAL_UNARY)) {
+            log.warn("Multiple matches found for unary reference '{}' for class {}", reference.getName(),
+                    targetClass.getName());
+            return false;
+        }
+
+        // try to invoke bind method
+        String bindMethodName = reference.getBind();
+        if (StringUtils.isNotEmpty(bindMethodName)) {
+            Method bindMethod = getFirstMethodWithNameAndSignature(targetClass, bindMethodName, new Class<?>[] { type });
+            if (bindMethod != null) {
+                bindMethod.setAccessible(true);
+                for (ServiceInfo matchingService : matchingServices) {
+                    try {
+                        bindMethod.invoke(target, matchingService.getServiceInstance());
+                    } catch (IllegalAccessException ex) {
+                        throw new RuntimeException("Unable to invoke method " + bindMethodName + " for class "
+                                + targetClass.getName(), ex);
+                    } catch (IllegalArgumentException ex) {
+                        throw new RuntimeException("Unable to invoke method " + bindMethodName + " for class "
+                                + targetClass.getName(), ex);
+                    } catch (InvocationTargetException ex) {
+                        throw new RuntimeException("Unable to invoke method " + bindMethodName + " for class "
+                                + targetClass.getName(), ex);
+                    }
+                }
+                return true;
+            } else {
+                Method bindMethodWithConfig = getFirstMethodWithNameAndSignature(targetClass, bindMethodName,
+                        new Class<?>[] { type, Map.class });
+                if (bindMethodWithConfig != null) {
+                    bindMethodWithConfig.setAccessible(true);
+                    for (ServiceInfo matchingService : matchingServices) {
+                        try {
+                            bindMethodWithConfig.invoke(target, matchingService.getServiceInstance(),
+                                    matchingService.getServiceConfig());
+                        } catch (IllegalAccessException ex) {
+                            throw new RuntimeException("Unable to invoke method " + bindMethodName + " for class "
+                                    + targetClass.getName(), ex);
+                        } catch (IllegalArgumentException ex) {
+                            throw new RuntimeException("Unable to invoke method " + bindMethodName + " for class "
+                                    + targetClass.getName(), ex);
+                        } catch (InvocationTargetException ex) {
+                            throw new RuntimeException("Unable to invoke method " + bindMethodName + " for class "
+                                    + targetClass.getName(), ex);
+                        }
+                    }
+                    return true;
+                } else {
+                    Method bindMethodServiceReference = getFirstMethodWithNameAndSignature(targetClass, bindMethodName,
+                            new Class<?>[] { ServiceReference.class });
+                    if (bindMethodServiceReference != null) {
+                        bindMethodServiceReference.setAccessible(true);
+                        for (ServiceInfo matchingService : matchingServices) {
+                            if (matchingService.getServiceReference() != null) {
+                                try {
+                                    bindMethodServiceReference.invoke(target, matchingService.getServiceReference());
+                                } catch (IllegalAccessException ex) {
+                                    throw new RuntimeException("Unable to invoke method " + bindMethodName
+                                            + " for class " + targetClass.getName(), ex);
+                                } catch (IllegalArgumentException ex) {
+                                    throw new RuntimeException("Unable to invoke method " + bindMethodName
+                                            + " for class " + targetClass.getName(), ex);
+                                } catch (InvocationTargetException ex) {
+                                    throw new RuntimeException("Unable to invoke method " + bindMethodName
+                                            + " for class " + targetClass.getName(), ex);
+                                }
+                            }
+                        }
+                        return true;
+                    }
+                }
+            }
+        }
+
+        log.warn("Bind method not found for reference '{}' for class {}", reference.getName(), targetClass.getName());
+        return false;
+    }
+
+    private static Method getFirstMethodWithNameAndSignature(Class<?> clazz, String methodName, Class<?>[] signature) {
+        Method[] methods = clazz.getDeclaredMethods();
+        for (Method method : methods) {
+            if (StringUtils.equals(method.getName(), methodName)
+                    && Arrays.equals(method.getParameterTypes(), signature)) {
+                return method;
+            }
+        }
+        // not found? check super classes
+        Class<?> superClass = clazz.getSuperclass();
+        if (superClass != null && superClass != Object.class) {
+            return getFirstMethodWithNameAndSignature(superClass, methodName, signature);
+        }
+        return null;
+    }
+
+    private static List<ServiceInfo> getMatchingServices(Class<?> type, BundleContext bundleContext) {
+        List<ServiceInfo> matchingServices = new ArrayList<ServiceInfo>();
+        try {
+            ServiceReference[] references = bundleContext.getServiceReferences(type.getName(), null);
+            if (references != null) {
+                for (ServiceReference serviceReference : references) {
+                    Object serviceInstance = bundleContext.getService(serviceReference);
+                    Map<String, Object> serviceConfig = new HashMap<String, Object>();
+                    String[] keys = serviceReference.getPropertyKeys();
+                    for (String key : keys) {
+                        serviceConfig.put(key, serviceReference.getProperty(key));
+                    }
+                    matchingServices.add(new ServiceInfo(serviceInstance, serviceConfig, serviceReference));
+                }
+            }
+        } catch (InvalidSyntaxException ex) {
+            // ignore
+        }
+        return matchingServices;
+    }
+
+    private static class ServiceInfo {
+
+        private final Object serviceInstance;
+        private final Map<String, Object> serviceConfig;
+        private final ServiceReference serviceReference;
+
+        public ServiceInfo(Object serviceInstance, Map<String, Object> serviceConfig, ServiceReference serviceReference) {
+            this.serviceInstance = serviceInstance;
+            this.serviceConfig = serviceConfig;
+            this.serviceReference = serviceReference;
+        }
+
+        public Object getServiceInstance() {
+            return this.serviceInstance;
+        }
+
+        public Map<String, Object> getServiceConfig() {
+            return this.serviceConfig;
+        }
+
+        public ServiceReference getServiceReference() {
+            return serviceReference;
+        }
+
+    }
+
+}
diff --git a/src/main/resources/simplelogger.properties b/src/main/resources/simplelogger.properties
new file mode 100644
index 0000000..1507469
--- /dev/null
+++ b/src/main/resources/simplelogger.properties
@@ -0,0 +1,18 @@
+# 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.
+
+org.slf4j.simpleLogger.defaultLogLevel=warn
diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md
new file mode 100644
index 0000000..acf7d98
--- /dev/null
+++ b/src/site/markdown/index.md
@@ -0,0 +1,35 @@
+## About OSGi Mocks
+
+Mock implementation of selected OSGi APIs.
+
+### Maven Dependency
+
+```xml
+<dependency>
+  <groupId>org.apache.sling</groupId>
+  <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
+  <version>1.0.0-SNAPHOT</version>
+</dependency>
+```
+
+### Documentation
+
+* [Usage](usage.html)
+* [API Documentation](apidocs/)
+* [Changelog](changes-report.html)
+
+### Implemented mock features
+
+The mock implementation supports:
+
+* Instantiating OSGi `Bundle`, `BundleContext` and `ComponentContext` objects and navigate between them.
+* Read and write properties on them.
+* Register OSGi services and get references to service instances
+* Service and bundle listener implementation
+* When adding services to BundleContext OSGi metadata from `/OSGI-INF/<pid>.xml` is read (e.g. for service ranking property)
+* Mock implementation of `LogService` which logs to SLF4J in JUnit context
+
+The following features are *not supported*:
+
+* Activation and deactivation methods of services are not called automatically (but helper methods exist)
+* Dependency injection does not take place automatically (but helper methods exist)
diff --git a/src/site/markdown/usage.md b/src/site/markdown/usage.md
new file mode 100644
index 0000000..c7e8bb8
--- /dev/null
+++ b/src/site/markdown/usage.md
@@ -0,0 +1,59 @@
+## Usage
+
+### Getting OSGi mock objects
+
+The factory class `MockOsgi` allows to instantiate the different mock implementations.
+
+Example:
+
+```java
+// get bundle context
+BundleContext bundleContext = MockOsgi.newBundleContext();
+
+// get component context
+Dictionary<String,Object> properties = new Hashtable<>();
+properties.put("prop1", "value1");
+BundleContext bundleContext = MockOsgi.newComponentContext(properties);
+```
+
+It is possible to simulate registering of OSGi services (backed by a simple hash map internally):
+
+```java
+// register service
+bundleContext.registerService(MyClass.class, myService, properties);
+
+// get service instance
+ServiceReference ref = bundleContext.getServiceReference(MyClass.class.getName());
+MyClass service = bundleContext.getService(ref);
+```
+
+### Activation and Dependency Injection
+
+It is possible to simulate OSGi service activation, deactivation and dependency injection and the mock implementation
+tries to to its best to execute all as expected for an OSGi environment.
+
+Example:
+
+```java
+// get bundle context
+BundleContext bundleContext = MockOsgi.newBundleContext();
+
+// create service instance manually
+MyService service = new MyService();
+
+// inject dependencies
+MockOsgi.injectServices(service, bundleContext);
+
+// activate service
+MockOsgi.activate(service, props);
+
+// operate with service...
+
+// deactivate service
+MockOsgi.deactivate(service);
+```
+
+Please note: The injectServices, activate and deactivate Methods can only work properly when the SCR XML metadata files
+are preset in the classpath at `/OSGI-INF`. They are generated automatically by the Maven SCR plugin, but might be
+missing if your clean and build the project within your IDE (e.g. Eclipse). In this case you have to compile the
+project again with maven and can run the tests - or use a Maven IDE Integration like m2eclipse.
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextTest.java
new file mode 100644
index 0000000..6eef138
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextTest.java
@@ -0,0 +1,159 @@
+/*
+ * 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.sling.testing.mock.osgi;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+@RunWith(MockitoJUnitRunner.class)
+public class MockBundleContextTest {
+
+    private BundleContext bundleContext;
+
+    @Before
+    public void setUp() {
+        this.bundleContext = MockOsgi.newBundleContext();
+    }
+
+    @Test
+    public void testBundle() {
+        assertNotNull(this.bundleContext.getBundle());
+    }
+
+    @Test
+    public void testServiceRegistration() throws InvalidSyntaxException {
+        // prepare test services
+        String clazz1 = String.class.getName();
+        Object service1 = new Object();
+        Dictionary properties1 = getServiceProperties(null);
+        ServiceRegistration reg1 = this.bundleContext.registerService(clazz1, service1, properties1);
+
+        String[] clazzes2 = new String[] { String.class.getName(), Integer.class.getName() };
+        Object service2 = new Object();
+        Dictionary properties2 = getServiceProperties(null);
+        ServiceRegistration reg2 = this.bundleContext.registerService(clazzes2, service2, properties2);
+
+        String clazz3 = Integer.class.getName();
+        Object service3 = new Object();
+        Dictionary properties3 = getServiceProperties(100L);
+        ServiceRegistration reg3 = this.bundleContext.registerService(clazz3, service3, properties3);
+
+        // test get service references
+        ServiceReference refString = this.bundleContext.getServiceReference(String.class.getName());
+        assertSame(reg1.getReference(), refString);
+
+        ServiceReference refInteger = this.bundleContext.getServiceReference(Integer.class.getName());
+        assertSame(reg3.getReference(), refInteger);
+
+        ServiceReference[] refsString = this.bundleContext.getServiceReferences(String.class.getName(), null);
+        assertEquals(2, refsString.length);
+        assertSame(reg1.getReference(), refsString[0]);
+        assertSame(reg2.getReference(), refsString[1]);
+
+        ServiceReference[] refsInteger = this.bundleContext.getServiceReferences(Integer.class.getName(), null);
+        assertEquals(2, refsInteger.length);
+        assertSame(reg3.getReference(), refsInteger[0]);
+        assertSame(reg2.getReference(), refsInteger[1]);
+
+        ServiceReference[] allRefsString = this.bundleContext.getAllServiceReferences(String.class.getName(), null);
+        assertArrayEquals(refsString, allRefsString);
+
+        // test get services
+        assertSame(service1, this.bundleContext.getService(refsString[0]));
+        assertSame(service2, this.bundleContext.getService(refsString[1]));
+        assertSame(service3, this.bundleContext.getService(refInteger));
+
+        // unget does nothing
+        this.bundleContext.ungetService(refsString[0]);
+        this.bundleContext.ungetService(refsString[1]);
+        this.bundleContext.ungetService(refInteger);
+    }
+
+    private Dictionary getServiceProperties(final Long serviceRanking) {
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
+        if (serviceRanking != null) {
+            props.put(Constants.SERVICE_RANKING, serviceRanking);
+        }
+        return props;
+    }
+
+    @Test
+    public void testGetBundles() throws Exception {
+        assertEquals(0, this.bundleContext.getBundles().length);
+    }
+
+    @Test
+    public void testServiceListener() throws Exception {
+        ServiceListener serviceListener = mock(ServiceListener.class);
+        bundleContext.addServiceListener(serviceListener);
+
+        // prepare test services
+        String clazz1 = String.class.getName();
+        Object service1 = new Object();
+        this.bundleContext.registerService(clazz1, service1, null);
+
+        verify(serviceListener).serviceChanged(any(ServiceEvent.class));
+
+        bundleContext.removeServiceListener(serviceListener);
+    }
+
+    @Test
+    public void testBundleListener() throws Exception {
+        BundleListener bundleListener = mock(BundleListener.class);
+        BundleEvent bundleEvent = mock(BundleEvent.class);
+
+        bundleContext.addBundleListener(bundleListener);
+
+        MockOsgi.sendBundleEvent(bundleContext, bundleEvent);
+        verify(bundleListener).bundleChanged(bundleEvent);
+
+        bundleContext.removeBundleListener(bundleListener);
+    }
+
+    @Test
+    public void testFrameworkListener() throws Exception {
+        // ensure that listeners can be called (although they are not expected
+        // to to anything)
+        this.bundleContext.addFrameworkListener(null);
+        this.bundleContext.removeFrameworkListener(null);
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleTest.java
new file mode 100644
index 0000000..7402241
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.sling.testing.mock.osgi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+
+public class MockBundleTest {
+
+    private Bundle bundle;
+
+    @Before
+    public void setUp() {
+        this.bundle = MockOsgi.newBundleContext().getBundle();
+    }
+
+    @Test
+    public void testBundleId() {
+        assertTrue(this.bundle.getBundleId() > 0);
+    }
+
+    @Test
+    public void testBundleContxt() {
+        assertNotNull(this.bundle.getBundleContext());
+    }
+
+    @Test
+    public void testGetEntry() {
+        assertNotNull(this.bundle.getEntry("/META-INF/test.txt"));
+        assertNull(this.bundle.getEntry("/invalid"));
+    }
+
+    @Test
+    public void testGetStatie() {
+        assertEquals(Bundle.ACTIVE, bundle.getState());
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/MockComponentContextTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/MockComponentContextTest.java
new file mode 100644
index 0000000..18f7ba4
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/MockComponentContextTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.sling.testing.mock.osgi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
+
+public class MockComponentContextTest {
+
+    private ComponentContext underTest;
+
+    @Before
+    public void setUp() {
+        underTest = MockOsgi.newComponentContext();
+    }
+
+    @Test
+    public void testBundleContext() {
+        assertNotNull(underTest.getBundleContext());
+    }
+
+    @Test
+    public void testInitialProperties() {
+        assertEquals(0, underTest.getProperties().size());
+    }
+
+    @Test
+    public void testProvidedProperties() {
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
+        props.put("prop1", "value1");
+        props.put("prop2", 25);
+        ComponentContext componentContextWithProperties = MockOsgi.newComponentContext(props);
+
+        Dictionary contextProps = componentContextWithProperties.getProperties();
+        assertEquals(2, contextProps.size());
+        assertEquals("value1", contextProps.get("prop1"));
+        assertEquals(25, contextProps.get("prop2"));
+    }
+
+    @Test
+    public void testLocateService() {
+        // prepare test service
+        String clazz = String.class.getName();
+        Object service = new Object();
+        underTest.getBundleContext().registerService(clazz, service, null);
+        ServiceReference ref = underTest.getBundleContext().getServiceReference(clazz);
+
+        // test locate service
+        Object locatedService = underTest.locateService(null, ref);
+        assertSame(service, locatedService);
+    }
+
+    @Test
+    public void testIgnoredMethods() {
+        underTest.enableComponent("myComponent");
+        underTest.disableComponent("myComponent");
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/MockFilterTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/MockFilterTest.java
new file mode 100644
index 0000000..9c4a955
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/MockFilterTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.sling.testing.mock.osgi;
+
+import static org.junit.Assert.assertFalse;
+
+import java.util.Hashtable;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+
+public class MockFilterTest {
+
+    private Filter filter;
+
+    @Before
+    public void setUp() {
+        this.filter = new MockFilter();
+    }
+
+    @Test
+    public void testDenyAll() {
+        assertFalse(this.filter.match((ServiceReference) null));
+        assertFalse(this.filter.match((Hashtable) null));
+        assertFalse(this.filter.matchCase(null));
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/MockLogServiceTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/MockLogServiceTest.java
new file mode 100644
index 0000000..7fbd7ab
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/MockLogServiceTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.sling.testing.mock.osgi;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.service.log.LogService;
+
+public class MockLogServiceTest {
+
+    private LogService logService;
+
+    @Before
+    public void setUp() throws Exception {
+        this.logService = new MockLogService(getClass());
+    }
+
+    @Test
+    public void testLog() {
+        this.logService.log(LogService.LOG_ERROR, "message 1");
+        this.logService.log(LogService.LOG_WARNING, "message 1");
+        this.logService.log(LogService.LOG_INFO, "message 1");
+        this.logService.log(LogService.LOG_DEBUG, "message 1");
+
+        this.logService.log(null, LogService.LOG_ERROR, "message 1");
+        this.logService.log(null, LogService.LOG_WARNING, "message 1");
+        this.logService.log(null, LogService.LOG_INFO, "message 1");
+        this.logService.log(null, LogService.LOG_DEBUG, "message 1");
+    }
+
+    @Test
+    public void testLogException() {
+        this.logService.log(LogService.LOG_ERROR, "message 2", new Exception());
+        this.logService.log(LogService.LOG_WARNING, "message 2", new Exception());
+        this.logService.log(LogService.LOG_INFO, "message 2", new Exception());
+        this.logService.log(LogService.LOG_DEBUG, "message 2", new Exception());
+
+        this.logService.log(null, LogService.LOG_ERROR, "message 2", new Exception());
+        this.logService.log(null, LogService.LOG_WARNING, "message 2", new Exception());
+        this.logService.log(null, LogService.LOG_INFO, "message 2", new Exception());
+        this.logService.log(null, LogService.LOG_DEBUG, "message 2", new Exception());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testLogInvalidLevel() {
+        this.logService.log(0, "message 1");
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testLogExceptionInvalidLevel() {
+        this.logService.log(0, "message 2", new Exception());
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/MockServiceReferenceTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/MockServiceReferenceTest.java
new file mode 100644
index 0000000..c525575
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/MockServiceReferenceTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.sling.testing.mock.osgi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.sling.testing.mock.osgi.OsgiMetadataUtilTest.ServiceWithMetadata;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+public class MockServiceReferenceTest {
+
+    private BundleContext bundleContext;
+    private ServiceReference serviceReference;
+    private Object service;
+
+    @Before
+    public void setUp() {
+        this.bundleContext = MockOsgi.newBundleContext();
+
+        this.service = new Object();
+        String clazz = String.class.getName();
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
+        props.put("customProp1", "value1");
+
+        this.bundleContext.registerService(clazz, this.service, props);
+        this.serviceReference = this.bundleContext.getServiceReference(clazz);
+    }
+
+    @Test
+    public void testBundle() {
+        assertSame(this.bundleContext.getBundle(), this.serviceReference.getBundle());
+    }
+
+    @Test
+    public void testServiceId() {
+        assertNotNull(this.serviceReference.getProperty(Constants.SERVICE_ID));
+    }
+
+    @Test
+    public void testProperties() {
+        assertEquals(2, this.serviceReference.getPropertyKeys().length);
+        assertEquals("value1", this.serviceReference.getProperty("customProp1"));
+    }
+
+    @Test
+    public void testWithOsgiMetadata() {
+        ServiceWithMetadata serviceWithMetadata = new OsgiMetadataUtilTest.ServiceWithMetadata();
+        bundleContext.registerService((String) null, serviceWithMetadata, null);
+        ServiceReference reference = this.bundleContext.getServiceReference(Comparable.class.getName());
+
+        assertEquals(5000, reference.getProperty("service.ranking"));
+        assertEquals("The Apache Software Foundation", reference.getProperty("service.vendor"));
+        assertEquals("org.apache.sling.models.impl.injectors.OSGiServiceInjector", reference.getProperty("service.pid"));
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtilTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtilTest.java
new file mode 100644
index 0000000..52f9011
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtilTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.sling.testing.mock.osgi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.Reference;
+import org.junit.Test;
+import org.w3c.dom.Document;
+
+public class OsgiMetadataUtilTest {
+
+    @Test
+    public void testMetadata() {
+        Document doc = OsgiMetadataUtil.getMetadata(ServiceWithMetadata.class);
+
+        Set<String> serviceInterfaces = OsgiMetadataUtil.getServiceInterfaces(ServiceWithMetadata.class, doc);
+        assertEquals(3, serviceInterfaces.size());
+        assertTrue(serviceInterfaces.contains("org.apache.sling.models.spi.Injector"));
+        assertTrue(serviceInterfaces
+                .contains("org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessorFactory"));
+        assertTrue(serviceInterfaces.contains("java.lang.Comparable"));
+
+        Map<String, Object> props = OsgiMetadataUtil.getProperties(ServiceWithMetadata.class, doc);
+        assertEquals(3, props.size());
+        assertEquals(5000, props.get("service.ranking"));
+        assertEquals("The Apache Software Foundation", props.get("service.vendor"));
+        assertEquals("org.apache.sling.models.impl.injectors.OSGiServiceInjector", props.get("service.pid"));
+    }
+
+    @Test
+    public void testNoMetadata() {
+        Document doc = OsgiMetadataUtil.getMetadata(ServiceWithoutMetadata.class);
+
+        Set<String> serviceInterfaces = OsgiMetadataUtil.getServiceInterfaces(ServiceWithoutMetadata.class, doc);
+        assertEquals(0, serviceInterfaces.size());
+
+        Map<String, Object> props = OsgiMetadataUtil.getProperties(ServiceWithoutMetadata.class, doc);
+        assertEquals(0, props.size());
+    }
+
+    @Test
+    public void testReferences() {
+        Document doc = OsgiMetadataUtil.getMetadata(ReflectionServiceUtilTest.Service3.class);
+        List<Reference> references = OsgiMetadataUtil.getReferences(ReflectionServiceUtilTest.Service3.class, doc);
+        assertEquals(3, references.size());
+
+        Reference ref1 = references.get(0);
+        assertEquals("reference2", ref1.getName());
+        assertEquals("org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$ServiceInterface2", ref1.getInterfaceType());
+        assertEquals(ReferenceCardinality.MANDATORY_MULTIPLE, ref1.getCardinality());
+        assertEquals("bindReference2", ref1.getBind());
+        assertEquals("unbindReference2", ref1.getUnbind());
+    }
+
+    @Test
+    public void testActivateMethodName() {
+        Document doc = OsgiMetadataUtil.getMetadata(ReflectionServiceUtilTest.Service3.class);
+        String methodName = OsgiMetadataUtil.getActivateMethodName(ReflectionServiceUtilTest.Service3.class, doc);
+        assertEquals("activate", methodName);
+    }
+
+    static class ServiceWithMetadata {
+        // empty class
+    }
+
+    static class ServiceWithoutMetadata {
+        // empty class
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtilTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtilTest.java
new file mode 100644
index 0000000..ff29037
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtilTest.java
@@ -0,0 +1,226 @@
+/*
+ * 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.sling.testing.mock.osgi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.References;
+import org.apache.felix.scr.annotations.Service;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
+
+public class ReflectionServiceUtilTest {
+
+    private BundleContext bundleContext = MockOsgi.newBundleContext();
+    private Service1 service1;
+    private Service2 service2;
+
+    @Before
+    public void setUp() {
+        service1 = new Service1();
+        service2 = new Service2();
+        bundleContext.registerService(ServiceInterface1.class.getName(), service1, null);
+        bundleContext.registerService(ServiceInterface2.class.getName(), service2, null);
+    }
+
+    @Test
+    public void testService3() {
+        Service3 service3 = new Service3();
+        assertTrue(MockOsgi.injectServices(service3, bundleContext));
+
+        Dictionary<String, Object> service3Config = new Hashtable<String, Object>();
+        service3Config.put("prop1", "value1");
+        assertTrue(MockOsgi.activate(service3, bundleContext, service3Config));
+
+        assertNotNull(service3.getComponentContext());
+        assertEquals(service3Config, service3.getComponentContext().getProperties());
+
+        assertSame(service1, service3.getReference1());
+
+        List<ServiceInterface2> references2 = service3.getReferences2();
+        assertEquals(1, references2.size());
+        assertSame(service2, references2.get(0));
+
+        List<ServiceInterface3> references3 = service3.getReferences3();
+        assertEquals(1, references3.size());
+        assertSame(service2, references3.get(0));
+
+        List<Map<String, Object>> reference3Configs = service3.getReference3Configs();
+        assertEquals(1, reference3Configs.size());
+        assertEquals(200, reference3Configs.get(0).get(Constants.SERVICE_RANKING));
+
+        assertTrue(MockOsgi.deactivate(service3));
+        assertNull(service3.getComponentContext());
+    }
+
+    @Test
+    public void testService4() {
+        Service4 service4 = new Service4();
+
+        assertTrue(MockOsgi.injectServices(service4, bundleContext));
+        assertFalse(MockOsgi.activate(service4));
+
+        assertSame(service1, service4.getReference1());
+    }
+
+    public interface ServiceInterface1 {
+        // no methods
+    }
+
+    public interface ServiceInterface2 {
+        // no methods
+    }
+
+    public interface ServiceInterface3 {
+        // no methods
+    }
+
+    @Component
+    @Service(ServiceInterface1.class)
+    @Property(name = Constants.SERVICE_RANKING, intValue = 100)
+    public static class Service1 implements ServiceInterface1 {
+        // dummy interface
+    }
+
+    @Component
+    @Service({ ServiceInterface2.class, ServiceInterface3.class })
+    @Property(name = Constants.SERVICE_RANKING, intValue = 200)
+    public static class Service2 implements ServiceInterface2, ServiceInterface3 {
+        // dummy interface
+    }
+
+    @Component
+    @References({ @Reference(name = "reference2", referenceInterface = ServiceInterface2.class, cardinality = ReferenceCardinality.MANDATORY_MULTIPLE) })
+    public static class Service3 {
+
+        @Reference
+        private ServiceInterface1 reference1;
+
+        private List<ServiceReference> references2 = new ArrayList<ServiceReference>();
+
+        @Reference(name = "reference3", referenceInterface = ServiceInterface3.class, cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE)
+        private List<ServiceInterface3> references3 = new ArrayList<ServiceInterface3>();
+        private List<Map<String, Object>> reference3Configs = new ArrayList<Map<String, Object>>();
+
+        private ComponentContext componentContext;
+
+        @Activate
+        private void activate(ComponentContext ctx) {
+            this.componentContext = ctx;
+        }
+
+        @Deactivate
+        private void deactivate(ComponentContext ctx) {
+            this.componentContext = null;
+        }
+
+        public ServiceInterface1 getReference1() {
+            return this.reference1;
+        }
+
+        public List<ServiceInterface2> getReferences2() {
+            List<ServiceInterface2> services = new ArrayList<ServiceInterface2>();
+            for (ServiceReference serviceReference : references2) {
+                services.add((ServiceInterface2)componentContext.getBundleContext().getService(serviceReference));
+            }
+            return services;
+        }
+
+        public List<ServiceInterface3> getReferences3() {
+            return this.references3;
+        }
+
+        public List<Map<String, Object>> getReference3Configs() {
+            return this.reference3Configs;
+        }
+
+        public ComponentContext getComponentContext() {
+            return this.componentContext;
+        }
+
+        protected void bindReference1(ServiceInterface1 service) {
+            reference1 = service;
+        }
+
+        protected void unbindReference1(ServiceInterface1 service) {
+            reference1 = null;
+        }
+
+        protected void bindReference2(ServiceReference serviceReference) {
+            references2.add(serviceReference);
+        }
+
+        protected void unbindReference2(ServiceReference serviceReference) {
+            references2.remove(serviceReference);
+        }
+
+        protected void bindReference3(ServiceInterface3 service, Map<String, Object> serviceConfig) {
+            references3.add(service);
+            reference3Configs.add(serviceConfig);
+        }
+
+        protected void unbindReference3(ServiceInterface3 service, Map<String, Object> serviceConfig) {
+            references3.remove(service);
+            reference3Configs.remove(serviceConfig);
+        }
+
+    }
+
+    @Component
+    @Reference(referenceInterface = ServiceInterface1.class, name = "customName", bind = "customBind", unbind = "customUnbind")
+    public static class Service4 {
+
+        private ServiceInterface1 reference1;
+
+        public ServiceInterface1 getReference1() {
+            return this.reference1;
+        }
+
+        protected void customBind(ServiceInterface1 service) {
+            reference1 = service;
+        }
+
+        protected void customUnbind(ServiceInterface1 service) {
+            reference1 = null;
+        }
+
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/package-info.java b/src/test/java/org/apache/sling/testing/mock/osgi/package-info.java
new file mode 100644
index 0000000..9c9ff28
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+/**
+ * Mock implementation of selected OSGi APIs.
+ */
+package org.apache.sling.testing.mock.osgi;
+
diff --git a/src/test/resources/META-INF/test.txt b/src/test/resources/META-INF/test.txt
new file mode 100644
index 0000000..af27ff4
--- /dev/null
+++ b/src/test/resources/META-INF/test.txt
@@ -0,0 +1 @@
+This is a test file.
\ No newline at end of file
diff --git a/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.OsgiMetadataUtilTest.xml b/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.OsgiMetadataUtilTest.xml
new file mode 100644
index 0000000..95ac503
--- /dev/null
+++ b/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.OsgiMetadataUtilTest.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<components xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0">
+  <scr:component name="org.apache.sling.testing.mock.osgi.OsgiMetadataUtilTest$ServiceWithMetadata" activate="activate">
+    <implementation class="org.apache.sling.testing.mock.osgi.OsgiMetadataUtilTest$ServiceWithMetadata"/>
+    <service servicefactory="false">
+      <provide interface="org.apache.sling.models.spi.Injector"/>
+      <provide interface="org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessorFactory"/>
+      <provide interface="java.lang.Comparable"/>
+    </service>
+    <property name="service.ranking" type="Integer" value="5000"/>
+    <property name="service.vendor" value="The Apache Software Foundation"/>
+    <property name="service.pid" value="org.apache.sling.models.impl.injectors.OSGiServiceInjector"/>
+  </scr:component>
+</components>
diff --git a/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest.xml b/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest.xml
new file mode 100644
index 0000000..923b90f
--- /dev/null
+++ b/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<components xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0">
+  <scr:component name="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service1">
+    <implementation class="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service1"/>
+    <service servicefactory="false">
+      <provide interface="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$ServiceInterface1"/>
+    </service>
+    <property name="service.ranking" type="Integer" value="100"/>
+    <property name="service.pid" value="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service1"/>
+  </scr:component>
+  <scr:component name="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service2">
+    <implementation class="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service2"/>
+    <service servicefactory="false">
+      <provide interface="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$ServiceInterface2"/>
+      <provide interface="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$ServiceInterface3"/>
+    </service>
+    <property name="service.ranking" type="Integer" value="200"/>
+    <property name="service.pid" value="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service2"/>
+  </scr:component>
+  <scr:component name="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service3" activate="activate" deactivate="deactivate">
+    <implementation class="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service3"/>
+    <property name="service.pid" value="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service3"/>
+    <reference name="reference2" interface="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$ServiceInterface2" cardinality="1..n" policy="static" bind="bindReference2" unbind="unbindReference2"/>
+    <reference name="reference1" interface="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$ServiceInterface1" cardinality="1..1" policy="static" bind="bindReference1" unbind="unbindReference1"/>
+    <reference name="reference3" interface="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$ServiceInterface3" cardinality="0..n" policy="static" bind="bindReference3" unbind="unbindReference3"/>
+  </scr:component>
+  <scr:component name="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service4">
+    <implementation class="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service4"/>
+    <property name="service.pid" value="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service4"/>
+    <reference name="customName" interface="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$ServiceInterface1" cardinality="1..1" policy="static" bind="customBind" unbind="customUnbind"/>
+  </scr:component>
+</components>
diff --git a/src/test/resources/simplelogger.properties b/src/test/resources/simplelogger.properties
new file mode 100644
index 0000000..1299698
--- /dev/null
+++ b/src/test/resources/simplelogger.properties
@@ -0,0 +1,18 @@
+# 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.
+
+org.slf4j.simpleLogger.defaultLogLevel=error

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 12/23: SLING-4162 Introduce "OsgiContext" junit rule for OSGi and OsgiContextImpl

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit a822c765b58d380fe9fc07a62ae574cc4c0a4ff1
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Fri Nov 14 09:55:05 2014 +0000

    SLING-4162 Introduce "OsgiContext" junit rule for OSGi and OsgiContextImpl
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1639589 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                                            |   2 +-
 .../testing/mock/osgi/context/OsgiContextImpl.java | 185 +++++++++++++++++++++
 .../testing/mock/osgi/context/package-info.java    |  23 +++
 .../sling/testing/mock/osgi/junit/OsgiContext.java | 111 +++++++++++++
 .../mock/osgi/junit/OsgiContextCallback.java       |  37 +++++
 .../testing/mock/osgi/junit/package-info.java      |  23 +++
 .../mock/osgi/context/OsgiContextImplTest.java     |  96 +++++++++++
 .../testing/mock/osgi/junit/OsgiContextTest.java   |  53 ++++++
 8 files changed, 529 insertions(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 83f3930..97b4b77 100644
--- a/pom.xml
+++ b/pom.xml
@@ -92,7 +92,7 @@
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
-            <scope>test</scope>
+            <scope>compile</scope>
         </dependency>
 
     </dependencies>
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImpl.java b/src/main/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImpl.java
new file mode 100644
index 0000000..d4cb74b
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImpl.java
@@ -0,0 +1,185 @@
+/*
+ * 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.sling.testing.mock.osgi.context;
+
+import java.lang.reflect.Array;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.sling.testing.mock.osgi.MockOsgi;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
+
+import aQute.bnd.annotation.ConsumerType;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Defines OSGi context objects and helper methods. Should not be used directly
+ * but via the {@link org.apache.sling.testing.mock.osgi.junit.OsgiContext} JUnit rule.
+ */
+@ConsumerType
+public class OsgiContextImpl {
+
+    protected ComponentContext componentContext;
+
+    /**
+     * Setup actions before test method execution
+     */
+    protected void setUp() {
+        // can be overridden by subclasses
+    }
+    
+    /**
+     * Teardown actions after test method execution
+     */
+    protected void tearDown() {
+        // can be overridden by subclasses
+    }
+
+    /**
+     * @return OSGi component context
+     */
+    public final ComponentContext componentContext() {
+        if (this.componentContext == null) {
+            this.componentContext = MockOsgi.newComponentContext();
+        }
+        return this.componentContext;
+    }
+
+    /**
+     * @return OSGi Bundle context
+     */
+    public final BundleContext bundleContext() {
+        return componentContext().getBundleContext();
+    }
+
+    /**
+     * Registers a service in the mocked OSGi environment.
+     * @param <T> Service type
+     * @param service Service instance
+     * @return Registered service instance
+     */
+    public final <T> T registerService(final T service) {
+        return registerService(null, service, null);
+    }
+
+    /**
+     * Registers a service in the mocked OSGi environment.
+     * @param <T> Service type
+     * @param serviceClass Service class
+     * @param service Service instance
+     * @return Registered service instance
+     */
+    public final <T> T registerService(final Class<T> serviceClass, final T service) {
+        return registerService(serviceClass, service, null);
+    }
+
+    /**
+     * Registers a service in the mocked OSGi environment.
+     * @param <T> Service type
+     * @param serviceClass Service class
+     * @param service Service instance
+     * @param properties Service properties (optional)
+     * @return Registered service instance
+     */
+    public final <T> T registerService(final Class<T> serviceClass, final T service, final Map<String, Object> properties) {
+        Dictionary<String, Object> serviceProperties = null;
+        if (properties != null) {
+            serviceProperties = new Hashtable<String, Object>(properties);
+        }
+        bundleContext().registerService(serviceClass != null ? serviceClass.getName() : null, service,
+                serviceProperties);
+        return service;
+    }
+
+    /**
+     * Injects dependencies, activates and registers a service in the mocked
+     * OSGi environment.
+     * @param <T> Service type
+     * @param service Service instance
+     * @return Registered service instance
+     */
+    public final <T> T registerInjectActivateService(final T service) {
+        return registerInjectActivateService(service, ImmutableMap.<String, Object> of());
+    }
+
+    /**
+     * Injects dependencies, activates and registers a service in the mocked
+     * OSGi environment.
+     * @param <T> Service type
+     * @param service Service instance
+     * @param properties Service properties (optional)
+     * @return Registered service instance
+     */
+    public final <T> T registerInjectActivateService(final T service, final Map<String, Object> properties) {
+        MockOsgi.injectServices(service, bundleContext());
+        MockOsgi.activate(service, bundleContext(), properties);
+        registerService(null, service, null);
+        return service;
+    }
+
+    /**
+     * Lookup a single service
+     * @param <ServiceType> Service type
+     * @param serviceType The type (interface) of the service.
+     * @return The service instance, or null if the service is not available.
+     */
+    @SuppressWarnings("unchecked")
+    public final <ServiceType> ServiceType getService(final Class<ServiceType> serviceType) {
+        ServiceReference serviceReference = bundleContext().getServiceReference(serviceType.getName());
+        if (serviceReference != null) {
+            return (ServiceType)bundleContext().getService(serviceReference);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Lookup one or several services
+     * @param <ServiceType> Service type
+     * @param serviceType The type (interface) of the service.
+     * @param filter An optional filter (LDAP-like, see OSGi spec)
+     * @return The services instances or an empty array.
+     * @throws RuntimeException If the <code>filter</code> string is not a valid OSGi service filter string.
+     */
+    @SuppressWarnings("unchecked")
+    public final <ServiceType> ServiceType[] getServices(final Class<ServiceType> serviceType, final String filter) {
+        try {
+            ServiceReference[] serviceReferences = bundleContext().getServiceReferences(serviceType.getName(),
+                    filter);
+            if (serviceReferences != null) {
+                ServiceType[] services = (ServiceType[])Array.newInstance(serviceType, serviceReferences.length);
+                for (int i = 0; i < serviceReferences.length; i++) {
+                    services[i] = (ServiceType)bundleContext().getService(serviceReferences[i]);
+                }
+                return services;
+            } else {
+                return (ServiceType[])ArrayUtils.EMPTY_OBJECT_ARRAY;
+            }
+        } catch (InvalidSyntaxException ex) {
+            throw new RuntimeException("Invalid filter syntax: " + filter, ex);
+        }
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/context/package-info.java b/src/main/java/org/apache/sling/testing/mock/osgi/context/package-info.java
new file mode 100644
index 0000000..1ac49a4
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/context/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+/**
+ * OSGi context implementation for unit tests.
+ */
+@aQute.bnd.annotation.Version("1.0")
+package org.apache.sling.testing.mock.osgi.context;
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContext.java b/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContext.java
new file mode 100644
index 0000000..1704b72
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContext.java
@@ -0,0 +1,111 @@
+/*
+ * 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.sling.testing.mock.osgi.junit;
+
+import org.apache.sling.testing.mock.osgi.context.OsgiContextImpl;
+import org.junit.rules.ExternalResource;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * JUnit rule for setting up and tearing down OSGi context for unit tests.
+ */
+public final class OsgiContext extends OsgiContextImpl implements TestRule {
+
+    private final OsgiContextCallback setUpCallback;
+    private final OsgiContextCallback tearDownCallback;
+    private final TestRule delegate;
+
+    /**
+     * Initialize Sling context with default resource resolver type:
+     * {@link org.apache.sling.testing.mock.sling.MockSling#DEFAULT_RESOURCERESOLVER_TYPE}.
+     */
+    public OsgiContext() {
+        this(null, null);
+    }
+
+    /**
+     * Initialize Sling context with default resource resolver type:
+     * {@link org.apache.sling.testing.mock.sling.MockSling#DEFAULT_RESOURCERESOLVER_TYPE}.
+     * @param setUpCallback Allows the application to register an own callback
+     *            function that is called after the built-in setup rules are
+     *            executed.
+     */
+    public OsgiContext(final OsgiContextCallback setUpCallback) {
+        this(setUpCallback, null);
+    }
+
+    /**
+     * Initialize Sling context with resource resolver type.
+     * @param setUpCallback Allows the application to register an own callback
+     *            function that is called after the built-in setup rules are
+     *            executed.
+     * @param tearDownCallback Allows the application to register an own
+     *            callback function that is called before the built-in teardown
+     *            rules are executed.
+     * @param resourceResolverType Resource resolver type.
+     */
+    public OsgiContext(final OsgiContextCallback setUpCallback, final OsgiContextCallback tearDownCallback) {
+
+        this.setUpCallback = setUpCallback;
+        this.tearDownCallback = tearDownCallback;
+
+        // wrap {@link ExternalResource} rule executes each test method once
+        this.delegate = new ExternalResource() {
+            @Override
+            protected void before() {
+                OsgiContext.this.setUp();
+                OsgiContext.this.executeSetUpCallback();
+            }
+
+            @Override
+            protected void after() {
+                OsgiContext.this.executeTearDownCallback();
+                OsgiContext.this.tearDown();
+            }
+        };
+    }
+
+    @Override
+    public Statement apply(final Statement base, final Description description) {
+        return this.delegate.apply(base, description);
+    }
+
+    private void executeSetUpCallback() {
+        if (this.setUpCallback != null) {
+            try {
+                this.setUpCallback.execute(this);
+            } catch (Throwable ex) {
+                throw new RuntimeException("Executing setup callback failed.", ex);
+            }
+        }
+    }
+
+    private void executeTearDownCallback() {
+        if (this.tearDownCallback != null) {
+            try {
+                this.tearDownCallback.execute(this);
+            } catch (Throwable ex) {
+                throw new RuntimeException("Executing setup callback failed.", ex);
+            }
+        }
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextCallback.java b/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextCallback.java
new file mode 100644
index 0000000..751ce7e
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextCallback.java
@@ -0,0 +1,37 @@
+/*
+ * 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.sling.testing.mock.osgi.junit;
+
+import java.io.IOException;
+
+/**
+ * Callback-interface for application-specific setup and teardown operations to
+ * customize the {@link OsgiContext} JUnit rule.
+ */
+public interface OsgiContextCallback {
+
+    /**
+     * Execute callback action
+     * @param context Sling context
+     * @throws IOException
+     * @throws PersistenceException
+     */
+    void execute(OsgiContext context) throws IOException;
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/junit/package-info.java b/src/main/java/org/apache/sling/testing/mock/osgi/junit/package-info.java
new file mode 100644
index 0000000..dd18eb6
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/junit/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+/**
+ * Rule for providing easy access to OSGi context in JUnit tests.
+ */
+@aQute.bnd.annotation.Version("1.0")
+package org.apache.sling.testing.mock.osgi.junit;
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImplTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImplTest.java
new file mode 100644
index 0000000..902624e
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImplTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.sling.testing.mock.osgi.context;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+public class OsgiContextImplTest {
+
+    private OsgiContextImpl context;
+
+    @Before
+    public void setUp() throws Exception {
+        this.context = new OsgiContextImpl();
+        this.context.setUp();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        this.context.tearDown();
+    }
+    
+    @Test
+    public void testContextObjects() {
+        assertNotNull(context.componentContext());
+        assertNotNull(context.bundleContext());
+    }
+
+    @Test
+    public void testRegisterService() {
+        Set<String> myService = new HashSet<String>();
+        context.registerService(Set.class, myService);
+
+        Set<?> serviceResult = context.getService(Set.class);
+        assertSame(myService, serviceResult);
+    }
+
+    @Test
+    public void testRegisterServiceWithProperties() {
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put("prop1", "value1");
+
+        Set<String> myService = new HashSet<String>();
+        context.registerService(Set.class, myService, props);
+
+        ServiceReference serviceReference = context.bundleContext().getServiceReference(Set.class.getName());
+        Object serviceResult = context.bundleContext().getService(serviceReference);
+        assertSame(myService, serviceResult);
+        assertEquals("value1", serviceReference.getProperty("prop1"));
+    }
+
+    @Test
+    public void testRegisterMultipleServices() {
+        Set<String> myService1 = new HashSet<String>();
+        context.registerService(Set.class, myService1);
+        Set<String> myService2 = new HashSet<String>();
+        context.registerService(Set.class, myService2);
+
+        Set[] serviceResults = context.getServices(Set.class, null);
+        assertSame(myService1, serviceResults[0]);
+        assertSame(myService2, serviceResults[1]);
+    }
+
+    @Test
+    public void testRegisterInjectActivate() {
+        context.registerInjectActivateService(new Object());
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextTest.java
new file mode 100644
index 0000000..0de149b
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.sling.testing.mock.osgi.junit;
+
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import java.io.IOException;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class OsgiContextTest {
+
+    private final OsgiContextCallback contextSetup = mock(OsgiContextCallback.class);
+    private final OsgiContextCallback contextTeardown = mock(OsgiContextCallback.class);
+
+    // Run all unit tests for each resource resolver types listed here
+    @Rule
+    public OsgiContext context = new OsgiContext(contextSetup, contextTeardown);
+
+    @Before
+    public void setUp() throws IOException {
+        verify(contextSetup).execute(context);
+    }
+
+    @Test
+    public void testBundleContext() {
+        assertNotNull(context.bundleContext());
+    }
+
+}

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 13/23: SLING-4162 fix javadoc

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit b30dd561dcceaad8271b06d5ee82c7df29c71b61
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Fri Nov 14 09:57:23 2014 +0000

    SLING-4162 fix javadoc
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1639590 13f79535-47bb-0310-9956-ffa450edef68
---
 .../org/apache/sling/testing/mock/osgi/junit/OsgiContext.java     | 8 +++-----
 .../apache/sling/testing/mock/osgi/junit/OsgiContextCallback.java | 2 +-
 2 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContext.java b/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContext.java
index 1704b72..652298b 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContext.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContext.java
@@ -34,16 +34,14 @@ public final class OsgiContext extends OsgiContextImpl implements TestRule {
     private final TestRule delegate;
 
     /**
-     * Initialize Sling context with default resource resolver type:
-     * {@link org.apache.sling.testing.mock.sling.MockSling#DEFAULT_RESOURCERESOLVER_TYPE}.
+     * Initialize OSGi context.
      */
     public OsgiContext() {
         this(null, null);
     }
 
     /**
-     * Initialize Sling context with default resource resolver type:
-     * {@link org.apache.sling.testing.mock.sling.MockSling#DEFAULT_RESOURCERESOLVER_TYPE}.
+     * Initialize OSGi context.
      * @param setUpCallback Allows the application to register an own callback
      *            function that is called after the built-in setup rules are
      *            executed.
@@ -53,7 +51,7 @@ public final class OsgiContext extends OsgiContextImpl implements TestRule {
     }
 
     /**
-     * Initialize Sling context with resource resolver type.
+     * Initialize OSGi context.
      * @param setUpCallback Allows the application to register an own callback
      *            function that is called after the built-in setup rules are
      *            executed.
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextCallback.java b/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextCallback.java
index 751ce7e..c6a77ff 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextCallback.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextCallback.java
@@ -28,7 +28,7 @@ public interface OsgiContextCallback {
 
     /**
      * Execute callback action
-     * @param context Sling context
+     * @param context OSGi context
      * @throws IOException
      * @throws PersistenceException
      */

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 19/23: SLING-4201 MockOsgi.activate()/deactivate()/modified() should fail fast if method is declared but can't be found

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 5538cda9ee2f83dcf2bc3536c6b44471765882db
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Wed Nov 26 21:56:24 2014 +0000

    SLING-4201 MockOsgi.activate()/deactivate()/modified() should fail fast if method is declared but can't be found
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1641947 13f79535-47bb-0310-9956-ffa450edef68
---
 .../apache/sling/testing/mock/osgi/MockOsgi.java   | 31 ++++++++++------------
 .../testing/mock/osgi/ReflectionServiceUtil.java   | 11 +++++---
 2 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java
index 7a7474f..d6e1b71 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java
@@ -115,11 +115,9 @@ public final class MockOsgi {
     }
 
     /**
-     * Simulate activation of service instance. Invokes the @Activate annotated
-     * method.
+     * Simulate activation of service instance. Invokes the @Activate annotated method.
      * @param target Service instance.
-     * @return true if activation method was called. False if such a method did
-     *         not exist.
+     * @return true if activation method was called. False if no activate method is defined.
      */
     public static boolean activate(Object target) {
         ComponentContext componentContext = newComponentContext();
@@ -130,7 +128,7 @@ public final class MockOsgi {
      * Simulate activation of service instance. Invokes the @Activate annotated method.
      * @param target Service instance.
      * @param properties Properties
-     * @return true if activation method was called. False if it failed.
+     * @return true if activation method was called. False if no activate method is defined.
      */
     public static boolean activate(Object target, Dictionary<String, Object> properties) {
         ComponentContext componentContext = newComponentContext(properties);
@@ -141,19 +139,18 @@ public final class MockOsgi {
      * Simulate activation of service instance. Invokes the @Activate annotated method.
      * @param target Service instance.
      * @param properties Properties
-     * @return true if activation method was called. False if it failed.
+     * @return true if activation method was called. False if no activate method is defined.
      */
     public static boolean activate(Object target, Map<String, Object> properties) {
         return activate(target, MapUtil.toDictionary(properties));
     }
 
     /**
-     * Simulate activation of service instance. Invokes the @Activate annotated
-     * method.
+     * Simulate activation of service instance. Invokes the @Activate annotated method.
      * @param target Service instance.
      * @param bundleContext Bundle context
      * @param properties Properties
-     * @return true if activation method was called. False if it failed.
+     * @return true if activation method was called. False if no activate method is defined.
      */
     public static boolean activate(Object target, BundleContext bundleContext, Dictionary<String, Object> properties) {
         ComponentContext componentContext = newComponentContext(bundleContext, properties);
@@ -165,7 +162,7 @@ public final class MockOsgi {
      * @param target Service instance.
      * @param bundleContext Bundle context
      * @param properties Properties
-     * @return true if activation method was called. False if it failed.
+     * @return true if activation method was called. False if no activate method is defined.
      */
     public static boolean activate(Object target, BundleContext bundleContext, Map<String, Object> properties) {
         return activate(target, bundleContext, MapUtil.toDictionary(properties));
@@ -174,7 +171,7 @@ public final class MockOsgi {
     /**
      * Simulate deactivation of service instance. Invokes the @Deactivate annotated method.
      * @param target Service instance.
-     * @return true if deactivation method was called. False if it failed.
+     * @return true if deactivation method was called. False if no deactivate method is defined.
      */
     public static boolean deactivate(Object target) {
         ComponentContext componentContext = newComponentContext();
@@ -185,7 +182,7 @@ public final class MockOsgi {
      * Simulate deactivation of service instance. Invokes the @Deactivate annotated method.
      * @param target Service instance.
      * @param properties Properties
-     * @return true if deactivation method was called. False if it failed.
+     * @return true if deactivation method was called. False if no deactivate method is defined.
      */
     public static boolean deactivate(Object target, Dictionary<String, Object> properties) {
         ComponentContext componentContext = newComponentContext(properties);
@@ -196,7 +193,7 @@ public final class MockOsgi {
      * Simulate deactivation of service instance. Invokes the @Deactivate annotated method.
      * @param target Service instance.
      * @param properties Properties
-     * @return true if deactivation method was called. False if it failed.
+     * @return true if deactivation method was called. False if no deactivate method is defined.
      */
     public static boolean deactivate(Object target, Map<String, Object> properties) {
         return deactivate(target, MapUtil.toDictionary(properties));
@@ -207,7 +204,7 @@ public final class MockOsgi {
      * @param target Service instance.
      * @param bundleContext Bundle context
      * @param properties Properties
-     * @return true if deactivation method was called. False if it failed.
+     * @return true if deactivation method was called. False if no deactivate method is defined.
      */
     public static boolean deactivate(Object target, BundleContext bundleContext, Dictionary<String, Object> properties) {
         ComponentContext componentContext = newComponentContext(bundleContext, properties);
@@ -219,7 +216,7 @@ public final class MockOsgi {
      * @param target Service instance.
      * @param bundleContext Bundle context
      * @param properties Properties
-     * @return true if activation method was called. False if it failed.
+     * @return true if deactivation method was called. False if no deactivate method is defined.
      */
     public static boolean deactivate(Object target, BundleContext bundleContext, Map<String, Object> properties) {
         return deactivate(target, bundleContext, MapUtil.toDictionary(properties));
@@ -230,7 +227,7 @@ public final class MockOsgi {
      * @param target Service instance.
      * @param bundleContext Bundle context
      * @param properties Properties
-     * @return true if modified method was called. False if it failed.
+     * @return true if modified method was called. False if no modified method is defined.
      */
     public static boolean modified(Object target, BundleContext bundleContext, Dictionary<String, Object> properties) {
         return modified(target, bundleContext, MapUtil.toMap(properties));
@@ -241,7 +238,7 @@ public final class MockOsgi {
      * @param target Service instance.
      * @param bundleContext Bundle context
      * @param properties Properties
-     * @return true if modified method was called. False if it failed.
+     * @return true if modified method was called. False if no modified method is defined.
      */
     public static boolean modified(Object target, BundleContext bundleContext, Map<String, Object> properties) {
         return ReflectionServiceUtil.modified(target, bundleContext, properties);
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java b/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
index 0ecc24f..4056ce4 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
@@ -146,8 +146,8 @@ final class ReflectionServiceUtil {
             return true;
         }
         
-        log.warn("Method {} not found in class {}", methodName, targetClass.getName());
-        return false;
+        throw new RuntimeException("No matching " + (activate ? "activation" : "deactivation") + " method with name '" + methodName + "' "
+                + " found in class " + targetClass.getName());
     }
 
     /**
@@ -165,6 +165,9 @@ final class ReflectionServiceUtil {
             throw new NoScrMetadataException(targetClass);
         }
         String methodName = OsgiMetadataUtil.getModifiedMethodName(targetClass, metadata);
+        if (StringUtils.isEmpty(methodName)) {
+            return false;
+        }
         
         // try to find matching modified method and execute it
         Method method = getMethod(targetClass, methodName, new Class<?>[] { Map.class });
@@ -173,8 +176,8 @@ final class ReflectionServiceUtil {
             return true;
         }
         
-        log.warn("Method {} not found in class {}", methodName, targetClass.getName());
-        return false;
+        throw new RuntimeException("No matching modified method with name '" + methodName + "' "
+                + " found in class " + targetClass.getName());
     }
 
     private static Method getMethod(Class clazz, String methodName, Class<?>[] types) {

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 18/23: SLING-4165 OSGi Mock: Fail-fast when calling methods requiring SCR metadata and this is not present

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 907c7dfd0c8a814dff013fd16c7fe9b67d46c6bb
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Fri Nov 14 21:32:42 2014 +0000

    SLING-4165 OSGi Mock: Fail-fast when calling methods requiring SCR metadata and this is not present
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1639791 13f79535-47bb-0310-9956-ffa450edef68
---
 .../apache/sling/testing/mock/osgi/MapUtil.java    | 52 +++++++++++++++
 .../testing/mock/osgi/MockComponentContext.java    |  4 +-
 .../apache/sling/testing/mock/osgi/MockOsgi.java   | 31 ++-------
 .../testing/mock/osgi/MockServiceRegistration.java |  6 +-
 .../testing/mock/osgi/NoScrMetadataException.java  | 31 +++++++++
 .../sling/testing/mock/osgi/OsgiMetadataUtil.java  | 74 ++++++++++------------
 .../testing/mock/osgi/ReflectionServiceUtil.java   | 23 ++++---
 .../testing/mock/osgi/context/OsgiContextImpl.java |  9 +--
 .../mock/osgi/ReflectionServiceUtilTest.java       | 22 ++++++-
 .../mock/osgi/context/OsgiContextImplTest.java     |  7 ++
 10 files changed, 177 insertions(+), 82 deletions(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MapUtil.java b/src/main/java/org/apache/sling/testing/mock/osgi/MapUtil.java
new file mode 100644
index 0000000..e819beb
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MapUtil.java
@@ -0,0 +1,52 @@
+/*
+ * 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.sling.testing.mock.osgi;
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+/**
+ * Map util methods.
+ */
+final class MapUtil {
+
+    public static Dictionary<String, Object> toDictionary(Map<String, Object> map) {
+        if (map == null) {
+            return null;
+        }
+        return new Hashtable<String, Object>(map);
+    }
+
+    public static Map<String, Object> toMap(Dictionary<String, Object> dictionary) {
+        if (dictionary == null) {
+            return null;
+        }
+        Map<String,Object> map = new HashMap<String, Object>();
+        Enumeration<String> keys = dictionary.keys();
+        while (keys.hasMoreElements()) {
+            String key = keys.nextElement();
+            map.put(key, dictionary.get(key));
+        }
+        return map;
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockComponentContext.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockComponentContext.java
index cf70b1d..40e57a9 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/MockComponentContext.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockComponentContext.java
@@ -36,12 +36,12 @@ class MockComponentContext implements ComponentContext {
     private final Dictionary<String, Object> properties;
 
     public MockComponentContext(final MockBundleContext mockBundleContext) {
-        this(mockBundleContext, new Hashtable<String, Object>());
+        this(mockBundleContext, null);
     }
 
     public MockComponentContext(final MockBundleContext mockBundleContext, final Dictionary<String, Object> properties) {
         this.bundleContext = mockBundleContext;
-        this.properties = properties;
+        this.properties = properties != null ? properties : new Hashtable<String, Object>();
     }
 
     @Override
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java
index 395f2c6..7a7474f 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java
@@ -19,9 +19,6 @@
 package org.apache.sling.testing.mock.osgi;
 
 import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Hashtable;
 import java.util.Map;
 
 import org.osgi.framework.BundleContext;
@@ -75,7 +72,7 @@ public final class MockOsgi {
      * @return Mocked {@link ComponentContext} instance
      */
     public static ComponentContext newComponentContext(Map<String, Object> properties) {
-        return newComponentContext(toDictionary(properties));
+        return newComponentContext(MapUtil.toDictionary(properties));
     }
 
     /**
@@ -94,7 +91,7 @@ public final class MockOsgi {
      * @return Mocked {@link ComponentContext} instance
      */
     public static ComponentContext newComponentContext(BundleContext bundleContext, Map<String, Object> properties) {
-        return newComponentContext(bundleContext, toDictionary(properties));
+        return newComponentContext(bundleContext, MapUtil.toDictionary(properties));
     }
 
     /**
@@ -147,7 +144,7 @@ public final class MockOsgi {
      * @return true if activation method was called. False if it failed.
      */
     public static boolean activate(Object target, Map<String, Object> properties) {
-        return activate(target, toDictionary(properties));
+        return activate(target, MapUtil.toDictionary(properties));
     }
 
     /**
@@ -171,7 +168,7 @@ public final class MockOsgi {
      * @return true if activation method was called. False if it failed.
      */
     public static boolean activate(Object target, BundleContext bundleContext, Map<String, Object> properties) {
-        return activate(target, bundleContext, toDictionary(properties));
+        return activate(target, bundleContext, MapUtil.toDictionary(properties));
     }
 
     /**
@@ -202,7 +199,7 @@ public final class MockOsgi {
      * @return true if deactivation method was called. False if it failed.
      */
     public static boolean deactivate(Object target, Map<String, Object> properties) {
-        return deactivate(target, toDictionary(properties));
+        return deactivate(target, MapUtil.toDictionary(properties));
     }
 
     /**
@@ -225,7 +222,7 @@ public final class MockOsgi {
      * @return true if activation method was called. False if it failed.
      */
     public static boolean deactivate(Object target, BundleContext bundleContext, Map<String, Object> properties) {
-        return deactivate(target, bundleContext, toDictionary(properties));
+        return deactivate(target, bundleContext, MapUtil.toDictionary(properties));
     }
 
     /**
@@ -236,7 +233,7 @@ public final class MockOsgi {
      * @return true if modified method was called. False if it failed.
      */
     public static boolean modified(Object target, BundleContext bundleContext, Dictionary<String, Object> properties) {
-        return modified(target, bundleContext, toMap(properties));
+        return modified(target, bundleContext, MapUtil.toMap(properties));
     }
 
     /**
@@ -250,18 +247,4 @@ public final class MockOsgi {
         return ReflectionServiceUtil.modified(target, bundleContext, properties);
     }
     
-    static Dictionary<String, Object> toDictionary(Map<String, Object> map) {
-        return new Hashtable<String, Object>(map);
-    }
-
-    static Map<String, Object> toMap(Dictionary<String, Object> dictionary) {
-        Map<String,Object> map = new HashMap<String, Object>();
-        Enumeration<String> keys = dictionary.keys();
-        while (keys.hasMoreElements()) {
-            String key = keys.nextElement();
-            map.put(key, dictionary.get(key));
-        }
-        return map;
-    }
-
 }
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceRegistration.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceRegistration.java
index a3bdaf5..1dc564b 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceRegistration.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceRegistration.java
@@ -44,12 +44,11 @@ class MockServiceRegistration implements ServiceRegistration {
     private Dictionary<String, Object> properties;
     private final ServiceReference serviceReference;
 
-    @SuppressWarnings("unchecked")
     public MockServiceRegistration(final Bundle bundle, final String[] clazzes, final Object service,
             final Dictionary<String, Object> properties) {
         this.clazzes = new HashSet<String>(ImmutableList.copyOf(clazzes));
         this.service = service;
-        this.properties = properties != null ? properties : new Hashtable();
+        this.properties = properties != null ? properties : new Hashtable<String,Object>();
         this.properties.put(Constants.SERVICE_ID, ++serviceCounter);
         this.serviceReference = new MockServiceReference(bundle, this);
         readOsgiMetadata();
@@ -91,6 +90,9 @@ class MockServiceRegistration implements ServiceRegistration {
     private void readOsgiMetadata() {
         Class<?> serviceClass = service.getClass();
         Document doc = OsgiMetadataUtil.getMetadata(serviceClass);
+        if (doc == null) {
+            return;
+        }
 
         // add service interfaces from OSGi metadata
         clazzes.addAll(OsgiMetadataUtil.getServiceInterfaces(serviceClass, doc));
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/NoScrMetadataException.java b/src/main/java/org/apache/sling/testing/mock/osgi/NoScrMetadataException.java
new file mode 100644
index 0000000..97b9260
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/NoScrMetadataException.java
@@ -0,0 +1,31 @@
+/*
+ * 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.sling.testing.mock.osgi;
+
+/**
+ * Is thrown when a OSGi mock method required SCR metadata and this is not found in the classpath.
+ */
+public final class NoScrMetadataException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    public NoScrMetadataException(Class<?> type) {
+        super("No OSGi SCR metadata found in classpath at " + OsgiMetadataUtil.getMetadataPath(type));
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtil.java b/src/main/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtil.java
index a1b7a0a..41fc4b5 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtil.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtil.java
@@ -89,6 +89,10 @@ final class OsgiMetadataUtil {
             return NAMESPACES.keySet().iterator();
         }
     };
+    
+    public static String getMetadataPath(Class clazz) {
+        return "/OSGI-INF/" + StringUtils.substringBefore(clazz.getName(), "$") + ".xml";
+    }
 
     /**
      * Try to read OSGI-metadata from /OSGI-INF and read all implemented
@@ -97,7 +101,7 @@ final class OsgiMetadataUtil {
      * @return Metadata document or null
      */
     public static Document getMetadata(Class clazz) {
-        String metadataPath = "/OSGI-INF/" + StringUtils.substringBefore(clazz.getName(), "$") + ".xml";
+        String metadataPath = getMetadataPath(clazz);
         InputStream metadataStream = clazz.getResourceAsStream(metadataPath);
         if (metadataStream == null) {
             log.debug("No OSGi metadata found at {}", metadataPath);
@@ -124,16 +128,14 @@ final class OsgiMetadataUtil {
 
     public static Set<String> getServiceInterfaces(Class clazz, Document metadata) {
         Set<String> serviceInterfaces = new HashSet<String>();
-        if (metadata != null) {
-            String query = "/components/component[@name='" + clazz.getName() + "']/service/provide[@interface!='']";
-            NodeList nodes = queryNodes(metadata, query);
-            if (nodes != null) {
-                for (int i = 0; i < nodes.getLength(); i++) {
-                    Node node = nodes.item(i);
-                    String serviceInterface = getAttributeValue(node, "interface");
-                    if (StringUtils.isNotBlank(serviceInterface)) {
-                        serviceInterfaces.add(serviceInterface);
-                    }
+        String query = "/components/component[@name='" + clazz.getName() + "']/service/provide[@interface!='']";
+        NodeList nodes = queryNodes(metadata, query);
+        if (nodes != null) {
+            for (int i = 0; i < nodes.getLength(); i++) {
+                Node node = nodes.item(i);
+                String serviceInterface = getAttributeValue(node, "interface");
+                if (StringUtils.isNotBlank(serviceInterface)) {
+                    serviceInterfaces.add(serviceInterface);
                 }
             }
         }
@@ -142,20 +144,18 @@ final class OsgiMetadataUtil {
 
     public static Map<String, Object> getProperties(Class clazz, Document metadata) {
         Map<String, Object> props = new HashMap<String, Object>();
-        if (metadata != null) {
-            String query = "/components/component[@name='" + clazz.getName() + "']/property[@name!='' and @value!='']";
-            NodeList nodes = queryNodes(metadata, query);
-            if (nodes != null) {
-                for (int i = 0; i < nodes.getLength(); i++) {
-                    Node node = nodes.item(i);
-                    String name = getAttributeValue(node, "name");
-                    String value = getAttributeValue(node, "value");
-                    String type = getAttributeValue(node, "type");
-                    if (StringUtils.equals("Integer", type)) {
-                        props.put(name, Integer.parseInt(value));
-                    } else {
-                        props.put(name, value);
-                    }
+        String query = "/components/component[@name='" + clazz.getName() + "']/property[@name!='' and @value!='']";
+        NodeList nodes = queryNodes(metadata, query);
+        if (nodes != null) {
+            for (int i = 0; i < nodes.getLength(); i++) {
+                Node node = nodes.item(i);
+                String name = getAttributeValue(node, "name");
+                String value = getAttributeValue(node, "value");
+                String type = getAttributeValue(node, "type");
+                if (StringUtils.equals("Integer", type)) {
+                    props.put(name, Integer.parseInt(value));
+                } else {
+                    props.put(name, value);
                 }
             }
         }
@@ -164,14 +164,12 @@ final class OsgiMetadataUtil {
 
     public static List<Reference> getReferences(Class clazz, Document metadata) {
         List<Reference> references = new ArrayList<Reference>();
-        if (metadata != null) {
-            String query = "/components/component[@name='" + clazz.getName() + "']/reference[@name!='']";
-            NodeList nodes = queryNodes(metadata, query);
-            if (nodes != null) {
-                for (int i = 0; i < nodes.getLength(); i++) {
-                    Node node = nodes.item(i);
-                    references.add(new Reference(node));
-                }
+        String query = "/components/component[@name='" + clazz.getName() + "']/reference[@name!='']";
+        NodeList nodes = queryNodes(metadata, query);
+        if (nodes != null) {
+            for (int i = 0; i < nodes.getLength(); i++) {
+                Node node = nodes.item(i);
+                references.add(new Reference(node));
             }
         }
         return references;
@@ -190,12 +188,10 @@ final class OsgiMetadataUtil {
     }
 
     private static String getLifecycleMethodName(Class clazz, Document metadata, String methodName) {
-        if (metadata != null) {
-            String query = "/components/component[@name='" + clazz.getName() + "']";
-            Node node = queryNode(metadata, query);
-            if (node != null) {
-                return getAttributeValue(node, methodName);
-            }
+        String query = "/components/component[@name='" + clazz.getName() + "']";
+        Node node = queryNode(metadata, query);
+        if (node != null) {
+            return getAttributeValue(node, methodName);
         }
         return null;
     }
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java b/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
index 8269501..0ecc24f 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
@@ -55,11 +55,15 @@ final class ReflectionServiceUtil {
      * @param componentContext Component context
      * @return true if activation/deactivation method was called. False if it failed.
      */
+    @SuppressWarnings("unchecked")
     public static boolean activateDeactivate(Object target, ComponentContext componentContext, boolean activate) {
         Class<?> targetClass = target.getClass();
 
         // get method name for activation/deactivation from osgi metadata
         Document metadata = OsgiMetadataUtil.getMetadata(targetClass);
+        if (metadata==null) {
+            throw new NoScrMetadataException(targetClass);
+        }
         String methodName;
         if (activate) {
             methodName = OsgiMetadataUtil.getActivateMethodName(targetClass, metadata);
@@ -89,7 +93,7 @@ final class ReflectionServiceUtil {
         // 3. map
         method = getMethod(targetClass, methodName, new Class<?>[] { Map.class });
         if (method != null) {
-            invokeMethod(target, method, new Object[] { componentContext.getProperties() });
+            invokeMethod(target, method, new Object[] { MapUtil.toMap(componentContext.getProperties()) });
             return true;
         }
         
@@ -125,7 +129,7 @@ final class ReflectionServiceUtil {
                     args[i] = componentContext.getBundleContext();
                 }
                 else if (method.getParameterTypes()[i] == Map.class) {
-                    args[i] = componentContext.getProperties();
+                    args[i] = MapUtil.toMap(componentContext.getProperties());
                 }
                 else if (method.getParameterTypes()[i] == int.class || method.getParameterTypes()[i] == Integer.class) {
                     args[i] = 0;
@@ -157,6 +161,9 @@ final class ReflectionServiceUtil {
 
         // get method name for activation/deactivation from osgi metadata
         Document metadata = OsgiMetadataUtil.getMetadata(targetClass);
+        if (metadata==null) {
+            throw new NoScrMetadataException(targetClass);
+        }
         String methodName = OsgiMetadataUtil.getModifiedMethodName(targetClass, metadata);
         
         // try to find matching modified method and execute it
@@ -257,7 +264,12 @@ final class ReflectionServiceUtil {
 
         // collect all declared reference annotations on class and field level
         Class<?> targetClass = target.getClass();
-        List<Reference> references = getReferences(targetClass);
+
+        Document metadata = OsgiMetadataUtil.getMetadata(targetClass);
+        if (metadata==null) {
+            throw new NoScrMetadataException(targetClass);
+        }
+        List<Reference> references = OsgiMetadataUtil.getReferences(targetClass, metadata);
 
         // try to inject services
         boolean allInjected = true;
@@ -268,11 +280,6 @@ final class ReflectionServiceUtil {
         return allInjected;
     }
 
-    private static List<Reference> getReferences(Class clazz) {
-        Document metadata = OsgiMetadataUtil.getMetadata(clazz);
-        return OsgiMetadataUtil.getReferences(clazz, metadata);
-    }
-
     private static boolean injectServiceReference(Reference reference, Object target, BundleContext bundleContext) {
         Class<?> targetClass = target.getClass();
 
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImpl.java b/src/main/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImpl.java
index d4cb74b..fb01663 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImpl.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImpl.java
@@ -32,8 +32,6 @@ import org.osgi.service.component.ComponentContext;
 
 import aQute.bnd.annotation.ConsumerType;
 
-import com.google.common.collect.ImmutableMap;
-
 /**
  * Defines OSGi context objects and helper methods. Should not be used directly
  * but via the {@link org.apache.sling.testing.mock.osgi.junit.OsgiContext} JUnit rule.
@@ -108,8 +106,7 @@ public class OsgiContextImpl {
         if (properties != null) {
             serviceProperties = new Hashtable<String, Object>(properties);
         }
-        bundleContext().registerService(serviceClass != null ? serviceClass.getName() : null, service,
-                serviceProperties);
+        bundleContext().registerService(serviceClass != null ? serviceClass.getName() : null, service, serviceProperties);
         return service;
     }
 
@@ -121,7 +118,7 @@ public class OsgiContextImpl {
      * @return Registered service instance
      */
     public final <T> T registerInjectActivateService(final T service) {
-        return registerInjectActivateService(service, ImmutableMap.<String, Object> of());
+        return registerInjectActivateService(service, null);
     }
 
     /**
@@ -135,7 +132,7 @@ public class OsgiContextImpl {
     public final <T> T registerInjectActivateService(final T service, final Map<String, Object> properties) {
         MockOsgi.injectServices(service, bundleContext());
         MockOsgi.activate(service, bundleContext(), properties);
-        registerService(null, service, null);
+        registerService(null, service, properties);
         return service;
     }
 
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtilTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtilTest.java
index 37e5c49..b8b8cea 100644
--- a/src/test/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtilTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtilTest.java
@@ -123,6 +123,26 @@ public class ReflectionServiceUtilTest {
         assertSame(service1, service4.getReference1());
     }
 
+    @Test(expected=NoScrMetadataException.class)
+    public void testInjectServicesNoMetadata() {
+        MockOsgi.injectServices(new Object(), MockOsgi.newBundleContext());
+    }
+    
+    @Test(expected=NoScrMetadataException.class)
+    public void testActivateNoMetadata() {
+        MockOsgi.activate(new Object());
+    }
+    
+    @Test(expected=NoScrMetadataException.class)
+    public void testDeactivateNoMetadata() {
+        MockOsgi.deactivate(new Object());
+    }
+    
+    @Test(expected=NoScrMetadataException.class)
+    public void testModifiedNoMetadata() {
+        MockOsgi.modified(new Object(), MockOsgi.newBundleContext(), ImmutableMap.<String,Object>of());
+    }
+    
     public interface ServiceInterface1 {
         // no methods
     }
@@ -173,7 +193,7 @@ public class ReflectionServiceUtilTest {
         @Activate
         private void activate(ComponentContext ctx) {
             this.componentContext = ctx;
-            this.config = MockOsgi.toMap(ctx.getProperties());
+            this.config = MapUtil.toMap(ctx.getProperties());
         }
 
         @Deactivate
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImplTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImplTest.java
index 902624e..19c5a5b 100644
--- a/src/test/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImplTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImplTest.java
@@ -27,6 +27,8 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.sling.testing.mock.osgi.NoScrMetadataException;
+import org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -90,6 +92,11 @@ public class OsgiContextImplTest {
 
     @Test
     public void testRegisterInjectActivate() {
+        context.registerInjectActivateService(new ReflectionServiceUtilTest.Service3());
+    }
+
+    @Test(expected=NoScrMetadataException.class)
+    public void testRegisterInjectActivateInvalid() {
         context.registerInjectActivateService(new Object());
     }
 

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 03/23: SLING-4042 move all mock projects to mocks/ subdirectory

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 8d208171a3f361725c1f4070f4caa5a93653f278
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Mon Oct 13 14:32:45 2014 +0000

    SLING-4042 move all mock projects to mocks/ subdirectory
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1631416 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                    |  2 +-
 src/site/markdown/index.md | 35 ---------------------------
 src/site/markdown/usage.md | 59 ----------------------------------------------
 3 files changed, 1 insertion(+), 95 deletions(-)

diff --git a/pom.xml b/pom.xml
index 708d885..b4060c4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,7 +24,7 @@
         <groupId>org.apache.sling</groupId>
         <artifactId>sling</artifactId>
         <version>22</version>
-        <relativePath>../../parent/pom.xml</relativePath>
+        <relativePath>../../../parent/pom.xml</relativePath>
     </parent>
 
     <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md
deleted file mode 100644
index acf7d98..0000000
--- a/src/site/markdown/index.md
+++ /dev/null
@@ -1,35 +0,0 @@
-## About OSGi Mocks
-
-Mock implementation of selected OSGi APIs.
-
-### Maven Dependency
-
-```xml
-<dependency>
-  <groupId>org.apache.sling</groupId>
-  <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
-  <version>1.0.0-SNAPHOT</version>
-</dependency>
-```
-
-### Documentation
-
-* [Usage](usage.html)
-* [API Documentation](apidocs/)
-* [Changelog](changes-report.html)
-
-### Implemented mock features
-
-The mock implementation supports:
-
-* Instantiating OSGi `Bundle`, `BundleContext` and `ComponentContext` objects and navigate between them.
-* Read and write properties on them.
-* Register OSGi services and get references to service instances
-* Service and bundle listener implementation
-* When adding services to BundleContext OSGi metadata from `/OSGI-INF/<pid>.xml` is read (e.g. for service ranking property)
-* Mock implementation of `LogService` which logs to SLF4J in JUnit context
-
-The following features are *not supported*:
-
-* Activation and deactivation methods of services are not called automatically (but helper methods exist)
-* Dependency injection does not take place automatically (but helper methods exist)
diff --git a/src/site/markdown/usage.md b/src/site/markdown/usage.md
deleted file mode 100644
index c7e8bb8..0000000
--- a/src/site/markdown/usage.md
+++ /dev/null
@@ -1,59 +0,0 @@
-## Usage
-
-### Getting OSGi mock objects
-
-The factory class `MockOsgi` allows to instantiate the different mock implementations.
-
-Example:
-
-```java
-// get bundle context
-BundleContext bundleContext = MockOsgi.newBundleContext();
-
-// get component context
-Dictionary<String,Object> properties = new Hashtable<>();
-properties.put("prop1", "value1");
-BundleContext bundleContext = MockOsgi.newComponentContext(properties);
-```
-
-It is possible to simulate registering of OSGi services (backed by a simple hash map internally):
-
-```java
-// register service
-bundleContext.registerService(MyClass.class, myService, properties);
-
-// get service instance
-ServiceReference ref = bundleContext.getServiceReference(MyClass.class.getName());
-MyClass service = bundleContext.getService(ref);
-```
-
-### Activation and Dependency Injection
-
-It is possible to simulate OSGi service activation, deactivation and dependency injection and the mock implementation
-tries to to its best to execute all as expected for an OSGi environment.
-
-Example:
-
-```java
-// get bundle context
-BundleContext bundleContext = MockOsgi.newBundleContext();
-
-// create service instance manually
-MyService service = new MyService();
-
-// inject dependencies
-MockOsgi.injectServices(service, bundleContext);
-
-// activate service
-MockOsgi.activate(service, props);
-
-// operate with service...
-
-// deactivate service
-MockOsgi.deactivate(service);
-```
-
-Please note: The injectServices, activate and deactivate Methods can only work properly when the SCR XML metadata files
-are preset in the classpath at `/OSGI-INF`. They are generated automatically by the Maven SCR plugin, but might be
-missing if your clean and build the project within your IDE (e.g. Eclipse). In this case you have to compile the
-project again with maven and can run the tests - or use a Maven IDE Integration like m2eclipse.

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 17/23: SLING-4166 update package version

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 4d131cd9b3f23abd09f94da2d699b44f604b35d3
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Fri Nov 14 17:20:50 2014 +0000

    SLING-4166 update package version
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1639707 13f79535-47bb-0310-9956-ffa450edef68
---
 src/main/java/org/apache/sling/testing/mock/osgi/package-info.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/package-info.java b/src/main/java/org/apache/sling/testing/mock/osgi/package-info.java
index 7682059..14b8744 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/package-info.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/package-info.java
@@ -19,5 +19,5 @@
 /**
  * Mock implementation of selected OSGi APIs.
  */
-@aQute.bnd.annotation.Version("1.0")
+@aQute.bnd.annotation.Version("1.1")
 package org.apache.sling.testing.mock.osgi;

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 14/23: SLING-4163 OSGi Mock: Reference bind/unbind method picking order

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit c40b2dd59892d5723bed1caa280f9e9488ffb60a
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Fri Nov 14 16:16:48 2014 +0000

    SLING-4163 OSGi Mock: Reference bind/unbind method picking order
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1639692 13f79535-47bb-0310-9956-ffa450edef68
---
 .../testing/mock/osgi/ReflectionServiceUtil.java   | 155 ++++++++++-----------
 .../mock/osgi/ReflectionServiceUtilTest.java       |  16 ++-
 2 files changed, 81 insertions(+), 90 deletions(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java b/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
index 1ee8370..fa75ebf 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
@@ -74,21 +74,21 @@ final class ReflectionServiceUtil {
         // try to find matchin activate/deactivate method and execute it
         
         // 1. componentContext
-        Method method = getMethod(targetClass, methodName, new Class<?>[] { ComponentContext.class }, activate);
+        Method method = getMethod(targetClass, methodName, new Class<?>[] { ComponentContext.class });
         if (method != null) {
             invokeMethod(target, method, new Object[] { componentContext });
             return true;
         }
         
         // 2. bundleContext
-        method = getMethod(targetClass, methodName, new Class<?>[] { BundleContext.class }, activate);
+        method = getMethod(targetClass, methodName, new Class<?>[] { BundleContext.class });
         if (method != null) {
             invokeMethod(target, method, new Object[] { componentContext.getBundleContext() });
             return true;
         }
         
         // 3. map
-        method = getMethod(targetClass, methodName, new Class<?>[] { Map.class }, activate);
+        method = getMethod(targetClass, methodName, new Class<?>[] { Map.class });
         if (method != null) {
             invokeMethod(target, method, new Object[] { componentContext.getProperties() });
             return true;
@@ -96,7 +96,7 @@ final class ReflectionServiceUtil {
         
         // 4. int (deactivation only)
         if (!activate) {
-            method = getMethod(targetClass, methodName, new Class<?>[] { int.class }, activate);
+            method = getMethod(targetClass, methodName, new Class<?>[] { int.class });
             if (method != null) {
                 invokeMethod(target, method, new Object[] { 0 });
                 return true;
@@ -105,7 +105,7 @@ final class ReflectionServiceUtil {
         
         // 5. Integer (deactivation only)
         if (!activate) {
-            method = getMethod(targetClass, methodName, new Class<?>[] { Integer.class }, activate);
+            method = getMethod(targetClass, methodName, new Class<?>[] { Integer.class });
             if (method != null) {
                 invokeMethod(target, method, new Object[] { 0 });
                 return true;
@@ -115,7 +115,7 @@ final class ReflectionServiceUtil {
         // 6. mixed arguments of componentContext, bundleContext and map
         Class<?>[] mixedArgsAllowed = activate ? new Class<?>[] { ComponentContext.class, BundleContext.class, Map.class }
                 : new Class<?>[] { ComponentContext.class, BundleContext.class, Map.class, int.class, Integer.class };
-        method = getMethodWithAnyCombinationArgs(targetClass, methodName, mixedArgsAllowed, activate);
+        method = getMethodWithAnyCombinationArgs(targetClass, methodName, mixedArgsAllowed);
         if (method != null) {
             Object[] args = new Object[method.getParameterTypes().length];
             for (int i=0; i<args.length; i++) {
@@ -137,7 +137,7 @@ final class ReflectionServiceUtil {
         }
 
         // 7. noargs
-        method = getMethod(targetClass, methodName, new Class<?>[0], activate);
+        method = getMethod(targetClass, methodName, new Class<?>[0]);
         if (method != null) {
             invokeMethod(target, method, new Object[0]);
             return true;
@@ -147,18 +147,47 @@ final class ReflectionServiceUtil {
         return false;
     }
 
-    private static Method getMethod(Class clazz, String methodName, Class<?>[] signature, boolean activate) {
+    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(), signature)) {
+                    && Arrays.equals(method.getParameterTypes(), types)) {
                 return method;
             }
         }
+        // not found? check super classes
+        Class<?> superClass = clazz.getSuperclass();
+        if (superClass != null && superClass != Object.class) {
+            return getMethod(superClass, methodName, types);
+        }
+        return null;
+    }
+    
+    private static Method getMethodWithAssignableTypes(Class clazz, String methodName, Class<?>[] types) {
+        Method[] methods = clazz.getDeclaredMethods();
+        for (Method method : methods) {
+            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].isAssignableFrom(types[i])) {
+                        foundMismatch = false;
+                        break;
+                    }
+                }
+                if (!foundMismatch) {
+                    return method;
+                }
+            }
+        }
+        // not found? check super classes
+        Class<?> superClass = clazz.getSuperclass();
+        if (superClass != null && superClass != Object.class) {
+            return getMethodWithAssignableTypes(superClass, methodName, types);
+        }
         return null;
     }
     
-    private static Method getMethodWithAnyCombinationArgs(Class clazz, String methodName, Class<?>[] types, boolean activate) {
+    private static Method getMethodWithAnyCombinationArgs(Class clazz, String methodName, Class<?>[] types) {
         Method[] methods = clazz.getDeclaredMethods();
         for (Method method : methods) {
             if (StringUtils.equals(method.getName(), methodName) && method.getParameterTypes().length > 1) {
@@ -170,6 +199,11 @@ final class ReflectionServiceUtil {
                 return method;
             }
         }
+        // not found? check super classes
+        Class<?> superClass = clazz.getSuperclass();
+        if (superClass != null && superClass != Object.class) {
+            return getMethodWithAnyCombinationArgs(superClass, methodName, types);
+        }
         return null;
     }
     
@@ -252,69 +286,38 @@ final class ReflectionServiceUtil {
         // try to invoke bind method
         String bindMethodName = reference.getBind();
         if (StringUtils.isNotEmpty(bindMethodName)) {
-            Method bindMethod = getFirstMethodWithNameAndSignature(targetClass, bindMethodName, new Class<?>[] { type });
+            
+            // 1. ServiceReference
+            Method bindMethod = getMethod(targetClass, bindMethodName, new Class<?>[] { ServiceReference.class });
             if (bindMethod != null) {
-                bindMethod.setAccessible(true);
                 for (ServiceInfo matchingService : matchingServices) {
-                    try {
-                        bindMethod.invoke(target, matchingService.getServiceInstance());
-                    } catch (IllegalAccessException ex) {
-                        throw new RuntimeException("Unable to invoke method " + bindMethodName + " for class "
-                                + targetClass.getName(), ex);
-                    } catch (IllegalArgumentException ex) {
-                        throw new RuntimeException("Unable to invoke method " + bindMethodName + " for class "
-                                + targetClass.getName(), ex);
-                    } catch (InvocationTargetException ex) {
-                        throw new RuntimeException("Unable to invoke method " + bindMethodName + " for class "
-                                + targetClass.getName(), ex.getCause());
-                    }
+                    invokeMethod(target, bindMethod, new Object[] { matchingService.getServiceReference() });
                 }
                 return true;
-            } else {
-                Method bindMethodWithConfig = getFirstMethodWithNameAndSignature(targetClass, bindMethodName,
-                        new Class<?>[] { type, Map.class });
-                if (bindMethodWithConfig != null) {
-                    bindMethodWithConfig.setAccessible(true);
-                    for (ServiceInfo matchingService : matchingServices) {
-                        try {
-                            bindMethodWithConfig.invoke(target, matchingService.getServiceInstance(),
-                                    matchingService.getServiceConfig());
-                        } catch (IllegalAccessException ex) {
-                            throw new RuntimeException("Unable to invoke method " + bindMethodName + " for class "
-                                    + targetClass.getName(), ex);
-                        } catch (IllegalArgumentException ex) {
-                            throw new RuntimeException("Unable to invoke method " + bindMethodName + " for class "
-                                    + targetClass.getName(), ex);
-                        } catch (InvocationTargetException ex) {
-                            throw new RuntimeException("Unable to invoke method " + bindMethodName + " for class "
-                                    + targetClass.getName(), ex.getCause());
-                        }
-                    }
-                    return true;
-                } else {
-                    Method bindMethodServiceReference = getFirstMethodWithNameAndSignature(targetClass, bindMethodName,
-                            new Class<?>[] { ServiceReference.class });
-                    if (bindMethodServiceReference != null) {
-                        bindMethodServiceReference.setAccessible(true);
-                        for (ServiceInfo matchingService : matchingServices) {
-                            if (matchingService.getServiceReference() != null) {
-                                try {
-                                    bindMethodServiceReference.invoke(target, matchingService.getServiceReference());
-                                } catch (IllegalAccessException ex) {
-                                    throw new RuntimeException("Unable to invoke method " + bindMethodName
-                                            + " for class " + targetClass.getName(), ex);
-                                } catch (IllegalArgumentException ex) {
-                                    throw new RuntimeException("Unable to invoke method " + bindMethodName
-                                            + " for class " + targetClass.getName(), ex);
-                                } catch (InvocationTargetException ex) {
-                                    throw new RuntimeException("Unable to invoke method " + bindMethodName
-                                            + " for class " + targetClass.getName(), ex.getCause());
-                                }
-                            }
-                        }
-                        return true;
-                    }
+            }
+            
+            // 2. assignable from service instance
+            Class<?> interfaceType;
+            try {
+                interfaceType = Class.forName(reference.getInterfaceType());
+            } catch (ClassNotFoundException e) {
+                throw new RuntimeException("Service reference type not found: " + reference.getInterfaceType());
+            }
+            bindMethod = getMethodWithAssignableTypes(targetClass, bindMethodName, new Class<?>[] { interfaceType });
+            if (bindMethod != null) {
+                for (ServiceInfo matchingService : matchingServices) {
+                    invokeMethod(target, bindMethod, new Object[] { matchingService.getServiceInstance() });
+                }
+                return true;
+            }
+            
+            // 3. assignable from service instance plus map
+            bindMethod = getMethodWithAssignableTypes(targetClass, bindMethodName, new Class<?>[] { interfaceType, Map.class });
+            if (bindMethod != null) {
+                for (ServiceInfo matchingService : matchingServices) {
+                    invokeMethod(target, bindMethod, new Object[] { matchingService.getServiceInstance(), matchingService.getServiceConfig() });
                 }
+                return true;
             }
         }
 
@@ -322,22 +325,6 @@ final class ReflectionServiceUtil {
         return false;
     }
 
-    private static Method getFirstMethodWithNameAndSignature(Class<?> clazz, String methodName, Class<?>[] signature) {
-        Method[] methods = clazz.getDeclaredMethods();
-        for (Method method : methods) {
-            if (StringUtils.equals(method.getName(), methodName)
-                    && Arrays.equals(method.getParameterTypes(), signature)) {
-                return method;
-            }
-        }
-        // not found? check super classes
-        Class<?> superClass = clazz.getSuperclass();
-        if (superClass != null && superClass != Object.class) {
-            return getFirstMethodWithNameAndSignature(superClass, methodName, signature);
-        }
-        return null;
-    }
-
     private static List<ServiceInfo> getMatchingServices(Class<?> type, BundleContext bundleContext) {
         List<ServiceInfo> matchingServices = new ArrayList<ServiceInfo>();
         try {
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtilTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtilTest.java
index ff29037..6fd4ec2 100644
--- a/src/test/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtilTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtilTest.java
@@ -78,7 +78,7 @@ public class ReflectionServiceUtilTest {
         assertEquals(1, references2.size());
         assertSame(service2, references2.get(0));
 
-        List<ServiceInterface3> references3 = service3.getReferences3();
+        List<ServiceSuperInterface3> references3 = service3.getReferences3();
         assertEquals(1, references3.size());
         assertSame(service2, references3.get(0));
 
@@ -108,7 +108,11 @@ public class ReflectionServiceUtilTest {
         // no methods
     }
 
-    public interface ServiceInterface3 {
+    public interface ServiceInterface3 extends ServiceSuperInterface3 {
+        // no methods
+    }
+
+    public interface ServiceSuperInterface3 {
         // no methods
     }
 
@@ -136,7 +140,7 @@ public class ReflectionServiceUtilTest {
         private List<ServiceReference> references2 = new ArrayList<ServiceReference>();
 
         @Reference(name = "reference3", referenceInterface = ServiceInterface3.class, cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE)
-        private List<ServiceInterface3> references3 = new ArrayList<ServiceInterface3>();
+        private List<ServiceSuperInterface3> references3 = new ArrayList<ServiceSuperInterface3>();
         private List<Map<String, Object>> reference3Configs = new ArrayList<Map<String, Object>>();
 
         private ComponentContext componentContext;
@@ -163,7 +167,7 @@ public class ReflectionServiceUtilTest {
             return services;
         }
 
-        public List<ServiceInterface3> getReferences3() {
+        public List<ServiceSuperInterface3> getReferences3() {
             return this.references3;
         }
 
@@ -191,12 +195,12 @@ public class ReflectionServiceUtilTest {
             references2.remove(serviceReference);
         }
 
-        protected void bindReference3(ServiceInterface3 service, Map<String, Object> serviceConfig) {
+        protected void bindReference3(ServiceSuperInterface3 service, Map<String, Object> serviceConfig) {
             references3.add(service);
             reference3Configs.add(serviceConfig);
         }
 
-        protected void unbindReference3(ServiceInterface3 service, Map<String, Object> serviceConfig) {
+        protected void unbindReference3(ServiceSuperInterface3 service, Map<String, Object> serviceConfig) {
             references3.remove(service);
             reference3Configs.remove(serviceConfig);
         }

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 06/23: SLING-4042 add README files

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 7e5bc2dbb4fca9add954f0c70157331758b47d9a
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Thu Oct 16 19:09:39 2014 +0000

    SLING-4042 add README files
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1632415 13f79535-47bb-0310-9956-ffa450edef68
---
 README.txt | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..5382c4f
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,6 @@
+Apache Sling Testing OSGi Mock
+
+Mock implementation of selected OSGi APIs.
+
+Documentation:
+http://sling.apache.org/documentation/development/osgi-mock.html

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 11/23: SLING-4142 MockOsgi: Activate/Deactivate method does not support different signatures

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 59f74f698a3683ce4270f6c6effc275005325808
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Fri Nov 7 00:08:14 2014 +0000

    SLING-4142 MockOsgi: Activate/Deactivate method does not support different signatures
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1637273 13f79535-47bb-0310-9956-ffa450edef68
---
 .../testing/mock/osgi/ReflectionServiceUtil.java   | 112 +++++++-
 ...eflectionServiceUtilActivateDeactivateTest.java | 285 +++++++++++++++++++++
 ...ReflectionServiceUtilActivateDeactivateTest.xml |  21 ++
 3 files changed, 405 insertions(+), 13 deletions(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java b/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
index fe363ab..1ee8370 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
@@ -26,6 +26,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.Reference;
@@ -70,24 +71,78 @@ final class ReflectionServiceUtil {
             return false;
         }
 
-        // if method is defined try to execute it
+        // try to find matchin activate/deactivate method and execute it
+        
+        // 1. componentContext
         Method method = getMethod(targetClass, methodName, new Class<?>[] { ComponentContext.class }, activate);
         if (method != null) {
-            try {
-                method.setAccessible(true);
-                method.invoke(target, componentContext);
+            invokeMethod(target, method, new Object[] { componentContext });
+            return true;
+        }
+        
+        // 2. bundleContext
+        method = getMethod(targetClass, methodName, new Class<?>[] { BundleContext.class }, activate);
+        if (method != null) {
+            invokeMethod(target, method, new Object[] { componentContext.getBundleContext() });
+            return true;
+        }
+        
+        // 3. map
+        method = getMethod(targetClass, methodName, new Class<?>[] { Map.class }, activate);
+        if (method != null) {
+            invokeMethod(target, method, new Object[] { componentContext.getProperties() });
+            return true;
+        }
+        
+        // 4. int (deactivation only)
+        if (!activate) {
+            method = getMethod(targetClass, methodName, new Class<?>[] { int.class }, activate);
+            if (method != null) {
+                invokeMethod(target, method, new Object[] { 0 });
+                return true;
+            }
+        }
+        
+        // 5. Integer (deactivation only)
+        if (!activate) {
+            method = getMethod(targetClass, methodName, new Class<?>[] { Integer.class }, activate);
+            if (method != null) {
+                invokeMethod(target, method, new Object[] { 0 });
                 return true;
-            } catch (IllegalAccessException ex) {
-                throw new RuntimeException("Unable to invoke activate/deactivate method for class "
-                        + targetClass.getName(), ex);
-            } catch (IllegalArgumentException ex) {
-                throw new RuntimeException("Unable to invoke activate/deactivate method for class "
-                        + targetClass.getName(), ex);
-            } catch (InvocationTargetException ex) {
-                throw new RuntimeException("Unable to invoke activate/deactivate method for class "
-                        + targetClass.getName(), ex.getCause());
             }
         }
+        
+        // 6. mixed arguments of componentContext, bundleContext and map
+        Class<?>[] mixedArgsAllowed = activate ? new Class<?>[] { ComponentContext.class, BundleContext.class, Map.class }
+                : new Class<?>[] { ComponentContext.class, BundleContext.class, Map.class, int.class, Integer.class };
+        method = getMethodWithAnyCombinationArgs(targetClass, methodName, mixedArgsAllowed, activate);
+        if (method != null) {
+            Object[] args = new Object[method.getParameterTypes().length];
+            for (int i=0; i<args.length; i++) {
+                if (method.getParameterTypes()[i] == ComponentContext.class) {
+                    args[i] = componentContext;
+                }
+                else if (method.getParameterTypes()[i] == BundleContext.class) {
+                    args[i] = componentContext.getBundleContext();
+                }
+                else if (method.getParameterTypes()[i] == Map.class) {
+                    args[i] = componentContext.getProperties();
+                }
+                else if (method.getParameterTypes()[i] == int.class || method.getParameterTypes()[i] == Integer.class) {
+                    args[i] = 0;
+                }
+            }
+            invokeMethod(target, method, args);
+            return true;
+        }
+
+        // 7. noargs
+        method = getMethod(targetClass, methodName, new Class<?>[0], activate);
+        if (method != null) {
+            invokeMethod(target, method, new Object[0]);
+            return true;
+        }
+        
         log.warn("Method {}(ComponentContext) not found in class {}", methodName, targetClass.getName());
         return false;
     }
@@ -102,6 +157,37 @@ final class ReflectionServiceUtil {
         }
         return null;
     }
+    
+    private static Method getMethodWithAnyCombinationArgs(Class clazz, String methodName, Class<?>[] types, boolean activate) {
+        Method[] methods = clazz.getDeclaredMethods();
+        for (Method method : methods) {
+            if (StringUtils.equals(method.getName(), methodName) && method.getParameterTypes().length > 1) {
+                for (Class<?> parameterType : method.getParameterTypes()) {
+                    if (!ArrayUtils.contains(types,  parameterType)) {
+                        return null;
+                    }
+                }
+                return method;
+            }
+        }
+        return null;
+    }
+    
+    private static void invokeMethod(Object target, Method method, Object[] args) {
+        try {
+            method.setAccessible(true);
+            method.invoke(target, args);
+        } catch (IllegalAccessException ex) {
+            throw new RuntimeException("Unable to invoke activate/deactivate method for class "
+                    + target.getClass().getName(), ex);
+        } catch (IllegalArgumentException ex) {
+            throw new RuntimeException("Unable to invoke activate/deactivate method for class "
+                    + target.getClass().getName(), ex);
+        } catch (InvocationTargetException ex) {
+            throw new RuntimeException("Unable to invoke activate/deactivate method for class "
+                    + target.getClass().getName(), ex.getCause());
+        }
+    }
 
     /**
      * Simulate OSGi service dependency injection. Injects direct references and
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtilActivateDeactivateTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtilActivateDeactivateTest.java
new file mode 100644
index 0000000..36cf88e
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtilActivateDeactivateTest.java
@@ -0,0 +1,285 @@
+/*
+ * 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.sling.testing.mock.osgi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Map;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.ComponentContext;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Test different variants of activate/deactivate methods with varying signatures.
+ */
+public class ReflectionServiceUtilActivateDeactivateTest {
+
+    private Map<String,Object> map = ImmutableMap.<String, Object>of("prop1", "value1");
+    private BundleContext bundleContext = MockOsgi.newBundleContext();
+    
+    @Test
+    public void testService1() {
+        Service1 service = new Service1();
+        
+        assertTrue(MockOsgi.activate(service, bundleContext, map));
+        assertTrue(service.isActivated());
+        assertSame(bundleContext, service.getComponentContext().getBundleContext());
+        
+        assertTrue(MockOsgi.deactivate(service, bundleContext, map));
+        assertFalse(service.isActivated());
+    }
+
+    @Test
+    public void testService2() {
+        Service2 service = new Service2();
+        
+        assertTrue(MockOsgi.activate(service, bundleContext, map));
+        assertTrue(service.isActivated());
+        assertSame(bundleContext, service.getBundleContext());
+        
+        assertTrue(MockOsgi.deactivate(service, bundleContext, map));
+        assertFalse(service.isActivated());
+    }
+
+    @Test
+    public void testService3() {
+        Service3 service = new Service3();
+        
+        assertTrue(MockOsgi.activate(service, bundleContext, map));
+        assertTrue(service.isActivated());
+        assertEquals(map, ImmutableMap.copyOf(service.getMap()));
+        
+        assertTrue(MockOsgi.deactivate(service, bundleContext, map));
+        assertFalse(service.isActivated());
+    }
+
+    @Test
+    public void testService4() {
+        Service4 service = new Service4();
+        
+        assertTrue(MockOsgi.activate(service, bundleContext, map));
+        assertTrue(service.isActivated());
+        
+        assertTrue(MockOsgi.deactivate(service, bundleContext, map));
+        assertFalse(service.isActivated());
+    }
+
+    @Test
+    public void testService5() {
+        Service5 service = new Service5();
+        
+        assertTrue(MockOsgi.activate(service, bundleContext, map));
+        assertTrue(service.isActivated());
+        
+        assertTrue(MockOsgi.deactivate(service, bundleContext, map));
+        assertFalse(service.isActivated());
+    }
+
+    @Test
+    public void testService6() {
+        Service6 service = new Service6();
+        
+        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());
+    }
+
+    @Component
+    public static class Service1 {
+        
+        private boolean activated;
+        private ComponentContext componentContext;
+
+        @Activate
+        private void activate(ComponentContext ctx) {
+            this.activated = true;
+            this.componentContext = ctx;
+        }
+
+        @Deactivate
+        private void deactivate(ComponentContext ctx) {
+            this.activated = false;
+            this.componentContext = null;
+        }
+        
+        public boolean isActivated() {
+            return activated;
+        }
+
+        public ComponentContext getComponentContext() {
+            return componentContext;
+        }
+
+    }
+
+    @Component
+    public static class Service2 {
+        
+        private boolean activated;
+        private BundleContext bundleContext;
+
+        @Activate
+        private void activate(BundleContext ctx) {
+            this.activated = true;
+            this.bundleContext = ctx;
+        }
+
+        @Deactivate
+        private void deactivate(BundleContext ctx) {
+            this.activated = false;
+            this.bundleContext = null;
+        }
+        
+        public boolean isActivated() {
+            return activated;
+        }
+
+        public BundleContext getBundleContext() {
+            return bundleContext;
+        }
+
+    }
+
+    @Component
+    public static class Service3 {
+        
+        private boolean activated;
+        private Map<String, Object> map;
+
+        @Activate
+        private void activate(Map<String,Object> map) {
+            this.activated = true;
+            this.map = map;
+        }
+
+        @Deactivate
+        private void deactivate(Map<String,Object> map) {
+            this.activated = false;
+            this.map = null;
+        }
+        
+        public boolean isActivated() {
+            return activated;
+        }
+
+        public Map<String, Object> getMap() {
+            return map;
+        }
+
+    }
+
+    @Component
+    public static class Service4 {
+        
+        private boolean activated;
+
+        @Activate
+        private void activate() {
+            this.activated = true;
+        }
+
+        @Deactivate
+        private void deactivate(int value) {
+            this.activated = false;
+        }
+        
+        public boolean isActivated() {
+            return activated;
+        }
+
+    }
+
+    @Component
+    public static class Service5 {
+        
+        private boolean activated;
+
+        @Activate
+        private void activate() {
+            this.activated = true;
+        }
+
+        @Deactivate
+        private void deactivate(Integer value) {
+            this.activated = false;
+        }
+        
+        public boolean isActivated() {
+            return activated;
+        }
+
+    }
+
+    @Component
+    public static class Service6 {
+        
+        private boolean activated;
+        private ComponentContext componentContext;
+        private BundleContext bundleContext;
+        private Map<String,Object> map;
+
+        @Activate
+        private void activate(ComponentContext componentContext, BundleContext bundleContext, Map<String,Object> map) {
+            this.activated = true;
+            this.componentContext = componentContext;
+            this.bundleContext = bundleContext;
+            this.map = map;
+        }
+
+        @Deactivate
+        private void deactivate(Map<String,Object> map, BundleContext bundleContext, int value1, Integer value2) {
+            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.ReflectionServiceUtilActivateDeactivateTest.xml b/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.ReflectionServiceUtilActivateDeactivateTest.xml
new file mode 100644
index 0000000..23c4585
--- /dev/null
+++ b/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.ReflectionServiceUtilActivateDeactivateTest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<components xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0">
+  <scr:component name="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilActivateDeactivateTest$Service1" activate="activate" deactivate="deactivate">
+    <implementation class="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilActivateDeactivateTest$Service1"/>
+  </scr:component>
+  <scr:component name="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilActivateDeactivateTest$Service2" activate="activate" deactivate="deactivate">
+    <implementation class="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilActivateDeactivateTest$Service2"/>
+  </scr:component>
+  <scr:component name="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilActivateDeactivateTest$Service3" activate="activate" deactivate="deactivate">
+    <implementation class="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilActivateDeactivateTest$Service3"/>
+  </scr:component>
+  <scr:component name="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilActivateDeactivateTest$Service4" activate="activate" deactivate="deactivate">
+    <implementation class="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilActivateDeactivateTest$Service4"/>
+  </scr:component>
+  <scr:component name="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilActivateDeactivateTest$Service5" activate="activate" deactivate="deactivate">
+    <implementation class="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilActivateDeactivateTest$Service5"/>
+  </scr:component>
+  <scr:component name="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilActivateDeactivateTest$Service6" activate="activate" deactivate="deactivate">
+    <implementation class="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilActivateDeactivateTest$Service6"/>
+  </scr:component>
+</components>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 22/23: [maven-release-plugin] prepare release org.apache.sling.testing.osgi-mock-1.1.0

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit d7f336c28bf19baaf0bdca55489ba6b282e5ef7f
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Tue Dec 9 23:02:06 2014 +0000

    [maven-release-plugin] prepare release org.apache.sling.testing.osgi-mock-1.1.0
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1644221 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/pom.xml b/pom.xml
index 97b4b77..b37d460 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@
     </parent>
 
     <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
-    <version>1.0.1-SNAPSHOT</version>
+    <version>1.1.0</version>
     <packaging>bundle</packaging>
 
     <name>Apache Sling Testing OSGi Mock</name>
@@ -39,9 +39,9 @@
     </properties>
 
     <scm>
-        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock</connection>
-        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock</developerConnection>
-        <url>http://svn.apache.org/viewvc/sling/trunk/testing/mocks/osgi-mock</url>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/tags/org.apache.sling.testing.osgi-mock-1.1.0</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.testing.osgi-mock-1.1.0</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/tags/org.apache.sling.testing.osgi-mock-1.1.0</url>
     </scm>
 
     <dependencies>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 04/23: SLING-4042 add missing package-info files

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit ad838b20b9d7dacb3376d7941d3e3842803219af
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Mon Oct 13 15:27:41 2014 +0000

    SLING-4042 add missing package-info files
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1631438 13f79535-47bb-0310-9956-ffa450edef68
---
 .../java/org/apache/sling/testing/mock/osgi/package-info.java            | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/package-info.java b/src/main/java/org/apache/sling/testing/mock/osgi/package-info.java
similarity index 99%
rename from src/test/java/org/apache/sling/testing/mock/osgi/package-info.java
rename to src/main/java/org/apache/sling/testing/mock/osgi/package-info.java
index 9c9ff28..4cf91fe 100644
--- a/src/test/java/org/apache/sling/testing/mock/osgi/package-info.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/package-info.java
@@ -20,4 +20,3 @@
  * Mock implementation of selected OSGi APIs.
  */
 package org.apache.sling.testing.mock.osgi;
-

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 21/23: fix some javadoc errors/warnings

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 70f54471b3a54799794ad348de75483c80ca7844
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Tue Dec 9 23:01:37 2014 +0000

    fix some javadoc errors/warnings
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1644220 13f79535-47bb-0310-9956-ffa450edef68
---
 .../java/org/apache/sling/testing/mock/osgi/junit/OsgiContext.java     | 1 -
 .../org/apache/sling/testing/mock/osgi/junit/OsgiContextCallback.java  | 3 +--
 2 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContext.java b/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContext.java
index 652298b..a3c4201 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContext.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContext.java
@@ -58,7 +58,6 @@ public final class OsgiContext extends OsgiContextImpl implements TestRule {
      * @param tearDownCallback Allows the application to register an own
      *            callback function that is called before the built-in teardown
      *            rules are executed.
-     * @param resourceResolverType Resource resolver type.
      */
     public OsgiContext(final OsgiContextCallback setUpCallback, final OsgiContextCallback tearDownCallback) {
 
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextCallback.java b/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextCallback.java
index c6a77ff..a283f38 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextCallback.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextCallback.java
@@ -29,8 +29,7 @@ public interface OsgiContextCallback {
     /**
      * Execute callback action
      * @param context OSGi context
-     * @throws IOException
-     * @throws PersistenceException
+     * @throws IOException I/O exception
      */
     void execute(OsgiContext context) throws IOException;
 

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 05/23: SLING-4042 make sure dependency injection is continued even if not all injections succeeded, and report root cause of invocation target exceptions

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 740687dbd680c91d78b0d7147adbd0a8c1cef1f1
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Thu Oct 16 16:10:16 2014 +0000

    SLING-4042 make sure dependency injection is continued even if not all injections succeeded, and report root cause of invocation target exceptions
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1632374 13f79535-47bb-0310-9956-ffa450edef68
---
 .../apache/sling/testing/mock/osgi/ReflectionServiceUtil.java | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java b/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
index aa338a3..fe363ab 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
@@ -85,7 +85,7 @@ final class ReflectionServiceUtil {
                         + targetClass.getName(), ex);
             } catch (InvocationTargetException ex) {
                 throw new RuntimeException("Unable to invoke activate/deactivate method for class "
-                        + targetClass.getName(), ex);
+                        + targetClass.getName(), ex.getCause());
             }
         }
         log.warn("Method {}(ComponentContext) not found in class {}", methodName, targetClass.getName());
@@ -119,7 +119,8 @@ final class ReflectionServiceUtil {
         // try to inject services
         boolean allInjected = true;
         for (Reference reference : references) {
-            allInjected = allInjected && injectServiceReference(reference, target, bundleContext);
+            boolean injectSuccess = injectServiceReference(reference, target, bundleContext);
+            allInjected = allInjected && injectSuccess;
         }
         return allInjected;
     }
@@ -179,7 +180,7 @@ final class ReflectionServiceUtil {
                                 + targetClass.getName(), ex);
                     } catch (InvocationTargetException ex) {
                         throw new RuntimeException("Unable to invoke method " + bindMethodName + " for class "
-                                + targetClass.getName(), ex);
+                                + targetClass.getName(), ex.getCause());
                     }
                 }
                 return true;
@@ -200,7 +201,7 @@ final class ReflectionServiceUtil {
                                     + targetClass.getName(), ex);
                         } catch (InvocationTargetException ex) {
                             throw new RuntimeException("Unable to invoke method " + bindMethodName + " for class "
-                                    + targetClass.getName(), ex);
+                                    + targetClass.getName(), ex.getCause());
                         }
                     }
                     return true;
@@ -221,7 +222,7 @@ final class ReflectionServiceUtil {
                                             + " for class " + targetClass.getName(), ex);
                                 } catch (InvocationTargetException ex) {
                                     throw new RuntimeException("Unable to invoke method " + bindMethodName
-                                            + " for class " + targetClass.getName(), ex);
+                                            + " for class " + targetClass.getName(), ex.getCause());
                                 }
                             }
                         }

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 10/23: SLING-4090 Define package versions for Sling Mock, JCR Mock, OSGi Mock

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 0a80e0cb30c4f421f4686f1c168f210027f18e59
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Wed Oct 22 20:40:31 2014 +0000

    SLING-4090 Define package versions for Sling Mock, JCR Mock, OSGi Mock
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1633717 13f79535-47bb-0310-9956-ffa450edef68
---
 src/main/java/org/apache/sling/testing/mock/osgi/package-info.java | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/package-info.java b/src/main/java/org/apache/sling/testing/mock/osgi/package-info.java
index 4cf91fe..7682059 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/package-info.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/package-info.java
@@ -19,4 +19,5 @@
 /**
  * Mock implementation of selected OSGi APIs.
  */
+@aQute.bnd.annotation.Version("1.0")
 package org.apache.sling.testing.mock.osgi;

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 07/23: add/update SCM urls

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 21a51520e87264607eac914fa60f457876d7d06f
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Fri Oct 17 08:10:43 2014 +0000

    add/update SCM urls
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1632490 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/pom.xml b/pom.xml
index b4060c4..4083ee6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -38,6 +38,12 @@
         <sling.java.version>6</sling.java.version>
     </properties>
 
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/trunk/testing/mocks/osgi-mock</url>
+    </scm>
+
     <dependencies>
   
         <dependency>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 15/23: fix some javadoc copy&paste errors and formatting

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit abe8b215743cded198e6befe2c695d8387c340cd
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Fri Nov 14 16:40:48 2014 +0000

    fix some javadoc copy&paste errors and formatting
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1639694 13f79535-47bb-0310-9956-ffa450edef68
---
 .../apache/sling/testing/mock/osgi/MockOsgi.java   | 51 ++++++++--------------
 1 file changed, 17 insertions(+), 34 deletions(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java
index fd65fe1..bffb7b3 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java
@@ -128,12 +128,10 @@ public final class MockOsgi {
     }
 
     /**
-     * Simulate activation of service instance. Invokes the @Activate annotated
-     * method.
+     * Simulate activation of service instance. Invokes the @Activate annotated method.
      * @param target Service instance.
      * @param properties Properties
-     * @return true if activation method was called. False if such a method did
-     *         not exist.
+     * @return true if activation method was called. False if it failed.
      */
     public static boolean activate(Object target, Dictionary<String, Object> properties) {
         ComponentContext componentContext = newComponentContext(properties);
@@ -141,12 +139,10 @@ public final class MockOsgi {
     }
 
     /**
-     * Simulate activation of service instance. Invokes the @Activate annotated
-     * method.
+     * Simulate activation of service instance. Invokes the @Activate annotated method.
      * @param target Service instance.
      * @param properties Properties
-     * @return true if activation method was called. False if such a method did
-     *         not exist.
+     * @return true if activation method was called. False if it failed.
      */
     public static boolean activate(Object target, Map<String, Object> properties) {
         return activate(target, toDictionary(properties));
@@ -158,8 +154,7 @@ public final class MockOsgi {
      * @param target Service instance.
      * @param bundleContext Bundle context
      * @param properties Properties
-     * @return true if activation method was called. False if such a method did
-     *         not exist.
+     * @return true if activation method was called. False if it failed.
      */
     public static boolean activate(Object target, BundleContext bundleContext, Dictionary<String, Object> properties) {
         ComponentContext componentContext = newComponentContext(bundleContext, properties);
@@ -167,24 +162,20 @@ public final class MockOsgi {
     }
 
     /**
-     * Simulate activation of service instance. Invokes the @Activate annotated
-     * method.
+     * Simulate activation of service instance. Invokes the @Activate annotated method.
      * @param target Service instance.
      * @param bundleContext Bundle context
      * @param properties Properties
-     * @return true if activation method was called. False if such a method did
-     *         not exist.
+     * @return true if activation method was called. False if it failed.
      */
     public static boolean activate(Object target, BundleContext bundleContext, Map<String, Object> properties) {
         return activate(target, bundleContext, toDictionary(properties));
     }
 
     /**
-     * Simulate deactivation of service instance. Invokes the @Activate
-     * annotated method.
+     * Simulate deactivation of service instance. Invokes the @Deactivate annotated method.
      * @param target Service instance.
-     * @return true if deactivation method was called. False if such a method
-     *         did not exist.
+     * @return true if deactivation method was called. False if it failed.
      */
     public static boolean deactivate(Object target) {
         ComponentContext componentContext = newComponentContext();
@@ -192,12 +183,10 @@ public final class MockOsgi {
     }
 
     /**
-     * Simulate deactivation of service instance. Invokes the @Activate
-     * annotated method.
+     * Simulate deactivation of service instance. Invokes the @Deactivate annotated method.
      * @param target Service instance.
      * @param properties Properties
-     * @return true if deactivation method was called. False if such a method
-     *         did not exist.
+     * @return true if deactivation method was called. False if it failed.
      */
     public static boolean deactivate(Object target, Dictionary<String, Object> properties) {
         ComponentContext componentContext = newComponentContext(properties);
@@ -205,25 +194,21 @@ public final class MockOsgi {
     }
 
     /**
-     * Simulate deactivation of service instance. Invokes the @Activate
-     * annotated method.
+     * Simulate deactivation of service instance. Invokes the @Deactivate annotated method.
      * @param target Service instance.
      * @param properties Properties
-     * @return true if deactivation method was called. False if such a method
-     *         did not exist.
+     * @return true if deactivation method was called. False if it failed.
      */
     public static boolean deactivate(Object target, Map<String, Object> properties) {
         return deactivate(target, toDictionary(properties));
     }
 
     /**
-     * Simulate deactivation of service instance. Invokes the @Activate
-     * annotated method.
+     * Simulate deactivation of service instance. Invokes the @Deactivate annotated method.
      * @param target Service instance.
      * @param bundleContext Bundle context
      * @param properties Properties
-     * @return true if deactivation method was called. False if such a method
-     *         did not exist.
+     * @return true if deactivation method was called. False if it failed.
      */
     public static boolean deactivate(Object target, BundleContext bundleContext, Dictionary<String, Object> properties) {
         ComponentContext componentContext = newComponentContext(bundleContext, properties);
@@ -231,13 +216,11 @@ public final class MockOsgi {
     }
 
     /**
-     * Simulate activation of service instance. Invokes the @Activate annotated
-     * method.
+     * Simulate activation of service instance. Invokes the @Deactivate annotated method.
      * @param target Service instance.
      * @param bundleContext Bundle context
      * @param properties Properties
-     * @return true if activation method was called. False if such a method did
-     *         not exist.
+     * @return true if activation method was called. False if it failed.
      */
     public static boolean deactivate(Object target, BundleContext bundleContext, Map<String, Object> properties) {
         return deactivate(target, bundleContext, toDictionary(properties));

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.