/** * Copyright 2012-2013 LMAX Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.lmax.ant.paralleljunit.remote.controller; import java.io.IOException; import java.net.ServerSocket; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.TimeoutException; import javax.net.ServerSocketFactory; import com.lmax.ant.paralleljunit.ParallelJUnitTaskConfig; import com.lmax.ant.paralleljunit.remote.TestSpecificationFactory; import com.lmax.ant.paralleljunit.util.net.ConnectionEstablisherFactory; import com.lmax.ant.paralleljunit.util.net.SocketConnection; import com.lmax.ant.paralleljunit.util.process.ManagedProcess; import com.lmax.ant.paralleljunit.util.process.ManagedProcessFactory; import org.apache.tools.ant.BuildException; import static java.util.concurrent.TimeUnit.SECONDS; public class RemoteTestRunnerControllerFactory { private static final int ANY_FREE_PORT = 0; private final ManagedProcessFactory managedProcessFactory; private final ExecutorService executorService; private final ServerSocketFactory serverSocketFactory; private final ConnectionEstablisherFactory connectionEstablisherFactory; private final TestSpecificationFactory testSpecificationFactory; public RemoteTestRunnerControllerFactory(final ManagedProcessFactory managedProcessFactory, final ExecutorService executorService, final ServerSocketFactory serverSocketFactory, final ConnectionEstablisherFactory connectionEstablisherFactory, final TestSpecificationFactory testSpecificationFactory) { this.managedProcessFactory = managedProcessFactory; this.executorService = executorService; this.serverSocketFactory = serverSocketFactory; this.connectionEstablisherFactory = connectionEstablisherFactory; this.testSpecificationFactory = testSpecificationFactory; } public RemoteTestRunnerController create(final int workerId, final ParallelJUnitTaskConfig config) { final ServerSocket serverSocket = createServerSocket(); final Future<SocketConnection> connectionFuture = executorService.submit(connectionEstablisherFactory.create(serverSocket)); final ManagedProcess jvmProcess = managedProcessFactory.create(workerId, config, serverSocket.getLocalPort()); final SocketConnection socketConnection = waitForSocketConnection(connectionFuture); return new RemoteTestRunnerController(jvmProcess, socketConnection, testSpecificationFactory); } private ServerSocket createServerSocket() { try { return serverSocketFactory.createServerSocket(ANY_FREE_PORT); } catch (final IOException e) { throw new BuildException("Could not open server socket.", e); } } private SocketConnection waitForSocketConnection(final Future<SocketConnection> connectionFuture) { try { return connectionFuture.get(10, SECONDS); } catch (final InterruptedException e) { throw new BuildException("Interrupted while waiting to accept connection.", e); } catch (final ExecutionException e) { throw new BuildException("Accepting connection caused an exception.", e); } catch (final TimeoutException e) { throw new BuildException("Timed out while waiting to accept connection.", e); } } }