private static void invokeBindUnbindMethod()

in core/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java [679:820]


    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();
        String fieldName = reference.getField();

        if (StringUtils.isNotEmpty(methodName) && serviceInfo != null) {

            boolean found = findAndInvokeNearestMethod(targetClass, candidateClass -> {
                // 1. ServiceReference
                Method method = getMethod(candidateClass, methodName, new Class<?>[] { ServiceReference.class });
                if (method != null) {
                    invokeMethod(target, method, new Object[] { serviceInfo.getServiceReference() });
                    return true;
                }

                // 2. ComponentServiceObjects
                method = getMethod(candidateClass, methodName, new Class<?>[] { ComponentServiceObjects.class });
                if (method != null) {
                    invokeMethod(target, method, new Object[] { serviceInfo });
                    return true;
                }

                // 3. assignable from service instance
                Class<?> interfaceType = reference.getInterfaceTypeAsClass();
                method = getMethodWithAssignableTypes(candidateClass, methodName, new Class<?>[] { interfaceType });
                if (method != null) {
                    invokeMethod(target, method, new Object[] { serviceInfo.getService() });
                    return true;
                }

                // 4. Map
                method = getMethod(candidateClass, methodName, new Class<?>[] { Map.class });
                if (method != null) {
                    invokeMethod(target, method, new Object[] { serviceInfo.getServiceConfig() });
                    return true;
                }

                // 5. mixed arguments
                Class<?>[] mixedArgsAllowed = new Class<?>[] { ServiceReference.class, ComponentServiceObjects.class, interfaceType, Map.class };
                method = getMethodWithAnyCombinationArgs(candidateClass, methodName, mixedArgsAllowed);
                if (method != null) {
                    Object[] args = new Object[method.getParameterTypes().length];
                    for (int i=0; i<args.length; i++) {
                        if (method.getParameterTypes()[i] == ServiceReference.class) {
                            args[i] = serviceInfo.getServiceReference();
                        }
                        else if (method.getParameterTypes()[i] == ComponentServiceObjects.class) {
                            args[i] = serviceInfo;
                        }
                        else if (method.getParameterTypes()[i].isAssignableFrom(interfaceType)) {
                            args[i] = serviceInfo.getService();
                        }
                        else if (method.getParameterTypes()[i] == Map.class) {
                            args[i] = serviceInfo.getServiceConfig();
                        }
                    }
                    invokeMethod(target, method, args);
                    return true;
                }

                return false;
            });

            if (!found) {
                throw new RuntimeException((bind ? "Bind" : "Unbind") + " method with name " + methodName + " not found "
                        + "for reference '" + reference.getName() + "' for class " +  targetClass.getName());
            }
        }

        // OSGi declarative services 1.3 supports modifying the field directly
        else if (StringUtils.isNotEmpty(fieldName)) {

            // check for field with list/collection reference
            if (reference.isCardinalityMultiple()) {
                switch (reference.getFieldCollectionType()) {
                    case SERVICE:
                    case REFERENCE:
                    case SERVICEOBJECTS:
                        Object item = null;
                        if (serviceInfo != null) {
                            item = serviceInfo.getService();
                            if (reference.getFieldCollectionType() == FieldCollectionType.REFERENCE) {
                                item = serviceInfo.getServiceReference();
                            }
                            else if (reference.getFieldCollectionType() == FieldCollectionType.SERVICEOBJECTS) {
                                item = serviceInfo;
                            }
                        }
                        Field field = getCollectionField(targetClass, fieldName);
                        if (field != null) {
                            if (bind) {
                                addToCollection(target, field, item);
                            }
                            else {
                                removeFromCollection(target, field, item);
                            }
                            return;
                        }
                        break;
                    default:
                        throw new RuntimeException("Field collection type '" + reference.getFieldCollectionType() + "' not supported "
                                + "for reference '" + reference.getName() + "' (" + reference.getInterfaceTypeAsClass().getName() +  ") for class " +  targetClass.getName());
                }
            }

            // check for single field reference
            else {
                // 1. assignable from service instance
                Class<?> interfaceType = reference.getInterfaceTypeAsClass();
                Field field = getFieldWithAssignableType(targetClass, fieldName, interfaceType);
                final boolean servicePresent = bind && serviceInfo != null;
                if (field != null) {
                    setField(target, field, servicePresent ? serviceInfo.getService() : null);
                    return;
                }

                // 2. ServiceReference
                field = getField(targetClass, fieldName, ServiceReference.class);
                if (field != null) {
                    setField(target, field, servicePresent ? serviceInfo.getServiceReference() : null);
                    return;
                }

                // 3. ComponentServiceObjects
                field = getField(targetClass, fieldName, ComponentServiceObjects.class);
                if (field != null) {
                    setField(target, field, servicePresent ? serviceInfo : null);
                    return;
                }

                // 4. Optional
                field = getField(targetClass, fieldName, Optional.class);
                if (field != null) {
                    setField(target, field, servicePresent ? Optional.of(serviceInfo.getService()) : Optional.empty());
                    return;
                }
            }
        }

    }