package geniusweb.runserver; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.net.URISyntaxException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.logging.Level; import geniusweb.events.ProtocolEvent; import geniusweb.protocol.CurrentNegoState; import geniusweb.protocol.NegoProtocol; import geniusweb.protocol.NegoSettings; import geniusweb.protocol.NegoState; import tudelft.utilities.logging.Reporter; import tudelft.utilities.repository.RepoElement; /** * Contains a currently running {@link NegoProtocol}. Listens to protocol * events. Kept so that we can keep track of the amount of running sessions and * show progress states. */ public class RunningNego implements RepoElement { private static final String LOGDIRNAME = "log"; private static final Path logdir = getLogDir(); private static long negoNr = System.currentTimeMillis(); // generate unique IDs. private final String sessionid; private final transient Reporter log; private final transient NegoProtocol protocol; private final transient RunningNegotiationsRepo repo; /** * Create new session wth unique ID. You should call {@link #start()} to * actually start this. * * @param settings the settings to use for this session * @param repo the {@link RunningNegotiationsRepo} to use (mainly for * testing) * @param logger the {@link Reporter} to be used. Usually "Protocol" or * "runserver". The logger is used both for logging protocol * events and for logging events from this RunningNego */ public RunningNego(NegoSettings settings, RunningNegotiationsRepo repo, Reporter logger) { this.log = logger; this.protocol = settings.getProtocol(logger); this.sessionid = "" + protocol.getRef().getURI() + (negoNr++); this.repo = repo; } public void start() { log.log(Level.INFO, "new negotiation session. logging to " + logdir); repo.put(this); protocol.addListener(evt -> handle(evt)); protocol.start(new PartyConnectionFactory(log)); } private void handle(ProtocolEvent evt) { if (evt instanceof CurrentNegoState) { NegoState state = ((CurrentNegoState) evt).getState(); writeLogFile(state); if (state.isFinal(System.currentTimeMillis())) { repo.remove(sessionid); } } } /** * Write the (final) state to the log file. * * @param sessionState * @throws IOException */ protected void writeLogFile(NegoState sessionState) { try { PrintWriter out = new PrintWriter( logdir.resolve(sessionid + ".json").toFile()); out.print(Jackson.instance().writeValueAsString(sessionState)); out.close(); } catch (Throwable e) { // also catch outOfMem etc. log.log(Level.SEVERE, "Failed to write log file for " + sessionid, e); } } /** * Search from location of this class upwards till we find a directory * called "domainsrepo". * * @return the root dir of the repo. This is the 'database' where all known * profiles are stored. If not found , returns log dir in * workingdirectory * @throws URISyntaxException */ protected static Path getLogDir() { // If you run this normal from tomcat we are somewhere inside // projectroot/WEB_INF/classes/.... // Search back upwards to projectroot. Path dir; try { dir = Paths.get(RunningNego.class.getProtectionDomain() .getCodeSource().getLocation().toURI()).getParent(); } catch (URISyntaxException e) { throw new RuntimeException("Problem with path URI", e); } System.out.println("searching from " + dir); while (dir.getNameCount() > 1) { Path repo = dir.resolve(LOGDIRNAME); if (repo.toFile().exists()) return repo; System.out.println( "Directory did not contain " + LOGDIRNAME + ":" + dir); dir = dir.getParent(); } // fallback to working dir File file = new File(LOGDIRNAME); if (!file.exists()) { file.mkdir(); } return file.toPath(); } public NegoProtocol getProtocol() { return protocol; } @Override public String getID() { return sessionid; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((protocol == null) ? 0 : protocol.hashCode()); result = prime * result + ((sessionid == null) ? 0 : sessionid.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; RunningNego other = (RunningNego) obj; if (protocol == null) { if (other.protocol != null) return false; } else if (!protocol.equals(other.protocol)) return false; if (sessionid == null) { if (other.sessionid != null) return false; } else if (!sessionid.equals(other.sessionid)) return false; return true; } }