package serverP2P; import tools.Logger; import tools.LogLevel; import tools.HostItem; import java.io.File; import java.util.Vector; import java.util.Arrays; import java.util.Map; import java.util.HashMap; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import protocolP2P.HashAlgorithm; import java.nio.file.Files; import java.nio.file.Paths; import java.io.IOException; /** Class allowing to keep the tracker informed about file list * @author Louis Royer * @author Flavien Haas * @author JS Auge * @version 1.0 */ public abstract class FileWatcher implements Runnable { protected String[] fileList = new String[0]; protected Logger logger; protected volatile boolean stop; protected long time; protected boolean force; protected HostItem server; protected HostItem tracker; protected String baseDirectory; protected Map sha512 = new HashMap<>(); protected Thread thread; /** Constructor * @param logger Logger * @param millis Time interval before recheck * @param server HostItem for the server * @param tracker HostItem for the tracker * @param baseDirectory Directory to search files */ public FileWatcher(Logger logger, long millis, HostItem server, HostItem tracker, String baseDirectory) { assert logger != null : "Logger is null"; assert server != null : "Server is null"; assert tracker != null : "Tracker is null"; assert baseDirectory != null : "baseDirectory is null"; this.logger = logger; time = millis; this.server = server; this.tracker = tracker; this.baseDirectory = baseDirectory; force = true; } /** FileList getter * @return fileList */ public String[] getFileList() { return fileList; } /** Sha512 map getter * @return sha512 hashmap */ public Map getSha512Map() { return sha512; } /** Allow a manual check */ public void trigger() { if (updateFileList() || force) { force = false; writeLog("File list watcher detected changes. Informing tracker.", LogLevel.Info); registerTracker(); } } /** Runnable implementation */ public void run() { writeLog("File list watcher started : delay " + time + " milliseconds.", LogLevel.Info); while(!stop) { trigger(); try { Thread.sleep(time); } catch(InterruptedException e) { writeLog("File list watcher interrupted", LogLevel.Info); setStop(); } } writeLog("File watcher end of loop", LogLevel.Debug); } /** Register server on tracker */ protected abstract void registerTracker(); /** Update fileList and returns true if different than old list. * @return true if changed */ protected boolean updateFileList() { File folder = new File(baseDirectory); Vector v = new Vector(); File[] files = folder.listFiles(); /* Add non-recursively files's names to fileList */ for (File f : files) { if (f.isFile()) { v.add(f.getName()); } } String[] newFileList = new String[v.size()]; v.toArray(newFileList); Arrays.sort(newFileList); if (!Arrays.equals(newFileList, fileList)) { fileList = newFileList; initSha512(); return true; } else { return false; } } /** Ask the thread to stop */ public void setStop() { stop = true; if (thread != null) { thread.interrupt(); } } /** Init sha512 map. */ protected void initSha512() { for(String f: fileList) { try { MessageDigest md = MessageDigest.getInstance(HashAlgorithm.SHA512.getName()); sha512.put(f, md.digest(Files.readAllBytes(Paths.get(baseDirectory + f)))); md.reset(); } catch (NoSuchAlgorithmException e) { writeLog("sha512 not supported", LogLevel.Error); } catch (IOException e) { writeLog("cannot read " + f, LogLevel.Warning); } } } /** Implementation of writeLog * @param text Text to log * @param logLevel level of logging */ protected abstract void writeLog(String text, LogLevel logLevel); /** Implementation of writeLog * @param e exception to log * @param logLevel level of logging */ protected abstract void writeLog(Exception e, LogLevel logLevel); /** Set thread * @param thread Thread */ public void setThread(Thread thread) { this.thread = thread; } }