diff --git a/bom/runtime/pom.xml b/bom/runtime/pom.xml
index 9e445fa83..ec625b86d 100644
--- a/bom/runtime/pom.xml
+++ b/bom/runtime/pom.xml
@@ -61,6 +61,12 @@
1.5.0
compile
+
+ org.osgi
+ org.osgi.service.component.annotations
+ 1.5.0
+ compile
+
org.apache.felix
org.apache.felix.scr
diff --git a/bundles/org.openhab.core.config.discovery/src/main/java/org/openhab/core/config/discovery/AbstractDiscoveryService.java b/bundles/org.openhab.core.config.discovery/src/main/java/org/openhab/core/config/discovery/AbstractDiscoveryService.java
index 6b9f9e04e..de96a4cb3 100644
--- a/bundles/org.openhab.core.config.discovery/src/main/java/org/openhab/core/config/discovery/AbstractDiscoveryService.java
+++ b/bundles/org.openhab.core.config.discovery/src/main/java/org/openhab/core/config/discovery/AbstractDiscoveryService.java
@@ -27,6 +27,7 @@ import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.common.ThreadPoolManager;
+import org.openhab.core.config.core.ConfigParser;
import org.openhab.core.i18n.I18nUtil;
import org.openhab.core.i18n.LocaleProvider;
import org.openhab.core.i18n.TranslationProvider;
@@ -347,10 +348,9 @@ public abstract class AbstractDiscoveryService implements DiscoveryService {
*/
protected void activate(@Nullable Map configProperties) {
if (configProperties != null) {
- Object property = configProperties.get(DiscoveryService.CONFIG_PROPERTY_BACKGROUND_DISCOVERY);
- if (property != null) {
- backgroundDiscoveryEnabled = getAutoDiscoveryEnabled(property);
- }
+ backgroundDiscoveryEnabled = ConfigParser.valueAsOrElse(
+ configProperties.get(DiscoveryService.CONFIG_PROPERTY_BACKGROUND_DISCOVERY), Boolean.class,
+ backgroundDiscoveryEnabled);
}
if (backgroundDiscoveryEnabled) {
startBackgroundDiscovery();
@@ -370,20 +370,18 @@ public abstract class AbstractDiscoveryService implements DiscoveryService {
*/
protected void modified(@Nullable Map configProperties) {
if (configProperties != null) {
- Object property = configProperties.get(DiscoveryService.CONFIG_PROPERTY_BACKGROUND_DISCOVERY);
- if (property != null) {
- boolean enabled = getAutoDiscoveryEnabled(property);
+ boolean enabled = ConfigParser.valueAsOrElse(
+ configProperties.get(DiscoveryService.CONFIG_PROPERTY_BACKGROUND_DISCOVERY), Boolean.class,
+ backgroundDiscoveryEnabled);
- if (backgroundDiscoveryEnabled && !enabled) {
- stopBackgroundDiscovery();
- logger.debug("Background discovery for discovery service '{}' disabled.",
- this.getClass().getName());
- } else if (!backgroundDiscoveryEnabled && enabled) {
- startBackgroundDiscovery();
- logger.debug("Background discovery for discovery service '{}' enabled.", this.getClass().getName());
- }
- backgroundDiscoveryEnabled = enabled;
+ if (backgroundDiscoveryEnabled && !enabled) {
+ stopBackgroundDiscovery();
+ logger.debug("Background discovery for discovery service '{}' disabled.", this.getClass().getName());
+ } else if (!backgroundDiscoveryEnabled && enabled) {
+ startBackgroundDiscovery();
+ logger.debug("Background discovery for discovery service '{}' enabled.", this.getClass().getName());
}
+ backgroundDiscoveryEnabled = enabled;
}
}
@@ -426,14 +424,6 @@ public abstract class AbstractDiscoveryService implements DiscoveryService {
return timestampOfLastScan;
}
- private boolean getAutoDiscoveryEnabled(Object autoDiscoveryEnabled) {
- if (autoDiscoveryEnabled instanceof String string) {
- return Boolean.parseBoolean(string);
- } else {
- return Boolean.TRUE.equals(autoDiscoveryEnabled);
- }
- }
-
private String inferKey(DiscoveryResult discoveryResult, String lastSegment) {
return "discovery." + discoveryResult.getThingUID().getAsString().replace(":", ".") + "." + lastSegment;
}
diff --git a/bundles/org.openhab.core.config.discovery/src/main/java/org/openhab/core/config/discovery/AbstractThingHandlerDiscoveryService.java b/bundles/org.openhab.core.config.discovery/src/main/java/org/openhab/core/config/discovery/AbstractThingHandlerDiscoveryService.java
new file mode 100644
index 000000000..4eee8b0ba
--- /dev/null
+++ b/bundles/org.openhab.core.config.discovery/src/main/java/org/openhab/core/config/discovery/AbstractThingHandlerDiscoveryService.java
@@ -0,0 +1,129 @@
+/**
+ * Copyright (c) 2010-2023 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.core.config.discovery;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.core.config.core.ConfigParser;
+import org.openhab.core.thing.ThingTypeUID;
+import org.openhab.core.thing.binding.ThingHandler;
+import org.openhab.core.thing.binding.ThingHandlerService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link AbstractThingHandlerDiscoveryService} extends the {@link AbstractDiscoveryService} for thing-based
+ * discovery services.
+ *
+ * It handles the injection of the {@link ThingHandler}
+ *
+ * @author Jan N. Klug - Initial contribution
+ */
+@NonNullByDefault
+public abstract class AbstractThingHandlerDiscoveryService extends AbstractDiscoveryService
+ implements ThingHandlerService {
+ private final Logger logger = LoggerFactory.getLogger(AbstractThingHandlerDiscoveryService.class);
+ private final Class thingClazz;
+ private boolean backgroundDiscoveryEnabled = false;
+
+ // this works around a bug in ecj: @NonNullByDefault({}) complains about the field not being
+ // initialized when the type is generic, so we have to initialize it with "something"
+ protected @NonNullByDefault({}) T thingHandler = (@NonNull T) null;
+
+ protected AbstractThingHandlerDiscoveryService(Class thingClazz, @Nullable Set supportedThingTypes,
+ int timeout, boolean backgroundDiscoveryEnabledByDefault) throws IllegalArgumentException {
+ super(supportedThingTypes, timeout, backgroundDiscoveryEnabledByDefault);
+ this.thingClazz = thingClazz;
+ }
+
+ protected AbstractThingHandlerDiscoveryService(Class thingClazz, @Nullable Set supportedThingTypes,
+ int timeout) throws IllegalArgumentException {
+ super(supportedThingTypes, timeout);
+ this.thingClazz = thingClazz;
+ }
+
+ protected AbstractThingHandlerDiscoveryService(Class thingClazz, int timeout) throws IllegalArgumentException {
+ super(timeout);
+ this.thingClazz = thingClazz;
+ }
+
+ @Override
+ protected abstract void startScan();
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void setThingHandler(ThingHandler handler) {
+ if (thingClazz.isAssignableFrom(handler.getClass())) {
+ this.thingHandler = (T) handler;
+ } else {
+ throw new IllegalArgumentException(
+ "Expected class is " + thingClazz + " but the parameter has class " + handler.getClass());
+ }
+ }
+
+ @Override
+ public @Nullable ThingHandler getThingHandler() {
+ return thingHandler;
+ }
+
+ @Override
+ public void activate(@Nullable Map config) {
+ // do not call super.activate here, otherwise the scan might be background scan might be started before the
+ // thing handler is set. This is correctly handled in initialize
+ if (config != null) {
+ backgroundDiscoveryEnabled = ConfigParser.valueAsOrElse(
+ config.get(DiscoveryService.CONFIG_PROPERTY_BACKGROUND_DISCOVERY), Boolean.class, false);
+ }
+ }
+
+ @Override
+ public void modified(@Nullable Map config) {
+ if (config != null) {
+ boolean enabled = ConfigParser.valueAsOrElse(
+ config.get(DiscoveryService.CONFIG_PROPERTY_BACKGROUND_DISCOVERY), Boolean.class, false);
+
+ if (backgroundDiscoveryEnabled && !enabled) {
+ stopBackgroundDiscovery();
+ logger.debug("Background discovery for discovery service '{}' disabled.", getClass().getName());
+ } else if (!backgroundDiscoveryEnabled && enabled) {
+ startBackgroundDiscovery();
+ logger.debug("Background discovery for discovery service '{}' enabled.", getClass().getName());
+ }
+ backgroundDiscoveryEnabled = enabled;
+ }
+ }
+
+ @Override
+ public void deactivate() {
+ // do not call super.deactivate here, background scan is already handled in dispose
+ }
+
+ @Override
+ public void initialize() {
+ if (backgroundDiscoveryEnabled) {
+ startBackgroundDiscovery();
+ logger.debug("Background discovery for discovery service '{}' enabled.", getClass().getName());
+ }
+ }
+
+ @Override
+ public void dispose() {
+ if (backgroundDiscoveryEnabled) {
+ stopBackgroundDiscovery();
+ }
+ }
+}
diff --git a/bundles/org.openhab.core.thing/src/main/java/org/openhab/core/thing/binding/BaseThingHandlerFactory.java b/bundles/org.openhab.core.thing/src/main/java/org/openhab/core/thing/binding/BaseThingHandlerFactory.java
index b991c7117..7ca48f9fe 100644
--- a/bundles/org.openhab.core.thing/src/main/java/org/openhab/core/thing/binding/BaseThingHandlerFactory.java
+++ b/bundles/org.openhab.core.thing/src/main/java/org/openhab/core/thing/binding/BaseThingHandlerFactory.java
@@ -15,9 +15,9 @@ package org.openhab.core.thing.binding;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashSet;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -34,8 +34,12 @@ import org.openhab.core.thing.binding.firmware.FirmwareUpdateHandler;
import org.openhab.core.thing.type.ThingType;
import org.openhab.core.thing.type.ThingTypeRegistry;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceObjects;
+import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ServiceScope;
import org.osgi.util.tracker.ServiceTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -52,10 +56,13 @@ import org.slf4j.LoggerFactory;
* @author Thomas Höfer - added config status provider and firmware update handler service registration
* @author Stefan Bußweiler - API changes due to bridge/thing life cycle refactoring, removed OSGi service registration
* for thing handlers
+ * @author Connor Petty - added osgi service registration for thing handler services.
*/
@NonNullByDefault
public abstract class BaseThingHandlerFactory implements ThingHandlerFactory {
+ private static final String THING_HANDLER_SERVICE_CANONICAL_NAME = ThingHandlerService.class.getCanonicalName();
+
protected @NonNullByDefault({}) BundleContext bundleContext;
private final Logger logger = LoggerFactory.getLogger(BaseThingHandlerFactory.class);
@@ -63,7 +70,7 @@ public abstract class BaseThingHandlerFactory implements ThingHandlerFactory {
private final Map> configStatusProviders = new ConcurrentHashMap<>();
private final Map> firmwareUpdateHandlers = new ConcurrentHashMap<>();
- private final Map>> thingHandlerServices = new ConcurrentHashMap<>();
+ private final Map>> thingHandlerServices = new ConcurrentHashMap<>();
private @NonNullByDefault({}) ServiceTracker thingTypeRegistryServiceTracker;
private @NonNullByDefault({}) ServiceTracker configDescriptionRegistryServiceTracker;
@@ -143,67 +150,72 @@ public abstract class BaseThingHandlerFactory implements ThingHandlerFactory {
private void registerServices(Thing thing, ThingHandler thingHandler) {
ThingUID thingUID = thing.getUID();
- for (Class> c : thingHandler.getServices()) {
+ for (Class extends ThingHandlerService> c : thingHandler.getServices()) {
+ if (!ThingHandlerService.class.isAssignableFrom(c)) {
+ logger.warn(
+ "Should register service={} for thingUID={}, but it does not implement the interface ThingHandlerService.",
+ c.getCanonicalName(), thingUID);
+ continue;
+ }
+ registerThingHandlerService(thingUID, thingHandler, c);
+ }
+ }
+
+ private void registerThingHandlerService(ThingUID thingUID,
+ ThingHandler thingHandler, Class c) {
+ RegisteredThingHandlerService registeredService;
+
+ Component component = c.getAnnotation(Component.class);
+ if (component != null && component.enabled()) {
+ if (component.scope() != ServiceScope.PROTOTYPE) {
+ // then we cannot use it.
+ logger.warn("Could not register service for class={}. Service must have a prototype scope",
+ c.getCanonicalName());
+ return;
+ }
+ if (component.service().length != 1 || component.service()[0] != c) {
+ logger.warn(
+ "Could not register service for class={}. ThingHandlerService with @Component must only label itself as a service.",
+ c.getCanonicalName());
+ return;
+ }
+ }
+
+ ServiceReference serviceRef = bundleContext.getServiceReference(c);
+ if (serviceRef != null) {
+ ServiceObjects serviceObjs = bundleContext.getServiceObjects(serviceRef);
+ registeredService = new RegisteredThingHandlerService<>(serviceObjs);
+ } else {
try {
- Object serviceInstance = c.getConstructor().newInstance();
-
- ThingHandlerService ths = null;
- if (serviceInstance instanceof ThingHandlerService service) {
- ths = service;
- ths.setThingHandler(thingHandler);
- } else {
- logger.warn(
- "Should register service={} for thingUID={}, but it does not implement the interface ThingHandlerService.",
- c.getCanonicalName(), thingUID);
- continue;
- }
-
- Set> interfaces = getAllInterfaces(c);
- List serviceNames = new LinkedList<>();
- interfaces.forEach(i -> {
- String className = i.getCanonicalName();
- // we only add specific ThingHandlerServices, i.e. those that derive from the ThingHandlerService
- // interface, NOT the ThingHandlerService itself. We do this to register them as specific OSGi
- // services later, rather than as a generic ThingHandlerService.
- if (className != null && !className.equals(ThingHandlerService.class.getCanonicalName())) {
- serviceNames.add(className);
- }
- });
- if (!serviceNames.isEmpty()) {
- String[] serviceNamesArray = serviceNames.toArray(new String[serviceNames.size()]);
- ServiceRegistration> serviceReg = bundleContext.registerService(serviceNamesArray,
- serviceInstance, null);
- if (serviceReg != null) {
- Set> serviceRegs = thingHandlerServices.get(thingUID);
- if (serviceRegs == null) {
- Set> set = new HashSet<>();
- set.add(serviceReg);
- thingHandlerServices.put(thingUID, set);
- } else {
- serviceRegs.add(serviceReg);
- }
- ths.activate();
- }
- }
+ T serviceInstance = c.getConstructor().newInstance();
+ registeredService = new RegisteredThingHandlerService<>(serviceInstance);
} catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException
| InvocationTargetException e) {
logger.warn("Could not register service for class={}", c.getCanonicalName(), e);
+ return;
}
}
+
+ String[] serviceNames = getAllInterfaces(c).stream()//
+ .map(Class::getCanonicalName)
+ // we only add specific ThingHandlerServices, i.e. those that derive from the
+ // ThingHandlerService
+ // interface, NOT the ThingHandlerService itself. We do this to register them as specific OSGi
+ // services later, rather than as a generic ThingHandlerService.
+ .filter(className -> className != null && !className.equals(THING_HANDLER_SERVICE_CANONICAL_NAME))
+ .toArray(String[]::new);
+
+ registeredService.initializeService(thingHandler, serviceNames);
+
+ Objects.requireNonNull(thingHandlerServices.computeIfAbsent(thingUID, uid -> new HashSet<>()))
+ .add(registeredService);
}
private void unregisterServices(Thing thing) {
ThingUID thingUID = thing.getUID();
- Set> serviceRegs = thingHandlerServices.remove(thingUID);
+ Set> serviceRegs = thingHandlerServices.remove(thingUID);
if (serviceRegs != null) {
- serviceRegs.forEach(serviceReg -> {
- ThingHandlerService ths = (ThingHandlerService) getBundleContext()
- .getService(serviceReg.getReference());
- serviceReg.unregister();
- if (ths != null) {
- ths.deactivate();
- }
- });
+ serviceRegs.forEach(RegisteredThingHandlerService::disposeService);
}
}
@@ -213,7 +225,7 @@ public abstract class BaseThingHandlerFactory implements ThingHandlerFactory {
* @param clazz The class
* @return A {@link List} of interfaces
*/
- private Set> getAllInterfaces(Class> clazz) {
+ private static Set> getAllInterfaces(Class> clazz) {
Set> interfaces = new HashSet<>();
for (Class> superclazz = clazz; superclazz != null; superclazz = superclazz.getSuperclass()) {
interfaces.addAll(Arrays.asList(superclazz.getInterfaces()));
@@ -354,4 +366,47 @@ public abstract class BaseThingHandlerFactory implements ThingHandlerFactory {
}
return configDescriptionRegistryServiceTracker.getService();
}
+
+ private class RegisteredThingHandlerService {
+
+ private final T serviceInstance;
+
+ private @Nullable ServiceObjects serviceObjects;
+
+ private @Nullable ServiceRegistration> serviceRegistration;
+
+ public RegisteredThingHandlerService(T serviceInstance) {
+ this.serviceInstance = serviceInstance;
+ }
+
+ public RegisteredThingHandlerService(ServiceObjects serviceObjs) {
+ this.serviceInstance = serviceObjs.getService();
+ this.serviceObjects = serviceObjs;
+ }
+
+ public void initializeService(ThingHandler handler, String[] serviceNames) {
+ serviceInstance.setThingHandler(handler);
+ if (serviceNames.length > 0) {
+ ServiceRegistration> serviceReg = bundleContext.registerService(serviceNames, serviceInstance, null);
+ if (serviceReg != null) {
+ serviceRegistration = serviceReg;
+ }
+ }
+ serviceInstance.initialize();
+ }
+
+ public void disposeService() {
+ serviceInstance.dispose();
+
+ ServiceRegistration> serviceReg = this.serviceRegistration;
+ if (serviceReg != null) {
+ serviceReg.unregister();
+ }
+
+ ServiceObjects serviceObjs = this.serviceObjects;
+ if (serviceObjs != null) {
+ serviceObjs.ungetService(serviceInstance);
+ }
+ }
+ }
}
diff --git a/bundles/org.openhab.core.thing/src/main/java/org/openhab/core/thing/binding/ThingHandlerService.java b/bundles/org.openhab.core.thing/src/main/java/org/openhab/core/thing/binding/ThingHandlerService.java
index 8b373a173..eaef4dd60 100644
--- a/bundles/org.openhab.core.thing/src/main/java/org/openhab/core/thing/binding/ThingHandlerService.java
+++ b/bundles/org.openhab.core.thing/src/main/java/org/openhab/core/thing/binding/ThingHandlerService.java
@@ -40,14 +40,44 @@ public interface ThingHandlerService {
ThingHandler getThingHandler();
/**
- * Method that will be called if this service will be activated
+ * This method is used by the framework during activation of the OSGi component.
+ * It is called BEFORE the thing handler is set.
+ *
+ * See {@link #initialize()}, {@link #deactivate()}
*/
default void activate() {
}
/**
- * Method that will be called if this service will be deactivated
+ * This method is used by the framework during de-activation of the OSGi component.
+ * It is NOT guaranteed that the thing handler is still valid.
+ *
+ * See {@link #dispose()}, {@link #activate()}
*/
default void deactivate() {
}
+
+ /**
+ * This method is used by the framework during activation of the service.
+ * It is called AFTER the component is fully activated and thing handler has been set.
+ *
+ * Implementations should override this method to add additional initialization code. This method should call
+ * super.initialize()
to ensure background discovery is properly handled.
+ *
+ * See {@link #activate(), #{@link #dispose()}
+ */
+ default void initialize() {
+ }
+
+ /**
+ * This method is used by the framework during de-activation of the service.
+ * It is called while the component is still activated.
+ *
+ * Code depending on an activated service should go here. This method should call super.dispose()
to
+ * ensure background discovery is properly handled.
+ *
+ * See {@link #deactivate()}, {@link #initialize()}
+ */
+ default void dispose() {
+ }
}
diff --git a/features/karaf/openhab-tp/src/main/feature/feature.xml b/features/karaf/openhab-tp/src/main/feature/feature.xml
index 47c0c7775..e9bf68d54 100644
--- a/features/karaf/openhab-tp/src/main/feature/feature.xml
+++ b/features/karaf/openhab-tp/src/main/feature/feature.xml
@@ -34,6 +34,7 @@
mvn:tech.units/indriya/2.2
mvn:tech.uom.lib/uom-lib-common/2.2
mvn:org.apiguardian/apiguardian-api/1.1.2
+ mvn:org.osgi/org.osgi.service.component.annotations/1.5.0
mvn:com.thoughtworks.xstream/xstream/1.4.20
diff --git a/itests/org.openhab.core.automation.integration.tests/itest.bndrun b/itests/org.openhab.core.automation.integration.tests/itest.bndrun
index e3f168f5e..4b6b9584a 100644
--- a/itests/org.openhab.core.automation.integration.tests/itest.bndrun
+++ b/itests/org.openhab.core.automation.integration.tests/itest.bndrun
@@ -74,4 +74,5 @@ Fragment-Host: org.openhab.core.automation
org.openhab.core.test;version='[4.2.0,4.2.1)',\
org.openhab.core.thing;version='[4.2.0,4.2.1)',\
org.openhab.core.transform;version='[4.2.0,4.2.1)',\
- org.osgi.service.cm;version='[1.6.0,1.6.1)'
+ org.osgi.service.cm;version='[1.6.0,1.6.1)',\
+ org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
diff --git a/itests/org.openhab.core.automation.module.core.tests/itest.bndrun b/itests/org.openhab.core.automation.module.core.tests/itest.bndrun
index 045360349..85054953f 100644
--- a/itests/org.openhab.core.automation.module.core.tests/itest.bndrun
+++ b/itests/org.openhab.core.automation.module.core.tests/itest.bndrun
@@ -74,4 +74,5 @@ Fragment-Host: org.openhab.core.automation
org.openhab.core.test;version='[4.2.0,4.2.1)',\
org.openhab.core.thing;version='[4.2.0,4.2.1)',\
org.openhab.core.transform;version='[4.2.0,4.2.1)',\
- org.osgi.service.cm;version='[1.6.0,1.6.1)'
+ org.osgi.service.cm;version='[1.6.0,1.6.1)',\
+ org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
diff --git a/itests/org.openhab.core.automation.module.script.tests/itest.bndrun b/itests/org.openhab.core.automation.module.script.tests/itest.bndrun
index 5955ec1d5..300921dc2 100644
--- a/itests/org.openhab.core.automation.module.script.tests/itest.bndrun
+++ b/itests/org.openhab.core.automation.module.script.tests/itest.bndrun
@@ -71,4 +71,5 @@ Fragment-Host: org.openhab.core.automation.module.script
org.openhab.core.test;version='[4.2.0,4.2.1)',\
org.openhab.core.thing;version='[4.2.0,4.2.1)',\
org.openhab.core.transform;version='[4.2.0,4.2.1)',\
- org.osgi.service.cm;version='[1.6.0,1.6.1)'
+ org.osgi.service.cm;version='[1.6.0,1.6.1)',\
+ org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
diff --git a/itests/org.openhab.core.automation.module.timer.tests/itest.bndrun b/itests/org.openhab.core.automation.module.timer.tests/itest.bndrun
index 799c71d51..d13331b4e 100644
--- a/itests/org.openhab.core.automation.module.timer.tests/itest.bndrun
+++ b/itests/org.openhab.core.automation.module.timer.tests/itest.bndrun
@@ -74,4 +74,5 @@ Fragment-Host: org.openhab.core.automation
org.openhab.core.test;version='[4.2.0,4.2.1)',\
org.openhab.core.thing;version='[4.2.0,4.2.1)',\
org.openhab.core.transform;version='[4.2.0,4.2.1)',\
- org.osgi.service.cm;version='[1.6.0,1.6.1)'
+ org.osgi.service.cm;version='[1.6.0,1.6.1)',\
+ org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
diff --git a/itests/org.openhab.core.automation.tests/itest.bndrun b/itests/org.openhab.core.automation.tests/itest.bndrun
index 6ee8b994b..f4f8707de 100644
--- a/itests/org.openhab.core.automation.tests/itest.bndrun
+++ b/itests/org.openhab.core.automation.tests/itest.bndrun
@@ -74,4 +74,5 @@ Fragment-Host: org.openhab.core.automation
org.openhab.core.test;version='[4.2.0,4.2.1)',\
org.openhab.core.thing;version='[4.2.0,4.2.1)',\
org.openhab.core.transform;version='[4.2.0,4.2.1)',\
- org.osgi.service.cm;version='[1.6.0,1.6.1)'
+ org.osgi.service.cm;version='[1.6.0,1.6.1)',\
+ org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
diff --git a/itests/org.openhab.core.config.discovery.mdns.tests/itest.bndrun b/itests/org.openhab.core.config.discovery.mdns.tests/itest.bndrun
index 83beeeb32..ec02ac3bf 100644
--- a/itests/org.openhab.core.config.discovery.mdns.tests/itest.bndrun
+++ b/itests/org.openhab.core.config.discovery.mdns.tests/itest.bndrun
@@ -74,4 +74,5 @@ Fragment-Host: org.openhab.core.config.discovery.mdns
org.openhab.core.test;version='[4.2.0,4.2.1)',\
org.openhab.core.thing;version='[4.2.0,4.2.1)',\
org.openhab.core.transform;version='[4.2.0,4.2.1)',\
- org.osgi.service.cm;version='[1.6.0,1.6.1)'
+ org.osgi.service.cm;version='[1.6.0,1.6.1)',\
+ org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
diff --git a/itests/org.openhab.core.config.discovery.tests/itest.bndrun b/itests/org.openhab.core.config.discovery.tests/itest.bndrun
index 330650031..b52595002 100644
--- a/itests/org.openhab.core.config.discovery.tests/itest.bndrun
+++ b/itests/org.openhab.core.config.discovery.tests/itest.bndrun
@@ -73,4 +73,5 @@ Fragment-Host: org.openhab.core.config.discovery
org.openhab.core.test;version='[4.2.0,4.2.1)',\
org.openhab.core.thing;version='[4.2.0,4.2.1)',\
org.openhab.core.transform;version='[4.2.0,4.2.1)',\
- org.osgi.service.cm;version='[1.6.0,1.6.1)'
+ org.osgi.service.cm;version='[1.6.0,1.6.1)',\
+ org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
diff --git a/itests/org.openhab.core.config.discovery.usbserial.linuxsysfs.tests/itest.bndrun b/itests/org.openhab.core.config.discovery.usbserial.linuxsysfs.tests/itest.bndrun
index 80181d1db..2983c0c77 100644
--- a/itests/org.openhab.core.config.discovery.usbserial.linuxsysfs.tests/itest.bndrun
+++ b/itests/org.openhab.core.config.discovery.usbserial.linuxsysfs.tests/itest.bndrun
@@ -74,4 +74,5 @@ Fragment-Host: org.openhab.core.config.discovery.usbserial.linuxsysfs
org.openhab.core.test;version='[4.2.0,4.2.1)',\
org.openhab.core.thing;version='[4.2.0,4.2.1)',\
org.openhab.core.transform;version='[4.2.0,4.2.1)',\
- org.osgi.service.cm;version='[1.6.0,1.6.1)'
+ org.osgi.service.cm;version='[1.6.0,1.6.1)',\
+ org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
diff --git a/itests/org.openhab.core.config.discovery.usbserial.tests/itest.bndrun b/itests/org.openhab.core.config.discovery.usbserial.tests/itest.bndrun
index e0d2c1147..6da760760 100644
--- a/itests/org.openhab.core.config.discovery.usbserial.tests/itest.bndrun
+++ b/itests/org.openhab.core.config.discovery.usbserial.tests/itest.bndrun
@@ -82,4 +82,5 @@ Provide-Capability: \
org.openhab.core.test;version='[4.2.0,4.2.1)',\
org.openhab.core.thing;version='[4.2.0,4.2.1)',\
org.openhab.core.transform;version='[4.2.0,4.2.1)',\
- org.osgi.service.cm;version='[1.6.0,1.6.1)'
+ org.osgi.service.cm;version='[1.6.0,1.6.1)',\
+ org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
diff --git a/itests/org.openhab.core.io.rest.core.tests/itest.bndrun b/itests/org.openhab.core.io.rest.core.tests/itest.bndrun
index da658b029..f393e591f 100644
--- a/itests/org.openhab.core.io.rest.core.tests/itest.bndrun
+++ b/itests/org.openhab.core.io.rest.core.tests/itest.bndrun
@@ -105,4 +105,6 @@ Fragment-Host: org.openhab.core.io.rest.core
org.openhab.core.semantics;version='[4.2.0,4.2.1)',\
org.openhab.core.test;version='[4.2.0,4.2.1)',\
org.openhab.core.thing;version='[4.2.0,4.2.1)',\
- org.openhab.core.transform;version='[4.2.0,4.2.1)'
+ org.openhab.core.transform;version='[4.2.0,4.2.1)',\
+ org.osgi.service.cm;version='[1.6.0,1.6.1)',\
+ org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
diff --git a/itests/org.openhab.core.model.item.tests/itest.bndrun b/itests/org.openhab.core.model.item.tests/itest.bndrun
index 9486738e7..d4abe3bef 100644
--- a/itests/org.openhab.core.model.item.tests/itest.bndrun
+++ b/itests/org.openhab.core.model.item.tests/itest.bndrun
@@ -110,7 +110,6 @@ Fragment-Host: org.openhab.core.model.item
org.openhab.core.model.item.tests;version='[4.2.0,4.2.1)',\
org.openhab.core.model.persistence;version='[4.2.0,4.2.1)',\
org.openhab.core.model.rule;version='[4.2.0,4.2.1)',\
- org.openhab.core.model.rule.runtime;version='[4.2.0,4.2.1)',\
org.openhab.core.model.script;version='[4.2.0,4.2.1)',\
org.openhab.core.model.script.runtime;version='[4.2.0,4.2.1)',\
org.openhab.core.model.sitemap;version='[4.2.0,4.2.1)',\
@@ -120,4 +119,6 @@ Fragment-Host: org.openhab.core.model.item
org.openhab.core.test;version='[4.2.0,4.2.1)',\
org.openhab.core.thing;version='[4.2.0,4.2.1)',\
org.openhab.core.transform;version='[4.2.0,4.2.1)',\
- org.openhab.core.voice;version='[4.2.0,4.2.1)'
+ org.openhab.core.voice;version='[4.2.0,4.2.1)',\
+ org.osgi.service.cm;version='[1.6.0,1.6.1)',\
+ org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
diff --git a/itests/org.openhab.core.model.rule.tests/itest.bndrun b/itests/org.openhab.core.model.rule.tests/itest.bndrun
index d8796e2b2..de5a9e3f2 100644
--- a/itests/org.openhab.core.model.rule.tests/itest.bndrun
+++ b/itests/org.openhab.core.model.rule.tests/itest.bndrun
@@ -123,4 +123,7 @@ Fragment-Host: org.openhab.core.model.rule.runtime
org.openhab.core.test;version='[4.2.0,4.2.1)',\
org.openhab.core.thing;version='[4.2.0,4.2.1)',\
org.openhab.core.transform;version='[4.2.0,4.2.1)',\
- org.openhab.core.voice;version='[4.2.0,4.2.1)'
+ org.openhab.core.voice;version='[4.2.0,4.2.1)',\
+ org.openhab.core.model.item.runtime;version='[4.2.0,4.2.1)',\
+ org.osgi.service.cm;version='[1.6.0,1.6.1)',\
+ org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
diff --git a/itests/org.openhab.core.model.script.tests/itest.bndrun b/itests/org.openhab.core.model.script.tests/itest.bndrun
index 7361d7de3..eb523e3db 100644
--- a/itests/org.openhab.core.model.script.tests/itest.bndrun
+++ b/itests/org.openhab.core.model.script.tests/itest.bndrun
@@ -116,7 +116,6 @@ Fragment-Host: org.openhab.core.model.script
org.openhab.core.model.item;version='[4.2.0,4.2.1)',\
org.openhab.core.model.persistence;version='[4.2.0,4.2.1)',\
org.openhab.core.model.rule;version='[4.2.0,4.2.1)',\
- org.openhab.core.model.rule.runtime;version='[4.2.0,4.2.1)',\
org.openhab.core.model.script;version='[4.2.0,4.2.1)',\
org.openhab.core.model.script.runtime;version='[4.2.0,4.2.1)',\
org.openhab.core.model.script.tests;version='[4.2.0,4.2.1)',\
@@ -127,4 +126,6 @@ Fragment-Host: org.openhab.core.model.script
org.openhab.core.test;version='[4.2.0,4.2.1)',\
org.openhab.core.thing;version='[4.2.0,4.2.1)',\
org.openhab.core.transform;version='[4.2.0,4.2.1)',\
- org.openhab.core.voice;version='[4.2.0,4.2.1)'
+ org.openhab.core.voice;version='[4.2.0,4.2.1)',\
+ org.openhab.core.model.item.runtime;version='[4.2.0,4.2.1)',\
+ org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
diff --git a/itests/org.openhab.core.model.thing.tests/itest.bndrun b/itests/org.openhab.core.model.thing.tests/itest.bndrun
index 3cdeeb8d7..e43c7deb2 100644
--- a/itests/org.openhab.core.model.thing.tests/itest.bndrun
+++ b/itests/org.openhab.core.model.thing.tests/itest.bndrun
@@ -116,7 +116,6 @@ Fragment-Host: org.openhab.core.model.thing
org.openhab.core.model.item.runtime;version='[4.2.0,4.2.1)',\
org.openhab.core.model.persistence;version='[4.2.0,4.2.1)',\
org.openhab.core.model.rule;version='[4.2.0,4.2.1)',\
- org.openhab.core.model.rule.runtime;version='[4.2.0,4.2.1)',\
org.openhab.core.model.script;version='[4.2.0,4.2.1)',\
org.openhab.core.model.script.runtime;version='[4.2.0,4.2.1)',\
org.openhab.core.model.sitemap;version='[4.2.0,4.2.1)',\
@@ -129,4 +128,6 @@ Fragment-Host: org.openhab.core.model.thing
org.openhab.core.test;version='[4.2.0,4.2.1)',\
org.openhab.core.thing;version='[4.2.0,4.2.1)',\
org.openhab.core.transform;version='[4.2.0,4.2.1)',\
- org.openhab.core.voice;version='[4.2.0,4.2.1)'
+ org.openhab.core.voice;version='[4.2.0,4.2.1)',\
+ org.osgi.service.cm;version='[1.6.0,1.6.1)',\
+ org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
diff --git a/itests/org.openhab.core.storage.json.tests/itest.bndrun b/itests/org.openhab.core.storage.json.tests/itest.bndrun
index 81bad6bd6..fb1d888ca 100644
--- a/itests/org.openhab.core.storage.json.tests/itest.bndrun
+++ b/itests/org.openhab.core.storage.json.tests/itest.bndrun
@@ -67,4 +67,5 @@ Fragment-Host: org.openhab.core.storage.json
org.openhab.core.test;version='[4.2.0,4.2.1)',\
org.openhab.core.thing;version='[4.2.0,4.2.1)',\
org.openhab.core.transform;version='[4.2.0,4.2.1)',\
- org.osgi.service.cm;version='[1.6.0,1.6.1)'
+ org.osgi.service.cm;version='[1.6.0,1.6.1)',\
+ org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
diff --git a/itests/org.openhab.core.thing.tests/itest.bndrun b/itests/org.openhab.core.thing.tests/itest.bndrun
index 55b410880..eebaaa0f1 100644
--- a/itests/org.openhab.core.thing.tests/itest.bndrun
+++ b/itests/org.openhab.core.thing.tests/itest.bndrun
@@ -74,4 +74,5 @@ Fragment-Host: org.openhab.core.thing
org.openhab.core.test;version='[4.2.0,4.2.1)',\
org.openhab.core.thing;version='[4.2.0,4.2.1)',\
org.openhab.core.thing.tests;version='[4.2.0,4.2.1)',\
- org.openhab.core.transform;version='[4.2.0,4.2.1)'
+ org.openhab.core.transform;version='[4.2.0,4.2.1)',\
+ org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
diff --git a/itests/org.openhab.core.voice.tests/itest.bndrun b/itests/org.openhab.core.voice.tests/itest.bndrun
index 9a7db26d7..025f5ed44 100644
--- a/itests/org.openhab.core.voice.tests/itest.bndrun
+++ b/itests/org.openhab.core.voice.tests/itest.bndrun
@@ -79,4 +79,5 @@ Fragment-Host: org.openhab.core.voice
org.openhab.core.thing;version='[4.2.0,4.2.1)',\
org.openhab.core.transform;version='[4.2.0,4.2.1)',\
org.openhab.core.voice;version='[4.2.0,4.2.1)',\
- org.openhab.core.voice.tests;version='[4.2.0,4.2.1)'
+ org.openhab.core.voice.tests;version='[4.2.0,4.2.1)',\
+ org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'