]> git.basschouten.com Git - openhab-addons.git/blob
61b795365aae3eda5faf2c95766da7e5cbbe7e02
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.transform.map.internal;
14
15 import java.io.IOException;
16 import java.io.StringReader;
17 import java.net.URI;
18 import java.util.Collection;
19 import java.util.Locale;
20 import java.util.Map;
21 import java.util.Properties;
22 import java.util.Set;
23 import java.util.concurrent.ConcurrentHashMap;
24 import java.util.stream.Collectors;
25
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.Transformation;
32 import org.openhab.core.transform.TransformationException;
33 import org.openhab.core.transform.TransformationRegistry;
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;
41
42 /**
43  * <p>
44  * The implementation of {@link TransformationService} which simply maps strings to other strings
45  *
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 TransformationRegistry}
49  */
50 @NonNullByDefault
51 @Component(service = { TransformationService.class, ConfigOptionProvider.class }, property = {
52         "openhab.transform=MAP" })
53 public class MapTransformationService
54         implements TransformationService, ConfigOptionProvider, RegistryChangeListener<Transformation> {
55     private static final String SOURCE_VALUE = "_source_";
56     private static final String PROFILE_CONFIG_URI = "profile:transform:MAP";
57     private static final String CONFIG_PARAM_FUNCTION = "function";
58     private static final Set<String> SUPPORTED_CONFIGURATION_TYPES = Set.of("map");
59
60     private final Logger logger = LoggerFactory.getLogger(MapTransformationService.class);
61     private final TransformationRegistry transformationRegistry;
62     private final Map<String, Properties> cachedTransformations = new ConcurrentHashMap<>();
63
64     @Activate
65     public MapTransformationService(@Reference TransformationRegistry transformationRegistry) {
66         this.transformationRegistry = transformationRegistry;
67         transformationRegistry.addRegistryChangeListener(this);
68     }
69
70     @Deactivate
71     public void deactivate() {
72         transformationRegistry.removeRegistryChangeListener(this);
73     }
74
75     @Override
76     public @Nullable String transform(String function, String source) throws TransformationException {
77         // always get a configuration from the registry to account for changed system locale
78         Transformation transformation = transformationRegistry.get(function, null);
79
80         if (transformation != null) {
81             if (!cachedTransformations.containsKey(transformation.getUID())) {
82                 importConfiguration(transformation);
83             }
84             Properties properties = cachedTransformations.get(transformation.getUID());
85             if (properties != null) {
86                 String target = properties.getProperty(source);
87
88                 if (target == null) {
89                     target = properties.getProperty("");
90                     if (target == null) {
91                         throw new TransformationException("Target value not found in map for '" + source + "'");
92                     } else if (SOURCE_VALUE.equals(target)) {
93                         target = source;
94                     }
95                 }
96
97                 logger.debug("Transformation resulted in '{}'", target);
98                 return target;
99             }
100         }
101         throw new TransformationException("Could not find configuration '" + function + "' or failed to parse it.");
102     }
103
104     @Override
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 transformationRegistry.getTransformations(SUPPORTED_CONFIGURATION_TYPES).stream()
110                         .map(c -> new ParameterOption(c.getUID(), c.getLabel())).collect(Collectors.toList());
111             }
112         }
113         return null;
114     }
115
116     @Override
117     public void added(Transformation element) {
118         // do nothing, configurations are added to cache if needed
119     }
120
121     @Override
122     public void removed(Transformation element) {
123         cachedTransformations.remove(element.getUID());
124     }
125
126     @Override
127     public void updated(Transformation oldElement, Transformation element) {
128         if (cachedTransformations.remove(oldElement.getUID()) != null) {
129             // import only if it was present before
130             importConfiguration(element);
131         }
132     }
133
134     private void importConfiguration(@Nullable Transformation transformation) {
135         if (transformation != null) {
136             try {
137                 Properties properties = new Properties();
138                 String function = transformation.getConfiguration().get(Transformation.FUNCTION);
139                 if (function == null || function.isBlank()) {
140                     logger.warn("Function not defined for transformation '{}'", transformation.getUID());
141                     return;
142                 }
143                 properties.load(new StringReader(function));
144                 cachedTransformations.put(transformation.getUID(), properties);
145             } catch (IOException ignored) {
146             }
147         }
148     }
149 }