/* * Copyright (C) 2014 Shashank Tulsyan * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package neembuu.release1.app; import java.io.IOException; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import static java.nio.file.StandardWatchEventKinds.*; import java.nio.file.WatchEvent; import java.nio.file.WatchKey; import java.nio.file.WatchService; import java.nio.file.attribute.BasicFileAttributeView; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import neembuu.release1.api.log.LoggerUtil; import neembuu.util.Throwables; /** * * @author Shashank Tulsyan */ public class DirectoryWatcherServiceImpl implements DirectoryWatcherService { private static final Logger logger = LoggerUtil.getLogger(DirectoryWatcherServiceImpl.class.getName()); private final MainCommandsListener mcl; private final Path commandsDir; private volatile Thread thread = null; public DirectoryWatcherServiceImpl(MainCommandsListener mcl) { this.mcl = mcl; commandsDir = Application.getResource("commands"); } @Override public void startService() { Throwables.start(new Runnable(){ @Override public void run() { startServiceImpl(); } },DirectoryWatcherServiceImpl.class.toString()); } @Override public void stopService(){ Thread localCopy = thread; thread = null; if(localCopy!=null){ try{ localCopy.interrupt(); }catch(Exception a){ //ignore } } } private void startServiceImpl() { if (!ensureDirectoryExists(commandsDir)) { return; } try (WatchService watcher = commandsDir.getFileSystem().newWatchService()) { commandsDir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); while(thread == Thread.currentThread()) { try{ WatchKey watckKey = null; try{ watckKey = watcher.take(); }catch(InterruptedException ie){ continue; } List<WatchEvent<?>> events = watckKey.pollEvents(); for (WatchEvent event : events) { logger.log(Level.INFO, "{0}: {1}", new Object[]{event.kind(), event.context().toString()}); if(event.kind()==ENTRY_MODIFY){ handle(watcher, true); } } }catch(Exception a){ logger.log(Level.INFO, "WatchService loop error", a); } } } catch (IOException ioe) { logger.log(Level.INFO, "WatchService died", ioe); } } private boolean ensureDirectoryExists(Path pth) { if (Files.isDirectory(pth)) { return true; } try { Files.createDirectories(pth); return true; } catch (IOException ex) { return false; } } @Override public void forceRescan(long time) { logger.info("An instance of neembuu was started, something must have happened.\n" + "Checking the commands directory."); Throwables.start(new Runnable(){ @Override public void run() { rescanDirectory(); } },null,true); } private void handle(Object pathObj,boolean isRelative){ logger.log(Level.FINE, "handling,{0}", pathObj); if(!(pathObj instanceof Path)){return;} Path path = (Path)pathObj; if(isRelative){ path = commandsDir.resolve(path); }else { path = path.toAbsolutePath(); } if(!Files.exists(path))return; if(!Files.isRegularFile(path))return; if(!Files.isReadable(path))return; long creationTime = getCreationTime(path); if(isTooOld(creationTime)){ try{Files.delete(path);}catch(IOException ioe){ioe.printStackTrace();} return; } String extesion = path.getFileName().toString(); try{ extesion = extesion.substring(extesion.lastIndexOf('.')+1); }catch(Exception a){ extesion = ""; } boolean res = mcl.handleFile(path,extesion,creationTime); if(!res){ logger.log(Level.FINE, "Could not handle file = {0}", path); } } private void rescanDirectory() { try (DirectoryStream<Path> ds = Files.newDirectoryStream(commandsDir)){ for(Path p : ds){ handle(p, false); } } catch (IOException ex) { ex.printStackTrace(); logger.log(Level.SEVERE,"could not scan directory",ex); } } private long getCreationTime(Path f){ String nm = f.getFileName().toString(); try{ long t = Long.parseLong(nm); return t; }catch(Exception a){ } try{ BasicFileAttributeView view = Files.getFileAttributeView(f, BasicFileAttributeView.class); return view.readAttributes().creationTime().toMillis(); }catch(IOException ioe){ } return System.currentTimeMillis(); } private boolean isTooOld(long t){ long maxGapAllowed = 15*60*1000; // 15mins if(System.currentTimeMillis() - t > maxGapAllowed){ return true; }return false; } }