Fix ConfigurableService deprecations (#1666)

Signed-off-by: Wouter Born <github@maindrain.net>
This commit is contained in:
Wouter Born 2020-09-24 14:55:50 +02:00 committed by GitHub
parent c5541a0391
commit 6b97328189
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 198 additions and 81 deletions

View File

@ -17,6 +17,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.osgi.framework.Constants;
import org.osgi.service.component.ComponentConstants;
import org.osgi.service.component.annotations.ComponentPropertyType;
@ -25,9 +26,8 @@ import org.osgi.service.component.annotations.ComponentPropertyType;
* <p>
* {@link ConfigurableService} can be used as a marker interface for configurable services. But the interface itself is
* not relevant for the runtime. Each service which has the property
* {@link ConfigurableService#SERVICE_PROPERTY_DESCRIPTION_URI} set will be considered as a configurable service. The
* properties {@link ConfigurableService#SERVICE_PROPERTY_LABEL} and
* {@link ConfigurableService#SERVICE_PROPERTY_CATEGORY} are optional.
* {@link ConfigurableService#description_uri} set will be considered as a configurable service. The
* properties {@link ConfigurableService#label} and {@link ConfigurableService#category} are optional.
*
* <p>
* The services are configured through the OSGi configuration admin. Therefore each service must provide a PID or a
@ -41,6 +41,7 @@ import org.osgi.service.component.annotations.ComponentPropertyType;
@ComponentPropertyType
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
@NonNullByDefault
public @interface ConfigurableService {
String PREFIX_ = "service.config.";
@ -64,36 +65,4 @@ public @interface ConfigurableService {
* Marker for multiple configurations for this service ("true" = multiple configurations possible)
*/
boolean factory() default false;
/**
* The config description URI for the configurable service. See also {@link ConfigDescription}.
*
* @deprecated annotate classes with <code>@ConfigurableService</code> instead
*/
@Deprecated
public static final String SERVICE_PROPERTY_DESCRIPTION_URI = PREFIX_ + "description.uri";
/**
* The label of the service to be configured.
*
* @deprecated annotate classes with <code>@ConfigurableService</code> instead
*/
@Deprecated
public static final String SERVICE_PROPERTY_LABEL = PREFIX_ + "label";
/**
* The category of the service to be configured (e.g. binding).
*
* @deprecated annotate classes with <code>@ConfigurableService</code> instead
*/
@Deprecated
public static final String SERVICE_PROPERTY_CATEGORY = PREFIX_ + "category";
/**
* Marker for multiple configurations for this service ("true" = multiple configurations possible)
*
* @deprecated annotate classes with <code>@ConfigurableService</code> instead
*/
@Deprecated
public static final String SERVICE_PROPERTY_FACTORY_SERVICE = PREFIX_ + "factory";
}

View File

@ -0,0 +1,96 @@
/**
* Copyright (c) 2010-2020 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.core;
import java.lang.annotation.Annotation;
import java.util.function.Function;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* Provides utility methods for working with {@link ConfigurableService} so the property names can remain hidden.
* These methods cannot be part of {@link ConfigurableService} as that introduces an annotation cycle.
*
* @author Wouter Born - Initial contribution
*/
@NonNullByDefault
public class ConfigurableServiceUtil {
/**
* The config description URI for the configurable service. See also {@link ConfigDescription}.
*/
static final String SERVICE_PROPERTY_DESCRIPTION_URI = ConfigurableService.PREFIX_ + "description.uri";
/**
* The label of the service to be configured.
*/
static final String SERVICE_PROPERTY_LABEL = ConfigurableService.PREFIX_ + "label";
/**
* The category of the service to be configured (e.g. binding).
*/
static final String SERVICE_PROPERTY_CATEGORY = ConfigurableService.PREFIX_ + "category";
/**
* Marker for multiple configurations for this service ("true" = multiple configurations possible)
*/
static final String SERVICE_PROPERTY_FACTORY_SERVICE = ConfigurableService.PREFIX_ + "factory";
// all singleton services without multi-config services
public static final String CONFIGURABLE_SERVICE_FILTER = "(&(" + SERVICE_PROPERTY_DESCRIPTION_URI + "=*)(!("
+ SERVICE_PROPERTY_FACTORY_SERVICE + "=*)))";
// all multi-config services without singleton services
public static final String CONFIGURABLE_MULTI_CONFIG_SERVICE_FILTER = "(" + SERVICE_PROPERTY_FACTORY_SERVICE
+ "=*)";
public static ConfigurableService asConfigurableService(Function<String, @Nullable Object> propertyResolver) {
return new ConfigurableService() {
@Override
public Class<? extends Annotation> annotationType() {
return ConfigurableService.class;
}
@Override
public String label() {
return resolveString(propertyResolver, SERVICE_PROPERTY_LABEL);
}
@Override
public boolean factory() {
return resolveBoolean(propertyResolver, SERVICE_PROPERTY_FACTORY_SERVICE);
}
@Override
public String description_uri() {
return resolveString(propertyResolver, SERVICE_PROPERTY_DESCRIPTION_URI);
}
@Override
public String category() {
return resolveString(propertyResolver, SERVICE_PROPERTY_CATEGORY);
}
};
}
private static String resolveString(Function<String, @Nullable Object> propertyResolver, String key) {
String value = (String) propertyResolver.apply(key);
return value == null ? "" : value;
}
private static boolean resolveBoolean(Function<String, @Nullable Object> propertyResolver, String key) {
Boolean value = (Boolean) propertyResolver.apply(key);
return value == null ? false : value.booleanValue();
}
}

View File

@ -0,0 +1,69 @@
/**
* Copyright (c) 2010-2020 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.core;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.text.IsEmptyString.emptyString;
import static org.openhab.core.config.core.ConfigurableServiceUtil.*;
import java.util.Properties;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.Test;
/**
* Tests {@link ConfigurableServiceUtil}.
*
* @author Wouter Born - Initial contribution
*/
@NonNullByDefault
public class ConfigurableServiceUtilTest {
@Test
public void asConfigurableServiceDefinedProperties() {
String category = "system";
String descriptionURI = "system:inbox";
boolean factory = true;
String label = "Inbox";
Properties properties = new Properties();
properties.put(SERVICE_PROPERTY_CATEGORY, category);
properties.put(SERVICE_PROPERTY_DESCRIPTION_URI, descriptionURI);
properties.put(SERVICE_PROPERTY_FACTORY_SERVICE, factory);
properties.put(SERVICE_PROPERTY_LABEL, label);
ConfigurableService configurableService = ConfigurableServiceUtil
.asConfigurableService((key) -> properties.get(key));
assertThat(configurableService.annotationType(), is(ConfigurableService.class));
assertThat(configurableService.category(), is(category));
assertThat(configurableService.description_uri(), is(descriptionURI));
assertThat(configurableService.factory(), is(factory));
assertThat(configurableService.label(), is(label));
}
@Test
public void asConfigurableServiceUndefinedProperties() {
Properties properties = new Properties();
ConfigurableService configurableService = ConfigurableServiceUtil
.asConfigurableService((key) -> properties.get(key));
assertThat(configurableService.annotationType(), is(ConfigurableService.class));
assertThat(configurableService.category(), is(emptyString()));
assertThat(configurableService.description_uri(), is(emptyString()));
assertThat(configurableService.factory(), is(false));
assertThat(configurableService.label(), is(emptyString()));
}
}

View File

@ -43,6 +43,7 @@ import org.openhab.core.config.core.ConfigDescription;
import org.openhab.core.config.core.ConfigDescriptionRegistry;
import org.openhab.core.config.core.ConfigUtil;
import org.openhab.core.config.core.ConfigurableService;
import org.openhab.core.config.core.ConfigurableServiceUtil;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.io.rest.RESTConstants;
import org.openhab.core.io.rest.RESTResource;
@ -98,15 +99,6 @@ public class ConfigurableServiceResource implements RESTResource {
/** The URI path to this resource */
public static final String PATH_SERVICES = "services";
// all singleton services without multi-config services
private static final String CONFIGURABLE_SERVICE_FILTER = "(&("
+ ConfigurableService.SERVICE_PROPERTY_DESCRIPTION_URI + "=*)(!("
+ ConfigurableService.SERVICE_PROPERTY_FACTORY_SERVICE + "=*)))";
// all multi-config services without singleton services
private static final String CONFIGURABLE_MULTI_CONFIG_SERVICE_FILTER = "("
+ ConfigurableService.SERVICE_PROPERTY_FACTORY_SERVICE + "=*)";
private final Logger logger = LoggerFactory.getLogger(ConfigurableServiceResource.class);
private final BundleContext bundleContext;
@ -284,24 +276,24 @@ public class ConfigurableServiceResource implements RESTResource {
if (serviceReferences != null) {
for (ServiceReference<?> serviceReference : serviceReferences) {
String id = getServiceId(serviceReference);
String label = (String) serviceReference.getProperty(ConfigurableService.SERVICE_PROPERTY_LABEL);
if (label == null) { // for multi context services the label can be changed and must be read from config
// admin.
ConfigurableService configurableService = ConfigurableServiceUtil
.asConfigurableService((key) -> serviceReference.getProperty(key));
String label = configurableService.label();
if (label.isEmpty()) { // for multi context services the label can be changed and must be read from
// config admin.
label = configurationService.getProperty(id, OpenHAB.SERVICE_CONTEXT);
}
String category = (String) serviceReference.getProperty(ConfigurableService.SERVICE_PROPERTY_CATEGORY);
String configDescriptionURI = (String) serviceReference
.getProperty(ConfigurableService.SERVICE_PROPERTY_DESCRIPTION_URI);
if (configDescriptionURI == null) {
String category = configurableService.category();
String configDescriptionURI = configurableService.description_uri();
if (configDescriptionURI.isEmpty()) {
String factoryPid = (String) serviceReference.getProperty(ConfigurationAdmin.SERVICE_FACTORYPID);
configDescriptionURI = getConfigDescriptionByFactoryPid(factoryPid);
}
Object factoryProperty = serviceReference
.getProperty(ConfigurableService.SERVICE_PROPERTY_FACTORY_SERVICE);
boolean multiple = factoryProperty instanceof Boolean ? (Boolean) factoryProperty
: Boolean.parseBoolean((String) factoryProperty);
boolean multiple = configurableService.factory();
services.add(new ConfigurableServiceDTO(id, label, category, configDescriptionURI, multiple));
}
@ -318,8 +310,9 @@ public class ConfigurableServiceResource implements RESTResource {
ServiceReference<?>[] refs = bundleContext.getServiceReferences((String) null, filter);
if (refs != null && refs.length > 0) {
configDescriptionURI = (String) refs[0]
.getProperty(ConfigurableService.SERVICE_PROPERTY_DESCRIPTION_URI);
ConfigurableService configurableService = ConfigurableServiceUtil
.asConfigurableService((key) -> refs[0].getProperty(key));
configDescriptionURI = configurableService.description_uri();
}
} catch (InvalidSyntaxException e) {
logger.error("Cannot get service references because the syntax of the filter '{}' is invalid.", filter);
@ -330,8 +323,8 @@ public class ConfigurableServiceResource implements RESTResource {
private List<ConfigurableServiceDTO> getConfigurableServices() {
List<ConfigurableServiceDTO> services = new ArrayList<>();
services.addAll(getServicesByFilter(CONFIGURABLE_SERVICE_FILTER));
services.addAll(getServicesByFilter(CONFIGURABLE_MULTI_CONFIG_SERVICE_FILTER));
services.addAll(getServicesByFilter(ConfigurableServiceUtil.CONFIGURABLE_SERVICE_FILTER));
services.addAll(getServicesByFilter(ConfigurableServiceUtil.CONFIGURABLE_MULTI_CONFIG_SERVICE_FILTER));
return services;
}

View File

@ -38,11 +38,9 @@ import org.slf4j.LoggerFactory;
* @author Henning Treu - Initial contribution
*/
@NonNullByDefault
@Component(configurationPid = "org.openhab.magic", service = ConfigOptionProvider.class, immediate = true, property = {
Constants.SERVICE_PID + "=org.openhab.core.magic",
ConfigurableService.SERVICE_PROPERTY_DESCRIPTION_URI + "=test:magic",
ConfigurableService.SERVICE_PROPERTY_LABEL + "=Magic",
ConfigurableService.SERVICE_PROPERTY_CATEGORY + "=test" })
@Component(configurationPid = "org.openhab.magic", service = ConfigOptionProvider.class, immediate = true, //
property = Constants.SERVICE_PID + "=org.openhab.core.magic")
@ConfigurableService(category = "test", label = "Magic", description_uri = "test:magic")
public class MagicServiceImpl implements MagicService {
private final Logger logger = LoggerFactory.getLogger(MagicServiceImpl.class);

View File

@ -21,12 +21,9 @@ import org.osgi.service.component.annotations.Component;
*
* @author Stefan Triller - Initial contribution
*/
@Component(immediate = true, service = MagicMultiActionMarker.class, property = {
Constants.SERVICE_PID + "=org.openhab.MagicMultiAction",
ConfigurableService.SERVICE_PROPERTY_FACTORY_SERVICE + "=true",
ConfigurableService.SERVICE_PROPERTY_LABEL + "=MagicMultiActionsService",
ConfigurableService.SERVICE_PROPERTY_CATEGORY + "=RuleActions",
ConfigurableService.SERVICE_PROPERTY_DESCRIPTION_URI + "=automationAction:magicMultiAction" })
@Component(immediate = true, service = MagicMultiActionMarker.class, //
property = Constants.SERVICE_PID + "=org.openhab.MagicMultiAction")
@ConfigurableService(category = "RuleActions", label = "MagicMultiActionsService", description_uri = "automationAction:magicMultiAction", factory = true)
public class MagicMultiActionMarker {
}

View File

@ -33,11 +33,9 @@ import org.slf4j.LoggerFactory;
*
* @author Stefan Triller - Initial contribution
*/
@Component(configurationPid = "org.openhab.magicsingleaction", property = {
Constants.SERVICE_PID + "=org.openhab.automation.action.magicSingleActionService",
ConfigurableService.SERVICE_PROPERTY_DESCRIPTION_URI + "=automationAction:magicSingleAction",
ConfigurableService.SERVICE_PROPERTY_LABEL + "=Magic Single Action Service",
ConfigurableService.SERVICE_PROPERTY_CATEGORY + "=RuleActions" })
@Component(configurationPid = "org.openhab.magicsingleaction", //
property = Constants.SERVICE_PID + "=org.openhab.automation.action.magicSingleActionService")
@ConfigurableService(category = "RuleActions", label = "Magic Single Action Service", description_uri = "automationAction:magicSingleAction")
@ActionScope(name = "binding.magicService")
public class MagicSingleActionService implements AnnotatedActions {

View File

@ -21,12 +21,9 @@ import org.osgi.service.component.annotations.Component;
* @author Stefan Triller - Initial contribution
*/
@Component(immediate = true, service = MagicMultiInstanceServiceMarker.class, property = {
Constants.SERVICE_PID + "=org.openhab.magicMultiInstance",
ConfigurableService.SERVICE_PROPERTY_FACTORY_SERVICE + "=true",
ConfigurableService.SERVICE_PROPERTY_LABEL + "=MagicMultiInstanceService",
ConfigurableService.SERVICE_PROPERTY_CATEGORY + "=test",
ConfigurableService.SERVICE_PROPERTY_DESCRIPTION_URI + "=test:multipleMagic" })
@Component(immediate = true, service = MagicMultiInstanceServiceMarker.class, //
property = Constants.SERVICE_PID + "=org.openhab.magicMultiInstance")
@ConfigurableService(category = "test", label = "MagicMultiInstanceService", description_uri = "test:multipleMagic", factory = true)
public class MagicMultiInstanceServiceMarker {
// this is a marker service and represents a service factory so multiple configuration instances of type
// "org.openhab.core.magicMultiInstance" can be created.