This is an automated email from the ASF dual-hosted git repository.

henrykuijpers pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 0a9626878e7ed5a350887c4c2469f0e377844bf4
Author: Bart Thierens <[email protected]>
AuthorDate: Thu Aug 22 17:14:05 2024 +0200

    Keep sorting consistent in collection references whenever services are 
registered
---
 .../sling/testing/mock/osgi/MockBundleContext.java |  6 +-
 .../sling/testing/mock/osgi/OsgiServiceUtil.java   | 78 +++++++---------------
 2 files changed, 29 insertions(+), 55 deletions(-)

diff --git 
a/core/src/main/java/org/apache/sling/testing/mock/osgi/MockBundleContext.java 
b/core/src/main/java/org/apache/sling/testing/mock/osgi/MockBundleContext.java
index 4075921..e4a373c 100644
--- 
a/core/src/main/java/org/apache/sling/testing/mock/osgi/MockBundleContext.java
+++ 
b/core/src/main/java/org/apache/sling/testing/mock/osgi/MockBundleContext.java
@@ -194,7 +194,8 @@ class MockBundleContext implements BundleContext {
                         OsgiServiceUtil.invokeBindMethod(
                                 reference,
                                 
referenceInfo.getServiceRegistration().getService(),
-                                new ServiceInfo(registration));
+                                new ServiceInfo(registration),
+                                this);
                         break;
                     default:
                         throw new RuntimeException("Unepxected cardinality: " 
+ reference.getCardinality());
@@ -289,7 +290,8 @@ class MockBundleContext implements BundleContext {
                         OsgiServiceUtil.invokeUnbindMethod(
                                 reference,
                                 
referenceInfo.getServiceRegistration().getService(),
-                                new ServiceInfo(registration));
+                                new ServiceInfo(registration),
+                                this);
                         break;
                     default:
                         throw new RuntimeException("Unepxected cardinality: " 
+ reference.getCardinality());
diff --git 
a/core/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java 
b/core/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java
index b1b89b1..e742af2 100644
--- a/core/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java
+++ b/core/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java
@@ -24,19 +24,7 @@ import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Parameter;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
+import java.util.*;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
@@ -695,7 +683,7 @@ final class OsgiServiceUtil {
             }
 
             // make sure at least empty array or empty Optional is set
-            invokeBindUnbindMethod(reference, target, null, true);
+            invokeBindUnbindMethod(reference, target, null, true, 
bundleContext);
         }
 
         // multiple references found? inject only first one with highest 
ranking
@@ -712,12 +700,12 @@ final class OsgiServiceUtil {
 
         // try to invoke bind method
         for (ServiceInfo<?> matchingService : matchingServices) {
-            invokeBindUnbindMethod(reference, target, matchingService, true);
+            invokeBindUnbindMethod(reference, target, matchingService, true, 
bundleContext);
         }
     }
 
     private static void invokeBindUnbindMethod(
-            Reference reference, Object target, ServiceInfo<?> serviceInfo, 
boolean bind) {
+            Reference reference, Object target, ServiceInfo<?> serviceInfo, 
boolean bind, BundleContext bundleContext) {
         Class<?> targetClass = target.getClass();
 
         // try to invoke bind method
@@ -808,11 +796,9 @@ final class OsgiServiceUtil {
                         }
                         Field field = getCollectionField(targetClass, 
fieldName);
                         if (field != null) {
-                            if (bind) {
-                                addToCollection(target, field, item);
-                            } else {
-                                removeFromCollection(target, field, item);
-                            }
+                            // to make sure components are consistently sorted 
(according to Felix sorting)
+                            // we (re-)bind the entire collection field every 
time a reference is added or removed
+                            bindCollectionReference(reference, bundleContext, 
target, field);
                             return;
                         }
                         break;
@@ -859,37 +845,21 @@ final class OsgiServiceUtil {
         }
     }
 
-    @SuppressWarnings("unchecked")
-    private static void addToCollection(Object target, Field field, Object 
item) {
+    private static void bindCollectionReference(
+            Reference reference, BundleContext bundleContext, Object target, 
Field field) {
         try {
             field.setAccessible(true);
-            Collection<Object> collection = (Collection<Object>) 
field.get(target);
-            if (collection == null) {
-                collection = newCollectionInstance(field.getType());
-            }
-            if (item != null) {
-                collection.add(item);
-            }
-            field.set(target, collection);
-
-        } catch (IllegalAccessException | IllegalArgumentException | 
InstantiationException ex) {
-            throw new RuntimeException(
-                    "Unable to set field '" + field.getName() + "' for class "
-                            + target.getClass().getName(),
-                    ex);
-        }
-    }
+            List<ServiceInfo<?>> matchingServices =
+                    getMatchingServices(reference.getInterfaceTypeAsClass(), 
bundleContext, reference.getTarget());
+            
matchingServices.sort(Comparator.comparing(ServiceInfo::getServiceReference));
 
-    @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) {
-                collection = newCollectionInstance(field.getType());
-            }
-            if (item != null) {
-                collection.remove(item);
+            Collection<Object> collection = 
newCollectionInstance(field.getType());
+            if 
(FieldCollectionType.REFERENCE.equals(reference.getFieldCollectionType())) {
+                
matchingServices.stream().map(ServiceInfo::getServiceReference).forEach(collection::add);
+            } else if 
(FieldCollectionType.SERVICE.equals(reference.getFieldCollectionType())) {
+                
matchingServices.stream().map(ServiceInfo::getService).forEach(collection::add);
+            } else {
+                collection.addAll(matchingServices);
             }
             field.set(target, collection);
 
@@ -923,8 +893,9 @@ final class OsgiServiceUtil {
      * @param serviceInfo Service on which to invoke the method
      * @param bundleContext Bundle context
      */
-    public static void invokeBindMethod(Reference reference, Object target, 
ServiceInfo<?> serviceInfo) {
-        invokeBindUnbindMethod(reference, target, serviceInfo, true);
+    public static void invokeBindMethod(
+            Reference reference, Object target, ServiceInfo<?> serviceInfo, 
BundleContext bundleContext) {
+        invokeBindUnbindMethod(reference, target, serviceInfo, true, 
bundleContext);
     }
 
     /**
@@ -934,8 +905,9 @@ final class OsgiServiceUtil {
      * @param serviceInfo Service on which to invoke the method
      * @param bundleContext Bundle context
      */
-    public static void invokeUnbindMethod(Reference reference, Object target, 
ServiceInfo<?> serviceInfo) {
-        invokeBindUnbindMethod(reference, target, serviceInfo, false);
+    public static void invokeUnbindMethod(
+            Reference reference, Object target, ServiceInfo<?> serviceInfo, 
BundleContext bundleContext) {
+        invokeBindUnbindMethod(reference, target, serviceInfo, false, 
bundleContext);
     }
 
     @SuppressWarnings("unchecked")

Reply via email to