Improved ThingHandlerService registrations / removals (#1548)

Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de>
This commit is contained in:
Christoph Weitkamp 2020-07-16 19:11:44 +02:00 committed by GitHub
parent 558f518feb
commit 729efeb37a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -12,6 +12,8 @@
*/ */
package org.openhab.core.thing.binding; package org.openhab.core.thing.binding;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -102,6 +104,7 @@ public abstract class BaseThingHandlerFactory implements ThingHandlerFactory {
configDescriptionRegistryServiceTracker.close(); configDescriptionRegistryServiceTracker.close();
configStatusProviders.clear(); configStatusProviders.clear();
firmwareUpdateHandlers.clear(); firmwareUpdateHandlers.clear();
thingHandlerServices.clear();
bundleContext = null; bundleContext = null;
} }
@ -138,13 +141,11 @@ public abstract class BaseThingHandlerFactory implements ThingHandlerFactory {
return thingHandler; return thingHandler;
} }
@SuppressWarnings("rawtypes")
private void registerServices(Thing thing, ThingHandler thingHandler) { private void registerServices(Thing thing, ThingHandler thingHandler) {
ThingUID thingUID = thing.getUID(); ThingUID thingUID = thing.getUID();
for (Class c : thingHandler.getServices()) { for (Class<?> c : thingHandler.getServices()) {
Object serviceInstance;
try { try {
serviceInstance = c.newInstance(); Object serviceInstance = c.getConstructor().newInstance();
ThingHandlerService ths = null; ThingHandlerService ths = null;
if (serviceInstance instanceof ThingHandlerService) { if (serviceInstance instanceof ThingHandlerService) {
@ -157,57 +158,67 @@ public abstract class BaseThingHandlerFactory implements ThingHandlerFactory {
continue; continue;
} }
Class[] interfaces = c.getInterfaces(); Set<Class<?>> interfaces = getAllInterfaces(c);
List<String> serviceNames = new LinkedList<>(); List<String> serviceNames = new LinkedList<>();
if (interfaces != null) { interfaces.forEach(i -> {
for (Class i : interfaces) {
String className = i.getCanonicalName(); String className = i.getCanonicalName();
// we only add specific ThingHandlerServices, i.e. those that derive from the // we only add specific ThingHandlerServices, i.e. those that derive from the ThingHandlerService
// ThingHandlerService interface, NOT the ThingHandlerService itself. We do this to register // interface, NOT the ThingHandlerService itself. We do this to register them as specific OSGi
// them as specific OSGi services later, rather than as a generic ThingHandlerService. // services later, rather than as a generic ThingHandlerService.
if (className != null && !className.equals(ThingHandlerService.class.getCanonicalName())) { if (className != null && !className.equals(ThingHandlerService.class.getCanonicalName())) {
serviceNames.add(className); serviceNames.add(className);
} }
} });
}
if (!serviceNames.isEmpty()) { if (!serviceNames.isEmpty()) {
String[] serviceNamesArray = serviceNames.toArray(new String[serviceNames.size()]); String[] serviceNamesArray = serviceNames.toArray(new String[serviceNames.size()]);
ServiceRegistration<?> serviceReg = bundleContext.registerService(serviceNamesArray, ServiceRegistration<?> serviceReg = bundleContext.registerService(serviceNamesArray,
serviceInstance, null); serviceInstance, null);
if (serviceReg != null) { if (serviceReg != null) {
Set<ServiceRegistration<?>> serviceRegs = this.thingHandlerServices.get(thingUID); Set<ServiceRegistration<?>> serviceRegs = thingHandlerServices.get(thingUID);
if (serviceRegs == null) { if (serviceRegs == null) {
Set<ServiceRegistration<?>> set = new HashSet<>(); Set<ServiceRegistration<?>> set = new HashSet<>();
set.add(serviceReg); set.add(serviceReg);
this.thingHandlerServices.put(thingUID, set); thingHandlerServices.put(thingUID, set);
} else { } else {
serviceRegs.add(serviceReg); serviceRegs.add(serviceReg);
} }
ths.activate(); ths.activate();
} }
} }
} catch (InstantiationException | IllegalAccessException e) { } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException
logger.warn("Could not register service for class={}", c, e); | InvocationTargetException e) {
logger.warn("Could not register service for class={}", c.getCanonicalName(), e);
} }
} }
} }
private void unregisterServices(Thing thing) { private void unregisterServices(Thing thing) {
ThingUID thingUID = thing.getUID(); ThingUID thingUID = thing.getUID();
Set<ServiceRegistration<?>> serviceRegs = thingHandlerServices.remove(thingUID);
Set<ServiceRegistration<?>> serviceRegs = this.thingHandlerServices.remove(thingUID);
if (serviceRegs != null) { if (serviceRegs != null) {
for (ServiceRegistration<?> serviceReg : serviceRegs) { serviceRegs.forEach(serviceReg -> {
ThingHandlerService service = (ThingHandlerService) getBundleContext() ThingHandlerService ths = (ThingHandlerService) getBundleContext()
.getService(serviceReg.getReference()); .getService(serviceReg.getReference());
serviceReg.unregister(); serviceReg.unregister();
if (service != null) { if (ths != null) {
service.deactivate(); ths.deactivate();
}
});
} }
} }
/**
* Returns all interfaces of the given class as well as all super classes.
*
* @param clazz The class
* @return A {@link List} of interfaces
*/
private Set<Class<?>> getAllInterfaces(Class<?> clazz) {
Set<Class<?>> interfaces = new HashSet<>();
for (Class<?> superclazz = clazz; superclazz != null; superclazz = superclazz.getSuperclass()) {
interfaces.addAll(Arrays.asList(superclazz.getInterfaces()));
} }
return interfaces;
} }
/** /**