package tracker; import tools.ServeErrors; import tools.HostItem; import tools.Logger; import tools.LogLevel; import java.util.Map; import java.util.HashMap; import java.util.ArrayList; import java.util.List; import protocolP2P.ProtocolP2PPacket; import protocolP2P.Payload; import protocolP2P.DiscoverRequest; import protocolP2P.DiscoverResponse; import protocolP2P.FileList; import protocolP2P.Unregister; import protocolP2P.Register; import protocolP2P.RequestResponseCode; import localException.InternalError; import remoteException.EmptyDirectory; import exception.LocalException; /** Tracker management implementation * @author Louis Royer * @author Flavien Haas * @author JS Auge * @version 1.0 */ public abstract class TrackerManagement extends ServeErrors implements Runnable { protected HostItem tracker; protected Logger logger; protected List<HostItem> hostList = new ArrayList<>(); protected Map<String, List<HostItem>> fileList = new HashMap<>(); protected volatile boolean stop; /** Constructor * @param tracker Tracker HostItem * @param logger Logger */ public TrackerManagement(HostItem tracker, Logger logger) { stop = false; this.tracker = tracker; this.logger = logger; } /** Handle Discover request * @param pd Received request * @throws InternalError */ protected < T extends ProtocolP2PPacket<?> > void handleDiscover(T pd) throws InternalError { Payload p = pd.getPayload(); assert p instanceof DiscoverRequest : "payload must be an instance of DiscoverRequest"; if (!(p instanceof DiscoverRequest)) { sendInternalError(pd); } else { String filename = ((DiscoverRequest)p).getFilename(); try { pd.sendResponse(createProtocolP2PPacket(new DiscoverResponse(filename, fileList.getOrDefault(filename, hostList)))); } catch (Exception e) { writeLog(e, LogLevel.Error); } } } /** Handle List Responses * @param pd Received response * @throws InternalError */ protected <T extends ProtocolP2PPacket<?> > void handleListResponse(T pd, HostItem host) throws InternalError { Payload p = pd.getPayload(); assert p instanceof FileList: "payload must be an instance of FileList"; if (!(p instanceof FileList)) { throw new InternalError(); } else { String[] f = ((FileList)p).getFileList(); for (String file: f) { List<HostItem> h = fileList.get(file); if (h != null) { if (!h.contains(host)) { h.add(host); } } else { List<HostItem> emptyH = new ArrayList<>(); emptyH.add(host); fileList.put(file, emptyH); } } } } /** Handle Unregistering * @param pd Request received * @throws InternalError */ protected < T extends ProtocolP2PPacket<?> > void handleUnregister(T pd) throws InternalError { Payload p = pd.getPayload(); assert p instanceof Unregister : "payload must be an instance of Unregister"; if (!(p instanceof Unregister)) { sendInternalError(pd); throw new InternalError(); } HostItem host = ((Unregister)p).getHostItem(); writeLog("Received UNREGISTER from host " + pd.getHostItem() + ". Removing host " + host, LogLevel.Action); hostList.remove(host); for(String f: fileList.keySet()) { fileList.get(f).remove(host); if(fileList.get(f).isEmpty()) { fileList.remove(f); } } } /** Getter for HostItem socket * @param hostItem HostItem */ protected abstract Object getHostItemSocket(HostItem hostItem); /** Close HostItem socket * @param hostItem HostItem */ protected abstract void closeHostItemSocket(HostItem hostItem); /** Handle Registering * @param pd Received request * @throws InternalError */ protected < T extends ProtocolP2PPacket<?> > void handleRegister(T pd) throws InternalError { Payload p = pd.getPayload(); assert p instanceof Register : "payload must be an instance of Register"; if (!(p instanceof Register)) { throw new InternalError(); } // add host to known host list HostItem host = ((Register)p).getHostItem(); if (!hostList.contains(host)) { hostList.add(host); } // send a list request try { ProtocolP2PPacket<?> pLReq = createProtocolP2PPacket(new Payload(RequestResponseCode.LIST_REQUEST)); pLReq.sendRequest(getHostItemSocket(host)); writeLog("Received REGISTER from host " + pd.getHostItem() + ". Adding host " + host + " to list. Sending List request", LogLevel.Action); handleListResponse(pLReq.receiveResponse(), host); writeLog("Received LIST RESPONSE from host " + pd.getHostItem(), LogLevel.Action); closeHostItemSocket(host); } catch (EmptyDirectory e) { writeLog("Empty Directory", LogLevel.Debug); hostList.remove(host); writeLog("Received EMPTY DIRECTORY from host " + pd.getHostItem() + ". Aborting.", LogLevel.Action); } catch (Exception e) { // remove from list because list request could not be send hostList.remove(host); writeLog("Aborting the add of host " + host, LogLevel.Action); writeLog(e, LogLevel.Error); } } /** Handle requests * @throws LocalException */ protected <T extends ProtocolP2PPacket<?> > void handleRequest(T pd) throws LocalException { Payload p = pd.getPayload(); switch (p.getRequestResponseCode()) { case LOAD_REQUEST: writeLog("Received LOAD_REQUEST from host " + pd.getHostItem() + ", sending NOT_FOUND", LogLevel.Action); sendNotFound(pd); break; case LIST_REQUEST: writeLog("Received LIST_REQUEST from host " + pd.getHostItem() + ", sending EMPTY_DIRECTORY", LogLevel.Action); sendEmptyDirectory(pd); break; case HASH_REQUEST: writeLog("Received HASH_REQUEST from host " + pd.getHostItem() + ", sending NOT_FOUND", LogLevel.Action); sendNotFound(pd); break; case REGISTER: writeLog("Received REGISTER from host " + pd.getHostItem(), LogLevel.Debug); handleRegister(pd); break; case UNREGISTER: writeLog("Received UNREGISTER from host " + pd.getHostItem(), LogLevel.Debug); handleUnregister(pd); break; case DISCOVER_REQUEST: writeLog("Received DISCOVER REQUEST from host " + pd.getHostItem(), LogLevel.Action); handleDiscover(pd); break; default: writeLog("Received grabbage from host " + pd.getHostItem(), LogLevel.Action); sendInternalError(pd); break; } } /** Stop the thread */ public void setStop() { stop = true; } }