package com.kodcu.service; import com.kodcu.component.MyTab; import com.kodcu.controller.ApplicationController; import com.kodcu.other.IOHelper; import com.kodcu.service.ui.FileBrowseService; import com.kodcu.service.ui.TabService; import javafx.collections.ObservableList; import javafx.scene.control.Tab; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.nio.file.*; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import static java.nio.file.StandardWatchEventKinds.*; /** * Created by usta on 31.12.2014. */ @Component public class FileWatchService { private final Logger logger = LoggerFactory.getLogger(FileWatchService.class); private WatchService watcher = null; private final ApplicationController controller; private final ThreadService threadService; @Autowired private FileBrowseService fileBrowseService; @Autowired private ApplicationContext applicationContext; private Map<WatchKey, Path> watchKeys = new ConcurrentHashMap<>(); @Autowired public FileWatchService(ApplicationController controller, ThreadService threadService) { this.controller = controller; this.threadService = threadService; } @PostConstruct public void init() { threadService.runTaskLater(this::watchPathChanges); } public void reCreateWatchService() { if (Objects.nonNull(watcher)) { try { if (watchKeys.keySet().size() > 10) { unRegisterAllPath(); applicationContext.getBean(TabService.class) .applyForEachMyTab(myTab -> { registerPathWatcher(myTab.getPath()); }); } } catch (Exception e) { logger.warn(e.getMessage()); } } else { watcher = IOHelper.newWatchService(); } } public void unRegisterAllPath() { for (Map.Entry<WatchKey, Path> entry : watchKeys.entrySet()) { WatchKey watchKey = entry.getKey(); watchKey.cancel(); Path path = entry.getValue(); logger.info("Watch service cancelled watching {}", path); } watchKeys.clear(); } private void watchPathChanges() { if (Objects.isNull(watcher)) { reCreateWatchService(); } while (true) { if (Objects.isNull(watcher)) { break; } WatchKey watchKey = null; Path path = null; try { watchKey = watcher.take(); path = watchKeys.get(watchKey); } catch (ClosedWatchServiceException cws) { if (Objects.nonNull(path)) { logger.info("Watch service closed for: {}", path); } } catch (Exception ex) { logger.warn(ex.getMessage()); continue; } List<WatchEvent<?>> watchEvents = watchKey.pollEvents(); boolean updateFsView = false; for (WatchEvent<?> event : watchEvents) { WatchEvent.Kind<?> kind = event.kind(); if (kind == ENTRY_MODIFY && event.count() == 1) { WatchEvent<Path> ev = (WatchEvent<Path>) event; Path modifiedPath = path.resolve(ev.context()); ObservableList<Tab> tabs = controller.getTabPane().getTabs(); for (Tab tab : tabs) { if (tab instanceof MyTab) { MyTab myTab = (MyTab) tab; if (modifiedPath.equals(myTab.getPath())) { threadService.runActionLater(() -> { myTab.reload(); }); break; } } } watchKey.reset(); } else if (kind == ENTRY_MODIFY && event.count() > 1) { watchKey.reset(); } else { updateFsView = true; watchKey.reset(); } } if (updateFsView) { Path changedPath = null; if (watchEvents.size() == 1) { WatchEvent<Path> ev = (WatchEvent<Path>) watchEvents.get(0); changedPath = path.resolve(ev.context()); } fileBrowseService.refreshPathToTree(path,changedPath); } } } public void registerPathWatcher(final Path path) { threadService.runTaskLater(() -> { if (Objects.isNull(path)) { return; } Path finalPath = null; if (!Files.isDirectory(path)) { finalPath = path.getParent(); } else { finalPath = path; } try { boolean isRegistered = isRegisteredPath(finalPath, watchKeys); if (!isRegistered) { WatchKey watchKey = finalPath.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); watchKeys.put(watchKey, finalPath); } } catch (Exception e) { logger.warn("Couldn't register watcher for: {}", finalPath); } }); } public boolean isRegisteredPath(Path finalPath, Map<WatchKey, Path> watchKeys) { boolean exist = false; for (Map.Entry<WatchKey, Path> entry : watchKeys.entrySet()) { WatchKey key = entry.getKey(); Path value = entry.getValue(); if (finalPath.equals(value)) { if (key.isValid()) { exist = true; break; } } } return exist; } public void unRegisterPath(Path path) { try { for (Map.Entry<WatchKey, Path> entry : watchKeys.entrySet()) { Path registeredPath = entry.getValue(); if (path.equals(registeredPath)) { WatchKey watchKey = entry.getKey(); watchKey.cancel(); watchKeys.remove(watchKey); break; } } } catch (Exception ex) { } } }