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 bf51720f966b0a801ccb5bb87cf9284a6ad47447 Author: Stefan Seifert <[email protected]> AuthorDate: Tue Nov 24 00:36:18 2015 +0000 SLING-5325 osgi-mock: Support target filtering on DS references git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1716001 13f79535-47bb-0310-9956-ffa450edef68 --- .../sling/testing/mock/osgi/MockBundleContext.java | 56 ++++++++++++---------- .../sling/testing/mock/osgi/OsgiMetadataUtil.java | 33 +++++++++++++ .../sling/testing/mock/osgi/OsgiServiceUtil.java | 43 ++++++++++------- ...ockBundleContextDynamicReferncesOsgiR6Test.java | 19 ++++++++ .../testing/mock/osgi/OsgiServiceUtilTest.java | 9 +++- ...sling.testing.mock.osgi.OsgiServiceUtilTest.xml | 1 + 6 files changed, 115 insertions(+), 46 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 6a659cb..7ea264c 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 @@ -125,18 +125,20 @@ class MockBundleContext implements BundleContext { List<ReferenceInfo> affectedReferences = OsgiServiceUtil.getMatchingDynamicReferences(registeredServices, registration); for (ReferenceInfo referenceInfo : affectedReferences) { 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: - OsgiServiceUtil.invokeBindMethod(reference, referenceInfo.getServiceRegistration().getService(), - new ServiceInfo(registration)); - break; - default: - throw new RuntimeException("Unepxected cardinality: " + reference.getCardinality()); + if (reference.matchesTargetFilter(registration.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: + OsgiServiceUtil.invokeBindMethod(reference, referenceInfo.getServiceRegistration().getService(), + new ServiceInfo(registration)); + break; + default: + throw new RuntimeException("Unepxected cardinality: " + reference.getCardinality()); + } } } } @@ -156,20 +158,22 @@ class MockBundleContext implements BundleContext { List<ReferenceInfo> affectedReferences = OsgiServiceUtil.getMatchingDynamicReferences(registeredServices, registration); for (ReferenceInfo referenceInfo : affectedReferences) { 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: - // it is currently not checked if for a MANDATORY_MULTIPLE reference the last reference is removed - OsgiServiceUtil.invokeUnbindMethod(reference, referenceInfo.getServiceRegistration().getService(), - new ServiceInfo(registration)); - break; - default: - throw new RuntimeException("Unepxected cardinality: " + reference.getCardinality()); + if (reference.matchesTargetFilter(registration.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: + // it is currently not checked if for a MANDATORY_MULTIPLE reference the last reference is removed + OsgiServiceUtil.invokeUnbindMethod(reference, referenceInfo.getServiceRegistration().getService(), + new ServiceInfo(registration)); + break; + default: + throw new RuntimeException("Unepxected cardinality: " + reference.getCardinality()); + } } } } 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 85db326..c3ad237 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 @@ -41,6 +41,10 @@ import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.apache.commons.lang3.StringUtils; +import org.apache.felix.framework.FilterImpl; +import org.osgi.framework.Filter; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; @@ -391,6 +395,8 @@ final class OsgiMetadataUtil { private final String unbind; private final String field; private final FieldCollectionType fieldCollectionType; + private final String target; + private final Filter targetFilter; private Reference(Class<?> clazz, Node node) { this.clazz = clazz; @@ -403,6 +409,17 @@ final class OsgiMetadataUtil { this.unbind = getAttributeValue(node, "unbind"); this.field = getAttributeValue(node, "field"); this.fieldCollectionType = toFieldCollectionType(getAttributeValue(node, "field-collection-type")); + this.target = getAttributeValue(node, "target"); + if (StringUtils.isNotEmpty(this.target)) { + try { + this.targetFilter = new FilterImpl(this.target); + } catch (InvalidSyntaxException ex) { + throw new RuntimeException("Invalid target filet in reference '" + this.name + "' of class " + clazz.getName(), ex); + } + } + else { + this.targetFilter = null; + } } public Class<?> getServiceClass() { @@ -434,6 +451,11 @@ final class OsgiMetadataUtil { || this.cardinality == ReferenceCardinality.MANDATORY_MULTIPLE; } + public boolean isCardinalityOptional() { + return this.cardinality == ReferenceCardinality.OPTIONAL_UNARY + || this.cardinality == ReferenceCardinality.OPTIONAL_MULTIPLE; + } + public ReferencePolicy getPolicy() { return policy; } @@ -454,6 +476,17 @@ final class OsgiMetadataUtil { return this.field; } + public String getTarget() { + return this.target; + } + + public boolean matchesTargetFilter(ServiceReference<?> serviceReference) { + if (targetFilter == null) { + return true; + } + return targetFilter.match(serviceReference); + } + public FieldCollectionType getFieldCollectionType() { return this.fieldCollectionType; } 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 1f8eaa0..ea304d5 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 @@ -34,7 +34,6 @@ 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; import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.ReferencePolicy; import org.osgi.framework.BundleContext; import org.osgi.framework.InvalidSyntaxException; @@ -343,20 +342,21 @@ final class OsgiServiceUtil { Class<?> type = reference.getInterfaceTypeAsClass(); // get matching service references - List<ServiceInfo> matchingServices = getMatchingServices(type, bundleContext); + List<ServiceInfo> matchingServices = getMatchingServices(type, bundleContext, reference.getTarget()); // 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) { + if (!reference.isCardinalityOptional()) { throw new ReferenceViolationException("Unable to inject mandatory reference '" + reference.getName() + "' for class " + targetClass.getName() + " : no matching services were found."); } + if (reference.isCardinalityMultiple()) { + // make sure at least empty array is set + invokeBindUnbindMethod(reference, target, null, true); + } } // multiple references found? check if reference is not multiple - if (matchingServices.size() > 1 - && (reference.getCardinality() == ReferenceCardinality.MANDATORY_UNARY || reference.getCardinality() == ReferenceCardinality.OPTIONAL_UNARY)) { + if (matchingServices.size() > 1 && !reference.isCardinalityMultiple()) { throw new ReferenceViolationException("Multiple matches found for unary reference '" + reference.getName() + "' for class "+ targetClass.getName()); } @@ -378,7 +378,7 @@ final class OsgiServiceUtil { + "for reference '" + reference.getName() + "' for class " + targetClass.getName()); } - if (StringUtils.isNotEmpty(methodName)) { + if (StringUtils.isNotEmpty(methodName) && serviceInfo != null) { // 1. ServiceReference Method method = getMethod(targetClass, methodName, new Class<?>[] { ServiceReference.class }); @@ -414,9 +414,12 @@ final class OsgiServiceUtil { switch (reference.getFieldCollectionType()) { case SERVICE: case REFERENCE: - Object item = serviceInfo.getServiceInstance(); - if (reference.getFieldCollectionType() == FieldCollectionType.REFERENCE) { - item = serviceInfo.getServiceReference(); + Object item = null; + if (serviceInfo != null) { + item = serviceInfo.getServiceInstance(); + if (reference.getFieldCollectionType() == FieldCollectionType.REFERENCE) { + item = serviceInfo.getServiceReference(); + } } // 1. collection Field field = getFieldWithAssignableType(targetClass, fieldName, Collection.class); @@ -454,14 +457,14 @@ final class OsgiServiceUtil { Class<?> interfaceType = reference.getInterfaceTypeAsClass(); Field field = getFieldWithAssignableType(targetClass, fieldName, interfaceType); if (field != null) { - setField(target, field, bind ? serviceInfo.getServiceInstance() : null); + setField(target, field, bind && serviceInfo != null ? serviceInfo.getServiceInstance() : null); return; } // 2. ServiceReference field = getField(targetClass, fieldName, ServiceReference.class); if (field != null) { - setField(target, field, bind ? serviceInfo.getServiceReference() : null); + setField(target, field, bind && serviceInfo != null ? serviceInfo.getServiceReference() : null); return; } } @@ -477,7 +480,9 @@ final class OsgiServiceUtil { if (collection == null) { collection = new ArrayList<>(); } - collection.add(item); + if (item != null) { + collection.add(item); + } field.set(target, collection); } catch (IllegalAccessException ex) { @@ -495,9 +500,11 @@ final class OsgiServiceUtil { field.setAccessible(true); Collection<Object> collection = (Collection<Object>)field.get(target); if (collection == null) { - return; + collection = new ArrayList<>(); + } + if (item != null) { + collection.remove(item); } - collection.remove(item); field.set(target, collection); } catch (IllegalAccessException ex) { @@ -529,10 +536,10 @@ final class OsgiServiceUtil { invokeBindUnbindMethod(reference, target, serviceInfo, false); } - private static List<ServiceInfo> getMatchingServices(Class<?> type, BundleContext bundleContext) { + private static List<ServiceInfo> getMatchingServices(Class<?> type, BundleContext bundleContext, String filter) { List<ServiceInfo> matchingServices = new ArrayList<ServiceInfo>(); try { - ServiceReference[] references = bundleContext.getServiceReferences(type.getName(), null); + ServiceReference[] references = bundleContext.getServiceReferences(type.getName(), filter); if (references != null) { for (ServiceReference<?> serviceReference : references) { Object serviceInstance = bundleContext.getService(serviceReference); 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 index 0af80e9..b73bf5f 100644 --- a/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextDynamicReferncesOsgiR6Test.java +++ b/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextDynamicReferncesOsgiR6Test.java @@ -36,6 +36,7 @@ import org.mockito.runners.MockitoJUnitRunner; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @RunWith(MockitoJUnitRunner.class) @@ -138,6 +139,19 @@ public class MockBundleContextDynamicReferncesOsgiR6Test { assertDependencies2(); } + @Test + public void testReferenceWithTargetFilter() { + assertDependencies3Filtered(); + + bundleContext.registerService(ServiceInterface3.class.getName(), dependency3a, + MapUtil.toDictionary(ImmutableMap.<String, Object>of("prop1", "abc"))); + + bundleContext.registerService(ServiceInterface3.class.getName(), dependency3b, + MapUtil.toDictionary(ImmutableMap.<String, Object>of("prop1", "def"))); + + assertDependencies3Filtered(dependency3a); + } + private void assertDependency1(ServiceInterface1 instance) { if (instance == null) { assertNull(service.getReference1()); @@ -166,4 +180,9 @@ public class MockBundleContextDynamicReferncesOsgiR6Test { ImmutableSet.<ServiceSuperInterface3>copyOf(service.getReferences3())); } + private void assertDependencies3Filtered(ServiceSuperInterface3... instances) { + assertEquals(ImmutableSet.<ServiceSuperInterface3>copyOf(instances), + ImmutableSet.<ServiceSuperInterface3>copyOf(service.getReferences3Filtered())); + } + } 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 9135bcf..8d086ad 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 @@ -339,8 +339,9 @@ public class OsgiServiceUtilTest { private ServiceInterface1 reference1; private ServiceInterface1Optional reference1Optional; - private List<ServiceReference> references2 = new ArrayList<ServiceReference>(); - private List<ServiceSuperInterface3> references3 = new ArrayList<ServiceSuperInterface3>(); + private List<ServiceReference> references2; + private List<ServiceSuperInterface3> references3; + private List<ServiceSuperInterface3> references3Filtered; private ComponentContext componentContext; private Map<String, Object> config; @@ -381,6 +382,10 @@ public class OsgiServiceUtilTest { return this.references3; } + public List<ServiceSuperInterface3> getReferences3Filtered() { + return this.references3Filtered; + } + public ComponentContext getComponentContext() { return this.componentContext; } 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 94602cc..d8d0095 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 @@ -50,6 +50,7 @@ <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"/> + <reference name="references3Filtered" interface="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$ServiceInterface3" cardinality="0..n" policy="dynamic" field="references3Filtered" field-collection-type="service" target="(prop1=abc)"/> </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"/> -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
