Skip to content

Commit

Permalink
[js] Added 'ConfigOptionProvider' to provide filenames ending with '.…
Browse files Browse the repository at this point in the history
…js' in Profile configuration (openhab#9646)

* Added ConfigOptionProvider to provide file names ending with '.js' in Profile configuration

Signed-off-by: Christoph Weitkamp <[email protected]>
  • Loading branch information
cweitkamp authored Jan 4, 2021
1 parent a6cf99b commit d10325b
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 54 deletions.
1 change: 1 addition & 0 deletions bundles/org.openhab.transform.javascript/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@
/**
* Simple cache for compiled JavaScript files.
*
* @author Thomas Kordelle - Initial contribution
* @author Thomas Kordelle - pre compiled scripts
*
*/
@NonNullByDefault
@Component(service = JavaScriptEngineManager.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -33,19 +45,22 @@
* @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) {
this.manager = manager;
}
private static final char EXTENSION_SEPARATOR = '.';

public void unsetJavaScriptEngineManager(JavaScriptEngineManager manager) {
this.manager = null;
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;
}

/**
Expand Down Expand Up @@ -83,4 +98,47 @@ public void unsetJavaScriptEngineManager(JavaScriptEngineManager manager) {
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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,37 +22,31 @@
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;

/**
* 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -30,29 +31,26 @@
/**
* 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;
Expand Down Expand Up @@ -116,15 +114,23 @@ public void onStateUpdateFromHandler(State state) {
}

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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,37 +27,37 @@
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<ProfileType> 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<ProfileTypeUID> getSupportedProfileTypeUIDs() {
return Arrays.asList(JavascriptTransformationProfile.PROFILE_TYPE_UID);
return Arrays.asList(JavaScriptTransformationProfile.PROFILE_TYPE_UID);
}

@Reference(target = "(openhab.transform=JS)")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
<label>JavaScript Filename</label>
<description>Filename of the JavaScript in the transform folder. The state will be available in the variable
\"input\".</description>
<limitToOptions>false</limitToOptions>
</parameter>
<parameter name="sourceFormat" type="text" required="false">
<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>
Expand Down

This file was deleted.

0 comments on commit d10325b

Please sign in to comment.