From d7eb01ffa5bcba23541fc4e33ac5e43fcb366efc Mon Sep 17 00:00:00 2001 From: Brian O'Connell Date: Sun, 29 Nov 2020 08:20:54 -0500 Subject: [PATCH 01/15] feat(jruby) JRuby scripting initial binding commit Signed-off-by: Brian O'Connell --- CODEOWNERS | 1 + bom/openhab-addons/pom.xml | 5 + .../NOTICE | 13 + .../README.md | 74 +++++ .../pom.xml | 35 +++ .../src/main/feature/feature.xml | 9 + .../JRubyScriptEngineConfiguration.java | 296 ++++++++++++++++++ .../internal/JRubyScriptEngineFactory.java | 115 +++++++ .../jrubyscripting/internal/package-info.java | 21 ++ bundles/pom.xml | 1 + 10 files changed, 570 insertions(+) create mode 100644 bundles/org.openhab.automation.jrubyscripting/NOTICE create mode 100644 bundles/org.openhab.automation.jrubyscripting/README.md create mode 100644 bundles/org.openhab.automation.jrubyscripting/pom.xml create mode 100644 bundles/org.openhab.automation.jrubyscripting/src/main/feature/feature.xml create mode 100644 bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineConfiguration.java create mode 100644 bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineFactory.java create mode 100644 bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/package-info.java diff --git a/CODEOWNERS b/CODEOWNERS index a74a451fe980..6f004ed451fe 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -6,6 +6,7 @@ # Add-on maintainers: /bundles/org.openhab.automation.groovyscripting/ @wborn +/bundles/org.openhab.automation.jrubyscripting/ @boc-tothefuture /bundles/org.openhab.automation.jsscripting/ @jpg0 /bundles/org.openhab.automation.jythonscripting/ @openhab/add-ons-maintainers /bundles/org.openhab.automation.pidcontroller/ @fwolter diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml index 67288274817e..6646e23c03d0 100644 --- a/bom/openhab-addons/pom.xml +++ b/bom/openhab-addons/pom.xml @@ -21,6 +21,11 @@ org.openhab.automation.groovyscripting ${project.version} + + org.openhab.addons.bundles + org.openhab.automation.jrubyscripting + ${project.version} + org.openhab.addons.bundles org.openhab.automation.jsscripting diff --git a/bundles/org.openhab.automation.jrubyscripting/NOTICE b/bundles/org.openhab.automation.jrubyscripting/NOTICE new file mode 100644 index 000000000000..38d625e34923 --- /dev/null +++ b/bundles/org.openhab.automation.jrubyscripting/NOTICE @@ -0,0 +1,13 @@ +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 diff --git a/bundles/org.openhab.automation.jrubyscripting/README.md b/bundles/org.openhab.automation.jrubyscripting/README.md new file mode 100644 index 000000000000..e415982b5b7d --- /dev/null +++ b/bundles/org.openhab.automation.jrubyscripting/README.md @@ -0,0 +1,74 @@ +# JRuby Scripting + +This add-on provides [JRuby](https://www.jruby.org/) 9.3.1 that can be used as a scripting language within automation rules. + +## JRuby Scripting Configuration + +JRuby configuration parameters may be set by creating a jruby.cfg file in $OPENHAB_CONF/services/ + + +| Parameter | Default | Description | +|-------------------------------------------------------|-----------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| org.openhab.automation.jrubyscripting:gem_home | $OPENHAB_CONF/scripts/lib/ruby/gem_home | Location ruby gems will be installed and loaded, directory will be created if missing and gem installs are specified from | +| org.openhab.automation.jrubyscripting:rubylib | $OPENHAB_CONF/automation/lib/ruby/ | Search path for user libraries | +| org.openhab.automation.jrubyscripting:local_context | threadsafe | The local context holds Ruby runtime, name-value pairs for sharing variables between Java and Ruby. See [this](https://github.com/jruby/jruby/wiki/RedBridge#Context_Instance_Type) for options and details | +| org.openhab.automation.jrubyscripting:local_variables | transient | Defines how variables are shared between Ruby and Java. See [this](https://github.com/jruby/jruby/wiki/RedBridge#local-variable-behavior-options) for options and details | +| org.openhab.automation.jrubyscripting:gems | | Comma separated list of [Ruby Gems](https://rubygems.org/) to install. | + + +## Ruby Gems + +This binding will install user specified gems and make them available on the library search path. +Gem versions may be specified using the standard ruby gem_name=version format. +The version number follows the [pessimistic version constraint](https://guides.rubygems.org/patterns/#pessimistic-version-constraint) syntax. + +For example this configuration will install version 4 or higher of the [OpenHAB JRuby Scripting Libray](https://boc-tothefuture.github.io/openhab-jruby/). + +```text +org.openhab.automation.jrubyscripting:gems=openhab-scripting=~>4.0 +``` + +## Creating JRuby Scripts + +When this add-on is installed, you can select JRuby as a scripting language when creating a script action within the rule editor of the UI. + +Alternatively, you can create scripts in the `automation/jsr223` configuration directory. +If you create an empty file called `test.rb`, you will see a log line with information similar to: + +```text + ... [INFO ] [.a.m.s.r.i.l.ScriptFileWatcher:150 ] - Loading script 'test.rb' +``` + +To enable debug logging, use the [console logging]({{base}}/administration/logging.html) commands to +enable debug logging for the automation functionality: + +```text +log:set DEBUG org.openhab.core.automation +log:set DEBUG org.openhab.automation.jrubyscripting +``` + +## Imports + +All [ScriptExtensions]({{base}}/configuration/jsr223.html#scriptextension-objects-all-jsr223-languages) are available in JRuby with the following exceptions/modifications: + +* The File variable, referencing java.io.File is not available as it conflicts with Ruby's File class preventing Ruby from initializing +* Globals scriptExtension, automationManager, ruleRegistry, items, voice, rules, things, events, itemRegistry, ir, actions, se, audio, lifecycleTracker are prepended with a $ (e.g. $automationManager) making them available as a global objects in Ruby. + + +## Script Examples + +JRuby scripts provide access to almost all the functionality in an openHAB runtime environment. +As a simple example, the following script logs "Hello, World!". +Note that `puts` will usually not work since the output has no terminal to display the text. +The openHAB server uses the [SLF4J](https://www.slf4j.org/) library for logging. + +```ruby +require 'java' +java_import org.slf4j.LoggerFactory + +LoggerFactory.getLogger("org.openhab.core.automation.examples").info("Hello world!") +``` + +JRuby can [import Java classes](https://github.com/jruby/jruby/wiki/CallingJavaFromJRuby). +Depending on the openHAB logging configuration, you may need to prefix logger names with `org.openhab.core.automation` for them to show up in the log file (or you modify the logging configuration). + diff --git a/bundles/org.openhab.automation.jrubyscripting/pom.xml b/bundles/org.openhab.automation.jrubyscripting/pom.xml new file mode 100644 index 000000000000..1d150eae7813 --- /dev/null +++ b/bundles/org.openhab.automation.jrubyscripting/pom.xml @@ -0,0 +1,35 @@ + + + + 4.0.0 + + + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + 3.2.0-SNAPSHOT + + + org.openhab.automation.jrubyscripting + + openHAB Add-ons :: Automation :: JRuby Scripting + + + + com.ibm.icu.*;resolution:=optional, + org.abego.treelayout.*;resolution:=optional, + org.apache.ivy.*;resolution:=optional, + org.stringtemplate.v4.*;resolution:=optional + 9.3.1.0 + + + + + org.jruby + jruby-complete + ${jruby.version} + compile + + + + diff --git a/bundles/org.openhab.automation.jrubyscripting/src/main/feature/feature.xml b/bundles/org.openhab.automation.jrubyscripting/src/main/feature/feature.xml new file mode 100644 index 000000000000..2ef4f1827772 --- /dev/null +++ b/bundles/org.openhab.automation.jrubyscripting/src/main/feature/feature.xml @@ -0,0 +1,9 @@ + + + mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features + + + openhab-runtime-base + mvn:org.openhab.addons.bundles/org.openhab.automation.jrubyscripting/${project.version} + + diff --git a/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineConfiguration.java b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineConfiguration.java new file mode 100644 index 000000000000..cf79d90ae0e3 --- /dev/null +++ b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineConfiguration.java @@ -0,0 +1,296 @@ +/** + * Copyright (c) 2010-2021 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.automation.jrubyscripting.internal; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; +import javax.script.ScriptException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.OpenHAB; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * Processes JRuby Configuration Parameters + * + * @author Brian O'Connell - Initial contribution + */ +@NonNullByDefault +public class JRubyScriptEngineConfiguration { + + private final Logger logger = LoggerFactory.getLogger(JRubyScriptEngineConfiguration.class); + + private final static Path DEFAULT_GEM_HOME = Paths.get(OpenHAB.getConfigFolder(), "scripts", "lib", "ruby", + "gem_home"); + + private final static Path DEFAULT_RUBYLIB = Paths.get(OpenHAB.getConfigFolder(), "automation", "lib", "ruby"); + + private final static String GEM_HOME = "gem_home"; + + // Map of configuration parameters + private final static Map CONFIGURATION_PARAMETERS = Map.ofEntries( + Map.entry("local_context", + new OptionalConfigurationElement.Builder(OptionalConfigurationElement.Type.SYSTEM_PROPERTY) + .mappedTo("org.jruby.embed.localcontext.scope").defaultValue("threadsafe").build()), + + Map.entry("local_variable", + new OptionalConfigurationElement.Builder(OptionalConfigurationElement.Type.SYSTEM_PROPERTY) + .mappedTo("org.jruby.embed.localvariable.behavior").defaultValue("transient").build()), + + Map.entry(GEM_HOME, + new OptionalConfigurationElement.Builder(OptionalConfigurationElement.Type.RUBY_ENVIRONMENT) + .mappedTo("GEM_HOME").defaultValue(DEFAULT_GEM_HOME.toString()).build()), + + Map.entry("rubylib", + new OptionalConfigurationElement.Builder(OptionalConfigurationElement.Type.RUBY_ENVIRONMENT) + .mappedTo("RUBYLIB").defaultValue(DEFAULT_RUBYLIB.toString()).build()), + + Map.entry("gems", new OptionalConfigurationElement.Builder(OptionalConfigurationElement.Type.GEM).build())); + + private final static Map> CONFIGURATION_TYPE_MAP = CONFIGURATION_PARAMETERS + .values().stream().collect(Collectors.groupingBy(v -> v.type)); + + /** + * Update configuration + * + * @param config Configuration parameters to apply to ScripEngine + * @param factory ScriptEngineFactory to configure + */ + void update(Map config, ScriptEngineFactory factory) { + logger.trace("JRuby Script Engine Configuration: {}", config); + config.forEach(this::processConfigValue); + configureScriptEngine(factory); + } + + /** + * Apply configuration key/value to known configuration parameters + * + * @param key Configuration key + * @param value Configuration value + */ + private void processConfigValue(String key, Object value) { + OptionalConfigurationElement configurationElement = CONFIGURATION_PARAMETERS.get(key); + if (configurationElement != null) { + configurationElement.setValue(value.toString()); + } else { + logger.debug("Ignoring unexpected configuration key: {}", key); + } + } + + /** + * Configure the ScriptEngine + * + * @param factory Script Engine to configure + */ + void configureScriptEngine(ScriptEngineFactory factory) { + + configureSystemProperties(CONFIGURATION_TYPE_MAP.getOrDefault(OptionalConfigurationElement.Type.SYSTEM_PROPERTY, + Collections. emptyList())); + + ScriptEngine engine = factory.getScriptEngine(); + + configureRubyEnvironment(CONFIGURATION_TYPE_MAP.getOrDefault(OptionalConfigurationElement.Type.RUBY_ENVIRONMENT, + Collections. emptyList()), engine); + + configureGems(CONFIGURATION_TYPE_MAP.getOrDefault(OptionalConfigurationElement.Type.GEM, + Collections. emptyList()), engine); + } + + /** + * Makes Gem home directory if it does not exist + */ + private void ensureGemHomeExists() { + + OptionalConfigurationElement gemHomeConfigElement = CONFIGURATION_PARAMETERS.get(GEM_HOME); + if (gemHomeConfigElement != null) { + Optional gemHome = gemHomeConfigElement.getValue(); + if (gemHome.isPresent()) { + File gemHomeDirectory = new File(gemHome.get()); + if (gemHomeDirectory.exists() == false) { + logger.debug("gem_home directory does not exist, creating"); + boolean created = gemHomeDirectory.mkdirs(); + if (created == false) { + logger.debug("Error creating gem_home direcotry"); + } + } + } else { + logger.debug("Gem install requested without gem_home specified, not ensuring gem_home path exists"); + } + } + } + + /** + * Install a gems in ScriptEngine + * + * @param gemsDirectives List of gems to install + * @param engine Engine to install gems + */ + private synchronized void configureGems(List gemDirectives, ScriptEngine engine) { + for (OptionalConfigurationElement gemDirective : gemDirectives) { + if (gemDirective.getValue().isPresent()) { + + ensureGemHomeExists(); + + String[] gems = gemDirective.getValue().get().split(","); + for (String gem : gems) { + gem = gem.trim(); + String gemCommand; + if (gem.contains("=")) { + String[] gemParts = gem.split("="); + gem = gemParts[0]; + String version = gemParts[1]; + gemCommand = "Gem.install('" + gem + "',version='" + version + "')\n"; + } else { + gemCommand = "Gem.install('" + gem + "')\n"; + } + + try { + logger.debug("Installing Gem: {} ", gem); + logger.trace("Gem install code:\n{}\n", gemCommand); + engine.eval(gemCommand); + } catch (Exception e) { + logger.error("Error installing Gem", e); + } + } + } else { + logger.debug("Ruby gem property has no value"); + } + } + } + + /** + * Configure the base Ruby Environment + * + * @param engine Engine to configure + */ + public ScriptEngine configureRubyEnvironment(ScriptEngine engine) { + configureRubyEnvironment(CONFIGURATION_TYPE_MAP.getOrDefault(OptionalConfigurationElement.Type.RUBY_ENVIRONMENT, + Collections. emptyList()), engine); + return engine; + } + + /** + * Configure the optional elements of the Ruby Environment + * + * @param optionalConfigurationElements Optional elements to configure in the ruby environment + * @param engine Engine in which to configure environment + */ + private void configureRubyEnvironment(List optionalConfigurationElements, + ScriptEngine engine) { + for (OptionalConfigurationElement configElement : optionalConfigurationElements) { + String environmentProperty = configElement.mappedTo().get(); + if (configElement.getValue().isPresent()) { + String environmentSetting = "ENV['" + environmentProperty + "']='" + configElement.getValue().get() + + "'"; + try { + logger.trace("Setting Ruby environment with code: {} ", environmentSetting); + engine.eval(environmentSetting); + } catch (ScriptException e) { + logger.error("Error setting ruby environment", e); + } + } else { + logger.debug("Ruby environment property ({}) has no value", environmentProperty); + } + } + } + + /** + * Configure system properties + * + * @param optionalConfigurationElements Optional system properties to configure + */ + private void configureSystemProperties(List optionalConfigurationElements) { + for (OptionalConfigurationElement configElement : optionalConfigurationElements) { + String systemProperty = configElement.mappedTo().get(); + if (configElement.getValue().isPresent()) { + String propertyValue = configElement.getValue().get(); + logger.trace("Setting system property ({}) to ({})", systemProperty, propertyValue); + System.setProperty(systemProperty, propertyValue); + } else { + logger.warn("System property ({}) has no value", systemProperty); + } + } + } + + /** + * Inner static companion class for configuration elements + */ + private static class OptionalConfigurationElement { + + private final Optional defaultValue; + private final Optional mappedTo; + private final Type type; + private Optional value; + + private OptionalConfigurationElement(Type type, @Nullable String mappedTo, @Nullable String defaultValue) { + this.type = type; + this.defaultValue = Optional.ofNullable(defaultValue); + this.mappedTo = Optional.ofNullable(mappedTo); + value = Optional.empty(); + } + + private Optional getValue() { + return value.or(() -> defaultValue); + } + + private void setValue(String value) { + this.value = Optional.of(value); + } + + private Optional mappedTo() { + return mappedTo; + } + + private enum Type { + SYSTEM_PROPERTY, + RUBY_ENVIRONMENT, + GEM + } + + private static class Builder { + private final Type type; + private @Nullable String defaultValue = null; + private @Nullable String mappedTo = null; + + private Builder(Type type) { + this.type = type; + } + + private Builder mappedTo(String mappedTo) { + this.mappedTo = mappedTo; + return this; + } + + private Builder defaultValue(String value) { + this.defaultValue = value; + return this; + } + + private OptionalConfigurationElement build() { + return new OptionalConfigurationElement(type, mappedTo, defaultValue); + } + } + } +} diff --git a/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineFactory.java b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineFactory.java new file mode 100644 index 000000000000..be60919899c1 --- /dev/null +++ b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineFactory.java @@ -0,0 +1,115 @@ +/** + * Copyright (c) 2010-2021 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.automation.jrubyscripting.internal; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.script.ScriptEngine; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.automation.module.script.AbstractScriptEngineFactory; +import org.openhab.core.automation.module.script.ScriptEngineFactory; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Modified; + +/** + * This is an implementation of a {@link ScriptEngineFactory} for Ruby. + * handlers. + * + * @author Brian O'Connell - Initial contribution + */ +@NonNullByDefault +@Component(service = ScriptEngineFactory.class, configurationPid = "org.openhab.automation.jrubyscripting") +public class JRubyScriptEngineFactory extends AbstractScriptEngineFactory { + + private final JRubyScriptEngineConfiguration configuration = new JRubyScriptEngineConfiguration(); + + // Filter out the File entry to prevent shadowing the Ruby File class which breaks Ruby in spectacularly + // difficult ways to debug. + private final static Set FILTERED_PRESETS = Set.of("File"); + private final static Set INSTANCE_PRESETS = Set.of(); + private final static Set GLOBAL_PRESETS = Set.of("scriptExtension", "automationManager", "ruleRegistry", + "items", "voice", "rules", "things", "events", "itemRegistry", "ir", "actions", "se", "audio", + "lifecycleTracker"); + + private final javax.script.ScriptEngineFactory factory = new org.jruby.embed.jsr223.JRubyEngineFactory(); + + // formatter turned off because it does not appropriately format chained streams + private final List scriptTypes = Stream + .concat(factory.getExtensions().stream(), factory.getMimeTypes().stream()) + .collect(Collectors.toUnmodifiableList()); + + // Adds @ in front of a set of variables so that Ruby recogonizes them as instance variables + private static Map.Entry mapInstancePresets(Map.Entry entry) { + if (INSTANCE_PRESETS.contains(entry.getKey())) { + return Map.entry("@" + entry.getKey(), entry.getValue()); + } else { + return entry; + } + } + + // Adds $ in front of a set of variables so that Ruby recogonizes them as global variables + private static Map.Entry mapGlobalPresets(Map.Entry entry) { + if (GLOBAL_PRESETS.contains(entry.getKey())) { + return Map.entry("$" + entry.getKey(), entry.getValue()); + } else { + return entry; + } + } + + // The activate call is activate binding and set the bindings configuration + @Activate + protected void activate(ComponentContext componentContext, Map config) { + configuration.update(config, factory); + } + + // The modified call updates configuration for binding + @Modified + protected void modified(Map config) { + configuration.update(config, factory); + } + + @Override + public List getScriptTypes() { + return scriptTypes; + } + + @Override + public void scopeValues(ScriptEngine scriptEngine, Map scopeValues) { + + // Empty comments prevent the formatter from breaking up the correct streams chaining + Map filteredScopeValues = // + scopeValues // + .entrySet() // + .stream() // + .filter(map -> !FILTERED_PRESETS.contains(map.getKey())) // + .map(JRubyScriptEngineFactory::mapInstancePresets) // + .map(JRubyScriptEngineFactory::mapGlobalPresets) // + .collect(Collectors.toMap(map -> map.getKey(), map -> map.getValue())); // + + super.scopeValues(scriptEngine, filteredScopeValues); + } + + @Override + public @Nullable ScriptEngine createScriptEngine(String scriptType) { + return scriptTypes.contains(scriptType) ? configuration.configureRubyEnvironment(factory.getScriptEngine()) + : null; + } +} diff --git a/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/package-info.java b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/package-info.java new file mode 100644 index 000000000000..0bd16bf30f16 --- /dev/null +++ b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/package-info.java @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2010-2021 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 + */ + +@org.osgi.annotation.bundle.Header(name = org.osgi.framework.Constants.DYNAMICIMPORT_PACKAGE, value = "*") +package org.openhab.automation.jrubyscripting.internal; + +/** + * Additional information for the JRuby Scripting package + * + * @author Brian O'Connell - Initial contribution + */ diff --git a/bundles/pom.xml b/bundles/pom.xml index 345fc9daecd3..aee3db282c39 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -21,6 +21,7 @@ org.openhab.automation.groovyscripting org.openhab.automation.jsscripting org.openhab.automation.jythonscripting + org.openhab.automation.jrubyscripting org.openhab.automation.pidcontroller org.openhab.automation.pwm From 25ea7110a1d7afcca6ef9493d6608734ad94dca8 Mon Sep 17 00:00:00 2001 From: boc-tothefuture Date: Mon, 8 Nov 2021 19:32:30 -0500 Subject: [PATCH 02/15] Update bundles/org.openhab.automation.jrubyscripting/README.md Co-authored-by: Wouter Born --- bundles/org.openhab.automation.jrubyscripting/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.automation.jrubyscripting/README.md b/bundles/org.openhab.automation.jrubyscripting/README.md index e415982b5b7d..e76530d66a98 100644 --- a/bundles/org.openhab.automation.jrubyscripting/README.md +++ b/bundles/org.openhab.automation.jrubyscripting/README.md @@ -18,7 +18,7 @@ JRuby configuration parameters may be set by creating a jruby.cfg file in $OPENH ## Ruby Gems -This binding will install user specified gems and make them available on the library search path. +This automation add-on will install user specified gems and make them available on the library search path. Gem versions may be specified using the standard ruby gem_name=version format. The version number follows the [pessimistic version constraint](https://guides.rubygems.org/patterns/#pessimistic-version-constraint) syntax. From d930333d0ec45ade39cacce3dcdc3f5ef0d6a76c Mon Sep 17 00:00:00 2001 From: boc-tothefuture Date: Mon, 8 Nov 2021 19:32:58 -0500 Subject: [PATCH 03/15] Update bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineFactory.java Co-authored-by: Wouter Born --- .../jrubyscripting/internal/JRubyScriptEngineFactory.java | 1 - 1 file changed, 1 deletion(-) diff --git a/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineFactory.java b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineFactory.java index be60919899c1..85785d81ad66 100644 --- a/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineFactory.java +++ b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineFactory.java @@ -51,7 +51,6 @@ public class JRubyScriptEngineFactory extends AbstractScriptEngineFactory { private final javax.script.ScriptEngineFactory factory = new org.jruby.embed.jsr223.JRubyEngineFactory(); - // formatter turned off because it does not appropriately format chained streams private final List scriptTypes = Stream .concat(factory.getExtensions().stream(), factory.getMimeTypes().stream()) .collect(Collectors.toUnmodifiableList()); From 460c6cdc786558a6ad6949feea17a739bf3036de Mon Sep 17 00:00:00 2001 From: boc-tothefuture Date: Mon, 8 Nov 2021 19:33:24 -0500 Subject: [PATCH 04/15] Update bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineConfiguration.java Co-authored-by: Wouter Born --- .../jrubyscripting/internal/JRubyScriptEngineConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineConfiguration.java b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineConfiguration.java index cf79d90ae0e3..28c8acec0c08 100644 --- a/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineConfiguration.java +++ b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineConfiguration.java @@ -75,7 +75,7 @@ public class JRubyScriptEngineConfiguration { /** * Update configuration * - * @param config Configuration parameters to apply to ScripEngine + * @param config Configuration parameters to apply to ScriptEngine * @param factory ScriptEngineFactory to configure */ void update(Map config, ScriptEngineFactory factory) { From 595f85a018cc280bb59242b4b00fdcd387db67a2 Mon Sep 17 00:00:00 2001 From: boc-tothefuture Date: Mon, 8 Nov 2021 19:33:45 -0500 Subject: [PATCH 05/15] Update bundles/org.openhab.automation.jrubyscripting/README.md Co-authored-by: Wouter Born --- bundles/org.openhab.automation.jrubyscripting/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.automation.jrubyscripting/README.md b/bundles/org.openhab.automation.jrubyscripting/README.md index e76530d66a98..4e45dd3ce000 100644 --- a/bundles/org.openhab.automation.jrubyscripting/README.md +++ b/bundles/org.openhab.automation.jrubyscripting/README.md @@ -22,7 +22,7 @@ This automation add-on will install user specified gems and make them available Gem versions may be specified using the standard ruby gem_name=version format. The version number follows the [pessimistic version constraint](https://guides.rubygems.org/patterns/#pessimistic-version-constraint) syntax. -For example this configuration will install version 4 or higher of the [OpenHAB JRuby Scripting Libray](https://boc-tothefuture.github.io/openhab-jruby/). +For example this configuration will install version 4 or higher of the [openHAB JRuby Scripting Library](https://boc-tothefuture.github.io/openhab-jruby/). ```text org.openhab.automation.jrubyscripting:gems=openhab-scripting=~>4.0 From 092011913a464cea8e206a7c638e8024a46428f2 Mon Sep 17 00:00:00 2001 From: boc-tothefuture Date: Mon, 8 Nov 2021 19:34:04 -0500 Subject: [PATCH 06/15] Update bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineFactory.java Co-authored-by: Wouter Born --- .../jrubyscripting/internal/JRubyScriptEngineFactory.java | 1 - 1 file changed, 1 deletion(-) diff --git a/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineFactory.java b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineFactory.java index 85785d81ad66..2f1b4e97b700 100644 --- a/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineFactory.java +++ b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineFactory.java @@ -92,7 +92,6 @@ public List getScriptTypes() { @Override public void scopeValues(ScriptEngine scriptEngine, Map scopeValues) { - // Empty comments prevent the formatter from breaking up the correct streams chaining Map filteredScopeValues = // scopeValues // From 01f33a86c0f3e0b9fdb958acec8dcdca03d6262f Mon Sep 17 00:00:00 2001 From: boc-tothefuture Date: Tue, 9 Nov 2021 19:29:19 -0500 Subject: [PATCH 07/15] Update bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineFactory.java Co-authored-by: Wouter Born --- .../jrubyscripting/internal/JRubyScriptEngineFactory.java | 1 - 1 file changed, 1 deletion(-) diff --git a/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineFactory.java b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineFactory.java index 2f1b4e97b700..3e7975e307e7 100644 --- a/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineFactory.java +++ b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineFactory.java @@ -31,7 +31,6 @@ /** * This is an implementation of a {@link ScriptEngineFactory} for Ruby. - * handlers. * * @author Brian O'Connell - Initial contribution */ From 162440912fbd8c35cb26a2f5b5ec4c2297e3742b Mon Sep 17 00:00:00 2001 From: Jimmy Tanagra Date: Sat, 13 Nov 2021 22:59:07 +1000 Subject: [PATCH 08/15] [jrubyscripting] Add ConfigurableService Signed-off-by: Jimmy Tanagra --- .../README.md | 32 ++++----- .../pom.xml | 6 +- .../src/main/feature/feature.xml | 1 + .../JRubyScriptEngineConfiguration.java | 2 +- .../internal/JRubyScriptEngineFactory.java | 4 ++ .../jrubyscripting/internal/package-info.java | 0 .../main/resources/OH-INF/config/config.xml | 70 +++++++++++++++++++ 7 files changed, 92 insertions(+), 23 deletions(-) rename bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/{binding => automation}/jrubyscripting/internal/JRubyScriptEngineConfiguration.java (99%) rename bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/{binding => automation}/jrubyscripting/internal/JRubyScriptEngineFactory.java (94%) rename bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/{binding => automation}/jrubyscripting/internal/package-info.java (100%) create mode 100644 bundles/org.openhab.automation.jrubyscripting/src/main/resources/OH-INF/config/config.xml diff --git a/bundles/org.openhab.automation.jrubyscripting/README.md b/bundles/org.openhab.automation.jrubyscripting/README.md index 4e45dd3ce000..62250bac5c4c 100644 --- a/bundles/org.openhab.automation.jrubyscripting/README.md +++ b/bundles/org.openhab.automation.jrubyscripting/README.md @@ -1,38 +1,38 @@ -# JRuby Scripting +# JRuby Scripting This add-on provides [JRuby](https://www.jruby.org/) 9.3.1 that can be used as a scripting language within automation rules. ## JRuby Scripting Configuration -JRuby configuration parameters may be set by creating a jruby.cfg file in $OPENHAB_CONF/services/ +After installing this add-on, you will find configuration options in the openHAB portal under _Settings -> Other Services -> JRuby Scripting_. +Alternatively, JRuby configuration parameters may be set by creating a `jruby.cfg` file in `conf/services/` -| Parameter | Default | Description | -|-------------------------------------------------------|-----------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| org.openhab.automation.jrubyscripting:gem_home | $OPENHAB_CONF/scripts/lib/ruby/gem_home | Location ruby gems will be installed and loaded, directory will be created if missing and gem installs are specified from | -| org.openhab.automation.jrubyscripting:rubylib | $OPENHAB_CONF/automation/lib/ruby/ | Search path for user libraries | -| org.openhab.automation.jrubyscripting:local_context | threadsafe | The local context holds Ruby runtime, name-value pairs for sharing variables between Java and Ruby. See [this](https://github.com/jruby/jruby/wiki/RedBridge#Context_Instance_Type) for options and details | -| org.openhab.automation.jrubyscripting:local_variables | transient | Defines how variables are shared between Ruby and Java. See [this](https://github.com/jruby/jruby/wiki/RedBridge#local-variable-behavior-options) for options and details | -| org.openhab.automation.jrubyscripting:gems | | Comma separated list of [Ruby Gems](https://rubygems.org/) to install. | - +| Parameter | Default | Description | +| --------------- | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| gem_home | $OPENHAB_CONF/scripts/lib/ruby/gem_home | Location ruby gems will be installed and loaded, directory will be created if missing and gem installs are specified | +| rubylib | $OPENHAB_CONF/automation/lib/ruby/ | Search path for user libraries. Separate each path with a colon (semicolon in Windows). | +| local_context | singlethread | The local context holds Ruby runtime, name-value pairs for sharing variables between Java and Ruby. See [this](https://github.com/jruby/jruby/wiki/RedBridge#Context_Instance_Type) for options and details | +| local_variables | transient | Defines how variables are shared between Ruby and Java. See [this](https://github.com/jruby/jruby/wiki/RedBridge#local-variable-behavior-options) for options and details | +| gems | | Comma separated list of [Ruby Gems](https://rubygems.org/) to install. | ## Ruby Gems This automation add-on will install user specified gems and make them available on the library search path. Gem versions may be specified using the standard ruby gem_name=version format. -The version number follows the [pessimistic version constraint](https://guides.rubygems.org/patterns/#pessimistic-version-constraint) syntax. +The version number follows the [pessimistic version constraint](https://guides.rubygems.org/patterns/#pessimistic-version-constraint) syntax. For example this configuration will install version 4 or higher of the [openHAB JRuby Scripting Library](https://boc-tothefuture.github.io/openhab-jruby/). ```text -org.openhab.automation.jrubyscripting:gems=openhab-scripting=~>4.0 +gems=openhab-scripting=~>4.0 ``` ## Creating JRuby Scripts When this add-on is installed, you can select JRuby as a scripting language when creating a script action within the rule editor of the UI. -Alternatively, you can create scripts in the `automation/jsr223` configuration directory. +Alternatively, you can create scripts in the `automation/jsr223/ruby/personal` configuration directory. If you create an empty file called `test.rb`, you will see a log line with information similar to: ```text @@ -51,9 +51,8 @@ log:set DEBUG org.openhab.automation.jrubyscripting All [ScriptExtensions]({{base}}/configuration/jsr223.html#scriptextension-objects-all-jsr223-languages) are available in JRuby with the following exceptions/modifications: -* The File variable, referencing java.io.File is not available as it conflicts with Ruby's File class preventing Ruby from initializing -* Globals scriptExtension, automationManager, ruleRegistry, items, voice, rules, things, events, itemRegistry, ir, actions, se, audio, lifecycleTracker are prepended with a $ (e.g. $automationManager) making them available as a global objects in Ruby. - +- The File variable, referencing java.io.File is not available as it conflicts with Ruby's File class preventing Ruby from initializing +- Globals scriptExtension, automationManager, ruleRegistry, items, voice, rules, things, events, itemRegistry, ir, actions, se, audio, lifecycleTracker are prepended with a $ (e.g. $automationManager) making them available as a global objects in Ruby. ## Script Examples @@ -71,4 +70,3 @@ LoggerFactory.getLogger("org.openhab.core.automation.examples").info("Hello worl JRuby can [import Java classes](https://github.com/jruby/jruby/wiki/CallingJavaFromJRuby). Depending on the openHAB logging configuration, you may need to prefix logger names with `org.openhab.core.automation` for them to show up in the log file (or you modify the logging configuration). - diff --git a/bundles/org.openhab.automation.jrubyscripting/pom.xml b/bundles/org.openhab.automation.jrubyscripting/pom.xml index 1d150eae7813..b5cd89e19042 100644 --- a/bundles/org.openhab.automation.jrubyscripting/pom.xml +++ b/bundles/org.openhab.automation.jrubyscripting/pom.xml @@ -15,11 +15,7 @@ openHAB Add-ons :: Automation :: JRuby Scripting - - com.ibm.icu.*;resolution:=optional, - org.abego.treelayout.*;resolution:=optional, - org.apache.ivy.*;resolution:=optional, - org.stringtemplate.v4.*;resolution:=optional + com.sun.nio.*;resolution:=optional,com.sun.security.*;resolution:=optional,org.apache.tools.ant.*;resolution:=optional,org.bouncycastle.*;resolution:=optional,org.joda.*;resolution:=optional,sun.management.*;resolution:=optional,sun.nio.*;resolution:=optional 9.3.1.0 diff --git a/bundles/org.openhab.automation.jrubyscripting/src/main/feature/feature.xml b/bundles/org.openhab.automation.jrubyscripting/src/main/feature/feature.xml index 2ef4f1827772..ad47c33895ae 100644 --- a/bundles/org.openhab.automation.jrubyscripting/src/main/feature/feature.xml +++ b/bundles/org.openhab.automation.jrubyscripting/src/main/feature/feature.xml @@ -5,5 +5,6 @@ openhab-runtime-base mvn:org.openhab.addons.bundles/org.openhab.automation.jrubyscripting/${project.version} + mvn:org.openhab.addons.features.karaf/org.openhab.addons.features.karaf.openhab-addons-external/${project.version}/cfg/jruby diff --git a/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineConfiguration.java b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/automation/jrubyscripting/internal/JRubyScriptEngineConfiguration.java similarity index 99% rename from bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineConfiguration.java rename to bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/automation/jrubyscripting/internal/JRubyScriptEngineConfiguration.java index 28c8acec0c08..0c121cfc39d8 100644 --- a/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineConfiguration.java +++ b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/automation/jrubyscripting/internal/JRubyScriptEngineConfiguration.java @@ -53,7 +53,7 @@ public class JRubyScriptEngineConfiguration { private final static Map CONFIGURATION_PARAMETERS = Map.ofEntries( Map.entry("local_context", new OptionalConfigurationElement.Builder(OptionalConfigurationElement.Type.SYSTEM_PROPERTY) - .mappedTo("org.jruby.embed.localcontext.scope").defaultValue("threadsafe").build()), + .mappedTo("org.jruby.embed.localcontext.scope").defaultValue("singlethread").build()), Map.entry("local_variable", new OptionalConfigurationElement.Builder(OptionalConfigurationElement.Type.SYSTEM_PROPERTY) diff --git a/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineFactory.java b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/automation/jrubyscripting/internal/JRubyScriptEngineFactory.java similarity index 94% rename from bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineFactory.java rename to bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/automation/jrubyscripting/internal/JRubyScriptEngineFactory.java index 3e7975e307e7..f50709c531e4 100644 --- a/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/JRubyScriptEngineFactory.java +++ b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/automation/jrubyscripting/internal/JRubyScriptEngineFactory.java @@ -24,6 +24,7 @@ import org.eclipse.jdt.annotation.Nullable; import org.openhab.core.automation.module.script.AbstractScriptEngineFactory; import org.openhab.core.automation.module.script.ScriptEngineFactory; +import org.openhab.core.config.core.ConfigurableService; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -36,10 +37,13 @@ */ @NonNullByDefault @Component(service = ScriptEngineFactory.class, configurationPid = "org.openhab.automation.jrubyscripting") +@ConfigurableService(category = "automation", label = "JRuby Scripting", description_uri = JRubyScriptEngineFactory.CONFIG_URI) public class JRubyScriptEngineFactory extends AbstractScriptEngineFactory { private final JRubyScriptEngineConfiguration configuration = new JRubyScriptEngineConfiguration(); + protected static final String CONFIG_URI = "automation:jruby"; + // Filter out the File entry to prevent shadowing the Ruby File class which breaks Ruby in spectacularly // difficult ways to debug. private final static Set FILTERED_PRESETS = Set.of("File"); diff --git a/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/package-info.java b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/automation/jrubyscripting/internal/package-info.java similarity index 100% rename from bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/binding/jrubyscripting/internal/package-info.java rename to bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/automation/jrubyscripting/internal/package-info.java diff --git a/bundles/org.openhab.automation.jrubyscripting/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.automation.jrubyscripting/src/main/resources/OH-INF/config/config.xml new file mode 100644 index 000000000000..994e072f9d81 --- /dev/null +++ b/bundles/org.openhab.automation.jrubyscripting/src/main/resources/OH-INF/config/config.xml @@ -0,0 +1,70 @@ + + + + + + + This group defines JRuby system properties. + true + + + + + This group defines Ruby's environment. + false + + + + + This group defines the list of GEMS to install. + false + + + + + The local context holds Ruby runtime, name-value pairs for sharing variables between Java and Ruby. See + https://github.com/jruby/jruby/wiki/RedBridge#Context_Instance_Type for options and details. + singlethread + + + + + + + + + + + Defines how variables are shared between Ruby and Java. See + https://github.com/jruby/jruby/wiki/RedBridge#local-variable-behavior-options for options and details. + transient + + + + + + + + + + Location ruby gems will be installed and loaded, directory will be created if missing and gem installs + are specified + + + + + + Search path for user libraries. Separate each path with a colon (semicolon in Windows). + + + + + Comma separated list of Ruby Gems to install. + + + + From e70f4ad769a03837d9a13a5b7af5954bc8a89500 Mon Sep 17 00:00:00 2001 From: boc-tothefuture Date: Sun, 14 Nov 2021 12:51:04 -0500 Subject: [PATCH 09/15] Update bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/automation/jrubyscripting/internal/JRubyScriptEngineConfiguration.java Co-authored-by: Wouter Born --- .../internal/JRubyScriptEngineConfiguration.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/automation/jrubyscripting/internal/JRubyScriptEngineConfiguration.java b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/automation/jrubyscripting/internal/JRubyScriptEngineConfiguration.java index 0c121cfc39d8..915388ae47a2 100644 --- a/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/automation/jrubyscripting/internal/JRubyScriptEngineConfiguration.java +++ b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/automation/jrubyscripting/internal/JRubyScriptEngineConfiguration.java @@ -32,8 +32,7 @@ import org.slf4j.LoggerFactory; /** - * - * Processes JRuby Configuration Parameters + * Processes JRuby Configuration Parameters. * * @author Brian O'Connell - Initial contribution */ From 3e93906bc5ceddf36247bfd156902361c3593001 Mon Sep 17 00:00:00 2001 From: boc-tothefuture Date: Sun, 14 Nov 2021 12:52:15 -0500 Subject: [PATCH 10/15] Update bundles/pom.xml Co-authored-by: Wouter Born --- bundles/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/pom.xml b/bundles/pom.xml index aee3db282c39..9cc1c10accae 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -19,9 +19,9 @@ org.openhab.automation.groovyscripting + org.openhab.automation.jrubyscripting org.openhab.automation.jsscripting org.openhab.automation.jythonscripting - org.openhab.automation.jrubyscripting org.openhab.automation.pidcontroller org.openhab.automation.pwm From 19f54b819b33188d32b220f68b281ffa89f8507b Mon Sep 17 00:00:00 2001 From: boc-tothefuture Date: Sun, 14 Nov 2021 14:05:30 -0500 Subject: [PATCH 11/15] Update bundles/org.openhab.automation.jrubyscripting/src/main/feature/feature.xml Co-authored-by: Wouter Born --- .../src/main/feature/feature.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/bundles/org.openhab.automation.jrubyscripting/src/main/feature/feature.xml b/bundles/org.openhab.automation.jrubyscripting/src/main/feature/feature.xml index ad47c33895ae..2ef4f1827772 100644 --- a/bundles/org.openhab.automation.jrubyscripting/src/main/feature/feature.xml +++ b/bundles/org.openhab.automation.jrubyscripting/src/main/feature/feature.xml @@ -5,6 +5,5 @@ openhab-runtime-base mvn:org.openhab.addons.bundles/org.openhab.automation.jrubyscripting/${project.version} - mvn:org.openhab.addons.features.karaf/org.openhab.addons.features.karaf.openhab-addons-external/${project.version}/cfg/jruby From 4310812c2ed8c618ca37c8f568a172b9cfcc3dc2 Mon Sep 17 00:00:00 2001 From: Jimmy Tanagra Date: Mon, 15 Nov 2021 14:59:43 +1000 Subject: [PATCH 12/15] [jrubyscripting] Use consistent labels Signed-off-by: Jimmy Tanagra --- .../src/main/resources/OH-INF/config/config.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bundles/org.openhab.automation.jrubyscripting/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.automation.jrubyscripting/src/main/resources/OH-INF/config/config.xml index 994e072f9d81..b0605b4d2fed 100644 --- a/bundles/org.openhab.automation.jrubyscripting/src/main/resources/OH-INF/config/config.xml +++ b/bundles/org.openhab.automation.jrubyscripting/src/main/resources/OH-INF/config/config.xml @@ -19,8 +19,8 @@ - - This group defines the list of GEMS to install. + + This group defines the list of Ruby Gems to install. false @@ -51,7 +51,7 @@ - Location ruby gems will be installed and loaded, directory will be created if missing and gem installs + Location Ruby Gems will be installed and loaded, directory will be created if missing and gem installs are specified @@ -62,7 +62,7 @@ - + Comma separated list of Ruby Gems to install. From 04b057d198c5aa3726fa3ecf2f1c143c2e1c7bf7 Mon Sep 17 00:00:00 2001 From: Jimmy Tanagra Date: Mon, 15 Nov 2021 18:55:26 +1000 Subject: [PATCH 13/15] [jrubyscripting] Address SAT warnings Signed-off-by: Jimmy Tanagra --- .../JRubyScriptEngineConfiguration.java | 18 +++++++----------- .../internal/JRubyScriptEngineFactory.java | 17 +++++++---------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/automation/jrubyscripting/internal/JRubyScriptEngineConfiguration.java b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/automation/jrubyscripting/internal/JRubyScriptEngineConfiguration.java index 915388ae47a2..df0db8c8d535 100644 --- a/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/automation/jrubyscripting/internal/JRubyScriptEngineConfiguration.java +++ b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/automation/jrubyscripting/internal/JRubyScriptEngineConfiguration.java @@ -41,15 +41,15 @@ public class JRubyScriptEngineConfiguration { private final Logger logger = LoggerFactory.getLogger(JRubyScriptEngineConfiguration.class); - private final static Path DEFAULT_GEM_HOME = Paths.get(OpenHAB.getConfigFolder(), "scripts", "lib", "ruby", + private static final Path DEFAULT_GEM_HOME = Paths.get(OpenHAB.getConfigFolder(), "scripts", "lib", "ruby", "gem_home"); - private final static Path DEFAULT_RUBYLIB = Paths.get(OpenHAB.getConfigFolder(), "automation", "lib", "ruby"); + private static final Path DEFAULT_RUBYLIB = Paths.get(OpenHAB.getConfigFolder(), "automation", "lib", "ruby"); - private final static String GEM_HOME = "gem_home"; + private static final String GEM_HOME = "gem_home"; // Map of configuration parameters - private final static Map CONFIGURATION_PARAMETERS = Map.ofEntries( + private static final Map CONFIGURATION_PARAMETERS = Map.ofEntries( Map.entry("local_context", new OptionalConfigurationElement.Builder(OptionalConfigurationElement.Type.SYSTEM_PROPERTY) .mappedTo("org.jruby.embed.localcontext.scope").defaultValue("singlethread").build()), @@ -68,7 +68,7 @@ public class JRubyScriptEngineConfiguration { Map.entry("gems", new OptionalConfigurationElement.Builder(OptionalConfigurationElement.Type.GEM).build())); - private final static Map> CONFIGURATION_TYPE_MAP = CONFIGURATION_PARAMETERS + private static final Map> CONFIGURATION_TYPE_MAP = CONFIGURATION_PARAMETERS .values().stream().collect(Collectors.groupingBy(v -> v.type)); /** @@ -104,7 +104,6 @@ private void processConfigValue(String key, Object value) { * @param factory Script Engine to configure */ void configureScriptEngine(ScriptEngineFactory factory) { - configureSystemProperties(CONFIGURATION_TYPE_MAP.getOrDefault(OptionalConfigurationElement.Type.SYSTEM_PROPERTY, Collections. emptyList())); @@ -121,16 +120,14 @@ void configureScriptEngine(ScriptEngineFactory factory) { * Makes Gem home directory if it does not exist */ private void ensureGemHomeExists() { - OptionalConfigurationElement gemHomeConfigElement = CONFIGURATION_PARAMETERS.get(GEM_HOME); if (gemHomeConfigElement != null) { Optional gemHome = gemHomeConfigElement.getValue(); if (gemHome.isPresent()) { File gemHomeDirectory = new File(gemHome.get()); - if (gemHomeDirectory.exists() == false) { + if (!gemHomeDirectory.exists()) { logger.debug("gem_home directory does not exist, creating"); - boolean created = gemHomeDirectory.mkdirs(); - if (created == false) { + if (!gemHomeDirectory.mkdirs()) { logger.debug("Error creating gem_home direcotry"); } } @@ -149,7 +146,6 @@ private void ensureGemHomeExists() { private synchronized void configureGems(List gemDirectives, ScriptEngine engine) { for (OptionalConfigurationElement gemDirective : gemDirectives) { if (gemDirective.getValue().isPresent()) { - ensureGemHomeExists(); String[] gems = gemDirective.getValue().get().split(","); diff --git a/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/automation/jrubyscripting/internal/JRubyScriptEngineFactory.java b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/automation/jrubyscripting/internal/JRubyScriptEngineFactory.java index f50709c531e4..cefa9b3e023d 100644 --- a/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/automation/jrubyscripting/internal/JRubyScriptEngineFactory.java +++ b/bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/automation/jrubyscripting/internal/JRubyScriptEngineFactory.java @@ -25,7 +25,6 @@ import org.openhab.core.automation.module.script.AbstractScriptEngineFactory; import org.openhab.core.automation.module.script.ScriptEngineFactory; import org.openhab.core.config.core.ConfigurableService; -import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Modified; @@ -37,18 +36,16 @@ */ @NonNullByDefault @Component(service = ScriptEngineFactory.class, configurationPid = "org.openhab.automation.jrubyscripting") -@ConfigurableService(category = "automation", label = "JRuby Scripting", description_uri = JRubyScriptEngineFactory.CONFIG_URI) +@ConfigurableService(category = "automation", label = "JRuby Scripting", description_uri = "automation:jruby") public class JRubyScriptEngineFactory extends AbstractScriptEngineFactory { private final JRubyScriptEngineConfiguration configuration = new JRubyScriptEngineConfiguration(); - protected static final String CONFIG_URI = "automation:jruby"; - // Filter out the File entry to prevent shadowing the Ruby File class which breaks Ruby in spectacularly // difficult ways to debug. - private final static Set FILTERED_PRESETS = Set.of("File"); - private final static Set INSTANCE_PRESETS = Set.of(); - private final static Set GLOBAL_PRESETS = Set.of("scriptExtension", "automationManager", "ruleRegistry", + private static final Set FILTERED_PRESETS = Set.of("File"); + private static final Set INSTANCE_PRESETS = Set.of(); + private static final Set GLOBAL_PRESETS = Set.of("scriptExtension", "automationManager", "ruleRegistry", "items", "voice", "rules", "things", "events", "itemRegistry", "ir", "actions", "se", "audio", "lifecycleTracker"); @@ -76,13 +73,13 @@ private static Map.Entry mapGlobalPresets(Map.Entry config) { + protected void activate(Map config) { configuration.update(config, factory); } - // The modified call updates configuration for binding + // The modified call updates configuration for the automation @Modified protected void modified(Map config) { configuration.update(config, factory); From 6dff8600eeca3a410a656c7bfcf4e66181b87576 Mon Sep 17 00:00:00 2001 From: Jimmy Tanagra Date: Mon, 15 Nov 2021 18:57:11 +1000 Subject: [PATCH 14/15] [jrubyscripting] re-add the configuration prefix Signed-off-by: Jimmy Tanagra --- .../README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/bundles/org.openhab.automation.jrubyscripting/README.md b/bundles/org.openhab.automation.jrubyscripting/README.md index 62250bac5c4c..f9cf01c86670 100644 --- a/bundles/org.openhab.automation.jrubyscripting/README.md +++ b/bundles/org.openhab.automation.jrubyscripting/README.md @@ -8,13 +8,13 @@ After installing this add-on, you will find configuration options in the openHAB Alternatively, JRuby configuration parameters may be set by creating a `jruby.cfg` file in `conf/services/` -| Parameter | Default | Description | -| --------------- | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| gem_home | $OPENHAB_CONF/scripts/lib/ruby/gem_home | Location ruby gems will be installed and loaded, directory will be created if missing and gem installs are specified | -| rubylib | $OPENHAB_CONF/automation/lib/ruby/ | Search path for user libraries. Separate each path with a colon (semicolon in Windows). | -| local_context | singlethread | The local context holds Ruby runtime, name-value pairs for sharing variables between Java and Ruby. See [this](https://github.com/jruby/jruby/wiki/RedBridge#Context_Instance_Type) for options and details | -| local_variables | transient | Defines how variables are shared between Ruby and Java. See [this](https://github.com/jruby/jruby/wiki/RedBridge#local-variable-behavior-options) for options and details | -| gems | | Comma separated list of [Ruby Gems](https://rubygems.org/) to install. | +| Parameter | Default | Description | +| ----------------------------------------------------- | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| org.openhab.automation.jrubyscripting:gem_home | $OPENHAB_CONF/scripts/lib/ruby/gem_home | Location ruby gems will be installed and loaded, directory will be created if missing and gem installs are specified | +| org.openhab.automation.jrubyscripting:rubylib | $OPENHAB_CONF/automation/lib/ruby/ | Search path for user libraries. Separate each path with a colon (semicolon in Windows). | +| org.openhab.automation.jrubyscripting:local_context | singlethread | The local context holds Ruby runtime, name-value pairs for sharing variables between Java and Ruby. See [this](https://github.com/jruby/jruby/wiki/RedBridge#Context_Instance_Type) for options and details | +| org.openhab.automation.jrubyscripting:local_variables | transient | Defines how variables are shared between Ruby and Java. See [this](https://github.com/jruby/jruby/wiki/RedBridge#local-variable-behavior-options) for options and details | +| org.openhab.automation.jrubyscripting:gems | | Comma separated list of [Ruby Gems](https://rubygems.org/) to install. | ## Ruby Gems @@ -25,7 +25,7 @@ The version number follows the [pessimistic version constraint](https://guides.r For example this configuration will install version 4 or higher of the [openHAB JRuby Scripting Library](https://boc-tothefuture.github.io/openhab-jruby/). ```text -gems=openhab-scripting=~>4.0 +org.openhab.automation.jrubyscripting:gems=openhab-scripting=~>4.0 ``` ## Creating JRuby Scripts From d88bdaa051d2bf2d8199a6748550f2f14f427c36 Mon Sep 17 00:00:00 2001 From: Jimmy Tanagra Date: Mon, 15 Nov 2021 18:57:52 +1000 Subject: [PATCH 15/15] [jrubyscripting] Add default i18n properties file Signed-off-by: Jimmy Tanagra --- .../resources/OH-INF/i18n/jruby.properties | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 bundles/org.openhab.automation.jrubyscripting/src/main/resources/OH-INF/i18n/jruby.properties diff --git a/bundles/org.openhab.automation.jrubyscripting/src/main/resources/OH-INF/i18n/jruby.properties b/bundles/org.openhab.automation.jrubyscripting/src/main/resources/OH-INF/i18n/jruby.properties new file mode 100644 index 000000000000..97e140816a72 --- /dev/null +++ b/bundles/org.openhab.automation.jrubyscripting/src/main/resources/OH-INF/i18n/jruby.properties @@ -0,0 +1,30 @@ + +# service + +service.automation.jrubyscripting.label = JRuby Scripting + +# bundle config + +automation.config.jruby.gem_home.label = GEM_HOME +automation.config.jruby.gem_home.description = Location Ruby Gems will be installed and loaded, directory will be created if missing and gem installs are specified +automation.config.jruby.gems.label = Ruby Gems +automation.config.jruby.gems.description = Comma separated list of Ruby Gems to install. +automation.config.jruby.group.environment.label = Ruby Environment +automation.config.jruby.group.environment.description = This group defines Ruby's environment. +automation.config.jruby.group.gems.label = Ruby Gems +automation.config.jruby.group.gems.description = This group defines the list of Ruby Gems to install. +automation.config.jruby.group.system.label = System Properties +automation.config.jruby.group.system.description = This group defines JRuby system properties. +automation.config.jruby.local_context.label = Context Instance Type +automation.config.jruby.local_context.description = The local context holds Ruby runtime, name-value pairs for sharing variables between Java and Ruby. See https://github.com/jruby/jruby/wiki/RedBridge#Context_Instance_Type for options and details. +automation.config.jruby.local_context.option.singleton = Singleton +automation.config.jruby.local_context.option.threadsafe = ThreadSafe +automation.config.jruby.local_context.option.singlethread = SingleThread +automation.config.jruby.local_context.option.concurrent = Concurrent +automation.config.jruby.local_variable.label = Local Variable Behavior +automation.config.jruby.local_variable.description = Defines how variables are shared between Ruby and Java. See https://github.com/jruby/jruby/wiki/RedBridge#local-variable-behavior-options for options and details. +automation.config.jruby.local_variable.option.transient = Transient +automation.config.jruby.local_variable.option.persistent = Persistent +automation.config.jruby.local_variable.option.global = Global +automation.config.jruby.rubylib.label = RUBYLIB +automation.config.jruby.rubylib.description = Search path for user libraries. Separate each path with a colon (semicolon in Windows).