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.2.0 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git
commit e3e8bb10f076e1ea30cdd1e47570ab0bbfab2389 Author: Stefan Seifert <[email protected]> AuthorDate: Thu Feb 19 16:18:00 2015 +0000 SLING-4439 implement dynamic service registration git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1660923 13f79535-47bb-0310-9956-ffa450edef68 --- .../sling/testing/mock/osgi/MockBundleContext.java | 41 +++++++- .../sling/testing/mock/osgi/OsgiServiceUtil.java | 112 +++++++++++++++++---- 2 files changed, 132 insertions(+), 21 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 37e6fd6..9ae85bc 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 @@ -28,6 +28,9 @@ import java.util.SortedSet; import java.util.TreeSet; import org.apache.commons.lang3.StringUtils; +import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.Reference; +import org.apache.sling.testing.mock.osgi.OsgiServiceUtil.ReferenceInfo; +import org.apache.sling.testing.mock.osgi.OsgiServiceUtil.ServiceInfo; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; @@ -91,7 +94,23 @@ class MockBundleContext implements BundleContext { * @param registration */ private void handleRefsUpdateOnRegister(MockServiceRegistration registration) { - // TODO: implement handling + List<ReferenceInfo> affectedReferences = OsgiServiceUtil.getMatchingReferences(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, registration.getService(), + new ServiceInfo(referenceInfo.getServiceRegistration())); + break; + default: + throw new RuntimeException("Unepxected cardinality: " + reference.getCardinality()); + } + } } void unregisterService(MockServiceRegistration registration) { @@ -106,7 +125,25 @@ class MockBundleContext implements BundleContext { * @param registration */ private void handleRefsUpdateOnUnregister(MockServiceRegistration registration) { - // TODO: implement handling + List<ReferenceInfo> affectedReferences = OsgiServiceUtil.getMatchingReferences(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, registration.getService(), + new ServiceInfo(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 306a967..152379f 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 @@ -25,6 +25,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.SortedSet; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; @@ -310,15 +311,22 @@ final class OsgiServiceUtil { } // try to invoke bind method - String bindMethodName = reference.getBind(); - if (StringUtils.isNotEmpty(bindMethodName)) { + for (ServiceInfo matchingService : matchingServices) { + invokeBindUnbindMethod(reference, target, matchingService, true); + } + } + + private static void invokeBindUnbindMethod(Reference reference, Object target, ServiceInfo serviceInfo, boolean bind) { + Class<?> targetClass = target.getClass(); + + // try to invoke bind method + String methodName = bind ? reference.getBind() : reference.getUnbind(); + if (StringUtils.isNotEmpty(methodName)) { // 1. ServiceReference - Method bindMethod = getMethod(targetClass, bindMethodName, new Class<?>[] { ServiceReference.class }); - if (bindMethod != null) { - for (ServiceInfo matchingService : matchingServices) { - invokeMethod(target, bindMethod, new Object[] { matchingService.getServiceReference() }); - } + Method method = getMethod(targetClass, methodName, new Class<?>[] { ServiceReference.class }); + if (method != null) { + invokeMethod(target, method, new Object[] { serviceInfo.getServiceReference() }); return; } @@ -329,27 +337,43 @@ final class OsgiServiceUtil { } 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() }); - } + method = getMethodWithAssignableTypes(targetClass, methodName, new Class<?>[] { interfaceType }); + if (method != null) { + invokeMethod(target, method, new Object[] { serviceInfo.getServiceInstance() }); return; } // 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() }); - } + method = getMethodWithAssignableTypes(targetClass, methodName, new Class<?>[] { interfaceType, Map.class }); + if (method != null) { + invokeMethod(target, method, new Object[] { serviceInfo.getServiceInstance(), serviceInfo.getServiceConfig() }); return; } } - throw new RuntimeException("Bind method with name " + bindMethodName + " not found " + throw new RuntimeException((bind ? "Bind" : "Unbind") + "method with name " + methodName + " not found " + "for reference '" + reference.getName() + "' for class {}" + targetClass.getName()); } + + /** + * Directly invoke bind method on service for the given reference. + * @param reference Reference metadata + * @param target Target object for reference + * @param serviceInfo Service on which to invoke the method + */ + public static void invokeBindMethod(Reference reference, Object target, ServiceInfo serviceInfo) { + invokeBindUnbindMethod(reference, target, serviceInfo, true); + } + + /** + * Directly invoke unbind method on service for the given reference. + * @param reference Reference metadata + * @param target Target object for reference + * @param serviceInfo Service on which to invoke the method + */ + public static void invokeUnbindMethod(Reference reference, Object target, ServiceInfo serviceInfo) { + invokeBindUnbindMethod(reference, target, serviceInfo, false); + } private static List<ServiceInfo> getMatchingServices(Class<?> type, BundleContext bundleContext) { List<ServiceInfo> matchingServices = new ArrayList<ServiceInfo>(); @@ -372,7 +396,31 @@ final class OsgiServiceUtil { return matchingServices; } - private static class ServiceInfo { + /** + * Collects all references of any registered service that match with any of the exported interfaces of the given service registration. + * @param registeredServices Registered Services + * @param registration Service registration + * @return List of references + */ + public static List<ReferenceInfo> getMatchingReferences(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()) { + 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; private final Map<String, Object> serviceConfig; @@ -384,6 +432,12 @@ final class OsgiServiceUtil { this.serviceReference = serviceReference; } + public ServiceInfo(MockServiceRegistration registration) { + this.serviceInstance = registration.getService(); + this.serviceConfig = MapUtil.toMap(registration.getProperties()); + this.serviceReference = registration.getReference(); + } + public Object getServiceInstance() { return this.serviceInstance; } @@ -398,4 +452,24 @@ final class OsgiServiceUtil { } + static class ReferenceInfo { + + private final MockServiceRegistration serviceRegistration; + private final Reference reference; + + public ReferenceInfo(MockServiceRegistration serviceRegistration, Reference reference) { + this.serviceRegistration = serviceRegistration; + this.reference = reference; + } + + public MockServiceRegistration getServiceRegistration() { + return serviceRegistration; + } + + public Reference getReference() { + return reference; + } + + } + } -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
