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:33 UTC

[sling-org-apache-sling-testing-osgi-mock] 05/07: SLING-6372 OSGi Mocks - Correctly handle static, greedy references

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

commit 3253df9cd1fa8e6641aad78b78bd706c3fb3511c
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Fri Dec 9 22:30:56 2016 +0000

    SLING-6372 OSGi Mocks - Correctly handle static, greedy references
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/branches/testing/mocks/osgi-mock-1.x@1773480 13f79535-47bb-0310-9956-ffa450edef68
---
 .../sling/testing/mock/osgi/MockBundleContext.java |  76 ++++++++-
 .../sling/testing/mock/osgi/OsgiServiceUtil.java   |  31 +++-
 ...ockBundleContextStaticGreedyReferencesTest.java | 186 +++++++++++++++++++++
 .../testing/mock/osgi/OsgiServiceUtilTest.java     | 103 ++++++++++++
 ...sling.testing.mock.osgi.OsgiServiceUtilTest.xml |   8 +
 5 files changed, 398 insertions(+), 6 deletions(-)

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
index ce94c04..ea0808a 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/MockBundleContext.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockBundleContext.java
@@ -111,8 +111,8 @@ class MockBundleContext implements BundleContext {
     public ServiceRegistration registerService(final String[] clazzes, final Object service, final Dictionary properties) {
         Dictionary<String, Object> mergedPropertes = MapMergeUtil.propertiesMergeWithOsgiMetadata(service, configAdmin, properties);
         MockServiceRegistration registration = new MockServiceRegistration(this.bundle, clazzes, service, mergedPropertes, this);
-        handleRefsUpdateOnRegister(registration);
         this.registeredServices.add(registration);
+        handleRefsUpdateOnRegister(registration);
         notifyServiceListeners(ServiceEvent.REGISTERED, registration.getReference());
         return registration;
     }
@@ -123,8 +123,10 @@ class MockBundleContext implements BundleContext {
      * @param registration
      */
     private void handleRefsUpdateOnRegister(MockServiceRegistration registration) {
-        List<ReferenceInfo> affectedReferences = OsgiServiceUtil.getMatchingDynamicReferences(registeredServices, registration);
-        for (ReferenceInfo referenceInfo : affectedReferences) {
+        
+        // handle DYNAMIC references to this registration
+        List<ReferenceInfo> affectedDynamicReferences = OsgiServiceUtil.getMatchingDynamicReferences(registeredServices, registration);
+        for (ReferenceInfo referenceInfo : affectedDynamicReferences) {
             Reference reference = referenceInfo.getReference();
             switch (reference.getCardinality()) {
             case MANDATORY_UNARY:
@@ -140,6 +142,24 @@ class MockBundleContext implements BundleContext {
                 throw new RuntimeException("Unepxected cardinality: " + reference.getCardinality());
             }
         }
+
+        // handle STATIC+GREEDY references to this registration
+        List<ReferenceInfo> affectedStaticGreedyReferences = OsgiServiceUtil.getMatchingStaticGreedyReferences(registeredServices, registration);
+        for (ReferenceInfo referenceInfo : affectedStaticGreedyReferences) {
+            Reference reference = referenceInfo.getReference();
+            switch (reference.getCardinality()) {
+            case MANDATORY_UNARY:
+                throw new ReferenceViolationException("Mandatory unary reference of type " + reference.getInterfaceType() + " already fulfilled "
+                        + "for service " + reference.getServiceClass().getName() + ", registration of new service with this interface failed.");
+            case MANDATORY_MULTIPLE:
+            case OPTIONAL_MULTIPLE:
+            case OPTIONAL_UNARY:
+                restartService(referenceInfo.getServiceRegistration());
+                break;
+            default:
+                throw new RuntimeException("Unepxected cardinality: " + reference.getCardinality());
+            }
+        }
     }
     
     void unregisterService(MockServiceRegistration registration) {
@@ -147,6 +167,31 @@ class MockBundleContext implements BundleContext {
         handleRefsUpdateOnUnregister(registration);
         notifyServiceListeners(ServiceEvent.UNREGISTERING, registration.getReference());
     }
+    
+    void restartService(MockServiceRegistration registration) {
+        // get current service properties
+        Class<?> serviceClass = registration.getService().getClass();
+        Map<String,Object> properties = MapUtil.toMap(registration.getProperties());
+        
+        // deactivate & unregister service
+        MockOsgi.deactivate(registration.getService(), this);
+        unregisterService(registration);
+        
+        // newly create and register service
+        Object newService;
+        try {
+            newService = serviceClass.newInstance();
+        }
+        catch (InstantiationException e) {
+            throw new RuntimeException("Unable to instantiate service: " + serviceClass);
+        }
+        catch (IllegalAccessException e) {
+            throw new RuntimeException("Unable to access service class: " + serviceClass);
+        }
+        MockOsgi.injectServices(newService, this);
+        MockOsgi.activate(newService, this, properties);
+        registerService(serviceClass.getName(), newService, MapUtil.toDictionary(properties));
+    }
 
     /**
      * Check for already registered services that may be affected by the service unregistration - either
@@ -154,8 +199,10 @@ class MockBundleContext implements BundleContext {
      * @param registration
      */
     private void handleRefsUpdateOnUnregister(MockServiceRegistration registration) {
-        List<ReferenceInfo> affectedReferences = OsgiServiceUtil.getMatchingDynamicReferences(registeredServices, registration);
-        for (ReferenceInfo referenceInfo : affectedReferences) {
+
+        // handle DYNAMIC references to this registration
+        List<ReferenceInfo> affectedDynamicReferences = OsgiServiceUtil.getMatchingDynamicReferences(registeredServices, registration);
+        for (ReferenceInfo referenceInfo : affectedDynamicReferences) {
             Reference reference = referenceInfo.getReference();
             switch (reference.getCardinality()) {
             case MANDATORY_UNARY:
@@ -173,6 +220,25 @@ class MockBundleContext implements BundleContext {
                 throw new RuntimeException("Unepxected cardinality: " + reference.getCardinality());
             }
         }
+
+        // handle STATIC+GREEDY references to this registration
+        List<ReferenceInfo> affectedStaticGreedyReferences = OsgiServiceUtil.getMatchingStaticGreedyReferences(registeredServices, registration);
+        for (ReferenceInfo referenceInfo : affectedStaticGreedyReferences) {
+            Reference reference = referenceInfo.getReference();
+            switch (reference.getCardinality()) {
+            case MANDATORY_UNARY:
+                throw new ReferenceViolationException("Reference of type " + reference.getInterfaceType() + " "
+                        + "for service " + reference.getServiceClass().getName() + " is mandatory unary, "
+                        + "unregistration of service with this interface failed.");
+            case MANDATORY_MULTIPLE:
+            case OPTIONAL_MULTIPLE:
+            case OPTIONAL_UNARY:
+                restartService(referenceInfo.getServiceRegistration());
+                break;
+            default:
+                throw new RuntimeException("Unepxected cardinality: " + reference.getCardinality());
+            }
+        }
     }
     
     @Override
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 05a26bc..15340d4 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
@@ -33,6 +33,7 @@ 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;
 import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.ReferencePolicy;
+import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.ReferencePolicyOption;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
@@ -407,7 +408,8 @@ final class OsgiServiceUtil {
     }
 
     /**
-     * Collects all references of any registered service that match with any of the exported interfaces of the given service registration.
+     * Collects all references of any registered service that match with any of the exported interfaces of the given service registration
+     * and are defined as DYNAMIC.
      * @param registeredServices Registered Services
      * @param registration Service registration
      * @return List of references
@@ -432,6 +434,33 @@ final class OsgiServiceUtil {
         return references;
     }
             
+    /**
+     * Collects all references of any registered service that match with any of the exported interfaces of the given service registration
+     * and are defined as STATIC + GREEDY.
+     * @param registeredServices Registered Services
+     * @param registration Service registration
+     * @return List of references
+     */
+    public static List<ReferenceInfo> getMatchingStaticGreedyReferences(SortedSet<MockServiceRegistration> registeredServices,
+            MockServiceRegistration registration) {
+        List<ReferenceInfo> references = new ArrayList<ReferenceInfo>();
+        for (MockServiceRegistration existingRegistration : registeredServices) {
+            OsgiMetadata metadata = OsgiMetadataUtil.getMetadata(existingRegistration.getService().getClass());
+            if (metadata != null) {
+                for (Reference reference : metadata.getReferences()) {
+                    if (reference.getPolicy() == ReferencePolicy.STATIC && reference.getPolicyOption() == ReferencePolicyOption.GREEDY) {
+                        for (String serviceInterface : registration.getClasses()) {
+                            if (StringUtils.equals(serviceInterface, reference.getInterfaceType())) {
+                                references.add(new ReferenceInfo(existingRegistration, reference));
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return references;
+    }
+            
     static class ServiceInfo {
 
         private final Object serviceInstance;
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextStaticGreedyReferencesTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextStaticGreedyReferencesTest.java
new file mode 100644
index 0000000..98d31c3
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextStaticGreedyReferencesTest.java
@@ -0,0 +1,186 @@
+/*
+ * 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.Service3StaticGreedy;
+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.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+import com.google.common.collect.ImmutableSet;
+
+@RunWith(MockitoJUnitRunner.class)
+public class MockBundleContextStaticGreedyReferencesTest {
+
+    private BundleContext bundleContext;
+    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);
+        
+        Service3StaticGreedy service = new Service3StaticGreedy();
+        MockOsgi.injectServices(service, bundleContext);
+        MockOsgi.activate(service, bundleContext);
+        bundleContext.registerService(Service3StaticGreedy.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);
+    }
+    
+    @Test(expected = ReferenceViolationException.class)
+    public void testAddRemoveMandatoryMultipleService_FailReg2aUnregister() {
+        ServiceRegistration reg2b = bundleContext.registerService(ServiceInterface2.class.getName(), dependency2b, null);
+        assertDependencies2(dependency2a, dependency2b);
+
+        reg2b.unregister();
+        assertDependencies2(dependency2a);
+        
+        // this should fail
+        reg2a.unregister();
+    }
+    
+    private void assertDependency1(ServiceInterface1 instance) {
+        Service3StaticGreedy service =getService();
+        if (instance == null) {
+            assertNull(service.getReference1());
+        }
+        else {
+            assertSame(instance, service.getReference1());
+        }
+    }
+    
+    private void assertDependency1Optional(ServiceInterface1Optional instance) {
+        Service3StaticGreedy service =getService();
+        if (instance == null) {
+            assertNull(service.getReference1Optional());
+        }
+        else {
+            assertSame(instance, service.getReference1Optional());
+        }
+    }
+    
+    private void assertDependencies2(ServiceInterface2... instances) {
+        Service3StaticGreedy service =getService();
+        assertEquals(ImmutableSet.<ServiceInterface2>copyOf(instances), 
+                ImmutableSet.<ServiceInterface2>copyOf(service.getReferences2()));
+    }
+    
+    private void assertDependencies3(ServiceSuperInterface3... instances) {
+        Service3StaticGreedy service =getService();
+        assertEquals(ImmutableSet.<ServiceSuperInterface3>copyOf(instances), 
+                ImmutableSet.<ServiceSuperInterface3>copyOf(service.getReferences3()));
+    }
+    
+    private Service3StaticGreedy getService() {
+        ServiceReference serviceRef = bundleContext.getServiceReference(Service3StaticGreedy.class.getName());
+        return (Service3StaticGreedy)bundleContext.getService(serviceRef);
+    }
+    
+}
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 253b401..988cf26 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
@@ -340,6 +340,109 @@ public class OsgiServiceUtilTest {
     }
 
     @Component
+    @References({ @Reference(name = "reference2", referenceInterface = ServiceInterface2.class, cardinality = ReferenceCardinality.MANDATORY_MULTIPLE) })
+    public static class Service3StaticGreedy {
+
+        @Reference
+        private ServiceInterface1 reference1;
+        @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY)
+        private ServiceInterface1Optional reference1Optional;
+
+        private List<ServiceReference> references2 = new ArrayList<ServiceReference>();
+
+        @Reference(name = "reference3", referenceInterface = ServiceInterface3.class, cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE)
+        private List<ServiceSuperInterface3> references3 = new ArrayList<ServiceSuperInterface3>();
+        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 = 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 List<Map<String, Object>> getReference3Configs() {
+            return this.reference3Configs;
+        }
+
+        public ComponentContext getComponentContext() {
+            return this.componentContext;
+        }
+
+        public Map<String, Object> getConfig() {
+            return config;
+        }
+
+        protected void bindReference1Optional(ServiceInterface1Optional service) {
+            reference1Optional = service;
+        }
+
+        protected void unbindReference1Optional(ServiceInterface1Optional service) {
+            reference1Optional = null;
+        }
+
+        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(ServiceSuperInterface3 service, Map<String, Object> serviceConfig) {
+            references3.add(service);
+            reference3Configs.add(serviceConfig);
+        }
+
+        protected void unbindReference3(ServiceSuperInterface3 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 {
 
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..bf88df7 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$Service3StaticGreedy" activate="activate" deactivate="deactivate" modified="modified">
+    <implementation class="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$Service3StaticGreedy"/>
+    <property name="service.pid" value="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$Service3StaticGreedy"/>
+    <reference name="reference1" interface="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$ServiceInterface1" cardinality="1..1" policy="static" policy-option="greedy" bind="bindReference1" unbind="unbindReference1"/>
+    <reference name="reference1Optional" interface="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$ServiceInterface1Optional" cardinality="0..1" policy="dynamic" policy-option="greedy" bind="bindReference1Optional" unbind="unbindReference1Optional"/>
+    <reference name="reference2" interface="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$ServiceInterface2" cardinality="1..n" policy="static" policy-option="greedy" bind="bindReference2" unbind="unbindReference2"/>
+    <reference name="reference3" interface="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$ServiceInterface3" cardinality="0..n" policy="static" policy-option="greedy" bind="bindReference3" unbind="unbindReference3"/>
+  </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>.