Fix rules stay uninitialized when using Java 17 (#2787)
On Java 17 there is no Nashorn scripting engine so it takes a bit longer before ScriptEngines are available. Rules would stay uninitialized forever because the ScriptModuleTypeProvider did not notify its listeners whenever script.ScriptAction, script.ScriptCondition became available. Signed-off-by: Wouter Born <github@maindrain.net>pull/2795/head
parent
5e33cfc26a
commit
2e0b242099
|
@ -17,10 +17,7 @@ import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import javax.script.ScriptEngine;
|
import javax.script.ScriptEngine;
|
||||||
|
|
||||||
|
@ -36,12 +33,13 @@ import org.openhab.core.automation.type.ConditionType;
|
||||||
import org.openhab.core.automation.type.ModuleType;
|
import org.openhab.core.automation.type.ModuleType;
|
||||||
import org.openhab.core.automation.type.ModuleTypeProvider;
|
import org.openhab.core.automation.type.ModuleTypeProvider;
|
||||||
import org.openhab.core.automation.type.Output;
|
import org.openhab.core.automation.type.Output;
|
||||||
import org.openhab.core.common.registry.ProviderChangeListener;
|
import org.openhab.core.common.registry.AbstractProvider;
|
||||||
import org.openhab.core.config.core.ConfigDescriptionParameter;
|
import org.openhab.core.config.core.ConfigDescriptionParameter;
|
||||||
import org.openhab.core.config.core.ConfigDescriptionParameter.Type;
|
import org.openhab.core.config.core.ConfigDescriptionParameter.Type;
|
||||||
import org.openhab.core.config.core.ConfigDescriptionParameterBuilder;
|
import org.openhab.core.config.core.ConfigDescriptionParameterBuilder;
|
||||||
import org.openhab.core.config.core.ParameterOption;
|
import org.openhab.core.config.core.ParameterOption;
|
||||||
import org.osgi.service.component.annotations.Component;
|
import org.osgi.service.component.annotations.Component;
|
||||||
|
import org.osgi.service.component.annotations.Deactivate;
|
||||||
import org.osgi.service.component.annotations.Reference;
|
import org.osgi.service.component.annotations.Reference;
|
||||||
import org.osgi.service.component.annotations.ReferenceCardinality;
|
import org.osgi.service.component.annotations.ReferenceCardinality;
|
||||||
import org.osgi.service.component.annotations.ReferencePolicy;
|
import org.osgi.service.component.annotations.ReferencePolicy;
|
||||||
|
@ -56,15 +54,23 @@ import org.slf4j.LoggerFactory;
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
@Component
|
@Component
|
||||||
public class ScriptModuleTypeProvider implements ModuleTypeProvider {
|
public class ScriptModuleTypeProvider extends AbstractProvider<ModuleType> implements ModuleTypeProvider {
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(ScriptModuleTypeProvider.class);
|
private final Logger logger = LoggerFactory.getLogger(ScriptModuleTypeProvider.class);
|
||||||
private final Map<String, String> parameterOptions = new TreeMap<>();
|
private final Map<String, String> parameterOptions = new TreeMap<>();
|
||||||
|
|
||||||
|
@Deactivate
|
||||||
|
public void deactivate() {
|
||||||
|
listeners.clear();
|
||||||
|
parameterOptions.clear();
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public @Nullable ModuleType getModuleType(String UID, @Nullable Locale locale) {
|
public @Nullable ModuleType getModuleType(String UID, @Nullable Locale locale) {
|
||||||
if (ScriptActionHandler.TYPE_ID.equals(UID)) {
|
if (parameterOptions.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
} else if (ScriptActionHandler.TYPE_ID.equals(UID)) {
|
||||||
return getScriptActionType(locale);
|
return getScriptActionType(locale);
|
||||||
} else if (ScriptConditionHandler.TYPE_ID.equals(UID)) {
|
} else if (ScriptConditionHandler.TYPE_ID.equals(UID)) {
|
||||||
return getScriptConditionType(locale);
|
return getScriptConditionType(locale);
|
||||||
|
@ -73,26 +79,22 @@ public class ScriptModuleTypeProvider implements ModuleTypeProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable ModuleType getScriptActionType(@Nullable Locale locale) {
|
private ModuleType getScriptActionType(@Nullable Locale locale) {
|
||||||
if (parameterOptions.isEmpty()) {
|
List<Output> outputs = new ArrayList<>();
|
||||||
return null;
|
Output result = new Output("result", "java.lang.Object", "result", "the script result", null, null, null);
|
||||||
} else {
|
outputs.add(result);
|
||||||
List<Output> outputs = new ArrayList<>();
|
return new ActionType(ScriptActionHandler.TYPE_ID, getConfigDescriptions(locale), "execute a given script",
|
||||||
Output result = new Output("result", "java.lang.Object", "result", "the script result", null, null, null);
|
"Allows the execution of a user-defined script.", null, Visibility.VISIBLE, null, outputs);
|
||||||
outputs.add(result);
|
|
||||||
return new ActionType(ScriptActionHandler.TYPE_ID, getConfigDescriptions(locale), "execute a given script",
|
|
||||||
"Allows the execution of a user-defined script.", null, Visibility.VISIBLE, null, outputs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable ModuleType getScriptConditionType(@Nullable Locale locale) {
|
private ModuleType getScriptConditionType(@Nullable Locale locale) {
|
||||||
if (parameterOptions.isEmpty()) {
|
return new ConditionType(ScriptConditionHandler.TYPE_ID, getConfigDescriptions(locale),
|
||||||
return null;
|
"a given script evaluates to true", "Allows the definition of a condition through a script.", null,
|
||||||
} else {
|
Visibility.VISIBLE, null);
|
||||||
return new ConditionType(ScriptConditionHandler.TYPE_ID, getConfigDescriptions(locale),
|
}
|
||||||
"a given script evaluates to true", "Allows the definition of a condition through a script.", null,
|
|
||||||
Visibility.VISIBLE, null);
|
private List<ModuleType> getModuleTypesUnconditionally(@Nullable Locale locale) {
|
||||||
}
|
return List.of(getScriptActionType(locale), getScriptConditionType(locale));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -118,10 +120,7 @@ public class ScriptModuleTypeProvider implements ModuleTypeProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<ModuleType> getModuleTypes(@Nullable Locale locale) {
|
public Collection<ModuleType> getModuleTypes(@Nullable Locale locale) {
|
||||||
return Stream
|
return parameterOptions.isEmpty() ? List.of() : getModuleTypesUnconditionally(locale);
|
||||||
.of(Optional.ofNullable(getScriptActionType(locale)),
|
|
||||||
Optional.ofNullable(getScriptConditionType(locale)))
|
|
||||||
.filter(Optional::isPresent).map(Optional::get).collect(Collectors.toUnmodifiableList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -129,14 +128,16 @@ public class ScriptModuleTypeProvider implements ModuleTypeProvider {
|
||||||
return getModuleTypes(null);
|
return getModuleTypes(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void notifyModuleTypesAdded() {
|
||||||
public void addProviderChangeListener(ProviderChangeListener<ModuleType> listener) {
|
for (ModuleType moduleType : getModuleTypesUnconditionally(null)) {
|
||||||
// does nothing because this provider does not change
|
notifyListenersAboutAddedElement(moduleType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void notifyModuleTypesRemoved() {
|
||||||
public void removeProviderChangeListener(ProviderChangeListener<ModuleType> listener) {
|
for (ModuleType moduleType : getModuleTypesUnconditionally(null)) {
|
||||||
// does nothing because this provider does not change
|
notifyListenersAboutRemovedElement(moduleType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -149,8 +150,12 @@ public class ScriptModuleTypeProvider implements ModuleTypeProvider {
|
||||||
if (!scriptTypes.isEmpty()) {
|
if (!scriptTypes.isEmpty()) {
|
||||||
ScriptEngine scriptEngine = engineFactory.createScriptEngine(scriptTypes.get(0));
|
ScriptEngine scriptEngine = engineFactory.createScriptEngine(scriptTypes.get(0));
|
||||||
if (scriptEngine != null) {
|
if (scriptEngine != null) {
|
||||||
|
boolean notifyListeners = parameterOptions.isEmpty();
|
||||||
parameterOptions.put(getPreferredMimeType(engineFactory), getLanguageName(scriptEngine.getFactory()));
|
parameterOptions.put(getPreferredMimeType(engineFactory), getLanguageName(scriptEngine.getFactory()));
|
||||||
logger.trace("ParameterOptions: {}", parameterOptions);
|
logger.trace("ParameterOptions: {}", parameterOptions);
|
||||||
|
if (notifyListeners) {
|
||||||
|
notifyModuleTypesAdded();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.trace("setScriptEngineFactory: engine was null");
|
logger.trace("setScriptEngineFactory: engine was null");
|
||||||
}
|
}
|
||||||
|
@ -166,6 +171,9 @@ public class ScriptModuleTypeProvider implements ModuleTypeProvider {
|
||||||
if (scriptEngine != null) {
|
if (scriptEngine != null) {
|
||||||
parameterOptions.remove(getPreferredMimeType(engineFactory));
|
parameterOptions.remove(getPreferredMimeType(engineFactory));
|
||||||
logger.trace("ParameterOptions: {}", parameterOptions);
|
logger.trace("ParameterOptions: {}", parameterOptions);
|
||||||
|
if (parameterOptions.isEmpty()) {
|
||||||
|
notifyModuleTypesRemoved();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.trace("unsetScriptEngineFactory: engine was null");
|
logger.trace("unsetScriptEngineFactory: engine was null");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue