2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.automation.jrubyscripting.internal.watch;
15 import java.nio.file.Path;
16 import java.util.ArrayList;
17 import java.util.HashSet;
18 import java.util.List;
20 import java.util.concurrent.ConcurrentHashMap;
21 import java.util.function.Consumer;
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.openhab.automation.jrubyscripting.internal.JRubyScriptEngineFactory;
25 import org.openhab.core.automation.module.script.ScriptDependencyTracker;
26 import org.openhab.core.service.WatchService;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
31 * Tracks Ruby dependencies
33 * @author Cody Cutrer - Initial contribution
34 * @author Jan N. Klug - Refactored to new WatchService
37 public class JRubyDependencyTracker implements ScriptDependencyTracker {
38 private final Logger logger = LoggerFactory.getLogger(JRubyDependencyTracker.class);
40 private final Set<ScriptDependencyTracker.Listener> dependencyChangeListeners = ConcurrentHashMap.newKeySet();
42 private final BidiSetBag<String, String> scriptToLibs = new BidiSetBag<>();
44 private final JRubyScriptEngineFactory scriptEngineFactory;
45 private final List<JRubyWatchService> dependencyWatchServices = new ArrayList<>();
46 private final WatchService watchService;
48 public JRubyDependencyTracker(final WatchService watchService, final JRubyScriptEngineFactory scriptEngineFactory) {
49 this.watchService = watchService;
50 this.scriptEngineFactory = scriptEngineFactory;
53 public void activate() {
54 String gemHome = scriptEngineFactory.getGemHome();
55 if (!gemHome.isEmpty()) {
56 dependencyWatchServices.add(new JRubyGemWatchService(watchService, gemHome, this));
58 List<Path> libPaths = scriptEngineFactory.getRubyLibPaths().stream().map(Path::of).toList();
59 dependencyWatchServices.add(new JRubyLibWatchService(watchService, libPaths, this));
61 dependencyWatchServices.forEach(JRubyWatchService::activate);
64 public void deactivate() {
65 dependencyWatchServices.forEach(JRubyWatchService::deactivate);
66 dependencyWatchServices.clear();
69 void dependencyChanged(String dependency) {
70 Set<String> scripts = new HashSet<>(scriptToLibs.getKeys(dependency)); // take a copy as it will change as we
71 logger.debug("{} changed; reimporting {} scripts...", dependency, scripts.size());
72 for (String scriptUrl : scripts) {
73 for (ScriptDependencyTracker.Listener listener : dependencyChangeListeners) {
75 listener.onDependencyChange(scriptUrl);
76 } catch (Exception e) {
77 logger.warn("Failed to notify tracker of dependency change: {}: {}", e.getClass(), e.getMessage());
84 public Consumer<String> getTracker(String scriptId) {
85 return dependencyPath -> startTracking(scriptId, dependencyPath);
89 public void removeTracking(String scriptId) {
90 scriptToLibs.removeKey(scriptId);
93 protected void startTracking(String scriptId, String libPath) {
94 scriptToLibs.put(scriptId, libPath);
97 public void addChangeTracker(ScriptDependencyTracker.Listener listener) {
98 logger.trace("adding change tracker listener {}", listener);
99 dependencyChangeListeners.add(listener);
102 public void removeChangeTracker(ScriptDependencyTracker.Listener listener) {
103 logger.trace("removing change tracker listener {}", listener);
104 dependencyChangeListeners.remove(listener);