diff --git a/bundles/org.openhab.transform.javascript/README.md b/bundles/org.openhab.transform.javascript/README.md
index a6e827989..bd6a09018 100644
--- a/bundles/org.openhab.transform.javascript/README.md
+++ b/bundles/org.openhab.transform.javascript/README.md
@@ -19,6 +19,7 @@ transform/getValue.js:
```
## Test JavaScript
+
You can use online JavaScript testers to validate your script.
E.g. https://www.webtoolkitonline.com/javascript-tester.html
diff --git a/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/JavaScriptEngineManager.java b/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/JavaScriptEngineManager.java
index 677ee887b..97ec03dad 100644
--- a/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/JavaScriptEngineManager.java
+++ b/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/JavaScriptEngineManager.java
@@ -35,8 +35,8 @@ 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)
diff --git a/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/JavaScriptTransformationService.java b/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/JavaScriptTransformationService.java
index 0a0179381..660bd632e 100644
--- a/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/JavaScriptTransformationService.java
+++ b/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/JavaScriptTransformationService.java
@@ -12,14 +12,26 @@
*/
package org.openhab.transform.javascript.internal;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+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;
@@ -33,21 +45,24 @@ import org.slf4j.LoggerFactory;
* @author Thomas Kordelle - pre compiled scripts
*/
@NonNullByDefault
-@Component(property = { "openhab.transform=JS" })
-public class JavaScriptTransformationService implements TransformationService {
+@Component(service = { TransformationService.class, ConfigOptionProvider.class }, property = { "openhab.transform=JS" })
+public class JavaScriptTransformationService implements TransformationService, ConfigOptionProvider {
- private Logger logger = LoggerFactory.getLogger(JavaScriptTransformationService.class);
- private @NonNullByDefault({}) JavaScriptEngineManager manager;
+ private final Logger logger = LoggerFactory.getLogger(JavaScriptTransformationService.class);
- @Reference
- public void setJavaScriptEngineManager(JavaScriptEngineManager manager) {
+ 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 final JavaScriptEngineManager manager;
+
+ @Activate
+ public JavaScriptTransformationService(final @Reference JavaScriptEngineManager manager) {
this.manager = manager;
}
- public void unsetJavaScriptEngineManager(JavaScriptEngineManager manager) {
- this.manager = null;
- }
-
/**
* Transforms the input source by Java Script. It expects the
* transformation rule to be read from a file which is stored under the
@@ -83,4 +98,47 @@ public class JavaScriptTransformationService implements TransformationService {
result);
}
}
+
+ @Override
+ public @Nullable Collection 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 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;
+ }
+ }
}
diff --git a/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/TransformationScriptWatcher.java b/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/TransformationScriptWatcher.java
index f5b0db0ca..ff06e9d52 100644
--- a/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/TransformationScriptWatcher.java
+++ b/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/TransformationScriptWatcher.java
@@ -22,6 +22,7 @@ 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;
@@ -29,30 +30,23 @@ import org.osgi.service.component.annotations.Reference;
* 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()
+@Component
public class TransformationScriptWatcher extends AbstractWatchService {
public static final String TRANSFORM_FOLDER = OpenHAB.getConfigFolder() + File.separator
+ TransformationService.TRANSFORM_FOLDER_NAME;
- private JavaScriptEngineManager manager;
+ private final JavaScriptEngineManager manager;
- public TransformationScriptWatcher() {
+ @Activate
+ public TransformationScriptWatcher(final @Reference JavaScriptEngineManager manager) {
super(TRANSFORM_FOLDER);
- }
-
- @Reference
- public void setJavaScriptEngineManager(JavaScriptEngineManager manager) {
this.manager = manager;
}
- public void unsetJavaScriptEngineManager(JavaScriptEngineManager manager) {
- this.manager = null;
- }
-
@Override
public void activate() {
super.activate();
diff --git a/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/profiles/JavascriptTransformationProfile.java b/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/profiles/JavaScriptTransformationProfile.java
similarity index 74%
rename from bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/profiles/JavascriptTransformationProfile.java
rename to bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/profiles/JavaScriptTransformationProfile.java
index 82fc0a97e..087e6bda5 100644
--- a/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/profiles/JavascriptTransformationProfile.java
+++ b/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/profiles/JavaScriptTransformationProfile.java
@@ -13,6 +13,7 @@
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;
@@ -30,29 +31,26 @@ import org.slf4j.LoggerFactory;
/**
* Profile to offer the JavascriptTransformationservice on a ItemChannelLink
*
- * @author Stefan Triller - initial contribution
- *
+ * @author Stefan Triller - Initial contribution
*/
@NonNullByDefault
-public class JavascriptTransformationProfile implements StateProfile {
+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 final Logger logger = LoggerFactory.getLogger(JavascriptTransformationProfile.class);
+ private static final String FUNCTION_PARAM = "function";
+ private static final String SOURCE_FORMAT_PARAM = "sourceFormat";
private final TransformationService service;
private final ProfileCallback callback;
- private static final String FUNCTION_PARAM = "function";
- private static final String SOURCE_FORMAT_PARAM = "sourceFormat";
+ private final @Nullable String function;
+ private final @Nullable String sourceFormat;
- @NonNullByDefault({})
- private final String function;
- @NonNullByDefault({})
- private final String sourceFormat;
-
- public JavascriptTransformationProfile(ProfileCallback callback, ProfileContext context,
+ public JavaScriptTransformationProfile(ProfileCallback callback, ProfileContext context,
TransformationService service) {
this.service = service;
this.callback = callback;
@@ -116,15 +114,23 @@ public class JavascriptTransformationProfile implements StateProfile {
}
private Type transformState(Type state) {
- String result = state.toFullString();
- try {
- result = TransformationHelper.transform(service, function, sourceFormat, state.toFullString());
- } catch (TransformationException e) {
- logger.warn("Could not transform state '{}' with function '{}' and format '{}'", state, function,
- sourceFormat);
+ 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;
}
- StringType resultType = new StringType(result);
- logger.debug("Transformed '{}' into '{}'", state, resultType);
- return resultType;
}
}
diff --git a/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/profiles/JavascriptTransformationProfileFactory.java b/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/profiles/JavaScriptTransformationProfileFactory.java
similarity index 79%
rename from bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/profiles/JavascriptTransformationProfileFactory.java
rename to bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/profiles/JavaScriptTransformationProfileFactory.java
index a43fd75ff..2803b857c 100644
--- a/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/profiles/JavascriptTransformationProfileFactory.java
+++ b/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/profiles/JavaScriptTransformationProfileFactory.java
@@ -27,37 +27,37 @@ 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;
/**
- * Profilefactory that creates the transformation profile for the javascript transformation service
- *
- * @author Stefan Triller - initial contribution
+ * {@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 {
+public class JavaScriptTransformationProfileFactory implements ProfileFactory, ProfileTypeProvider {
@NonNullByDefault({})
private TransformationService service;
@Override
public Collection getProfileTypes(@Nullable Locale locale) {
- return Arrays.asList(ProfileTypeBuilder.newState(JavascriptTransformationProfile.PROFILE_TYPE_UID,
- JavascriptTransformationProfile.PROFILE_TYPE_UID.getId()).build());
+ 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);
+ return new JavaScriptTransformationProfile(callback, profileContext, service);
}
@Override
public Collection getSupportedProfileTypeUIDs() {
- return Arrays.asList(JavascriptTransformationProfile.PROFILE_TYPE_UID);
+ return Arrays.asList(JavaScriptTransformationProfile.PROFILE_TYPE_UID);
}
@Reference(target = "(openhab.transform=JS)")
diff --git a/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/config/javascriptProfile.xml b/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/config/javascriptProfile.xml
index 75887da9f..a921594ef 100644
--- a/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/config/javascriptProfile.xml
+++ b/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/config/javascriptProfile.xml
@@ -9,8 +9,9 @@
Filename of the JavaScript in the transform folder. The state will be available in the variable
\"input\".
+ false
-
+
How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s)
true
diff --git a/bundles/org.openhab.transform.javascript/src/main/resources/readme.txt b/bundles/org.openhab.transform.javascript/src/main/resources/readme.txt
deleted file mode 100644
index a2ee892dc..000000000
--- a/bundles/org.openhab.transform.javascript/src/main/resources/readme.txt
+++ /dev/null
@@ -1 +0,0 @@
-Bundle resources go in here!