Adjust transformations to core changes (#13126)

Signed-off-by: Jan N. Klug <github@klug.nrw>
This commit is contained in:
J-N-K 2022-07-14 22:47:48 +02:00 committed by GitHub
parent 8e16c411f0
commit 9f8c1772d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 81 additions and 85 deletions

View File

@ -28,9 +28,9 @@ import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.common.registry.RegistryChangeListener; import org.openhab.core.common.registry.RegistryChangeListener;
import org.openhab.core.config.core.ConfigOptionProvider; import org.openhab.core.config.core.ConfigOptionProvider;
import org.openhab.core.config.core.ParameterOption; import org.openhab.core.config.core.ParameterOption;
import org.openhab.core.transform.TransformationConfiguration; import org.openhab.core.transform.Transformation;
import org.openhab.core.transform.TransformationConfigurationRegistry;
import org.openhab.core.transform.TransformationException; import org.openhab.core.transform.TransformationException;
import org.openhab.core.transform.TransformationRegistry;
import org.openhab.core.transform.TransformationService; import org.openhab.core.transform.TransformationService;
import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Component;
@ -45,43 +45,41 @@ import org.slf4j.LoggerFactory;
* *
* @author Kai Kreuzer - Initial contribution and API * @author Kai Kreuzer - Initial contribution and API
* @author Gaël L'hopital - Make it localizable * @author Gaël L'hopital - Make it localizable
* @author Jan N. Klug - Refactored to use {@link TransformationConfigurationRegistry} * @author Jan N. Klug - Refactored to use {@link TransformationRegistry}
*/ */
@NonNullByDefault @NonNullByDefault
@Component(service = { TransformationService.class, ConfigOptionProvider.class }, property = { @Component(service = { TransformationService.class, ConfigOptionProvider.class }, property = {
"openhab.transform=MAP" }) "openhab.transform=MAP" })
public class MapTransformationService public class MapTransformationService
implements TransformationService, ConfigOptionProvider, RegistryChangeListener<TransformationConfiguration> { implements TransformationService, ConfigOptionProvider, RegistryChangeListener<Transformation> {
private final Logger logger = LoggerFactory.getLogger(MapTransformationService.class); private final Logger logger = LoggerFactory.getLogger(MapTransformationService.class);
private static final String PROFILE_CONFIG_URI = "profile:transform:MAP"; private static final String PROFILE_CONFIG_URI = "profile:transform:MAP";
private static final String CONFIG_PARAM_FUNCTION = "function"; private static final String CONFIG_PARAM_FUNCTION = "function";
private static final Set<String> SUPPORTED_CONFIGURATION_TYPES = Set.of("map"); private static final Set<String> SUPPORTED_CONFIGURATION_TYPES = Set.of("map");
private final TransformationConfigurationRegistry transformationConfigurationRegistry; private final TransformationRegistry transformationRegistry;
private final Map<String, Properties> cachedTransformations = new ConcurrentHashMap<>(); private final Map<String, Properties> cachedTransformations = new ConcurrentHashMap<>();
@Activate @Activate
public MapTransformationService( public MapTransformationService(@Reference TransformationRegistry transformationRegistry) {
@Reference TransformationConfigurationRegistry transformationConfigurationRegistry) { this.transformationRegistry = transformationRegistry;
this.transformationConfigurationRegistry = transformationConfigurationRegistry; transformationRegistry.addRegistryChangeListener(this);
transformationConfigurationRegistry.addRegistryChangeListener(this);
} }
@Deactivate @Deactivate
public void deactivate() { public void deactivate() {
transformationConfigurationRegistry.removeRegistryChangeListener(this); transformationRegistry.removeRegistryChangeListener(this);
} }
@Override @Override
public @Nullable String transform(String function, String source) throws TransformationException { public @Nullable String transform(String function, String source) throws TransformationException {
// always get a configuration from the registry to account for changed system locale // always get a configuration from the registry to account for changed system locale
TransformationConfiguration transformationConfiguration = transformationConfigurationRegistry.get(function, Transformation transformation = transformationRegistry.get(function, null);
null);
if (transformationConfiguration != null) { if (transformation != null) {
if (!cachedTransformations.containsKey(transformationConfiguration.getUID())) { if (!cachedTransformations.containsKey(transformation.getUID())) {
importConfiguration(transformationConfiguration); importConfiguration(transformation);
} }
Properties properties = cachedTransformations.get(function); Properties properties = cachedTransformations.get(function);
if (properties != null) { if (properties != null) {
@ -106,7 +104,7 @@ public class MapTransformationService
@Nullable Locale locale) { @Nullable Locale locale) {
if (PROFILE_CONFIG_URI.equals(uri.toString())) { if (PROFILE_CONFIG_URI.equals(uri.toString())) {
if (CONFIG_PARAM_FUNCTION.equals(param)) { if (CONFIG_PARAM_FUNCTION.equals(param)) {
return transformationConfigurationRegistry.getConfigurations(SUPPORTED_CONFIGURATION_TYPES).stream() return transformationRegistry.getTransformations(SUPPORTED_CONFIGURATION_TYPES).stream()
.map(c -> new ParameterOption(c.getUID(), c.getLabel())).collect(Collectors.toList()); .map(c -> new ParameterOption(c.getUID(), c.getLabel())).collect(Collectors.toList());
} }
} }
@ -114,29 +112,34 @@ public class MapTransformationService
} }
@Override @Override
public void added(TransformationConfiguration element) { public void added(Transformation element) {
// do nothing, configurations are added to cache if needed // do nothing, configurations are added to cache if needed
} }
@Override @Override
public void removed(TransformationConfiguration element) { public void removed(Transformation element) {
cachedTransformations.remove(element.getUID()); cachedTransformations.remove(element.getUID());
} }
@Override @Override
public void updated(TransformationConfiguration oldElement, TransformationConfiguration element) { public void updated(Transformation oldElement, Transformation element) {
if (cachedTransformations.remove(oldElement.getUID()) != null) { if (cachedTransformations.remove(oldElement.getUID()) != null) {
// import only if it was present before // import only if it was present before
importConfiguration(element); importConfiguration(element);
} }
} }
private void importConfiguration(@Nullable TransformationConfiguration configuration) { private void importConfiguration(@Nullable Transformation transformation) {
if (configuration != null) { if (transformation != null) {
try { try {
Properties properties = new Properties(); Properties properties = new Properties();
properties.load(new StringReader(configuration.getContent())); String function = transformation.getConfiguration().get(Transformation.FUNCTION);
cachedTransformations.put(configuration.getUID(), properties); if (function == null || function.isBlank()) {
logger.warn("Function not defined for transformation '{}'", transformation.getUID());
return;
}
properties.load(new StringReader(function));
cachedTransformations.put(transformation.getUID(), properties);
} catch (IOException ignored) { } catch (IOException ignored) {
} }
} }

View File

@ -35,13 +35,13 @@ import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness; import org.mockito.quality.Strictness;
import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer;
import org.openhab.core.test.java.JavaTest; import org.openhab.core.test.java.JavaTest;
import org.openhab.core.transform.TransformationConfiguration; import org.openhab.core.transform.Transformation;
import org.openhab.core.transform.TransformationConfigurationRegistry;
import org.openhab.core.transform.TransformationException; import org.openhab.core.transform.TransformationException;
import org.openhab.core.transform.TransformationRegistry;
/** /**
* @author Gaël L'hopital - Initial contribution * @author Gaël L'hopital - Initial contribution
* @author Jan N. Klug - Refactored to use {@link TransformationConfigurationRegistry} * @author Jan N. Klug - Refactored to use {@link TransformationRegistry}
*/ */
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT) @MockitoSettings(strictness = Strictness.LENIENT)
@ -58,10 +58,10 @@ public class MapTransformationServiceTest extends JavaTest {
private static final String SRC_FOLDER = "conf" + File.separator + "transform"; private static final String SRC_FOLDER = "conf" + File.separator + "transform";
@Mock @Mock
private @NonNullByDefault({}) TransformationConfigurationRegistry transformationConfigurationRegistry; private @NonNullByDefault({}) TransformationRegistry transformationRegistry;
private @NonNullByDefault({}) MapTransformationService processor; private @NonNullByDefault({}) MapTransformationService processor;
private final Map<String, TransformationConfiguration> configurationMap = new HashMap<>(); private final Map<String, Transformation> configurationMap = new HashMap<>();
@BeforeEach @BeforeEach
public void setUp() throws IOException { public void setUp() throws IOException {
@ -70,20 +70,20 @@ public class MapTransformationServiceTest extends JavaTest {
try { try {
String content = new String(Files.readAllBytes(file), StandardCharsets.UTF_8); String content = new String(Files.readAllBytes(file), StandardCharsets.UTF_8);
String uid = Path.of(SRC_FOLDER).relativize(file).toString(); String uid = Path.of(SRC_FOLDER).relativize(file).toString();
TransformationConfiguration transformationConfiguration = new TransformationConfiguration(uid, uid, Transformation transformation = new Transformation(uid, uid, "map",
"map", null, content); Map.of(Transformation.FUNCTION, content));
configurationMap.put(uid, transformationConfiguration); configurationMap.put(uid, transformation);
} catch (IOException ignored) { } catch (IOException ignored) {
} }
}); });
Mockito.when(transformationConfigurationRegistry.get(anyString(), eq(null))) Mockito.when(transformationRegistry.get(anyString(), eq(null)))
.thenAnswer((Answer<TransformationConfiguration>) invocation -> { .thenAnswer((Answer<Transformation>) invocation -> {
Object[] args = invocation.getArguments(); Object[] args = invocation.getArguments();
return configurationMap.get(args[0]); return configurationMap.get(args[0]);
}); });
processor = new MapTransformationService(transformationConfigurationRegistry); processor = new MapTransformationService(transformationRegistry);
} }
@Test @Test
@ -109,49 +109,40 @@ public class MapTransformationServiceTest extends JavaTest {
} }
@Test @Test
public void setTransformationConfigurationIsRemoved() throws TransformationException { public void setTransformationIsRemoved() throws TransformationException {
assertEquals("zu", processor.transform(NON_DEFAULTED_TRANSFORMATION_DE, SOURCE_CLOSED)); assertEquals("zu", processor.transform(NON_DEFAULTED_TRANSFORMATION_DE, SOURCE_CLOSED));
TransformationConfiguration transformationConfiguration = configurationMap Transformation transformation = configurationMap.remove(NON_DEFAULTED_TRANSFORMATION_DE);
.remove(NON_DEFAULTED_TRANSFORMATION_DE); processor.removed(Objects.requireNonNull(transformation));
processor.removed(Objects.requireNonNull(transformationConfiguration));
assertThrows(TransformationException.class, assertThrows(TransformationException.class,
() -> processor.transform(NON_DEFAULTED_TRANSFORMATION_DE, SOURCE_CLOSED)); () -> processor.transform(NON_DEFAULTED_TRANSFORMATION_DE, SOURCE_CLOSED));
} }
@Test @Test
public void setTransformationConfigurationIsNotUpdatedIfOldElementMissing() throws TransformationException { public void setTransformationIsNotUpdatedIfOldElementMissing() throws TransformationException {
// update configuration // update configuration
TransformationConfiguration transformationConfigurationDE = Objects Transformation transformationDE = Objects.requireNonNull(configurationMap.get(NON_DEFAULTED_TRANSFORMATION_DE));
.requireNonNull(configurationMap.get(NON_DEFAULTED_TRANSFORMATION_DE)); Transformation transformationFR = Objects.requireNonNull(configurationMap.get(NON_DEFAULTED_TRANSFORMATION_FR));
TransformationConfiguration transformationConfigurationFR = Objects Transformation transformationModified = new Transformation(transformationDE.getUID(),
.requireNonNull(configurationMap.get(NON_DEFAULTED_TRANSFORMATION_FR)); transformationDE.getLabel(), transformationDE.getType(), transformationDE.getConfiguration());
TransformationConfiguration transformationConfigurationModified = new TransformationConfiguration( processor.updated(transformationDE, transformationModified);
transformationConfigurationDE.getUID(), transformationConfigurationDE.getLabel(),
transformationConfigurationDE.getType(), transformationConfigurationDE.getLanguage(),
transformationConfigurationFR.getContent());
processor.updated(transformationConfigurationDE, transformationConfigurationModified);
// assert there is no modified cached version // assert there is no modified cached version
assertEquals("zu", processor.transform(NON_DEFAULTED_TRANSFORMATION_DE, SOURCE_CLOSED)); assertEquals("zu", processor.transform(NON_DEFAULTED_TRANSFORMATION_DE, SOURCE_CLOSED));
} }
@Test @Test
public void setTransformationConfigurationIsUpdatedIfOldElementPresent() throws TransformationException { public void setTransformationIsUpdatedIfOldElementPresent() throws TransformationException {
// ensure old transformation is cached // ensure old transformation is cached
processor.transform(NON_DEFAULTED_TRANSFORMATION_DE, SOURCE_CLOSED); processor.transform(NON_DEFAULTED_TRANSFORMATION_DE, SOURCE_CLOSED);
// update configuration // update configuration
TransformationConfiguration transformationConfigurationDE = Objects Transformation transformationDE = Objects.requireNonNull(configurationMap.get(NON_DEFAULTED_TRANSFORMATION_DE));
.requireNonNull(configurationMap.get(NON_DEFAULTED_TRANSFORMATION_DE)); Transformation transformationFR = Objects.requireNonNull(configurationMap.get(NON_DEFAULTED_TRANSFORMATION_FR));
TransformationConfiguration transformationConfigurationFR = Objects Transformation transformationModified = new Transformation(transformationDE.getUID(),
.requireNonNull(configurationMap.get(NON_DEFAULTED_TRANSFORMATION_FR)); transformationDE.getLabel(), transformationDE.getType(), transformationFR.getConfiguration());
TransformationConfiguration transformationConfigurationModified = new TransformationConfiguration( processor.updated(transformationDE, transformationModified);
transformationConfigurationDE.getUID(), transformationConfigurationDE.getLabel(),
transformationConfigurationDE.getType(), transformationConfigurationDE.getLanguage(),
transformationConfigurationFR.getContent());
processor.updated(transformationConfigurationDE, transformationConfigurationModified);
// ensure modified configuration is applied // ensure modified configuration is applied
assertEquals("fermé", processor.transform(NON_DEFAULTED_TRANSFORMATION_DE, SOURCE_CLOSED)); assertEquals("fermé", processor.transform(NON_DEFAULTED_TRANSFORMATION_DE, SOURCE_CLOSED));

View File

@ -37,9 +37,9 @@ import org.openhab.core.common.registry.RegistryChangeListener;
import org.openhab.core.config.core.ConfigOptionProvider; import org.openhab.core.config.core.ConfigOptionProvider;
import org.openhab.core.config.core.ParameterOption; import org.openhab.core.config.core.ParameterOption;
import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.types.QuantityType;
import org.openhab.core.transform.TransformationConfiguration; import org.openhab.core.transform.Transformation;
import org.openhab.core.transform.TransformationConfigurationRegistry;
import org.openhab.core.transform.TransformationException; import org.openhab.core.transform.TransformationException;
import org.openhab.core.transform.TransformationRegistry;
import org.openhab.core.transform.TransformationService; import org.openhab.core.transform.TransformationService;
import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Component;
@ -59,7 +59,7 @@ import org.slf4j.LoggerFactory;
"openhab.transform=SCALE" }) "openhab.transform=SCALE" })
@NonNullByDefault @NonNullByDefault
public class ScaleTransformationService public class ScaleTransformationService
implements TransformationService, ConfigOptionProvider, RegistryChangeListener<TransformationConfiguration> { implements TransformationService, ConfigOptionProvider, RegistryChangeListener<Transformation> {
private final Logger logger = LoggerFactory.getLogger(ScaleTransformationService.class); private final Logger logger = LoggerFactory.getLogger(ScaleTransformationService.class);
@ -77,34 +77,33 @@ public class ScaleTransformationService
/** Inaccessible range used to store presentation format ]0..0[ */ /** Inaccessible range used to store presentation format ]0..0[ */
private static final Range FORMAT_RANGE = Range.range(BigDecimal.ZERO, false, BigDecimal.ZERO, false); private static final Range FORMAT_RANGE = Range.range(BigDecimal.ZERO, false, BigDecimal.ZERO, false);
private final TransformationConfigurationRegistry transformationConfigurationRegistry; private final TransformationRegistry transformationRegistry;
private final Map<String, Map<@Nullable Range, String>> cachedTransformations = new ConcurrentHashMap<>(); private final Map<String, Map<@Nullable Range, String>> cachedTransformations = new ConcurrentHashMap<>();
@Activate @Activate
public ScaleTransformationService( public ScaleTransformationService(@Reference TransformationRegistry transformationRegistry) {
@Reference TransformationConfigurationRegistry transformationConfigurationRegistry) { this.transformationRegistry = transformationRegistry;
this.transformationConfigurationRegistry = transformationConfigurationRegistry; transformationRegistry.addRegistryChangeListener(this);
transformationConfigurationRegistry.addRegistryChangeListener(this);
} }
@Deactivate @Deactivate
public void deactivate() { public void deactivate() {
transformationConfigurationRegistry.removeRegistryChangeListener(this); transformationRegistry.removeRegistryChangeListener(this);
} }
@Override @Override
public void added(TransformationConfiguration element) { public void added(Transformation element) {
// do nothing, configurations are added to cache if needed // do nothing, configurations are added to cache if needed
} }
@Override @Override
public void removed(TransformationConfiguration element) { public void removed(Transformation element) {
cachedTransformations.remove(element.getUID()); cachedTransformations.remove(element.getUID());
} }
@Override @Override
public void updated(TransformationConfiguration oldElement, TransformationConfiguration element) { public void updated(Transformation oldElement, Transformation element) {
if (cachedTransformations.remove(oldElement.getUID()) != null) { if (cachedTransformations.remove(oldElement.getUID()) != null) {
// import only if it was present before // import only if it was present before
importConfiguration(element); importConfiguration(element);
@ -144,12 +143,11 @@ public class ScaleTransformationService
@Override @Override
public @Nullable String transform(String function, String source) throws TransformationException { public @Nullable String transform(String function, String source) throws TransformationException {
// always get a configuration from the registry to account for changed system locale // always get a configuration from the registry to account for changed system locale
TransformationConfiguration transformationConfiguration = transformationConfigurationRegistry.get(function, Transformation transformation = transformationRegistry.get(function, null);
null);
if (transformationConfiguration != null) { if (transformation != null) {
if (!cachedTransformations.containsKey(transformationConfiguration.getUID())) { if (!cachedTransformations.containsKey(transformation.getUID())) {
importConfiguration(transformationConfiguration); importConfiguration(transformation);
} }
Map<@Nullable Range, String> data = cachedTransformations.get(function); Map<@Nullable Range, String> data = cachedTransformations.get(function);
@ -196,13 +194,17 @@ public class ScaleTransformationService
.orElseThrow(() -> new TransformationException("No matching range for '" + source + "'")); .orElseThrow(() -> new TransformationException("No matching range for '" + source + "'"));
} }
private void importConfiguration(@Nullable TransformationConfiguration configuration) { private void importConfiguration(@Nullable Transformation configuration) {
if (configuration != null) { if (configuration != null) {
try { try {
final Map<@Nullable Range, String> data = new LinkedHashMap<>(); final Map<@Nullable Range, String> data = new LinkedHashMap<>();
data.put(FORMAT_RANGE, FORMAT_LABEL); data.put(FORMAT_RANGE, FORMAT_LABEL);
final OrderedProperties properties = new OrderedProperties(); final OrderedProperties properties = new OrderedProperties();
properties.load(new StringReader(configuration.getContent())); String function = configuration.getConfiguration().get(Transformation.FUNCTION);
if (function == null) {
return;
}
properties.load(new StringReader(function));
for (Object orderedKey : properties.orderedKeys()) { for (Object orderedKey : properties.orderedKeys()) {
final String entry = (String) orderedKey; final String entry = (String) orderedKey;
@ -244,7 +246,7 @@ public class ScaleTransformationService
@Nullable Locale locale) { @Nullable Locale locale) {
if (PROFILE_CONFIG_URI.equals(uri.toString())) { if (PROFILE_CONFIG_URI.equals(uri.toString())) {
if (CONFIG_PARAM_FUNCTION.equals(param)) { if (CONFIG_PARAM_FUNCTION.equals(param)) {
return transformationConfigurationRegistry.getConfigurations(SUPPORTED_CONFIGURATION_TYPES).stream() return transformationRegistry.getTransformations(SUPPORTED_CONFIGURATION_TYPES).stream()
.map(c -> new ParameterOption(c.getUID(), c.getLabel())).collect(Collectors.toList()); .map(c -> new ParameterOption(c.getUID(), c.getLabel())).collect(Collectors.toList());
} }
} }

View File

@ -37,9 +37,9 @@ import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness; import org.mockito.quality.Strictness;
import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer;
import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.types.QuantityType;
import org.openhab.core.transform.TransformationConfiguration; import org.openhab.core.transform.Transformation;
import org.openhab.core.transform.TransformationConfigurationRegistry;
import org.openhab.core.transform.TransformationException; import org.openhab.core.transform.TransformationException;
import org.openhab.core.transform.TransformationRegistry;
/** /**
* @author Gaël L'hopital - Initial contribution * @author Gaël L'hopital - Initial contribution
@ -51,8 +51,8 @@ public class ScaleTransformServiceTest {
private static final String SRC_FOLDER = "conf" + File.separator + "transform"; private static final String SRC_FOLDER = "conf" + File.separator + "transform";
@Mock @Mock
private @NonNullByDefault({}) TransformationConfigurationRegistry transformationConfigurationRegistry; private @NonNullByDefault({}) TransformationRegistry transformationConfigurationRegistry;
private final Map<String, TransformationConfiguration> configurationMap = new HashMap<>(); private final Map<String, Transformation> configurationMap = new HashMap<>();
private @NonNullByDefault({}) ScaleTransformationService processor; private @NonNullByDefault({}) ScaleTransformationService processor;
@BeforeEach @BeforeEach
@ -62,15 +62,15 @@ public class ScaleTransformServiceTest {
try { try {
String content = new String(Files.readAllBytes(file), StandardCharsets.UTF_8); String content = new String(Files.readAllBytes(file), StandardCharsets.UTF_8);
String uid = Path.of(SRC_FOLDER).relativize(file).toString(); String uid = Path.of(SRC_FOLDER).relativize(file).toString();
TransformationConfiguration transformationConfiguration = new TransformationConfiguration(uid, uid, Transformation transformationConfiguration = new Transformation(uid, uid, "scale",
"scale", null, content); Map.of(Transformation.FUNCTION, content));
configurationMap.put(uid, transformationConfiguration); configurationMap.put(uid, transformationConfiguration);
} catch (IOException ignored) { } catch (IOException ignored) {
} }
}); });
Mockito.when(transformationConfigurationRegistry.get(anyString(), eq(null))) Mockito.when(transformationConfigurationRegistry.get(anyString(), eq(null)))
.thenAnswer((Answer<TransformationConfiguration>) invocation -> { .thenAnswer((Answer<Transformation>) invocation -> {
Object[] args = invocation.getArguments(); Object[] args = invocation.getArguments();
return configurationMap.get(args[0]); return configurationMap.get(args[0]);
}); });