// 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.daemon; import fi.jumi.actors.eventizers.Event; import fi.jumi.actors.queue.MessageSender; import fi.jumi.core.api.SuiteListener; import fi.jumi.core.config.SuiteConfiguration; import fi.jumi.core.events.SuiteListenerEventizer; import fi.jumi.core.ipc.IpcCommandSender; import fi.jumi.core.ipc.api.RequestListener; import fi.jumi.core.ipc.channel.*; import fi.jumi.core.ipc.dirs.*; import fi.jumi.core.ipc.encoding.SuiteListenerEncoding; import fi.jumi.core.network.*; import fi.jumi.core.suite.SuiteFactory; import fi.jumi.core.util.timeout.*; import javax.annotation.concurrent.ThreadSafe; import java.io.IOException; import java.nio.file.Path; import java.util.concurrent.*; @ThreadSafe public class DaemonNetworkEndpoint implements NetworkEndpoint<Event<RequestListener>, Event<SuiteListener>>, RequestListener { // TODO: remove this class private final SuiteFactory suiteFactory; private final Runnable shutdownHook; private final Timeout startupTimeout; private final DaemonDir daemonDir; private final VacancyTimeout connections; private final ExecutorService executor = Executors.newCachedThreadPool(); private MessageSender<Event<SuiteListener>> sender; public DaemonNetworkEndpoint(SuiteFactory suiteFactory, Runnable shutdownHook, Timeout startupTimeout, Timeout idleTimeout, DaemonDir daemonDir) { this.suiteFactory = suiteFactory; this.shutdownHook = shutdownHook; this.startupTimeout = startupTimeout; this.daemonDir = daemonDir; this.connections = new VacancyTimeout(idleTimeout); } @Override public void onConnected(NetworkConnection connection, MessageSender<Event<SuiteListener>> sender) { this.sender = sender; startupTimeout.cancel(); connections.checkIn(); } @Override public void onDisconnected() { connections.checkOut(); } @Override public void onMessage(Event<RequestListener> message) { message.fireOn(this); } @Override public void runTests(SuiteConfiguration suite) { SuiteListener suiteListener = new SuiteListenerEventizer().newFrontend(sender); // suiteFactory.configure(suite); // suiteFactory.start(suiteListener); // XXX: routing the commands through IPC to make sure that IPC works try { CommandDir commandDir = daemonDir.createCommandDir(); IpcCommandSender sender = new IpcCommandSender(commandDir, executor); Future<Path> suiteResults = sender.runTests(suite); sender.close(); executor.execute(() -> { try { IpcReader<SuiteListener> suiteReader = IpcChannel.reader(suiteResults.get(), SuiteListenerEncoding::new); IpcReaders.decodeAll(suiteReader, suiteListener); } catch (InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupt(); } catch (ExecutionException e) { e.printStackTrace(); throw new RuntimeException(e); } }); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } @Override public void shutdown() { // shutdownHook.run(); // XXX: routing the commands through IPC to make sure that IPC works try { CommandDir commandDir = daemonDir.createCommandDir(); IpcCommandSender sender = new IpcCommandSender(commandDir, executor); sender.shutdown(); sender.close(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } }