Skip to content

Commit

Permalink
Prepare automation for ScriptEngineFactory projects
Browse files Browse the repository at this point in the history
These changes prepare for custom ScriptEngineFactories and does not
include any breaking changes.
* Moved AbstractScriptEngineFactory out of internal so that it can be
used by custom factories
* Modified ScriptEngineModuleTypeProvider to include engines from custom
factories
* Fully qualified some names to eliminate confusion with javax.script
classes
* Cleaned up some logging

Signed-off-by: Scott Rushworth <openhab@5iver.com>
  • Loading branch information
Scott Rushworth committed Dec 1, 2019
1 parent 0046774 commit 1cdcbe6
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.core.automation.module.script.internal;
package org.openhab.core.automation.module.script;

import java.util.ArrayList;
import java.util.Collections;
Expand All @@ -22,7 +22,6 @@

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.automation.module.script.ScriptEngineFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -32,9 +31,10 @@
* @author Scott Rushworth - Initial contribution
*/
@NonNullByDefault
public abstract class AbstractScriptEngineFactory implements ScriptEngineFactory {
public abstract class AbstractScriptEngineFactory
implements org.openhab.core.automation.module.script.ScriptEngineFactory {

protected final Logger logger = LoggerFactory.getLogger(AbstractScriptEngineFactory.class);
protected final static Logger logger = LoggerFactory.getLogger(AbstractScriptEngineFactory.class);

@Override
public List<String> getScriptTypes() {
Expand Down Expand Up @@ -65,5 +65,4 @@ public void scopeValues(ScriptEngine scriptEngine, Map<String, Object> scopeValu
}
return scriptEngine;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package org.openhab.core.automation.module.script.internal;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.automation.module.script.AbstractScriptEngineFactory;
import org.openhab.core.automation.module.script.ScriptEngineFactory;
import org.osgi.service.component.annotations.Component;

Expand All @@ -23,7 +24,7 @@
* @author Scott Rushworth - added service and removed methods now inherited from AbstractScriptEngineFactory
*/
@NonNullByDefault
@Component(service = ScriptEngineFactory.class)
@Component(service = org.openhab.core.automation.module.script.ScriptEngineFactory.class)
public class GenericScriptEngineFactory extends AbstractScriptEngineFactory {

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import javax.script.ScriptException;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.automation.module.script.AbstractScriptEngineFactory;
import org.openhab.core.automation.module.script.ScriptEngineFactory;
import org.osgi.service.component.annotations.Component;

Expand All @@ -34,7 +35,7 @@
* @author Scott Rushworth - removed default methods provided by ScriptEngineFactory
*/
@NonNullByDefault
@Component(service = ScriptEngineFactory.class)
@Component(service = org.openhab.core.automation.module.script.ScriptEngineFactory.class)
public class NashornScriptEngineFactory extends AbstractScriptEngineFactory {

private static final String SCRIPT_TYPE = "js";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.automation.module.script.ScriptEngineContainer;
import org.openhab.core.automation.module.script.ScriptEngineFactory;
import org.openhab.core.automation.module.script.ScriptEngineManager;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
Expand All @@ -40,10 +39,10 @@
* @author Scott Rushworth - replaced GenericScriptEngineFactory with a service and cleaned up logging
*/
@NonNullByDefault
@Component(service = ScriptEngineManager.class)
public class ScriptEngineManagerImpl implements ScriptEngineManager {
@Component(service = org.openhab.core.automation.module.script.ScriptEngineManager.class)
public class ScriptEngineManagerImpl implements org.openhab.core.automation.module.script.ScriptEngineManager {

private final Logger logger = LoggerFactory.getLogger(ScriptEngineManagerImpl.class);
private static final Logger logger = LoggerFactory.getLogger(ScriptEngineManagerImpl.class);
private final Map<String, @Nullable ScriptEngineContainer> loadedScriptEngineInstances = new HashMap<>();
private final Map<String, @Nullable ScriptEngineFactory> customSupport = new HashMap<>();
private final Map<String, @Nullable ScriptEngineFactory> genericSupport = new HashMap<>();
Expand All @@ -70,12 +69,20 @@ public void addScriptEngineFactory(ScriptEngineFactory engineFactory) {
this.genericSupport.put(scriptType, engineFactory);
}
}
logger.debug("Added {}", engineFactory.getClass().getSimpleName());
for (javax.script.ScriptEngineFactory f : ScriptEngineFactory.ENGINE_MANAGER.getEngineFactories()) {
logger.debug(
"ScriptEngineFactory details for {} ({}): supports {} ({}) with file extensions {}, names {}, and mimetypes {}",
f.getEngineName(), f.getEngineVersion(), f.getLanguageName(), f.getLanguageVersion(),
f.getExtensions(), f.getNames(), f.getMimeTypes());
if (!engineFactory.getScriptTypes().isEmpty()) {
ScriptEngine scriptEngine = engineFactory.createScriptEngine(engineFactory.getScriptTypes().get(0));
if (scriptEngine != null) {
javax.script.ScriptEngineFactory factory = scriptEngine.getFactory();
logger.debug(
"Initialized a {} ScriptEngineFactory for {} ({}): supports {} ({}) with file extensions {}, names {}, and mimetypes {}",
(isCustomFactory(engineFactory)) ? "custom" : "generic", factory.getEngineName(),
factory.getEngineVersion(), factory.getLanguageName(), factory.getLanguageVersion(),
factory.getExtensions(), factory.getNames(), factory.getMimeTypes());
} else {
logger.trace("addScriptEngineFactory: engine was null");
}
} else {
logger.trace("addScriptEngineFactory: scriptTypes was empty");
}
}

Expand Down Expand Up @@ -126,7 +133,7 @@ private boolean isCustomFactory(ScriptEngineFactory engineFactory) {
logger.debug("Added ScriptEngine for language '{}' with identifier: {}", scriptType,
engineIdentifier);
} else {
logger.error("ScriptEngine for language '{}' could not be found for identifier: {}", scriptType,
logger.error("ScriptEngine for language '{}' could not be created for identifier: {}", scriptType,
engineIdentifier);
}
} catch (Exception ex) {
Expand Down Expand Up @@ -193,7 +200,7 @@ private void removeScriptExtensions(String pathIdentifier) {

/**
* This method will find and return a {@link ScriptEngineFactory} capable of executing a script of the given type,
* if one exists.
* if one exists. Custom ScriptEngineFactories are preferred over generic.
*
* @param scriptType a file extension (script) or MimeType (ScriptAction or ScriptCondition)
* @return {@link ScriptEngineFactory} or null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.lang.StringUtils;
import javax.script.ScriptEngine;

import org.eclipse.smarthome.config.core.ConfigDescriptionParameter;
import org.eclipse.smarthome.config.core.ConfigDescriptionParameter.Type;
import org.eclipse.smarthome.config.core.ConfigDescriptionParameterBuilder;
Expand Down Expand Up @@ -53,7 +55,7 @@
public class ScriptModuleTypeProvider implements ModuleTypeProvider {

private final Logger logger = LoggerFactory.getLogger(ScriptModuleTypeProvider.class);
private final List<ParameterOption> parameterOptions = new CopyOnWriteArrayList<>();
private final TreeMap<String, String> parameterOptions = new TreeMap<>();

@SuppressWarnings("unchecked")
@Override
Expand Down Expand Up @@ -97,10 +99,14 @@ private ModuleType getScriptConditionType(Locale locale) {
* @return a list of {#link ConfigurationDescriptionParameter}s
*/
private List<ConfigDescriptionParameter> getConfigDescriptions(Locale locale) {
List<ParameterOption> parameterOptionsList = new ArrayList<ParameterOption>();
for (Map.Entry<String, String> entry : parameterOptions.entrySet()) {
parameterOptionsList.add(new ParameterOption(entry.getKey(), entry.getValue()));
}
final ConfigDescriptionParameter scriptType = ConfigDescriptionParameterBuilder.create("type", Type.TEXT)
.withRequired(true).withReadOnly(true).withMultiple(false).withLabel("Script Type")
.withDescription("the scripting language used").withOptions(parameterOptions).withLimitToOptions(true)
.build();
.withDescription("the scripting language used").withOptions(parameterOptionsList)
.withLimitToOptions(true).build();
final ConfigDescriptionParameter script = ConfigDescriptionParameterBuilder.create("script", Type.TEXT)
.withRequired(true).withReadOnly(false).withMultiple(false).withLabel("Script").withContext("script")
.withDescription("the script to execute").build();
Expand Down Expand Up @@ -128,26 +134,30 @@ public void removeProviderChangeListener(ProviderChangeListener<ModuleType> list
}

/**
* As {@link ScriptEngineFactory}s are added/changed, this method will create the {@link ParameterOption}s
* As {@link ScriptEngineFactory}s are added/removed, this method will create the {@link ParameterOption}s
* that are available when selecting a script type in a ScriptActionType or ScriptConditionType.
*/
@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
public void setScriptEngineFactory(ScriptEngineFactory engineFactory) {
parameterOptions.clear();
for (javax.script.ScriptEngineFactory f : ScriptEngineFactory.ENGINE_MANAGER.getEngineFactories()) {
String languageName = String.format("%s (%s)", StringUtils.capitalize(f.getLanguageName()),
f.getLanguageVersion());
ScriptEngine scriptEngine = engineFactory.createScriptEngine(engineFactory.getScriptTypes().get(0));
if (scriptEngine != null) {
List<String> mimeTypes = new ArrayList<>();

mimeTypes.addAll(f.getMimeTypes());
javax.script.ScriptEngineFactory factory = scriptEngine.getFactory();
String languageName = String.format("%s (%s)",
factory.getLanguageName().substring(0, 1).toUpperCase() + factory.getLanguageName().substring(1),
factory.getLanguageVersion());
mimeTypes.addAll(factory.getMimeTypes());
String preferredMimeType = mimeTypes.get(0);
mimeTypes.removeIf(mimeType -> !mimeType.contains("application") || mimeType.contains("x-"));
if (!mimeTypes.isEmpty()) {
preferredMimeType = mimeTypes.get(0);
}
parameterOptions.add(new ParameterOption(preferredMimeType, languageName));
parameterOptions.put(preferredMimeType, languageName);
logger.trace("ParameterOptions: {}", parameterOptions);
} else {
logger.trace("setScriptEngineFactory: engine was null");
}
logger.trace("ParameterOptions: {}", parameterOptions);
}

public void unsetScriptEngineFactory(ScriptEngineFactory scriptEngineFactory) {
Expand Down

0 comments on commit 1cdcbe6

Please sign in to comment.