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

[sling-org-apache-sling-testing-osgi-mock] 05/10: SLING-4439 implement dynamic service registration

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 <ss...@apache.org>
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
"commits@sling.apache.org" <co...@sling.apache.org>.