diff --git a/bundles/org.openhab.core.automation.module.script/src/main/java/org/openhab/core/automation/module/script/internal/provider/ScriptModuleTypeProvider.java b/bundles/org.openhab.core.automation.module.script/src/main/java/org/openhab/core/automation/module/script/internal/provider/ScriptModuleTypeProvider.java index eabf9b442f2..c7c09b856ca 100644 --- a/bundles/org.openhab.core.automation.module.script/src/main/java/org/openhab/core/automation/module/script/internal/provider/ScriptModuleTypeProvider.java +++ b/bundles/org.openhab.core.automation.module.script/src/main/java/org/openhab/core/automation/module/script/internal/provider/ScriptModuleTypeProvider.java @@ -14,13 +14,11 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Optional; import java.util.TreeMap; -import java.util.stream.Collectors; -import java.util.stream.Stream; import javax.script.ScriptEngine; @@ -42,6 +40,7 @@ import org.openhab.core.config.core.ConfigDescriptionParameterBuilder; import org.openhab.core.config.core.ParameterOption; 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.ReferenceCardinality; import org.osgi.service.component.annotations.ReferencePolicy; @@ -59,12 +58,20 @@ public class ScriptModuleTypeProvider implements ModuleTypeProvider { private final Logger logger = LoggerFactory.getLogger(ScriptModuleTypeProvider.class); + private final List> listeners = new LinkedList<>(); private final Map parameterOptions = new TreeMap<>(); + @Deactivate + public void deactivate() { + listeners.clear(); + } + @SuppressWarnings("unchecked") @Override 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); } else if (ScriptConditionHandler.TYPE_ID.equals(UID)) { return getScriptConditionType(locale); @@ -73,26 +80,22 @@ public class ScriptModuleTypeProvider implements ModuleTypeProvider { } } - private @Nullable ModuleType getScriptActionType(@Nullable Locale locale) { - if (parameterOptions.isEmpty()) { - return null; - } else { - List outputs = new ArrayList<>(); - Output result = new Output("result", "java.lang.Object", "result", "the script result", null, null, null); - 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 ModuleType getScriptActionType(@Nullable Locale locale) { + List outputs = new ArrayList<>(); + Output result = new Output("result", "java.lang.Object", "result", "the script result", null, null, null); + 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) { - if (parameterOptions.isEmpty()) { - return null; - } else { - 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 ModuleType getScriptConditionType(@Nullable Locale locale) { + 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 getModuleTypesUnconditionally(@Nullable Locale locale) { + return List.of(getScriptActionType(locale), getScriptConditionType(locale)); } /** @@ -118,10 +121,7 @@ private List getConfigDescriptions(@Nullable Locale @Override public Collection getModuleTypes(@Nullable Locale locale) { - return Stream - .of(Optional.ofNullable(getScriptActionType(locale)), - Optional.ofNullable(getScriptConditionType(locale))) - .filter(Optional::isPresent).map(Optional::get).collect(Collectors.toUnmodifiableList()); + return parameterOptions.isEmpty() ? List.of() : getModuleTypesUnconditionally(locale); } @Override @@ -131,12 +131,40 @@ public Collection getAll() { @Override public void addProviderChangeListener(ProviderChangeListener listener) { - // does nothing because this provider does not change + synchronized (listeners) { + listeners.add(listener); + } } @Override public void removeProviderChangeListener(ProviderChangeListener listener) { - // does nothing because this provider does not change + synchronized (listeners) { + listeners.remove(listener); + } + } + + private void notifyModuleTypesAdded() { + List> snapshot = null; + synchronized (listeners) { + snapshot = new LinkedList<>(listeners); + } + for (ModuleType moduleType : getModuleTypesUnconditionally(null)) { + for (ProviderChangeListener listener : snapshot) { + listener.added(this, moduleType); + } + } + } + + private void notifyModuleTypesRemoved() { + List> snapshot = null; + synchronized (listeners) { + snapshot = new LinkedList<>(listeners); + } + for (ModuleType moduleType : getModuleTypesUnconditionally(null)) { + for (ProviderChangeListener listener : snapshot) { + listener.removed(this, moduleType); + } + } } /** @@ -149,8 +177,12 @@ public void setScriptEngineFactory(ScriptEngineFactory engineFactory) { if (!scriptTypes.isEmpty()) { ScriptEngine scriptEngine = engineFactory.createScriptEngine(scriptTypes.get(0)); if (scriptEngine != null) { + boolean notifyListeners = parameterOptions.isEmpty(); parameterOptions.put(getPreferredMimeType(engineFactory), getLanguageName(scriptEngine.getFactory())); logger.trace("ParameterOptions: {}", parameterOptions); + if (notifyListeners) { + notifyModuleTypesAdded(); + } } else { logger.trace("setScriptEngineFactory: engine was null"); } @@ -166,6 +198,9 @@ public void unsetScriptEngineFactory(ScriptEngineFactory engineFactory) { if (scriptEngine != null) { parameterOptions.remove(getPreferredMimeType(engineFactory)); logger.trace("ParameterOptions: {}", parameterOptions); + if (parameterOptions.isEmpty()) { + notifyModuleTypesRemoved(); + } } else { logger.trace("unsetScriptEngineFactory: engine was null"); }