package serverP2P; import tools.Logger; import tools.LogLevel; import tools.HostItem; import java.util.Map; import java.util.HashMap; import java.io.IOException; import exception.RemoteException; import exception.LocalException; import protocolP2P.RatioRequest; import protocolP2P.RatioResponse; import protocolP2P.Payload; import protocolP2P.ProtocolP2PPacket; import remoteException.UnknownHost; import remoteException.NotATracker; import localException.InternalError; /** Class allowing to keep the tracker informed about ratios * @author Louis Royer * @author Flavien Haas * @author JS Auge * @version 1.0 */ public abstract class RatioWatcher implements Runnable { final static double punishmentFactor = 1.2; protected Logger logger; protected volatile boolean stop; protected long time; protected boolean force; protected HostItem tracker; protected Thread thread; protected Map cachePunishmentProbability = new HashMap<>(); protected boolean lock; /** Constructor * @param logger Logger * @param millis Time interval before recheck * @param tracker HostItem for the tracker */ public RatioWatcher(Logger logger, long millis, HostItem tracker) { assert logger != null : "Logger is null"; assert tracker != null : "Tracker is null"; this.logger = logger; time = millis; this.tracker = tracker; lock = false; } /** Runnable implementation */ public void run() { writeLog("Ratio watcher started : delay " + time + " milliseconds.", LogLevel.Info); while(!stop) { try { clean(); Thread.sleep(time); } catch(InterruptedException e) { writeLog("Ratio watcher interrupted", LogLevel.Info); setStop(); } } writeLog("Ratio watcher end of loop", LogLevel.Debug); } /** Invalidate the cache by cleaning all hashmaps * @throws InterruptedException */ protected synchronized void clean() throws InterruptedException{ while(lock) { this.wait(); } lock = true; cachePunishmentProbability.clear(); lock = false; this.notifyAll(); } /** Get Up-ratio for an applications * @param application HostItem of the application * @return Punishment Probability * @throws UnknownHost */ protected synchronized double getPunishmentProbability(HostItem application) throws InternalError, UnknownHost { try { while(lock) { this.wait(); } lock = true; if (!cachePunishmentProbability.containsKey(application)) { // update if not in cache try { ProtocolP2PPacket p = createProtocolP2PPacket(new RatioRequest(application)); p.sendRequest(getTrackerSocket()); Payload resp = p.receiveResponse().getPayload(); if (!(resp instanceof RatioResponse)) { throw new InternalError(); } RatioResponse rresp = (RatioResponse)resp; if (!rresp.getHostItem().equals(application)) { writeLog("Ratio response host is not the expected one. Expected : " + application + ". Received : " + rresp.getHostItem(), LogLevel.Debug); throw new InternalError(); } long up = rresp.getTotalUp(); long down = rresp.getTotalDown(); assert punishmentFactor > 1 : "The punishment factor must be greater than 1"; if (down == 0 || (punishmentFactor * up) >= down) { cachePunishmentProbability.put(application, Double.valueOf(0)); } else { cachePunishmentProbability.put(application, Double.valueOf((down - up)/(down * punishmentFactor))); } } catch (UnknownHost e) { throw e; } catch (IOException e) { throw new InternalError(); } catch (LocalException e) { writeLog(e, LogLevel.Error); throw new InternalError(); } catch (RemoteException e) { writeLog(e, LogLevel.Error); throw new InternalError(); } } double ret = cachePunishmentProbability.get(application); lock = false; this.notifyAll(); return ret; } catch (InterruptedException e) { throw new InternalError(); } } /** Ask the thread to stop */ public void setStop() { stop = true; if (thread != null) { thread.interrupt(); } } /** 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; } /** Create packets * @param payload Payload */ protected abstract < T extends Payload > ProtocolP2PPacket createProtocolP2PPacket(T payload); /** Tracker socket getter * @return tracker socket */ protected abstract Object getTrackerSocket(); /** Closes tracker socket */ protected abstract void closeTrackerSocket(); }