1d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann/*******************************************************************************
2b9d1b54e300318b470d9fedccc69d75187016444Evgeny Mandrikov * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
3d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann * All rights reserved. This program and the accompanying materials
4d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann * are made available under the terms of the Eclipse Public License v1.0
5d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann * which accompanies this distribution, and is available at
6d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann * http://www.eclipse.org/legal/epl-v10.html
7d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann *
8d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann * Contributors:
9d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann *    Marc R. Hoffmann - initial API and implementation
10d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann *
11d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann *******************************************************************************/
12d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmannpackage org.jacoco.core.tools;
13d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann
14d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmannimport java.io.IOException;
15d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmannimport java.io.InterruptedIOException;
16d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmannimport java.net.InetAddress;
17d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmannimport java.net.Socket;
18d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann
19d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmannimport org.jacoco.core.runtime.RemoteControlReader;
20d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmannimport org.jacoco.core.runtime.RemoteControlWriter;
21d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann
22d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann/**
23d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann * A client for remote execution data dumps.
24d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann */
25d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmannpublic class ExecDumpClient {
26d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann
27d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	private boolean dump;
28d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	private boolean reset;
29d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	private int retryCount;
30d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	private long retryDelay;
31d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann
32d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	/**
33d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * New instance with the defaults <code>dump==true</code>,
34d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * <code>reset==false</code>, <code>retryCount==0</code> and
35d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * <code>retryDelay=1000</code>.
36d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 */
37d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	public ExecDumpClient() {
38d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann		this.dump = true;
39d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann		this.reset = false;
40d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann		this.retryCount = 0;
41d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann		this.setRetryDelay(1000);
42d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	}
43d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann
44d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	/**
45d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * Specifies whether a dump should be requested
46d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 *
47d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * @param dump
48d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 *            <code>true</code> if a dump should be requested
49d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 */
50d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	public void setDump(final boolean dump) {
51d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann		this.dump = dump;
52d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	}
53d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann
54d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	/**
55d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * Specifies whether execution data should be reset.
56d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 *
57d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * @param reset
58d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 *            <code>true</code> if execution data should be reset
59d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 */
60d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	public void setReset(final boolean reset) {
61d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann		this.reset = reset;
62d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	}
63d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann
64d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	/**
65d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * Sets the number of retry attempts to connect to the target socket. This
66d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * allows to wait for a certain time until the target agent has initialized.
67d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 *
68d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * @param retryCount
69d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 *            number of retries
70d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 */
71d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	public void setRetryCount(final int retryCount) {
72d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann		this.retryCount = retryCount;
73d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	}
74d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann
75d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	/**
76d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * Sets the delay time before between connection attempts.
77d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 *
78d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * @param retryDelay
79d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 *            delay in milliseconds
80d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 */
81d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	public void setRetryDelay(final long retryDelay) {
82d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann		this.retryDelay = retryDelay;
83d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	}
84d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann
85d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	/**
86d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * Requests a dump from the given end-point.
87d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 *
88d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * @param address
89d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 *            IP-Address to connect to
90d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * @param port
91d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 *            port to connect to
92d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * @return container for the dumped data
93d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * @throws IOException
94d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 *             in case the dump can not be requested
95d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 */
96d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	public ExecFileLoader dump(final String address, final int port)
97d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann			throws IOException {
98d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann		return dump(InetAddress.getByName(address), port);
99d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	}
100d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann
101d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	/**
102d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * Requests a dump from the given end-point.
103d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 *
104d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * @param address
105d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 *            host name or IP-Address to connect to
106d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * @param port
107d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 *            port to connect to
108d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * @return container for the dumped data
109d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * @throws IOException
110d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 *             in case the dump can not be requested
111d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 */
112d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	public ExecFileLoader dump(final InetAddress address, final int port)
113d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann			throws IOException {
114d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann		final ExecFileLoader loader = new ExecFileLoader();
115d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann		final Socket socket = tryConnect(address, port);
116d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann		try {
117d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann			final RemoteControlWriter remoteWriter = new RemoteControlWriter(
118d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann					socket.getOutputStream());
119d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann			final RemoteControlReader remoteReader = new RemoteControlReader(
120d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann					socket.getInputStream());
121d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann			remoteReader.setSessionInfoVisitor(loader.getSessionInfoStore());
122d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann			remoteReader
123d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann					.setExecutionDataVisitor(loader.getExecutionDataStore());
124d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann
125d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann			remoteWriter.visitDumpCommand(dump, reset);
12610f3ff0dd010d647625ef5937f301126250267d0Marc R. Hoffmann
12710f3ff0dd010d647625ef5937f301126250267d0Marc R. Hoffmann			if (!remoteReader.read()) {
12810f3ff0dd010d647625ef5937f301126250267d0Marc R. Hoffmann				throw new IOException("Socket closed unexpectedly.");
12910f3ff0dd010d647625ef5937f301126250267d0Marc R. Hoffmann			}
130d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann
131d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann		} finally {
132d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann			socket.close();
133d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann		}
134d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann		return loader;
135d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	}
136d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann
137d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	private Socket tryConnect(final InetAddress address, final int port)
138d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann			throws IOException {
139d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann		int count = 0;
140d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann		while (true) {
141d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann			try {
142d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann				onConnecting(address, port);
143d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann				return new Socket(address, port);
144d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann			} catch (final IOException e) {
145d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann				if (++count > retryCount) {
146d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann					throw e;
147d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann				}
148d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann				onConnectionFailure(e);
149d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann				sleep();
150d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann			}
151d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann		}
152d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	}
153d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann
154d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	private void sleep() throws InterruptedIOException {
155d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann		try {
156d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann			Thread.sleep(retryDelay);
157d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann		} catch (final InterruptedException e) {
158d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann			throw new InterruptedIOException();
159d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann		}
160d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	}
161d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann
162d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	/**
163d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * This method can be overwritten to get an event just before a connection
164d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * is made.
165d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 *
166d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * @param address
167d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 *            target address
168d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * @param port
169d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 *            target port
170d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 */
171d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	protected void onConnecting(
172d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann			@SuppressWarnings("unused") final InetAddress address,
173d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann			@SuppressWarnings("unused") final int port) {
174d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	}
175d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann
176d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	/**
177d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * This method can be overwritten to get an event for connection failures
178d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * when another retry will be attempted.
179d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 *
180d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 * @param exception
181d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 *            connection error
182d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	 */
183d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	protected void onConnectionFailure(
184d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann			@SuppressWarnings("unused") final IOException exception) {
185d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann	}
186d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann
187d3982ef1fff1bf2168f63a6d41102def386fd180Marc R. Hoffmann}
188