2 * Copyright (c) 2010-2022 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.transform.map.internal;
15 import java.io.IOException;
16 import java.io.StringReader;
18 import java.util.Collection;
19 import java.util.Locale;
21 import java.util.Properties;
23 import java.util.concurrent.ConcurrentHashMap;
24 import java.util.stream.Collectors;
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.openhab.core.common.registry.RegistryChangeListener;
29 import org.openhab.core.config.core.ConfigOptionProvider;
30 import org.openhab.core.config.core.ParameterOption;
31 import org.openhab.core.transform.TransformationConfiguration;
32 import org.openhab.core.transform.TransformationConfigurationRegistry;
33 import org.openhab.core.transform.TransformationException;
34 import org.openhab.core.transform.TransformationService;
35 import org.osgi.service.component.annotations.Activate;
36 import org.osgi.service.component.annotations.Component;
37 import org.osgi.service.component.annotations.Deactivate;
38 import org.osgi.service.component.annotations.Reference;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
44 * The implementation of {@link TransformationService} which simply maps strings to other strings
46 * @author Kai Kreuzer - Initial contribution and API
47 * @author Gaƫl L'hopital - Make it localizable
48 * @author Jan N. Klug - Refactored to use {@link TransformationConfigurationRegistry}
51 @Component(service = { TransformationService.class, ConfigOptionProvider.class }, property = {
52 "openhab.transform=MAP" })
53 public class MapTransformationService
54 implements TransformationService, ConfigOptionProvider, RegistryChangeListener<TransformationConfiguration> {
55 private final Logger logger = LoggerFactory.getLogger(MapTransformationService.class);
57 private static final String PROFILE_CONFIG_URI = "profile:transform:MAP";
58 private static final String CONFIG_PARAM_FUNCTION = "function";
59 private static final Set<String> SUPPORTED_CONFIGURATION_TYPES = Set.of("map");
61 private final TransformationConfigurationRegistry transformationConfigurationRegistry;
62 private final Map<String, Properties> cachedTransformations = new ConcurrentHashMap<>();
65 public MapTransformationService(
66 @Reference TransformationConfigurationRegistry transformationConfigurationRegistry) {
67 this.transformationConfigurationRegistry = transformationConfigurationRegistry;
68 transformationConfigurationRegistry.addRegistryChangeListener(this);
72 public void deactivate() {
73 transformationConfigurationRegistry.removeRegistryChangeListener(this);
77 public @Nullable String transform(String function, String source) throws TransformationException {
78 // always get a configuration from the registry to account for changed system locale
79 TransformationConfiguration transformationConfiguration = transformationConfigurationRegistry.get(function,
82 if (transformationConfiguration != null) {
83 if (!cachedTransformations.containsKey(transformationConfiguration.getUID())) {
84 importConfiguration(transformationConfiguration);
86 Properties properties = cachedTransformations.get(function);
87 if (properties != null) {
88 String target = properties.getProperty(source);
91 target = properties.getProperty("");
93 throw new TransformationException("Target value not found in map for '" + source + "'");
97 logger.debug("Transformation resulted in '{}'", target);
101 throw new TransformationException("Could not find configuration '" + function + "' or failed to parse it.");
105 public @Nullable Collection<ParameterOption> getParameterOptions(URI uri, String param, @Nullable String context,
106 @Nullable Locale locale) {
107 if (PROFILE_CONFIG_URI.equals(uri.toString())) {
108 if (CONFIG_PARAM_FUNCTION.equals(param)) {
109 return transformationConfigurationRegistry.getConfigurations(SUPPORTED_CONFIGURATION_TYPES).stream()
110 .map(c -> new ParameterOption(c.getUID(), c.getLabel())).collect(Collectors.toList());
117 public void added(TransformationConfiguration element) {
118 // do nothing, configurations are added to cache if needed
122 public void removed(TransformationConfiguration element) {
123 cachedTransformations.remove(element.getUID());
127 public void updated(TransformationConfiguration oldElement, TransformationConfiguration element) {
128 if (cachedTransformations.remove(oldElement.getUID()) != null) {
129 // import only if it was present before
130 importConfiguration(element);
134 private void importConfiguration(@Nullable TransformationConfiguration configuration) {
135 if (configuration != null) {
137 Properties properties = new Properties();
138 properties.load(new StringReader(configuration.getContent()));
139 cachedTransformations.put(configuration.getUID(), properties);
140 } catch (IOException ignored) {