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:20:50 UTC

[sling-org-apache-sling-testing-osgi-mock] 02/10: SLING-5324 osgi-mock: Support OSGi R6 field-based reference bindings

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-2.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 3f5a1729ed9dcc5b10affea05320b3f0f9d91612
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Mon Nov 23 23:45:50 2015 +0000

    SLING-5324 osgi-mock: Support OSGi R6 field-based reference bindings
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1715990 13f79535-47bb-0310-9956-ffa450edef68
---
 .../sling/testing/mock/osgi/OsgiMetadataUtil.java  | 108 +++++++++++++
 .../sling/testing/mock/osgi/OsgiServiceUtil.java   | 173 +++++++++++++++++++--
 ...ockBundleContextDynamicReferncesOsgiR6Test.java | 169 ++++++++++++++++++++
 .../testing/mock/osgi/OsgiServiceUtilTest.java     |  56 +++++++
 ...sling.testing.mock.osgi.OsgiServiceUtilTest.xml |   8 +
 5 files changed, 500 insertions(+), 14 deletions(-)

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 7c3db48..85db326 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
@@ -386,8 +386,11 @@ final class OsgiMetadataUtil {
         private final String interfaceType;
         private final ReferenceCardinality cardinality;
         private final ReferencePolicy policy;
+        private final ReferencePolicyOption policyOption;
         private final String bind;
         private final String unbind;
+        private final String field;
+        private final FieldCollectionType fieldCollectionType;
 
         private Reference(Class<?> clazz, Node node) {
             this.clazz = clazz;
@@ -395,8 +398,11 @@ final class OsgiMetadataUtil {
             this.interfaceType = getAttributeValue(node, "interface");
             this.cardinality = toCardinality(getAttributeValue(node, "cardinality"));
             this.policy = toPolicy(getAttributeValue(node, "policy"));
+            this.policyOption = toPolicyOption(getAttributeValue(node, "policy-option"));
             this.bind = getAttributeValue(node, "bind");
             this.unbind = getAttributeValue(node, "unbind");
+            this.field = getAttributeValue(node, "field");
+            this.fieldCollectionType = toFieldCollectionType(getAttributeValue(node, "field-collection-type"));
         }
 
         public Class<?> getServiceClass() {
@@ -411,14 +417,31 @@ final class OsgiMetadataUtil {
             return this.interfaceType;
         }
 
+        public Class getInterfaceTypeAsClass() {
+            try {
+                return Class.forName(getInterfaceType());
+            } catch (ClassNotFoundException e) {
+                throw new RuntimeException("Service reference type not found: " + getInterfaceType());
+            }
+        }
+
         public ReferenceCardinality getCardinality() {
             return this.cardinality;
         }
+        
+        public boolean isCardinalityMultiple() {
+            return this.cardinality == ReferenceCardinality.OPTIONAL_MULTIPLE
+                    || this.cardinality == ReferenceCardinality.MANDATORY_MULTIPLE;
+        }
 
         public ReferencePolicy getPolicy() {
             return policy;
         }
 
+        public ReferencePolicyOption getPolicyOption() {
+            return policyOption;
+        }
+
         public String getBind() {
             return this.bind;
         }
@@ -427,6 +450,14 @@ final class OsgiMetadataUtil {
             return this.unbind;
         }
 
+        public String getField() {
+            return this.field;
+        }
+        
+        public FieldCollectionType getFieldCollectionType() {
+            return this.fieldCollectionType;
+        }
+
         private static ReferenceCardinality toCardinality(String value) {
             for (ReferenceCardinality item : ReferenceCardinality.values()) {
                 if (StringUtils.equals(item.getCardinalityString(), value)) {
@@ -445,6 +476,24 @@ final class OsgiMetadataUtil {
             return ReferencePolicy.STATIC;
         }
 
+        private static ReferencePolicyOption toPolicyOption(String value) {
+            for (ReferencePolicyOption item : ReferencePolicyOption.values()) {
+                if (StringUtils.equalsIgnoreCase(item.name(), value)) {
+                    return item;
+                }
+            }
+            return ReferencePolicyOption.RELUCTANT;
+        }
+
+        private static FieldCollectionType toFieldCollectionType(String value) {
+            for (FieldCollectionType item : FieldCollectionType.values()) {
+                if (StringUtils.equalsIgnoreCase(item.name(), value)) {
+                    return item;
+                }
+            }
+            return null;
+        }
+
     }
 
 
@@ -513,4 +562,63 @@ final class OsgiMetadataUtil {
         DYNAMIC;
     }
 
+
+    /**
+     * Options for {@link Reference#policyOption()} property.
+     */
+    enum ReferencePolicyOption {
+
+        /**
+         * The reluctant policy option is the default policy option.
+         * When a new target service for a reference becomes available,
+         * references having the reluctant policy option for the static
+         * policy or the dynamic policy with a unary cardinality will
+         * ignore the new target service. References having the dynamic
+         * policy with a multiple cardinality will bind the new
+         * target service
+         */
+        RELUCTANT,
+
+        /**
+         * When a new target service for a reference becomes available,
+         * references having the greedy policy option will bind the new
+         * target service.
+         */
+        GREEDY;
+    }
+
+    /**
+     * Options for {@link Reference#policyOption()} property.
+     */
+    enum FieldCollectionType {
+
+        /**
+         * The bound service object. This is the default field collection type.
+         */
+        SERVICE,
+
+        /**
+         * A Service Reference for the bound service.
+         */
+        REFERENCE,
+
+        /**
+         * A Component Service Objects for the bound service.
+         */
+        SERVICEOBJECTS,
+
+        /**
+         * An unmodifiable Map containing the service properties of the bound service.
+         * This Map must implement Comparable.
+         */
+        PROPERTIES,
+
+        /**
+         * An unmodifiable Map.Entry whose key is an unmodifiable Map containing the 
+         * service properties of the bound service, as above, and whose value is the 
+         * bound service object. This Map.Entry must implement Comparable.
+         */
+        TUPLE;
+    }
+
 }
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java b/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java
index 84ccbf8..1f8eaa0 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java
@@ -18,10 +18,12 @@
  */
 package org.apache.sling.testing.mock.osgi;
 
+import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -29,6 +31,7 @@ import java.util.SortedSet;
 
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.FieldCollectionType;
 import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.OsgiMetadata;
 import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.Reference;
 import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.ReferenceCardinality;
@@ -262,6 +265,49 @@ final class OsgiServiceUtil {
         }
     }
 
+    private static Field getField(Class clazz, String fieldName, Class<?> type) {
+        Field[] fields = clazz.getDeclaredFields();
+        for (Field field : fields) {
+            if (StringUtils.equals(field.getName(), fieldName) && field.getType().equals(type)) {
+                return field;
+            }
+        }
+        // not found? check super classes
+        Class<?> superClass = clazz.getSuperclass();
+        if (superClass != null && superClass != Object.class) {
+            return getField(superClass, fieldName, type);
+        }
+        return null;
+    }
+    
+    private static Field getFieldWithAssignableType(Class clazz, String fieldName, Class<?> type) {
+        Field[] fields = clazz.getDeclaredFields();
+        for (Field field : fields) {
+            if (StringUtils.equals(field.getName(), fieldName) && field.getType().isAssignableFrom(type)) {
+                return field;
+            }
+        }
+        // not found? check super classes
+        Class<?> superClass = clazz.getSuperclass();
+        if (superClass != null && superClass != Object.class) {
+            return getFieldWithAssignableType(superClass, fieldName, type);
+        }
+        return null;
+    }
+    
+    private static void setField(Object target, Field field, Object value) {
+        try {
+            field.setAccessible(true);
+            field.set(target, value);
+        } catch (IllegalAccessException ex) {
+            throw new RuntimeException("Unable to set field '" + field.getName() + "' for class "
+                    + target.getClass().getName(), ex);
+        } catch (IllegalArgumentException ex) {
+            throw new RuntimeException("Unable to set field '" + field.getName() + "' for class "
+                    + target.getClass().getName(), ex);
+        }
+    }
+    
     /**
      * Simulate OSGi service dependency injection. Injects direct references and
      * multiple references.
@@ -294,12 +340,7 @@ final class OsgiServiceUtil {
         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);
-        }
+        Class<?> type = reference.getInterfaceTypeAsClass();
 
         // get matching service references
         List<ServiceInfo> matchingServices = getMatchingServices(type, bundleContext);
@@ -330,6 +371,13 @@ final class OsgiServiceUtil {
 
         // try to invoke bind method
         String methodName = bind ? reference.getBind() : reference.getUnbind();
+        String fieldName = reference.getField();
+        
+        if (StringUtils.isEmpty(methodName) && StringUtils.isEmpty(fieldName)) {
+            throw new RuntimeException("No bind/unbind method name or file name defined "
+                    + "for reference '" + reference.getName() + "' for class " +  targetClass.getName());
+        }
+
         if (StringUtils.isNotEmpty(methodName)) {
             
             // 1. ServiceReference
@@ -340,12 +388,7 @@ final class OsgiServiceUtil {
             }
             
             // 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());
-            }
+            Class<?> interfaceType = reference.getInterfaceTypeAsClass();
             method = getMethodWithAssignableTypes(targetClass, methodName, new Class<?>[] { interfaceType });
             if (method != null) {
                 invokeMethod(target, method, new Object[] { serviceInfo.getServiceInstance() });
@@ -358,10 +401,112 @@ final class OsgiServiceUtil {
                 invokeMethod(target, method, new Object[] { serviceInfo.getServiceInstance(), serviceInfo.getServiceConfig() });
                 return;
             }
+        
+            throw new RuntimeException((bind ? "Bind" : "Unbind") + " method with name " + methodName + " not found "
+                    + "for reference '" + reference.getName() + "' for class " +  targetClass.getName());
+        }
+        
+        // in OSGi declarative services 1.3 there are no bind/unbind methods - modify the field directly
+        else if (StringUtils.isNotEmpty(fieldName)) {
+            
+            // check for field with list/collection reference
+            if (reference.isCardinalityMultiple()) {
+                switch (reference.getFieldCollectionType()) {
+                    case SERVICE:
+                    case REFERENCE:
+                        Object item = serviceInfo.getServiceInstance();
+                        if (reference.getFieldCollectionType() == FieldCollectionType.REFERENCE) {
+                            item = serviceInfo.getServiceReference();
+                        }
+                        // 1. collection
+                        Field field = getFieldWithAssignableType(targetClass, fieldName, Collection.class);
+                        if (field != null) {
+                            if (bind) {
+                                addToCollection(target, field, item);
+                            }
+                            else {
+                                removeFromCollection(target, field, item);
+                            }
+                            return;
+                        }
+                        
+                        // 2. list
+                        field = getField(targetClass, fieldName, List.class);
+                        if (field != null) {
+                            if (bind) {
+                                addToCollection(target, field, item);
+                            }
+                            else {
+                                removeFromCollection(target, field, item);
+                            }
+                            return;
+                        }
+                        break;
+                    default:
+                        throw new RuntimeException("Field collection type '" + reference.getFieldCollectionType() + "' not supported "
+                                + "for reference '" + reference.getName() + "' for class " +  targetClass.getName());
+                }
+            }
+            
+            // check for single field reference
+            else {
+                // 1. assignable from service instance
+                Class<?> interfaceType = reference.getInterfaceTypeAsClass();
+                Field field = getFieldWithAssignableType(targetClass, fieldName, interfaceType);
+                if (field != null) {
+                    setField(target, field, bind ? serviceInfo.getServiceInstance() : null);
+                    return;
+                }
+                
+                // 2. ServiceReference
+                field = getField(targetClass, fieldName, ServiceReference.class);
+                if (field != null) {
+                    setField(target, field, bind ? serviceInfo.getServiceReference() : null);
+                    return;
+                }
+            }
         }
 
-        throw new RuntimeException((bind ? "Bind" : "Unbind") + " method with name " + methodName + " not found "
-                + "for reference '" + reference.getName() + "' for class " +  targetClass.getName());
+    }
+    
+    @SuppressWarnings("unchecked")
+    private static void addToCollection(Object target, Field field, Object item) {
+        try {
+            field.setAccessible(true);
+            Collection<Object> collection = (Collection<Object>)field.get(target);
+            if (collection == null) {
+                collection = new ArrayList<>();
+            }
+            collection.add(item);
+            field.set(target, collection);
+            
+        } catch (IllegalAccessException ex) {
+            throw new RuntimeException("Unable to set field '" + field.getName() + "' for class "
+                    + target.getClass().getName(), ex);
+        } catch (IllegalArgumentException ex) {
+            throw new RuntimeException("Unable to set field '" + field.getName() + "' for class "
+                    + target.getClass().getName(), ex);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private static void removeFromCollection(Object target, Field field, Object item) {
+        try {
+            field.setAccessible(true);
+            Collection<Object> collection = (Collection<Object>)field.get(target);
+            if (collection == null) {
+                return;
+            }
+            collection.remove(item);
+            field.set(target, collection);
+            
+        } catch (IllegalAccessException ex) {
+            throw new RuntimeException("Unable to set field '" + field.getName() + "' for class "
+                    + target.getClass().getName(), ex);
+        } catch (IllegalArgumentException ex) {
+            throw new RuntimeException("Unable to set field '" + field.getName() + "' for class "
+                    + target.getClass().getName(), ex);
+        }
     }
 
     /**
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextDynamicReferncesOsgiR6Test.java b/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextDynamicReferncesOsgiR6Test.java
new file mode 100644
index 0000000..0af80e9
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextDynamicReferncesOsgiR6Test.java
@@ -0,0 +1,169 @@
+/*
+ * 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.assertNull;
+import static org.junit.Assert.assertSame;
+
+import org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest.Service3OsgiR6;
+import org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest.ServiceInterface1;
+import org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest.ServiceInterface1Optional;
+import org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest.ServiceInterface2;
+import org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest.ServiceInterface3;
+import org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest.ServiceSuperInterface3;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+import com.google.common.collect.ImmutableSet;
+
+@RunWith(MockitoJUnitRunner.class)
+public class MockBundleContextDynamicReferncesOsgiR6Test {
+
+    private BundleContext bundleContext;
+    private Service3OsgiR6 service;
+    private ServiceRegistration reg1a;
+    private ServiceRegistration reg2a;
+    
+    @Mock
+    private ServiceInterface1 dependency1a;
+    @Mock
+    private ServiceInterface1 dependency1b;
+    @Mock
+    private ServiceInterface1Optional dependency1aOptional;
+    @Mock
+    private ServiceInterface1Optional dependency1bOptional;
+    @Mock
+    private ServiceInterface2 dependency2a;
+    @Mock
+    private ServiceInterface2 dependency2b;
+    @Mock
+    private ServiceSuperInterface3 dependency3a;
+    @Mock
+    private ServiceSuperInterface3 dependency3b;
+
+    @Before
+    public void setUp() {
+        bundleContext = MockOsgi.newBundleContext();
+        
+        // setup service instance with only minimum mandatory references
+        reg1a = bundleContext.registerService(ServiceInterface1.class.getName(), dependency1a, null);
+        reg2a = bundleContext.registerService(ServiceInterface2.class.getName(), dependency2a, null);
+        
+        service = new Service3OsgiR6();
+        MockOsgi.injectServices(service, bundleContext);
+        MockOsgi.activate(service, bundleContext);
+        bundleContext.registerService(Service3OsgiR6.class.getName(), service, null);
+        
+        assertDependency1(dependency1a);
+        assertDependency1Optional(null);
+        assertDependencies2(dependency2a);
+        assertDependencies3();
+    }
+
+    @Test
+    public void testAddRemoveOptionalUnaryService() {
+        ServiceRegistration reg1aOptional = bundleContext.registerService(ServiceInterface1Optional.class.getName(), dependency1aOptional, null);
+        assertDependency1Optional(dependency1aOptional);
+        
+        reg1aOptional.unregister();
+        assertDependency1Optional(null);
+    }
+    
+    public void testAddOptionalUnaryService_TooMany() {
+        bundleContext.registerService(ServiceInterface1Optional.class.getName(), dependency1aOptional, null);
+        assertDependency1Optional(dependency1aOptional);
+        
+        // in real OSGi this should fail - but this is not covered by the current implementation. so test the real implementation here.
+        bundleContext.registerService(ServiceInterface1Optional.class.getName(), dependency1bOptional, null);
+        assertDependency1Optional(dependency1bOptional);
+    }
+    
+    @Test(expected = ReferenceViolationException.class)
+    public void testAddMandatoryUnaryService_TooMany() {
+        bundleContext.registerService(ServiceInterface1.class.getName(), dependency1b, null);
+    }
+    
+    @Test(expected = ReferenceViolationException.class)
+    public void testRemoveMandatoryUnaryService_TooMany() {
+        reg1a.unregister();
+    }
+    
+    @Test
+    public void testAddRemoveOptionalMultipleService() {
+        ServiceRegistration reg3a = bundleContext.registerService(ServiceInterface3.class.getName(), dependency3a, null);
+        assertDependencies3(dependency3a);
+
+        ServiceRegistration reg3b = bundleContext.registerService(ServiceInterface3.class.getName(), dependency3b, null);
+        assertDependencies3(dependency3a, dependency3b);
+
+        reg3a.unregister();
+        assertDependencies3(dependency3b);
+        
+        reg3b.unregister();
+        assertDependencies3();
+    }
+    
+    @Test
+    public void testAddRemoveMandatoryMultipleService() {
+        ServiceRegistration reg2b = bundleContext.registerService(ServiceInterface2.class.getName(), dependency2b, null);
+        assertDependencies2(dependency2a, dependency2b);
+
+        reg2b.unregister();
+        assertDependencies2(dependency2a);
+        
+        // in real OSGi this should fail - but this is not covered by the current implementation. so test the real implementation here.
+        reg2a.unregister();
+        assertDependencies2();
+    }
+    
+    private void assertDependency1(ServiceInterface1 instance) {
+        if (instance == null) {
+            assertNull(service.getReference1());
+        }
+        else {
+            assertSame(instance, service.getReference1());
+        }
+    }
+    
+    private void assertDependency1Optional(ServiceInterface1Optional instance) {
+        if (instance == null) {
+            assertNull(service.getReference1Optional());
+        }
+        else {
+            assertSame(instance, service.getReference1Optional());
+        }
+    }
+    
+    private void assertDependencies2(ServiceInterface2... instances) {
+        assertEquals(ImmutableSet.<ServiceInterface2>copyOf(instances), 
+                ImmutableSet.<ServiceInterface2>copyOf(service.getReferences2()));
+    }
+    
+    private void assertDependencies3(ServiceSuperInterface3... instances) {
+        assertEquals(ImmutableSet.<ServiceSuperInterface3>copyOf(instances), 
+                ImmutableSet.<ServiceSuperInterface3>copyOf(service.getReferences3()));
+    }
+    
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtilTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtilTest.java
index 170957f..9135bcf 100644
--- a/src/test/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtilTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtilTest.java
@@ -335,6 +335,62 @@ public class OsgiServiceUtilTest {
 
     }
 
+    public static class Service3OsgiR6 {
+
+        private ServiceInterface1 reference1;
+        private ServiceInterface1Optional reference1Optional;
+        private List<ServiceReference> references2 = new ArrayList<ServiceReference>();
+        private List<ServiceSuperInterface3> references3 = new ArrayList<ServiceSuperInterface3>();
+
+        private ComponentContext componentContext;
+        private Map<String, Object> config;
+
+        @Activate
+        private void activate(ComponentContext ctx) {
+            this.componentContext = ctx;
+            this.config = MapUtil.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;
+        }
+
+        public ServiceInterface1Optional getReference1Optional() {
+            return this.reference1Optional;
+        }
+
+        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<ServiceSuperInterface3> getReferences3() {
+            return this.references3;
+        }
+
+        public ComponentContext getComponentContext() {
+            return this.componentContext;
+        }
+
+        public Map<String, Object> getConfig() {
+            return config;
+        }
+
+    }
+
     @Component
     @Reference(referenceInterface = ServiceInterface1.class, name = "customName", bind = "customBind", unbind = "customUnbind")
     public static class Service4 {
diff --git a/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest.xml b/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest.xml
index a9d3623..94602cc 100644
--- a/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest.xml
+++ b/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest.xml
@@ -43,6 +43,14 @@
     <reference name="reference2" interface="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$ServiceInterface2" cardinality="1..n" policy="dynamic" bind="bindReference2" unbind="unbindReference2"/>
     <reference name="reference3" interface="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$ServiceInterface3" cardinality="0..n" policy="dynamic" bind="bindReference3" unbind="unbindReference3"/>
   </scr:component>
+  <scr:component name="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$Service3OsgiR6" activate="activate" deactivate="deactivate" modified="modified">
+    <implementation class="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$Service3OsgiR6"/>
+    <property name="service.pid" value="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$Service3OsgiR6"/>
+    <reference name="reference1" interface="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$ServiceInterface1" cardinality="1..1" policy="dynamic" field="reference1"/>
+    <reference name="reference1Optional" interface="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$ServiceInterface1Optional" cardinality="0..1" policy="dynamic" field="reference1Optional"/>
+    <reference name="reference2" interface="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$ServiceInterface2" cardinality="1..n" policy="dynamic" field="references2" field-collection-type="reference"/>
+    <reference name="reference3" interface="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$ServiceInterface3" cardinality="0..n" policy="dynamic" field="references3" field-collection-type="service"/>
+  </scr:component>
   <scr:component name="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$Service4_other_name">
     <implementation class="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$Service4"/>
     <property name="service.pid" value="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$Service4"/>

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