]> git.basschouten.com Git - openhab-addons.git/blob
c70bfa37ffb5761efe4b423df4a1cacd2f98d9e1
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 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 final Logger logger = LoggerFactory.getLogger(MapTransformationService.class);
56
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");
60
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(function);
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                     }
93                 }
94
95                 logger.debug("Transformation resulted in '{}'", target);
96                 return target;
97             }
98         }
99         throw new TransformationException("Could not find configuration '" + function + "' or failed to parse it.");
100     }
101
102     @Override
103     public @Nullable Collection<ParameterOption> getParameterOptions(URI uri, String param, @Nullable String context,
104             @Nullable Locale locale) {
105         if (PROFILE_CONFIG_URI.equals(uri.toString())) {
106             if (CONFIG_PARAM_FUNCTION.equals(param)) {
107                 return transformationRegistry.getTransformations(SUPPORTED_CONFIGURATION_TYPES).stream()
108                         .map(c -> new ParameterOption(c.getUID(), c.getLabel())).collect(Collectors.toList());
109             }
110         }
111         return null;
112     }
113
114     @Override
115     public void added(Transformation element) {
116         // do nothing, configurations are added to cache if needed
117     }
118
119     @Override
120     public void removed(Transformation element) {
121         cachedTransformations.remove(element.getUID());
122     }
123
124     @Override
125     public void updated(Transformation oldElement, Transformation element) {
126         if (cachedTransformations.remove(oldElement.getUID()) != null) {
127             // import only if it was present before
128             importConfiguration(element);
129         }
130     }
131
132     private void importConfiguration(@Nullable Transformation transformation) {
133         if (transformation != null) {
134             try {
135                 Properties properties = new Properties();
136                 String function = transformation.getConfiguration().get(Transformation.FUNCTION);
137                 if (function == null || function.isBlank()) {
138                     logger.warn("Function not defined for transformation '{}'", transformation.getUID());
139                     return;
140                 }
141                 properties.load(new StringReader(function));
142                 cachedTransformations.put(transformation.getUID(), properties);
143             } catch (IOException ignored) {
144             }
145         }
146     }
147 }