mirror of
https://github.com/danieldemus/openhab-core.git
synced 2025-01-10 13:21:53 +01:00
Refactor ThingHandlerService to an OSGi component prototype (#3957)
Also-by: Connor Petty <mistercpp2000+gitsignoff@gmail.com> Signed-off-by: J-N-K <github@klug.nrw>
This commit is contained in:
parent
1ddbe3180a
commit
a5316f920e
@ -61,6 +61,12 @@
|
|||||||
<version>1.5.0</version>
|
<version>1.5.0</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.osgi</groupId>
|
||||||
|
<artifactId>org.osgi.service.component.annotations</artifactId>
|
||||||
|
<version>1.5.0</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.felix</groupId>
|
<groupId>org.apache.felix</groupId>
|
||||||
<artifactId>org.apache.felix.scr</artifactId>
|
<artifactId>org.apache.felix.scr</artifactId>
|
||||||
|
@ -27,6 +27,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.core.common.ThreadPoolManager;
|
import org.openhab.core.common.ThreadPoolManager;
|
||||||
|
import org.openhab.core.config.core.ConfigParser;
|
||||||
import org.openhab.core.i18n.I18nUtil;
|
import org.openhab.core.i18n.I18nUtil;
|
||||||
import org.openhab.core.i18n.LocaleProvider;
|
import org.openhab.core.i18n.LocaleProvider;
|
||||||
import org.openhab.core.i18n.TranslationProvider;
|
import org.openhab.core.i18n.TranslationProvider;
|
||||||
@ -347,10 +348,9 @@ public abstract class AbstractDiscoveryService implements DiscoveryService {
|
|||||||
*/
|
*/
|
||||||
protected void activate(@Nullable Map<String, Object> configProperties) {
|
protected void activate(@Nullable Map<String, Object> configProperties) {
|
||||||
if (configProperties != null) {
|
if (configProperties != null) {
|
||||||
Object property = configProperties.get(DiscoveryService.CONFIG_PROPERTY_BACKGROUND_DISCOVERY);
|
backgroundDiscoveryEnabled = ConfigParser.valueAsOrElse(
|
||||||
if (property != null) {
|
configProperties.get(DiscoveryService.CONFIG_PROPERTY_BACKGROUND_DISCOVERY), Boolean.class,
|
||||||
backgroundDiscoveryEnabled = getAutoDiscoveryEnabled(property);
|
backgroundDiscoveryEnabled);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (backgroundDiscoveryEnabled) {
|
if (backgroundDiscoveryEnabled) {
|
||||||
startBackgroundDiscovery();
|
startBackgroundDiscovery();
|
||||||
@ -370,20 +370,18 @@ public abstract class AbstractDiscoveryService implements DiscoveryService {
|
|||||||
*/
|
*/
|
||||||
protected void modified(@Nullable Map<String, Object> configProperties) {
|
protected void modified(@Nullable Map<String, Object> configProperties) {
|
||||||
if (configProperties != null) {
|
if (configProperties != null) {
|
||||||
Object property = configProperties.get(DiscoveryService.CONFIG_PROPERTY_BACKGROUND_DISCOVERY);
|
boolean enabled = ConfigParser.valueAsOrElse(
|
||||||
if (property != null) {
|
configProperties.get(DiscoveryService.CONFIG_PROPERTY_BACKGROUND_DISCOVERY), Boolean.class,
|
||||||
boolean enabled = getAutoDiscoveryEnabled(property);
|
backgroundDiscoveryEnabled);
|
||||||
|
|
||||||
if (backgroundDiscoveryEnabled && !enabled) {
|
if (backgroundDiscoveryEnabled && !enabled) {
|
||||||
stopBackgroundDiscovery();
|
stopBackgroundDiscovery();
|
||||||
logger.debug("Background discovery for discovery service '{}' disabled.",
|
logger.debug("Background discovery for discovery service '{}' disabled.", this.getClass().getName());
|
||||||
this.getClass().getName());
|
} else if (!backgroundDiscoveryEnabled && enabled) {
|
||||||
} else if (!backgroundDiscoveryEnabled && enabled) {
|
startBackgroundDiscovery();
|
||||||
startBackgroundDiscovery();
|
logger.debug("Background discovery for discovery service '{}' enabled.", this.getClass().getName());
|
||||||
logger.debug("Background discovery for discovery service '{}' enabled.", this.getClass().getName());
|
|
||||||
}
|
|
||||||
backgroundDiscoveryEnabled = enabled;
|
|
||||||
}
|
}
|
||||||
|
backgroundDiscoveryEnabled = enabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,14 +424,6 @@ public abstract class AbstractDiscoveryService implements DiscoveryService {
|
|||||||
return timestampOfLastScan;
|
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) {
|
private String inferKey(DiscoveryResult discoveryResult, String lastSegment) {
|
||||||
return "discovery." + discoveryResult.getThingUID().getAsString().replace(":", ".") + "." + lastSegment;
|
return "discovery." + discoveryResult.getThingUID().getAsString().replace(":", ".") + "." + lastSegment;
|
||||||
}
|
}
|
||||||
|
@ -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<T extends ThingHandler> extends AbstractDiscoveryService
|
||||||
|
implements ThingHandlerService {
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(AbstractThingHandlerDiscoveryService.class);
|
||||||
|
private final Class<T> 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<T> thingClazz, @Nullable Set<ThingTypeUID> supportedThingTypes,
|
||||||
|
int timeout, boolean backgroundDiscoveryEnabledByDefault) throws IllegalArgumentException {
|
||||||
|
super(supportedThingTypes, timeout, backgroundDiscoveryEnabledByDefault);
|
||||||
|
this.thingClazz = thingClazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractThingHandlerDiscoveryService(Class<T> thingClazz, @Nullable Set<ThingTypeUID> supportedThingTypes,
|
||||||
|
int timeout) throws IllegalArgumentException {
|
||||||
|
super(supportedThingTypes, timeout);
|
||||||
|
this.thingClazz = thingClazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractThingHandlerDiscoveryService(Class<T> 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<String, Object> 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<String, Object> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,9 +15,9 @@ package org.openhab.core.thing.binding;
|
|||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
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.ThingType;
|
||||||
import org.openhab.core.thing.type.ThingTypeRegistry;
|
import org.openhab.core.thing.type.ThingTypeRegistry;
|
||||||
import org.osgi.framework.BundleContext;
|
import org.osgi.framework.BundleContext;
|
||||||
|
import org.osgi.framework.ServiceObjects;
|
||||||
|
import org.osgi.framework.ServiceReference;
|
||||||
import org.osgi.framework.ServiceRegistration;
|
import org.osgi.framework.ServiceRegistration;
|
||||||
import org.osgi.service.component.ComponentContext;
|
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.osgi.util.tracker.ServiceTracker;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
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 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
|
* @author Stefan Bußweiler - API changes due to bridge/thing life cycle refactoring, removed OSGi service registration
|
||||||
* for thing handlers
|
* for thing handlers
|
||||||
|
* @author Connor Petty - added osgi service registration for thing handler services.
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public abstract class BaseThingHandlerFactory implements ThingHandlerFactory {
|
public abstract class BaseThingHandlerFactory implements ThingHandlerFactory {
|
||||||
|
|
||||||
|
private static final String THING_HANDLER_SERVICE_CANONICAL_NAME = ThingHandlerService.class.getCanonicalName();
|
||||||
|
|
||||||
protected @NonNullByDefault({}) BundleContext bundleContext;
|
protected @NonNullByDefault({}) BundleContext bundleContext;
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(BaseThingHandlerFactory.class);
|
private final Logger logger = LoggerFactory.getLogger(BaseThingHandlerFactory.class);
|
||||||
@ -63,7 +70,7 @@ public abstract class BaseThingHandlerFactory implements ThingHandlerFactory {
|
|||||||
private final Map<String, ServiceRegistration<ConfigStatusProvider>> configStatusProviders = new ConcurrentHashMap<>();
|
private final Map<String, ServiceRegistration<ConfigStatusProvider>> configStatusProviders = new ConcurrentHashMap<>();
|
||||||
private final Map<String, ServiceRegistration<FirmwareUpdateHandler>> firmwareUpdateHandlers = new ConcurrentHashMap<>();
|
private final Map<String, ServiceRegistration<FirmwareUpdateHandler>> firmwareUpdateHandlers = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private final Map<ThingUID, Set<ServiceRegistration<?>>> thingHandlerServices = new ConcurrentHashMap<>();
|
private final Map<ThingUID, Set<RegisteredThingHandlerService<?>>> thingHandlerServices = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private @NonNullByDefault({}) ServiceTracker<ThingTypeRegistry, ThingTypeRegistry> thingTypeRegistryServiceTracker;
|
private @NonNullByDefault({}) ServiceTracker<ThingTypeRegistry, ThingTypeRegistry> thingTypeRegistryServiceTracker;
|
||||||
private @NonNullByDefault({}) ServiceTracker<ConfigDescriptionRegistry, ConfigDescriptionRegistry> configDescriptionRegistryServiceTracker;
|
private @NonNullByDefault({}) ServiceTracker<ConfigDescriptionRegistry, ConfigDescriptionRegistry> configDescriptionRegistryServiceTracker;
|
||||||
@ -143,67 +150,72 @@ public abstract class BaseThingHandlerFactory implements ThingHandlerFactory {
|
|||||||
|
|
||||||
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<? 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 <T extends ThingHandlerService> void registerThingHandlerService(ThingUID thingUID,
|
||||||
|
ThingHandler thingHandler, Class<T> c) {
|
||||||
|
RegisteredThingHandlerService<T> 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<T> serviceRef = bundleContext.getServiceReference(c);
|
||||||
|
if (serviceRef != null) {
|
||||||
|
ServiceObjects<T> serviceObjs = bundleContext.getServiceObjects(serviceRef);
|
||||||
|
registeredService = new RegisteredThingHandlerService<>(serviceObjs);
|
||||||
|
} else {
|
||||||
try {
|
try {
|
||||||
Object serviceInstance = c.getConstructor().newInstance();
|
T serviceInstance = c.getConstructor().newInstance();
|
||||||
|
registeredService = new RegisteredThingHandlerService<>(serviceInstance);
|
||||||
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<Class<?>> interfaces = getAllInterfaces(c);
|
|
||||||
List<String> 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<ServiceRegistration<?>> serviceRegs = thingHandlerServices.get(thingUID);
|
|
||||||
if (serviceRegs == null) {
|
|
||||||
Set<ServiceRegistration<?>> set = new HashSet<>();
|
|
||||||
set.add(serviceReg);
|
|
||||||
thingHandlerServices.put(thingUID, set);
|
|
||||||
} else {
|
|
||||||
serviceRegs.add(serviceReg);
|
|
||||||
}
|
|
||||||
ths.activate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException
|
} catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException
|
||||||
| InvocationTargetException e) {
|
| InvocationTargetException e) {
|
||||||
logger.warn("Could not register service for class={}", c.getCanonicalName(), 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) {
|
private void unregisterServices(Thing thing) {
|
||||||
ThingUID thingUID = thing.getUID();
|
ThingUID thingUID = thing.getUID();
|
||||||
Set<ServiceRegistration<?>> serviceRegs = thingHandlerServices.remove(thingUID);
|
Set<RegisteredThingHandlerService<?>> serviceRegs = thingHandlerServices.remove(thingUID);
|
||||||
if (serviceRegs != null) {
|
if (serviceRegs != null) {
|
||||||
serviceRegs.forEach(serviceReg -> {
|
serviceRegs.forEach(RegisteredThingHandlerService::disposeService);
|
||||||
ThingHandlerService ths = (ThingHandlerService) getBundleContext()
|
|
||||||
.getService(serviceReg.getReference());
|
|
||||||
serviceReg.unregister();
|
|
||||||
if (ths != null) {
|
|
||||||
ths.deactivate();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,7 +225,7 @@ public abstract class BaseThingHandlerFactory implements ThingHandlerFactory {
|
|||||||
* @param clazz The class
|
* @param clazz The class
|
||||||
* @return A {@link List} of interfaces
|
* @return A {@link List} of interfaces
|
||||||
*/
|
*/
|
||||||
private Set<Class<?>> getAllInterfaces(Class<?> clazz) {
|
private static Set<Class<?>> getAllInterfaces(Class<?> clazz) {
|
||||||
Set<Class<?>> interfaces = new HashSet<>();
|
Set<Class<?>> interfaces = new HashSet<>();
|
||||||
for (Class<?> superclazz = clazz; superclazz != null; superclazz = superclazz.getSuperclass()) {
|
for (Class<?> superclazz = clazz; superclazz != null; superclazz = superclazz.getSuperclass()) {
|
||||||
interfaces.addAll(Arrays.asList(superclazz.getInterfaces()));
|
interfaces.addAll(Arrays.asList(superclazz.getInterfaces()));
|
||||||
@ -354,4 +366,47 @@ public abstract class BaseThingHandlerFactory implements ThingHandlerFactory {
|
|||||||
}
|
}
|
||||||
return configDescriptionRegistryServiceTracker.getService();
|
return configDescriptionRegistryServiceTracker.getService();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class RegisteredThingHandlerService<T extends ThingHandlerService> {
|
||||||
|
|
||||||
|
private final T serviceInstance;
|
||||||
|
|
||||||
|
private @Nullable ServiceObjects<T> serviceObjects;
|
||||||
|
|
||||||
|
private @Nullable ServiceRegistration<?> serviceRegistration;
|
||||||
|
|
||||||
|
public RegisteredThingHandlerService(T serviceInstance) {
|
||||||
|
this.serviceInstance = serviceInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegisteredThingHandlerService(ServiceObjects<T> 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<T> serviceObjs = this.serviceObjects;
|
||||||
|
if (serviceObjs != null) {
|
||||||
|
serviceObjs.ungetService(serviceInstance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,14 +40,44 @@ public interface ThingHandlerService {
|
|||||||
ThingHandler getThingHandler();
|
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() {
|
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() {
|
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
|
||||||
|
* <code>super.initialize()</code> 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 <code>super.dispose()</code> to
|
||||||
|
* ensure background discovery is properly handled.
|
||||||
|
*
|
||||||
|
* See {@link #deactivate()}, {@link #initialize()}
|
||||||
|
*/
|
||||||
|
default void dispose() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
<bundle dependency="true">mvn:tech.units/indriya/2.2</bundle>
|
<bundle dependency="true">mvn:tech.units/indriya/2.2</bundle>
|
||||||
<bundle dependency="true">mvn:tech.uom.lib/uom-lib-common/2.2</bundle>
|
<bundle dependency="true">mvn:tech.uom.lib/uom-lib-common/2.2</bundle>
|
||||||
<bundle dependency="true">mvn:org.apiguardian/apiguardian-api/1.1.2</bundle>
|
<bundle dependency="true">mvn:org.apiguardian/apiguardian-api/1.1.2</bundle>
|
||||||
|
<bundle dependency="true">mvn:org.osgi/org.osgi.service.component.annotations/1.5.0</bundle>
|
||||||
|
|
||||||
<!-- TODO: Unbundled libraries -->
|
<!-- TODO: Unbundled libraries -->
|
||||||
<bundle dependency="true">mvn:com.thoughtworks.xstream/xstream/1.4.20</bundle>
|
<bundle dependency="true">mvn:com.thoughtworks.xstream/xstream/1.4.20</bundle>
|
||||||
|
@ -74,4 +74,5 @@ Fragment-Host: org.openhab.core.automation
|
|||||||
org.openhab.core.test;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.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.cm;version='[1.6.0,1.6.1)',\
|
||||||
|
org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
|
||||||
|
@ -74,4 +74,5 @@ Fragment-Host: org.openhab.core.automation
|
|||||||
org.openhab.core.test;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.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.cm;version='[1.6.0,1.6.1)',\
|
||||||
|
org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
|
||||||
|
@ -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.test;version='[4.2.0,4.2.1)',\
|
||||||
org.openhab.core.thing;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.cm;version='[1.6.0,1.6.1)',\
|
||||||
|
org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
|
||||||
|
@ -74,4 +74,5 @@ Fragment-Host: org.openhab.core.automation
|
|||||||
org.openhab.core.test;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.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.cm;version='[1.6.0,1.6.1)',\
|
||||||
|
org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
|
||||||
|
@ -74,4 +74,5 @@ Fragment-Host: org.openhab.core.automation
|
|||||||
org.openhab.core.test;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.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.cm;version='[1.6.0,1.6.1)',\
|
||||||
|
org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
|
||||||
|
@ -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.test;version='[4.2.0,4.2.1)',\
|
||||||
org.openhab.core.thing;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.cm;version='[1.6.0,1.6.1)',\
|
||||||
|
org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
|
||||||
|
@ -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.test;version='[4.2.0,4.2.1)',\
|
||||||
org.openhab.core.thing;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.cm;version='[1.6.0,1.6.1)',\
|
||||||
|
org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
|
||||||
|
@ -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.test;version='[4.2.0,4.2.1)',\
|
||||||
org.openhab.core.thing;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.cm;version='[1.6.0,1.6.1)',\
|
||||||
|
org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
|
||||||
|
@ -82,4 +82,5 @@ Provide-Capability: \
|
|||||||
org.openhab.core.test;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.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.cm;version='[1.6.0,1.6.1)',\
|
||||||
|
org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
|
||||||
|
@ -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.semantics;version='[4.2.0,4.2.1)',\
|
||||||
org.openhab.core.test;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.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)'
|
||||||
|
@ -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.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.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;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;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.runtime;version='[4.2.0,4.2.1)',\
|
||||||
org.openhab.core.model.sitemap;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.test;version='[4.2.0,4.2.1)',\
|
||||||
org.openhab.core.thing;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.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)'
|
||||||
|
@ -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.test;version='[4.2.0,4.2.1)',\
|
||||||
org.openhab.core.thing;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.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)'
|
||||||
|
@ -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.item;version='[4.2.0,4.2.1)',\
|
||||||
org.openhab.core.model.persistence;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;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;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.runtime;version='[4.2.0,4.2.1)',\
|
||||||
org.openhab.core.model.script.tests;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.test;version='[4.2.0,4.2.1)',\
|
||||||
org.openhab.core.thing;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.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)'
|
||||||
|
@ -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.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.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;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;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.runtime;version='[4.2.0,4.2.1)',\
|
||||||
org.openhab.core.model.sitemap;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.test;version='[4.2.0,4.2.1)',\
|
||||||
org.openhab.core.thing;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.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)'
|
||||||
|
@ -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.test;version='[4.2.0,4.2.1)',\
|
||||||
org.openhab.core.thing;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.cm;version='[1.6.0,1.6.1)',\
|
||||||
|
org.osgi.service.component.annotations;version='[1.5.0,1.5.1)'
|
||||||
|
@ -74,4 +74,5 @@ Fragment-Host: org.openhab.core.thing
|
|||||||
org.openhab.core.test;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.thing;version='[4.2.0,4.2.1)',\
|
||||||
org.openhab.core.thing.tests;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)'
|
||||||
|
@ -79,4 +79,5 @@ Fragment-Host: org.openhab.core.voice
|
|||||||
org.openhab.core.thing;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.openhab.core.voice;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)'
|
||||||
|
Loading…
Reference in New Issue
Block a user