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;
}
}
}
}