[automation] implement a listener for ScriptEngineFactory changes (#2459)
* implement a listener for ScriptEngineFactory changes Signed-off-by: Jan N. Klug <jan.n.klug@rub.de>pull/2462/head
parent
d11a72272e
commit
b02dfdc067
|
@ -24,10 +24,10 @@ import java.nio.charset.StandardCharsets;
|
|||
import java.nio.file.Path;
|
||||
import java.nio.file.WatchEvent;
|
||||
import java.nio.file.WatchEvent.Kind;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -62,8 +62,8 @@ import org.slf4j.LoggerFactory;
|
|||
* @author Jonathan Gilbert - added dependency tracking & per-script start levels
|
||||
*/
|
||||
@Component(immediate = true)
|
||||
public class ScriptFileWatcher extends AbstractWatchService
|
||||
implements ReadyService.ReadyTracker, DependencyTracker.DependencyChangeListener {
|
||||
public class ScriptFileWatcher extends AbstractWatchService implements ReadyService.ReadyTracker,
|
||||
DependencyTracker.DependencyChangeListener, ScriptEngineManager.FactoryChangeListener {
|
||||
|
||||
private static final String FILE_DIRECTORY = "automation" + File.separator + "jsr223";
|
||||
private static final long RECHECK_INTERVAL = 20;
|
||||
|
@ -75,10 +75,10 @@ public class ScriptFileWatcher extends AbstractWatchService
|
|||
private final ReadyService readyService;
|
||||
|
||||
private @Nullable ScheduledExecutorService scheduler;
|
||||
private Supplier<ScheduledExecutorService> executerFactory;
|
||||
private Supplier<ScheduledExecutorService> executorFactory;
|
||||
|
||||
private final Set<ScriptFileReference> pending = new HashSet<>();
|
||||
private final Set<ScriptFileReference> loaded = new HashSet<>();
|
||||
private final Set<ScriptFileReference> pending = ConcurrentHashMap.newKeySet();
|
||||
private final Set<ScriptFileReference> loaded = ConcurrentHashMap.newKeySet();
|
||||
|
||||
private volatile int currentStartLevel = 0;
|
||||
|
||||
|
@ -89,15 +89,17 @@ public class ScriptFileWatcher extends AbstractWatchService
|
|||
this.manager = manager;
|
||||
this.dependencyTracker = dependencyTracker;
|
||||
this.readyService = readyService;
|
||||
this.executerFactory = () -> Executors
|
||||
this.executorFactory = () -> Executors
|
||||
.newSingleThreadScheduledExecutor(new NamedThreadFactory("scriptwatcher"));
|
||||
|
||||
manager.addFactoryChangeListener(this);
|
||||
readyService.registerTracker(this, new ReadyMarkerFilter().withType(StartLevelService.STARTLEVEL_MARKER_TYPE));
|
||||
}
|
||||
|
||||
@Deactivate
|
||||
@Override
|
||||
public void deactivate() {
|
||||
manager.removeFactoryChangeListener(this);
|
||||
readyService.unregisterTracker(this);
|
||||
|
||||
ScheduledExecutorService localScheduler = scheduler;
|
||||
|
@ -112,10 +114,10 @@ public class ScriptFileWatcher extends AbstractWatchService
|
|||
/**
|
||||
* Override the executor service. Can be used for testing.
|
||||
*
|
||||
* @param executerFactory supplier of ScheduledExecutorService
|
||||
* @param executorFactory supplier of ScheduledExecutorService
|
||||
*/
|
||||
void setExecuterFactory(Supplier<ScheduledExecutorService> executerFactory) {
|
||||
this.executerFactory = executerFactory;
|
||||
void setExecutorFactory(Supplier<ScheduledExecutorService> executorFactory) {
|
||||
this.executorFactory = executorFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -261,7 +263,7 @@ public class ScriptFileWatcher extends AbstractWatchService
|
|||
|
||||
if (previousLevel < StartLevelService.STARTLEVEL_MODEL) { // not yet started
|
||||
if (newLevel >= StartLevelService.STARTLEVEL_MODEL) { // start
|
||||
ScheduledExecutorService localScheduler = executerFactory.get();
|
||||
ScheduledExecutorService localScheduler = executorFactory.get();
|
||||
scheduler = localScheduler;
|
||||
localScheduler.submit(() -> importResources(new File(pathToWatch)));
|
||||
localScheduler.scheduleWithFixedDelay(() -> checkFiles(currentStartLevel), 0, RECHECK_INTERVAL,
|
||||
|
@ -309,4 +311,16 @@ public class ScriptFileWatcher extends AbstractWatchService
|
|||
onStartLevelChanged(newLevel);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void factoryAdded(@Nullable String scriptType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void factoryRemoved(@Nullable String scriptType) {
|
||||
if (scriptType == null) {
|
||||
return;
|
||||
}
|
||||
loaded.stream().filter(ref -> scriptType.equals(ref.getScriptType().get())).forEach(this::importFileWhenReady);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -212,7 +212,7 @@ class ScriptFileWatcherTest {
|
|||
ScheduledExecutorService scheduledExecutorService = spy(
|
||||
new DelegatingScheduledExecutorService(Executors.newSingleThreadScheduledExecutor()));
|
||||
ArgumentCaptor<Runnable> scheduledTask = ArgumentCaptor.forClass(Runnable.class);
|
||||
scriptFileWatcher.setExecuterFactory(() -> scheduledExecutorService);
|
||||
scriptFileWatcher.setExecutorFactory(() -> scheduledExecutorService);
|
||||
|
||||
when(scriptEngineManager.isSupported("js")).thenReturn(false);
|
||||
ScriptEngineContainer scriptEngineContainer = mock(ScriptEngineContainer.class);
|
||||
|
|
|
@ -69,4 +69,35 @@ public interface ScriptEngineManager {
|
|||
* @return true, if supported, else false
|
||||
*/
|
||||
boolean isSupported(String scriptType);
|
||||
|
||||
/**
|
||||
* Add a listener that is notified when a ScriptEngineFactory is added or removed
|
||||
*
|
||||
* @param listener an object that implements {@link FactoryChangeListener}
|
||||
*/
|
||||
void addFactoryChangeListener(FactoryChangeListener listener);
|
||||
|
||||
/**
|
||||
* Remove a listener that is notified when a ScriptEngineFactory is added or removed
|
||||
*
|
||||
* @param listener an object that implements {@link FactoryChangeListener}
|
||||
*/
|
||||
void removeFactoryChangeListener(FactoryChangeListener listener);
|
||||
|
||||
interface FactoryChangeListener {
|
||||
|
||||
/**
|
||||
* Called by the {@link ScriptEngineManager} when a ScriptEngineFactory is added
|
||||
*
|
||||
* @param scriptType the script type supported by the newly added factory
|
||||
*/
|
||||
void factoryAdded(String scriptType);
|
||||
|
||||
/**
|
||||
* Called by the {@link ScriptEngineManager} when a ScriptEngineFactory is removed
|
||||
*
|
||||
* @param scriptType the script type supported by the removed factory
|
||||
*/
|
||||
void factoryRemoved(String scriptType);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,8 +16,10 @@ import static org.openhab.core.automation.module.script.ScriptEngineFactory.*;
|
|||
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.script.Invocable;
|
||||
import javax.script.ScriptContext;
|
||||
|
@ -54,6 +56,7 @@ public class ScriptEngineManagerImpl implements ScriptEngineManager {
|
|||
private final Map<String, ScriptEngineFactory> customSupport = new HashMap<>();
|
||||
private final Map<String, ScriptEngineFactory> genericSupport = new HashMap<>();
|
||||
private final ScriptExtensionManager scriptExtensionManager;
|
||||
private final Set<FactoryChangeListener> listeners = new HashSet<>();
|
||||
|
||||
@Activate
|
||||
public ScriptEngineManagerImpl(final @Reference ScriptExtensionManager scriptExtensionManager) {
|
||||
|
@ -70,6 +73,7 @@ public class ScriptEngineManagerImpl implements ScriptEngineManager {
|
|||
} else {
|
||||
this.genericSupport.put(scriptType, engineFactory);
|
||||
}
|
||||
listeners.forEach(listener -> listener.factoryAdded(scriptType));
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
if (!scriptTypes.isEmpty()) {
|
||||
|
@ -99,6 +103,7 @@ public class ScriptEngineManagerImpl implements ScriptEngineManager {
|
|||
} else {
|
||||
this.genericSupport.remove(scriptType, engineFactory);
|
||||
}
|
||||
listeners.forEach(listener -> listener.factoryRemoved(scriptType));
|
||||
}
|
||||
logger.debug("Removed {}", engineFactory.getClass().getSimpleName());
|
||||
}
|
||||
|
@ -248,4 +253,14 @@ public class ScriptEngineManagerImpl implements ScriptEngineManager {
|
|||
|
||||
scriptContext.setAttribute(name, value, ScriptContext.ENGINE_SCOPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFactoryChangeListener(FactoryChangeListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFactoryChangeListener(FactoryChangeListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue