mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 07:02:02 +01:00
Raise minimum JDK version to 17 (#13276)
Signed-off-by: Jan N. Klug <github@klug.nrw>
This commit is contained in:
parent
4d6d6443ef
commit
9f3b8e1c04
@ -395,7 +395,6 @@
|
||||
/bundles/org.openhab.persistence.rrd4j/ @openhab/add-ons-maintainers
|
||||
/bundles/org.openhab.transform.bin2json/ @paulianttila
|
||||
/bundles/org.openhab.transform.exec/ @openhab/add-ons-maintainers
|
||||
/bundles/org.openhab.transform.javascript/ @openhab/add-ons-maintainers
|
||||
/bundles/org.openhab.transform.jinja/ @jochen314
|
||||
/bundles/org.openhab.transform.jsonpath/ @clinique
|
||||
/bundles/org.openhab.transform.map/ @openhab/add-ons-maintainers
|
||||
|
@ -1966,11 +1966,6 @@
|
||||
<artifactId>org.openhab.transform.exec</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.transform.javascript</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.transform.jinja</artifactId>
|
||||
|
@ -109,9 +109,9 @@ public class EnOceanDeviceDiscoveryService extends AbstractDiscoveryService impl
|
||||
|
||||
String enoceanId = HexUtils.bytesToHex(eep.getSenderId());
|
||||
|
||||
bridgeHandler.getThing().getThings().stream()
|
||||
.filter(t -> t.getConfiguration().getProperties().getOrDefault(PARAMETER_ENOCEANID, EMPTYENOCEANID)
|
||||
.toString().equals(enoceanId))
|
||||
bridgeHandler
|
||||
.getThing().getThings().stream().filter(t -> t.getConfiguration().getProperties()
|
||||
.getOrDefault(PARAMETER_ENOCEANID, EMPTYENOCEANID).toString().equals(enoceanId))
|
||||
.findFirst().ifPresentOrElse(t -> {
|
||||
// If repeated learn is not allowed => send teach out
|
||||
// otherwise do nothing
|
||||
|
@ -73,8 +73,8 @@ final class ChannelSceneSilentmode extends ChannelHandlerTemplate {
|
||||
LOGGER.debug("handleCommand({},{},{},{}) called.", channelUID, channelId, command, thisBridgeHandler);
|
||||
Command newValue = null;
|
||||
do { // just for common exit
|
||||
assert thisBridgeHandler.bridgeParameters.scenes
|
||||
.getChannel().existingScenes != null : "VeluxBridgeHandler.existingScenes not initialized.";
|
||||
assert thisBridgeHandler.bridgeParameters.scenes.getChannel().existingScenes != null
|
||||
: "VeluxBridgeHandler.existingScenes not initialized.";
|
||||
if (!ThingConfiguration.exists(thisBridgeHandler, channelUID, VeluxBindingProperties.PROPERTY_SCENE_NAME)) {
|
||||
LOGGER.trace("handleCommand(): aborting processing as scene name is not set.");
|
||||
break;
|
||||
|
@ -1,13 +0,0 @@
|
||||
This content is produced and maintained by the openHAB project.
|
||||
|
||||
* Project home: https://www.openhab.org
|
||||
|
||||
== Declared Project Licenses
|
||||
|
||||
This program and the accompanying materials are made available under the terms
|
||||
of the Eclipse Public License 2.0 which is available at
|
||||
https://www.eclipse.org/legal/epl-2.0/.
|
||||
|
||||
== Source Code
|
||||
|
||||
https://github.com/openhab/openhab-addons
|
@ -1,78 +0,0 @@
|
||||
# JavaScript Transformation Service
|
||||
|
||||
Transform an input to an output using JavaScript.
|
||||
|
||||
It expects the transformation rule to be read from a file which is stored under the `transform` folder.
|
||||
To organize the various transformations, one should use subfolders.
|
||||
|
||||
Simple transformation rules can also be given as an inline script.
|
||||
Inline script should be start by `|` character following the JavaScript.
|
||||
Beware that complex inline script could cause issues to e.g. item file parsing.
|
||||
|
||||
## Examples
|
||||
|
||||
Let's assume we have received a string containing `foo bar baz` and we're looking for a length of the last word (`baz`).
|
||||
|
||||
transform/getValue.js:
|
||||
|
||||
```
|
||||
(function(i) {
|
||||
var array = i.split(" ");
|
||||
return array[array.length - 1].length;
|
||||
})(input)
|
||||
```
|
||||
|
||||
JavaScript transformation syntax also support additional parameters which can be passed to the script.
|
||||
This can prevent redundancy when transformation is needed for several use cases, but with small adaptations.
|
||||
Additional parameters can be passed to the script via [URI](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier) query syntax.
|
||||
|
||||
As `input` name is reserved for transformed data, it can't be used in query parameters.
|
||||
Also `?` and `&` characters are reserved, but if they need to passed as additional data, they can be escaped according to URI syntax.
|
||||
|
||||
|
||||
transform/scale.js:
|
||||
```
|
||||
(function(data, cf, d) {
|
||||
return parseFloat(data) * parseFloat(cf) / parseFloat(d);
|
||||
})(input, correctionFactor, divider)
|
||||
```
|
||||
|
||||
`transform/scale.js?correctionFactor=1.1÷r=10`
|
||||
|
||||
Following example will return value `23.54` when `input` data is `214`.
|
||||
|
||||
### Inline script example:
|
||||
|
||||
Normally JavaScript transformation is given by filename, e.g. `JS(transform/getValue.js)`.
|
||||
Inline script can be given by `|` character following the JavaScript, e.g. `JS(| input / 10)`.
|
||||
|
||||
## Test JavaScript
|
||||
|
||||
You can use online JavaScript testers to validate your script.
|
||||
E.g. https://www.webtoolkitonline.com/javascript-tester.html
|
||||
|
||||
`Input` variable need to be replaced by the test string, e.g. earlier test string `foo bar baz`
|
||||
|
||||
```
|
||||
(function(i) {
|
||||
var array = i.split(" ");
|
||||
return array[array.length - 1].length;
|
||||
})("foo bar baz")
|
||||
```
|
||||
|
||||
When you press execute button, tester will show the result returned by the script or error if script contains any.
|
||||
|
||||
## Usage as a Profile
|
||||
|
||||
The functionality of this `TransformationService` can be used in a `Profile` on an `ItemChannelLink` too.
|
||||
To do so, it can be configured in the `.items` file as follows:
|
||||
|
||||
```java
|
||||
String <itemName> { channel="<channelUID>"[profile="transform:JS", function="<filename>", sourceFormat="<valueFormat>"]}
|
||||
```
|
||||
|
||||
The Javascript file (from within the `transform` folder) to be used has to be set in the `function` parameter.
|
||||
The parameter `sourceFormat` is optional and can be used to format the input value **before** the transformation, i.e. `%.3f`.
|
||||
If omitted the default is `%s`, so the input value will be put into the transformation without any format changes.
|
||||
|
||||
Please note: This profile is a one-way transformation, i.e. only values from a device towards the item are changed, the other direction is left untouched.
|
@ -1,4 +0,0 @@
|
||||
(function(i) {
|
||||
var array = i.split(" ");
|
||||
return array[array.length - 1].length;
|
||||
})(input)
|
@ -1,4 +0,0 @@
|
||||
(function(i) {
|
||||
var array = i.split(" ");
|
||||
return array[array.length - 1].length;
|
||||
})(input)
|
@ -1,3 +0,0 @@
|
||||
(function(i, a, b) {
|
||||
return b;
|
||||
})(input, a, test)
|
@ -1,3 +0,0 @@
|
||||
(function(data, cf, d) {
|
||||
return parseFloat(data) * parseFloat(cf) / parseFloat(d);
|
||||
})(input, correctionFactor, divider)
|
@ -1,3 +0,0 @@
|
||||
(function(i, a, b) {
|
||||
return parseInt(i) + parseInt(a) + parseInt(b);
|
||||
})(input, a, b)
|
@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.transform.javascript-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
|
||||
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
|
||||
|
||||
<feature name="openhab-transformation-javascript" description="Javascript Transformation" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="75">mvn:org.openhab.addons.bundles/org.openhab.transform.javascript/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
@ -1,133 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.transform.javascript.internal;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.time.Duration;
|
||||
import java.util.Base64;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.script.Compilable;
|
||||
import javax.script.CompiledScript;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.cache.ExpiringCacheMap;
|
||||
import org.openhab.core.transform.TransformationException;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Simple cache for compiled JavaScript files.
|
||||
*
|
||||
* @author Thomas Kordelle - Initial contribution
|
||||
* @author Thomas Kordelle - pre compiled scripts
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = JavaScriptEngineManager.class)
|
||||
public class JavaScriptEngineManager {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(JavaScriptEngineManager.class);
|
||||
private final ScriptEngineManager manager = new ScriptEngineManager();
|
||||
/* keep memory foot print low. max 2 concurrent threads are estimated */
|
||||
private final Map<String, CompiledScript> compiledScriptMap = new ConcurrentHashMap<>(4, 0.5f, 2);
|
||||
private final ExpiringCacheMap<String, CompiledScript> cacheForInlineScripts = new ExpiringCacheMap<>(
|
||||
Duration.ofDays(1));
|
||||
|
||||
/**
|
||||
* Get a pre compiled script {@link CompiledScript} from cache. If it is not in the cache, then load it from
|
||||
* storage and put a pre compiled version into the cache.
|
||||
*
|
||||
* @param filename name of the JavaScript file to load
|
||||
* @return a pre compiled script {@link CompiledScript}
|
||||
* @throws TransformationException if compile of JavaScript failed
|
||||
*/
|
||||
protected CompiledScript getCompiledScriptByFilename(final String filename) throws TransformationException {
|
||||
synchronized (compiledScriptMap) {
|
||||
CompiledScript compiledScript = compiledScriptMap.get(filename);
|
||||
if (compiledScript != null) {
|
||||
logger.debug("Loading JavaScript {} from cache.", filename);
|
||||
return compiledScript;
|
||||
} else {
|
||||
final String path = TransformationScriptWatcher.TRANSFORM_FOLDER + File.separator + filename;
|
||||
logger.debug("Loading script {} from storage ", path);
|
||||
try (final Reader reader = new InputStreamReader(new FileInputStream(path))) {
|
||||
final ScriptEngine engine = manager.getEngineByName("javascript");
|
||||
final CompiledScript cScript = ((Compilable) engine).compile(reader);
|
||||
logger.debug("Putting compiled JavaScript {} to cache.", cScript);
|
||||
compiledScriptMap.put(filename, cScript);
|
||||
return cScript;
|
||||
} catch (IOException | ScriptException e) {
|
||||
throw new TransformationException("An error occurred while loading JavaScript. " + e.getMessage(),
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a pre compiled script {@link CompiledScript} from cache. If it is not in the cache, then compile
|
||||
* it and put a pre compiled version into the cache.
|
||||
*
|
||||
* @param script JavaScript which should be returned as a pre compiled
|
||||
* @return a pre compiled script {@link CompiledScript}
|
||||
* @throws TransformationException if compile of JavaScript failed
|
||||
*/
|
||||
protected CompiledScript getCompiledScriptByInlineScript(final String script) throws TransformationException {
|
||||
synchronized (cacheForInlineScripts) {
|
||||
try {
|
||||
final String hash = calcHash(script);
|
||||
final CompiledScript compiledScript = cacheForInlineScripts.get(hash);
|
||||
if (compiledScript != null) {
|
||||
logger.debug("Loading JavaScript from cache.");
|
||||
return compiledScript;
|
||||
} else {
|
||||
logger.debug("Compiling script {}", script);
|
||||
final ScriptEngine engine = manager.getEngineByName("javascript");
|
||||
final CompiledScript cScript = ((Compilable) engine).compile(script);
|
||||
cacheForInlineScripts.put(hash, () -> cScript);
|
||||
return cScript;
|
||||
}
|
||||
} catch (ScriptException | NoSuchAlgorithmException e) {
|
||||
throw new TransformationException("An error occurred while compiling JavaScript. " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* remove a pre compiled script from cache.
|
||||
*
|
||||
* @param fileName name of the script file to remove
|
||||
*/
|
||||
protected void removeFromCache(String fileName) {
|
||||
logger.debug("Removing JavaScript {} from cache.", fileName);
|
||||
compiledScriptMap.remove(fileName);
|
||||
}
|
||||
|
||||
private String calcHash(final String script) throws NoSuchAlgorithmException {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
byte[] hash = digest.digest(script.getBytes(StandardCharsets.UTF_8));
|
||||
return Base64.getEncoder().encodeToString(hash);
|
||||
}
|
||||
}
|
@ -1,204 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.transform.javascript.internal;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.net.URI;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.CompiledScript;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.config.core.ConfigOptionProvider;
|
||||
import org.openhab.core.config.core.ParameterOption;
|
||||
import org.openhab.core.transform.TransformationException;
|
||||
import org.openhab.core.transform.TransformationService;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The implementation of {@link TransformationService} which transforms the
|
||||
* input by Java Script.
|
||||
*
|
||||
* @author Pauli Anttila - Initial contribution
|
||||
* @author Thomas Kordelle - pre compiled scripts
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = { TransformationService.class, ConfigOptionProvider.class }, property = { "openhab.transform=JS" })
|
||||
public class JavaScriptTransformationService implements TransformationService, ConfigOptionProvider {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(JavaScriptTransformationService.class);
|
||||
|
||||
private static final char EXTENSION_SEPARATOR = '.';
|
||||
|
||||
private static final String PROFILE_CONFIG_URI = "profile:transform:JS";
|
||||
private static final String CONFIG_PARAM_FUNCTION = "function";
|
||||
private static final String[] FILE_NAME_EXTENSIONS = { "js" };
|
||||
|
||||
private static final String SCRIPT_DATA_WORD = "input";
|
||||
|
||||
private final JavaScriptEngineManager manager;
|
||||
|
||||
@Activate
|
||||
public JavaScriptTransformationService(final @Reference JavaScriptEngineManager manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the input <code>source</code> by Java Script. If script is a filename, it expects the
|
||||
* transformation rule to be read from a file which is stored under the
|
||||
* 'configurations/transform' folder. To organize the various
|
||||
* transformations one should use subfolders.
|
||||
*
|
||||
* @param filenameOrInlineScript parameter can be 1) the name of the file which contains the Java script
|
||||
* transformation rule. Filename can also include additional
|
||||
* variables in URI query variable format which will be injected
|
||||
* to script engine. 2) inline script when starting with '|' character.
|
||||
* Transformation service inject input (source) to 'input' variable.
|
||||
* @param source the input to transform
|
||||
*/
|
||||
@Override
|
||||
public @Nullable String transform(String filenameOrInlineScript, String source) throws TransformationException {
|
||||
final long startTime = System.currentTimeMillis();
|
||||
logger.debug("about to transform '{}' by the JavaScript '{}'", source, filenameOrInlineScript);
|
||||
|
||||
Map<String, String> vars = Collections.emptyMap();
|
||||
String result = "";
|
||||
|
||||
CompiledScript cScript;
|
||||
|
||||
if (filenameOrInlineScript.startsWith("|")) {
|
||||
// inline java script
|
||||
cScript = manager.getCompiledScriptByInlineScript(filenameOrInlineScript.substring(1));
|
||||
} else {
|
||||
String filename = filenameOrInlineScript;
|
||||
|
||||
if (filename.contains("?")) {
|
||||
String[] parts = filename.split("\\?");
|
||||
if (parts.length > 2) {
|
||||
throw new TransformationException("Questionmark should be defined only once in the filename");
|
||||
}
|
||||
filename = parts[0];
|
||||
try {
|
||||
vars = splitQuery(parts[1]);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new TransformationException("Illegal filename syntax");
|
||||
}
|
||||
if (isReservedWordUsed(vars)) {
|
||||
throw new TransformationException(
|
||||
"'" + SCRIPT_DATA_WORD + "' word is reserved and can't be used in additional parameters");
|
||||
}
|
||||
}
|
||||
|
||||
cScript = manager.getCompiledScriptByFilename(filename);
|
||||
}
|
||||
|
||||
try {
|
||||
final Bindings bindings = cScript.getEngine().createBindings();
|
||||
bindings.put(SCRIPT_DATA_WORD, source);
|
||||
vars.forEach((k, v) -> bindings.put(k, v));
|
||||
result = String.valueOf(cScript.eval(bindings));
|
||||
return result;
|
||||
} catch (ScriptException e) {
|
||||
throw new TransformationException("An error occurred while executing script. " + e.getMessage(), e);
|
||||
} finally {
|
||||
logger.trace("JavaScript execution elapsed {} ms. Result: {}", System.currentTimeMillis() - startTime,
|
||||
result);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isReservedWordUsed(Map<String, String> map) {
|
||||
for (String key : map.keySet()) {
|
||||
if (SCRIPT_DATA_WORD.equals(key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Map<String, String> splitQuery(@Nullable String query) throws IllegalArgumentException {
|
||||
Map<String, String> result = new LinkedHashMap<>();
|
||||
if (query != null) {
|
||||
String[] pairs = query.split("&");
|
||||
for (String pair : pairs) {
|
||||
String[] keyval = pair.split("=");
|
||||
if (keyval.length != 2) {
|
||||
throw new IllegalArgumentException();
|
||||
} else {
|
||||
result.put(URLDecoder.decode(keyval[0], StandardCharsets.UTF_8),
|
||||
URLDecoder.decode(keyval[1], StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Collection<ParameterOption> getParameterOptions(URI uri, String param, @Nullable String context,
|
||||
@Nullable Locale locale) {
|
||||
if (PROFILE_CONFIG_URI.equals(uri.toString())) {
|
||||
switch (param) {
|
||||
case CONFIG_PARAM_FUNCTION:
|
||||
return getFilenames(FILE_NAME_EXTENSIONS).stream().map(f -> new ParameterOption(f, f))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all files with the given extensions in the transformation folder
|
||||
*/
|
||||
private List<String> getFilenames(String[] validExtensions) {
|
||||
File path = new File(TransformationScriptWatcher.TRANSFORM_FOLDER + File.separator);
|
||||
return Arrays.asList(path.listFiles(new FileExtensionsFilter(validExtensions))).stream().map(f -> f.getName())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private class FileExtensionsFilter implements FilenameFilter {
|
||||
|
||||
private final String[] validExtensions;
|
||||
|
||||
public FileExtensionsFilter(String[] validExtensions) {
|
||||
this.validExtensions = validExtensions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(@Nullable File dir, @Nullable String name) {
|
||||
if (name != null) {
|
||||
for (String extension : validExtensions) {
|
||||
if (name.toLowerCase().endsWith(EXTENSION_SEPARATOR + extension)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.transform.javascript.internal;
|
||||
|
||||
import static java.nio.file.StandardWatchEventKinds.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.WatchEvent;
|
||||
import java.nio.file.WatchEvent.Kind;
|
||||
|
||||
import org.openhab.core.OpenHAB;
|
||||
import org.openhab.core.service.AbstractWatchService;
|
||||
import org.openhab.core.transform.TransformationService;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link TransformationScriptWatcher} watches the transformation directory for files. If a deleted/modified file is
|
||||
* detected, the script is passed to the {@link JavaScriptEngineManager}.
|
||||
*
|
||||
* @author Thomas Kordelle - Initial contribution
|
||||
* @author Thomas Kordelle - pre compiled scripts
|
||||
*/
|
||||
@Component
|
||||
public class TransformationScriptWatcher extends AbstractWatchService {
|
||||
public static final String TRANSFORM_FOLDER = OpenHAB.getConfigFolder() + File.separator
|
||||
+ TransformationService.TRANSFORM_FOLDER_NAME;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(TransformationScriptWatcher.class);
|
||||
|
||||
private final JavaScriptEngineManager manager;
|
||||
|
||||
@Activate
|
||||
public TransformationScriptWatcher(final @Reference JavaScriptEngineManager manager) {
|
||||
super(TRANSFORM_FOLDER);
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activate() {
|
||||
super.activate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean watchSubDirectories() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Kind<?>[] getWatchEventKinds(Path directory) {
|
||||
return new Kind<?>[] { ENTRY_DELETE, ENTRY_MODIFY };
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected void processWatchEvent(WatchEvent<?> event, Kind<?> kind, Path path) {
|
||||
logger.debug("New watch event {} for path {}.", kind, path);
|
||||
|
||||
if (kind == OVERFLOW) {
|
||||
return;
|
||||
}
|
||||
|
||||
final WatchEvent<Path> ev = (WatchEvent<Path>) event;
|
||||
final Path filename = ev.context();
|
||||
|
||||
logger.debug("Reloading javascript file {}.", filename);
|
||||
|
||||
manager.removeFromCache(filename.toString());
|
||||
}
|
||||
}
|
@ -1,136 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.transform.javascript.internal.profiles;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.profiles.ProfileCallback;
|
||||
import org.openhab.core.thing.profiles.ProfileContext;
|
||||
import org.openhab.core.thing.profiles.ProfileTypeUID;
|
||||
import org.openhab.core.thing.profiles.StateProfile;
|
||||
import org.openhab.core.transform.TransformationException;
|
||||
import org.openhab.core.transform.TransformationHelper;
|
||||
import org.openhab.core.transform.TransformationService;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.Type;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Profile to offer the JavascriptTransformationservice on an ItemChannelLink
|
||||
*
|
||||
* @author Stefan Triller - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class JavaScriptTransformationProfile implements StateProfile {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(JavaScriptTransformationProfile.class);
|
||||
|
||||
public static final ProfileTypeUID PROFILE_TYPE_UID = new ProfileTypeUID(
|
||||
TransformationService.TRANSFORM_PROFILE_SCOPE, "JS");
|
||||
|
||||
private static final String FUNCTION_PARAM = "function";
|
||||
private static final String SOURCE_FORMAT_PARAM = "sourceFormat";
|
||||
|
||||
private final TransformationService service;
|
||||
private final ProfileCallback callback;
|
||||
|
||||
private final @Nullable String function;
|
||||
private final @Nullable String sourceFormat;
|
||||
|
||||
public JavaScriptTransformationProfile(ProfileCallback callback, ProfileContext context,
|
||||
TransformationService service) {
|
||||
this.service = service;
|
||||
this.callback = callback;
|
||||
|
||||
Object paramFunction = context.getConfiguration().get(FUNCTION_PARAM);
|
||||
Object paramSource = context.getConfiguration().get(SOURCE_FORMAT_PARAM);
|
||||
|
||||
logger.debug("Profile configured with '{}'='{}', '{}'={}", FUNCTION_PARAM, paramFunction, SOURCE_FORMAT_PARAM,
|
||||
paramSource);
|
||||
// SOURCE_FORMAT_PARAM is an advanced parameter and we assume "%s" if it is not set
|
||||
if (paramSource == null) {
|
||||
paramSource = "%s";
|
||||
}
|
||||
if (paramFunction instanceof String && paramSource instanceof String) {
|
||||
function = (String) paramFunction;
|
||||
sourceFormat = (String) paramSource;
|
||||
} else {
|
||||
logger.error("Parameter '{}' and '{}' have to be Strings. Profile will be inactive.", FUNCTION_PARAM,
|
||||
SOURCE_FORMAT_PARAM);
|
||||
function = null;
|
||||
sourceFormat = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProfileTypeUID getProfileTypeUID() {
|
||||
return PROFILE_TYPE_UID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStateUpdateFromItem(State state) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCommandFromItem(Command command) {
|
||||
callback.handleCommand(command);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCommandFromHandler(Command command) {
|
||||
if (function == null || sourceFormat == null) {
|
||||
logger.warn(
|
||||
"Please specify a function and a source format for this Profile in the '{}', and '{}' parameters. Returning the original command now.",
|
||||
FUNCTION_PARAM, SOURCE_FORMAT_PARAM);
|
||||
callback.sendCommand(command);
|
||||
return;
|
||||
}
|
||||
callback.sendCommand((Command) transformState(command));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStateUpdateFromHandler(State state) {
|
||||
if (function == null || sourceFormat == null) {
|
||||
logger.warn(
|
||||
"Please specify a function and a source format for this Profile in the '{}' and '{}' parameters. Returning the original state now.",
|
||||
FUNCTION_PARAM, SOURCE_FORMAT_PARAM);
|
||||
callback.sendUpdate(state);
|
||||
return;
|
||||
}
|
||||
callback.sendUpdate((State) transformState(state));
|
||||
}
|
||||
|
||||
private Type transformState(Type state) {
|
||||
String localFunction = function, localSourceFormat = sourceFormat;
|
||||
if (localFunction != null && localSourceFormat != null) {
|
||||
String result = state.toFullString();
|
||||
try {
|
||||
result = TransformationHelper.transform(service, localFunction, localSourceFormat, result);
|
||||
} catch (TransformationException e) {
|
||||
logger.warn("Could not transform state '{}' with function '{}' and format '{}'", state, function,
|
||||
sourceFormat);
|
||||
}
|
||||
StringType resultType = new StringType(result);
|
||||
logger.debug("Transformed '{}' into '{}'", state, resultType);
|
||||
return resultType;
|
||||
} else {
|
||||
logger.warn(
|
||||
"Please specify a function and a source format for this Profile in the '{}' and '{}' parameters. Returning the original state now.",
|
||||
FUNCTION_PARAM, SOURCE_FORMAT_PARAM);
|
||||
return state;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.transform.javascript.internal.profiles;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.thing.profiles.Profile;
|
||||
import org.openhab.core.thing.profiles.ProfileCallback;
|
||||
import org.openhab.core.thing.profiles.ProfileContext;
|
||||
import org.openhab.core.thing.profiles.ProfileFactory;
|
||||
import org.openhab.core.thing.profiles.ProfileType;
|
||||
import org.openhab.core.thing.profiles.ProfileTypeBuilder;
|
||||
import org.openhab.core.thing.profiles.ProfileTypeProvider;
|
||||
import org.openhab.core.thing.profiles.ProfileTypeUID;
|
||||
import org.openhab.core.transform.TransformationService;
|
||||
import org.openhab.transform.javascript.internal.JavaScriptTransformationService;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* {@link ProfileFactory} that creates the transformation profile for the {@link JavaScriptTransformationService}
|
||||
*
|
||||
* @author Stefan Triller - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = { ProfileFactory.class, ProfileTypeProvider.class })
|
||||
public class JavaScriptTransformationProfileFactory implements ProfileFactory, ProfileTypeProvider {
|
||||
|
||||
@NonNullByDefault({})
|
||||
private TransformationService service;
|
||||
|
||||
@Override
|
||||
public Collection<ProfileType> getProfileTypes(@Nullable Locale locale) {
|
||||
return Arrays.asList(ProfileTypeBuilder.newState(JavaScriptTransformationProfile.PROFILE_TYPE_UID,
|
||||
JavaScriptTransformationProfile.PROFILE_TYPE_UID.getId()).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Profile createProfile(ProfileTypeUID profileTypeUID, ProfileCallback callback,
|
||||
ProfileContext profileContext) {
|
||||
return new JavaScriptTransformationProfile(callback, profileContext, service);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ProfileTypeUID> getSupportedProfileTypeUIDs() {
|
||||
return Arrays.asList(JavaScriptTransformationProfile.PROFILE_TYPE_UID);
|
||||
}
|
||||
|
||||
@Reference(target = "(openhab.transform=JS)")
|
||||
public void addTransformationService(TransformationService service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
public void removeTransformationService(TransformationService service) {
|
||||
this.service = null;
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config-description:config-descriptions
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0 https://openhab.org/schemas/config-description-1.0.0.xsd">
|
||||
|
||||
<config-description uri="profile:transform:JS">
|
||||
<parameter name="function" type="text" required="true">
|
||||
<label>JavaScript Filename or Inline Script</label>
|
||||
<description>Filename of the JavaScript in the transform folder or inline script starting with "|" character. The
|
||||
state will be available in the variable "input".</description>
|
||||
<limitToOptions>false</limitToOptions>
|
||||
</parameter>
|
||||
<parameter name="sourceFormat" type="text">
|
||||
<label>State Formatter</label>
|
||||
<description>How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s).</description>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</config-description:config-descriptions>
|
@ -1,8 +0,0 @@
|
||||
profile.config.transform.JS.function.label = JavaScript Filename
|
||||
profile.config.transform.JS.function.description = Filename of the JavaScript in the transform folder. The state will be available in the variable \"input\".
|
||||
profile.config.transform.JS.sourceFormat.label = State Formatter
|
||||
profile.config.transform.JS.sourceFormat.description = How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s).
|
||||
|
||||
# profile type
|
||||
|
||||
profile-type.transform.JS.label = JS
|
@ -1,8 +0,0 @@
|
||||
profile.config.transform.JS.function.label = Dateiname
|
||||
profile.config.transform.JS.function.description = Datei mit dem JavaScript Code. Der Item State wird in der Variable `input` an das Skript übergeben.
|
||||
profile.config.transform.JS.sourceFormat.label = State Format
|
||||
profile.config.transform.JS.sourceFormat.description = Format, welches auf den State des Channels angewendet.wird, bevor das Mapping erfolgt (z.B. %s oder %.1f °C, Standard ist %s).
|
||||
|
||||
# profile type
|
||||
|
||||
profile-type.transform.JS.label = JavaScript
|
@ -1,8 +0,0 @@
|
||||
profile.config.transform.JS.function.label = JavaScript-tiedostonimi
|
||||
profile.config.transform.JS.function.description = JavaScriptin tiedostonimi muunnoskansiossa. Tila on käytettävissä muuttujassa "input".
|
||||
profile.config.transform.JS.sourceFormat.label = Tilan muotoilija
|
||||
profile.config.transform.JS.sourceFormat.description = Miten kanavan tila muotoillaan ennen muunnosta, esim. %s tai %.1f °C (oletus on %s).
|
||||
|
||||
# profile type
|
||||
|
||||
profile-type.transform.JS.label = JS
|
@ -1,8 +0,0 @@
|
||||
profile.config.transform.JS.function.label = Nom du fichier JavaScript
|
||||
profile.config.transform.JS.function.description = Nom du fichier JavaScript dans le dossier transform. L'état sera disponible dans la variable "input".
|
||||
profile.config.transform.JS.sourceFormat.label = Formatage de l'état
|
||||
profile.config.transform.JS.sourceFormat.description = Comment formater l'état du canal avant de le transformer, par exemple %s ou %.1f °C (par défaut %s).
|
||||
|
||||
# profile type
|
||||
|
||||
profile-type.transform.JS.label = JS
|
@ -1,8 +0,0 @@
|
||||
profile.config.transform.JS.function.label = Javascript fájl neve
|
||||
profile.config.transform.JS.function.description = A javascript átalakító neve a mappában. Az átalakítandó érték elérhető lesz az "input" nevű változóban.
|
||||
profile.config.transform.JS.sourceFormat.label = Formázandó állapotérték
|
||||
profile.config.transform.JS.sourceFormat.description = Hogyan formázzuk az állapot csatornát, mielőtt átalakítjuk. Pl.\: %s vagy %.1f °C (alapértelmezetten %s).
|
||||
|
||||
# profile type
|
||||
|
||||
profile-type.transform.JS.label = JS
|
@ -1,193 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.transform.javascript.internal;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Comparator;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
import org.openhab.core.transform.TransformationException;
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
||||
/**
|
||||
* @author Pauli Anttila - Initial contribution
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
public class JavaScriptTransformationServiceTest {
|
||||
|
||||
private static final boolean NASHORN_AVAILABLE = isNashornAvailable();
|
||||
|
||||
private static final String BASE_FOLDER = "target";
|
||||
private static final String SRC_FOLDER = "conf";
|
||||
private static final String CONFIG_FOLDER = BASE_FOLDER + File.separator + SRC_FOLDER;
|
||||
|
||||
private @Mock BundleContext bundleContext;
|
||||
|
||||
private TestableJavaScriptTransformationService processor;
|
||||
|
||||
private class TestableJavaScriptTransformationService extends JavaScriptTransformationService {
|
||||
public TestableJavaScriptTransformationService(JavaScriptEngineManager manager) {
|
||||
super(manager);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns if the Nashorn JavaScript engine is available based on the Java specification version property.
|
||||
* Nashorn has been removed from JDK 15 and onwards.
|
||||
*
|
||||
* @return {@code true} if Nashorn is available, {@code false} otherwise
|
||||
*/
|
||||
private static boolean isNashornAvailable() {
|
||||
try {
|
||||
String javaVersion = System.getProperty("java.specification.version");
|
||||
return javaVersion == null ? false : Long.parseLong(javaVersion) < 15;
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() throws IOException {
|
||||
assumeTrue(NASHORN_AVAILABLE);
|
||||
|
||||
JavaScriptEngineManager manager = new JavaScriptEngineManager();
|
||||
processor = new TestableJavaScriptTransformationService(manager);
|
||||
copyDirectory(SRC_FOLDER, CONFIG_FOLDER);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown() throws IOException {
|
||||
Path path = Path.of(CONFIG_FOLDER);
|
||||
if (Files.exists(path)) {
|
||||
try (Stream<Path> walk = Files.walk(path)) {
|
||||
walk.sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void copyDirectory(String from, String to) throws IOException {
|
||||
Files.walk(Paths.get(from)).forEach(fromPath -> {
|
||||
Path toPath = Paths.get(to, fromPath.toString().substring(from.length()));
|
||||
try {
|
||||
Files.copy(fromPath, toPath);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInlineScript() throws Exception {
|
||||
final String DATA = "100";
|
||||
final String SCRIPT = "| input / 10";
|
||||
|
||||
String transformedResponse = processor.transform(SCRIPT, DATA);
|
||||
assertEquals("10.0", transformedResponse);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInlineScriptIncludingPipe() throws Exception {
|
||||
final String DATA = "1";
|
||||
final String SCRIPT = "| false || (input == '1')";
|
||||
|
||||
String transformedResponse = processor.transform(SCRIPT, DATA);
|
||||
assertEquals("true", transformedResponse);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadmeExampleWithoutSubFolder() throws Exception {
|
||||
final String DATA = "foo bar baz";
|
||||
final String SCRIPT = "readme.js";
|
||||
|
||||
String transformedResponse = processor.transform(SCRIPT, DATA);
|
||||
assertEquals("3", transformedResponse);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadmeExampleWithSubFolders() throws Exception {
|
||||
final String DATA = "foo bar baz";
|
||||
final String SCRIPT = "js/readme/readme.js";
|
||||
|
||||
String transformedResponse = processor.transform(SCRIPT, DATA);
|
||||
assertEquals("3", transformedResponse);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadmeScaleExample() throws Exception {
|
||||
final String DATA = "214";
|
||||
final String SCRIPT = "scale.js?correctionFactor=1.1÷r=10.js";
|
||||
|
||||
String transformedResponse = processor.transform(SCRIPT, DATA);
|
||||
assertEquals("23.54", transformedResponse);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAdditionalVariables() throws Exception {
|
||||
final String DATA = "100";
|
||||
final String SCRIPT = "sum.js?a=10&b=1";
|
||||
|
||||
String transformedResponse = processor.transform(SCRIPT, DATA);
|
||||
assertEquals("111", transformedResponse);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIllegalVariableName() throws Exception {
|
||||
final String DATA = "100";
|
||||
final String SCRIPT = "sum.js?a=10&input=fail&b=1";
|
||||
|
||||
Exception exception = assertThrows(TransformationException.class, () -> processor.transform(SCRIPT, DATA));
|
||||
assertEquals("'input' word is reserved and can't be used in additional parameters", exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIllegalQuestionmarkSequence() throws Exception {
|
||||
final String DATA = "100";
|
||||
final String SCRIPT = "sum.js?a=1&test=ab?d&b=2";
|
||||
|
||||
Exception exception = assertThrows(TransformationException.class, () -> processor.transform(SCRIPT, DATA));
|
||||
assertEquals("Questionmark should be defined only once in the filename", exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIllegalAmbersandSequence() throws Exception {
|
||||
final String DATA = "foo";
|
||||
final String SCRIPT = "returntest.js?a=1&test=ab&d&b=2";
|
||||
|
||||
Exception exception = assertThrows(TransformationException.class, () -> processor.transform(SCRIPT, DATA));
|
||||
assertEquals("Illegal filename syntax", exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodedSpecialCharacters() throws Exception {
|
||||
final String DATA = "100";
|
||||
final String SCRIPT = "returntest.js?a=1&test=ab%3Fd%26f&b=2";
|
||||
|
||||
String transformedResponse = processor.transform(SCRIPT, DATA);
|
||||
assertEquals("ab?d&f", transformedResponse);
|
||||
}
|
||||
}
|
@ -34,7 +34,6 @@
|
||||
<!-- transformations -->
|
||||
<module>org.openhab.transform.bin2json</module>
|
||||
<module>org.openhab.transform.exec</module>
|
||||
<module>org.openhab.transform.javascript</module>
|
||||
<module>org.openhab.transform.jinja</module>
|
||||
<module>org.openhab.transform.jsonpath</module>
|
||||
<module>org.openhab.transform.map</module>
|
||||
|
@ -19,7 +19,7 @@ Test-Cases: ${classes;CONCRETE;PUBLIC;NAMED;*Test}
|
||||
-runsystempackages: sun.reflect
|
||||
|
||||
-runfw: org.eclipse.osgi
|
||||
-runee: JavaSE-11
|
||||
-runee: JavaSE-17
|
||||
|
||||
# An unused random HTTP port is used during tests to prevent resource conflicts
|
||||
# This property is set by the build-helper-maven-plugin in the itests pom.xml
|
||||
@ -39,7 +39,6 @@ Export-Package:
|
||||
bnd.identity;id='junit-jupiter-engine'
|
||||
|
||||
-runproperties: \
|
||||
nashorn.args=--no-deprecation-warning,\
|
||||
org.ops4j.pax.logging.DefaultServiceLog.level=WARN
|
||||
|
||||
-runvm.java9plus: \
|
||||
|
21
pom.xml
21
pom.xml
@ -63,7 +63,7 @@
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<oh.java.version>11</oh.java.version>
|
||||
<oh.java.version>17</oh.java.version>
|
||||
<maven.compiler.source>${oh.java.version}</maven.compiler.source>
|
||||
<maven.compiler.target>${oh.java.version}</maven.compiler.target>
|
||||
<maven.compiler.compilerVersion>${oh.java.version}</maven.compiler.compilerVersion>
|
||||
@ -77,7 +77,8 @@
|
||||
<netty.version>4.1.72.Final</netty.version>
|
||||
<okhttp.version>3.14.9</okhttp.version>
|
||||
<sat.version>0.13.0</sat.version>
|
||||
<spotless.version>2.0.3</spotless.version>
|
||||
<spotless.version>2.28.0</spotless.version>
|
||||
<spotless.eclipse.version>4.21.0</spotless.eclipse.version>
|
||||
|
||||
<bnd.importpackage/>
|
||||
<bnd.exportpackage/>
|
||||
@ -311,12 +312,12 @@ Import-Package: \\
|
||||
<dependency>
|
||||
<groupId>org.codehaus.plexus</groupId>
|
||||
<artifactId>plexus-compiler-eclipse</artifactId>
|
||||
<version>2.11.1</version>
|
||||
<version>2.12.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jdt</groupId>
|
||||
<artifactId>ecj</artifactId>
|
||||
<version>3.28.0</version>
|
||||
<version>3.30.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
@ -384,7 +385,7 @@ Import-Package: \\
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0-M5</version>
|
||||
<version>3.0.0-M7</version>
|
||||
<configuration>
|
||||
<argLine>
|
||||
--add-opens java.base/java.lang=ALL-UNNAMED
|
||||
@ -479,7 +480,7 @@ Import-Package: \\
|
||||
<java>
|
||||
<eclipse>
|
||||
<file>openhab_codestyle.xml</file>
|
||||
<version>4.13.0</version>
|
||||
<version>${spotless.eclipse.version}</version>
|
||||
</eclipse>
|
||||
<removeUnusedImports/>
|
||||
<importOrder>
|
||||
@ -507,7 +508,7 @@ Import-Package: \\
|
||||
<files>
|
||||
<file>openhab_wst_xml_files.prefs</file>
|
||||
</files>
|
||||
<version>4.13.0</version>
|
||||
<version>${spotless.eclipse.version}</version>
|
||||
</eclipseWtp>
|
||||
<trimTrailingWhitespace/>
|
||||
<endWithNewline/>
|
||||
@ -522,7 +523,7 @@ Import-Package: \\
|
||||
<files>
|
||||
<file>openhab_wst_feature_file.prefs</file>
|
||||
</files>
|
||||
<version>4.13.0</version>
|
||||
<version>${spotless.eclipse.version}</version>
|
||||
</eclipseWtp>
|
||||
<trimTrailingWhitespace/>
|
||||
<endWithNewline/>
|
||||
@ -537,7 +538,7 @@ Import-Package: \\
|
||||
<files>
|
||||
<file>openhab_wst_pom_file.prefs</file>
|
||||
</files>
|
||||
<version>4.13.0</version>
|
||||
<version>${spotless.eclipse.version}</version>
|
||||
</eclipseWtp>
|
||||
<trimTrailingWhitespace/>
|
||||
<endWithNewline/>
|
||||
@ -599,7 +600,7 @@ Import-Package: \\
|
||||
<configuration>
|
||||
<rules>
|
||||
<requireJavaVersion>
|
||||
<version>[11.0,18.0)</version>
|
||||
<version>[17.0,18.0)</version>
|
||||
</requireJavaVersion>
|
||||
</rules>
|
||||
</configuration>
|
||||
|
Loading…
Reference in New Issue
Block a user