// Copyright © 2011-2014, Esko Luontola <www.orfjackal.net>
// This software is released under the Apache License 2.0.
// The license text is at http://www.apache.org/licenses/LICENSE-2.0
package fi.jumi.core.ipc;
import fi.jumi.actors.*;
import fi.jumi.core.api.SuiteListener;
import fi.jumi.core.config.SuiteConfiguration;
import fi.jumi.core.events.*;
import fi.jumi.core.events.suiteListener.OnSuiteFinishedEvent;
import fi.jumi.core.ipc.api.*;
import fi.jumi.core.ipc.channel.*;
import fi.jumi.core.ipc.dirs.*;
import fi.jumi.core.ipc.encoding.*;
import fi.jumi.core.util.Boilerplate;
import javax.annotation.concurrent.NotThreadSafe;
import java.io.IOException;
import java.nio.file.Path;
@NotThreadSafe
public class IpcCommandReceiver implements Runnable {
private final DaemonDir daemonDir;
private final CommandDir commandDir;
private final CommandListener commandListener;
private final ActorThread actorThread;
public IpcCommandReceiver(DaemonDir daemonDir, CommandDir commandDir, CommandListener commandListener, ActorThread actorThread) {
this.daemonDir = daemonDir;
this.commandDir = commandDir;
this.commandListener = commandListener;
this.actorThread = actorThread;
}
@Override
public void run() {
IpcReader<RequestListener> requestReader = IpcChannel.reader(commandDir.getRequestPath(), RequestListenerEncoding::new);
ActorRef<RequestHandler> requestHandler = actorThread.bindActor(RequestHandler.class,
new RequestHandlerImpl(daemonDir, commandDir, commandListener, actorThread));
requestHandler.tell().start();
try {
IpcReaders.decodeAll(requestReader, requestHandler.tell());
} catch (InterruptedException e) {
System.err.println(this + " interrupted");
Thread.currentThread().interrupt();
}
requestHandler.tell().finish();
}
@NotThreadSafe
private static class RequestHandlerImpl implements RequestHandler {
private final DaemonDir daemonDir;
private final CommandDir commandDir;
private final CommandListener commandListener;
private final ActorThread actorThread;
private IpcWriter<ResponseListener> responseWriter;
private ResponseListener response;
public RequestHandlerImpl(DaemonDir daemonDir, CommandDir commandDir, CommandListener commandListener, ActorThread actorThread) {
this.daemonDir = daemonDir;
this.commandDir = commandDir;
this.commandListener = commandListener;
this.actorThread = actorThread;
}
@Override
public void start() {
this.responseWriter = IpcChannel.writer(commandDir.getResponsePath(), ResponseListenerEncoding::new);
this.response = new ResponseListenerEventizer().newFrontend(responseWriter);
}
@Override
public void finish() {
responseWriter.close();
}
@Override
public void runTests(SuiteConfiguration suiteConfiguration) {
Path suiteResults = newSuiteResultsFile();
ActorRef<SuiteListener> suiteWriter = startSuiteWriter(suiteResults);
response.onSuiteStarted(suiteResults);
commandListener.runTests(suiteConfiguration, suiteWriter);
}
private Path newSuiteResultsFile() {
try {
return daemonDir.createSuiteDir().getSuiteResultsPath();
} catch (IOException e) {
// TODO: write a failure to results file?
throw Boilerplate.rethrow(e);
}
}
private ActorRef<SuiteListener> startSuiteWriter(Path suiteResults) {
IpcWriter<SuiteListener> suiteWriter = IpcChannel.writer(suiteResults, SuiteListenerEncoding::new);
SuiteListener frontend = new SuiteListenerEventizer().newFrontend(message -> {
suiteWriter.send(message);
if (message instanceof OnSuiteFinishedEvent) { // XXX
suiteWriter.close();
}
});
return actorThread.bindActor(SuiteListener.class, frontend);
}
@Override
public void shutdown() {
commandListener.shutdown();
}
@Override
public String toString() {
return Boilerplate.toString(getClass(), commandDir);
}
}
}