Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 130e096955e6f066e8907edfc0fc0408b865b4b2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*******************************************************************************
 * Copyright (c) 2000, 2006 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jdt.core.tests.eval.target;

import java.io.*;
import java.net.*;
/**
 * The interface to the IDE. When connected, it uses TCP/IP sockets
 * to get code snippet classes and global variable classes from the IDE.
 * It sends the result of the evaluation back using the same socket.
 * <p>
 * The format from the socket input stream is the following:
 * <pre>
 *		[run flag: boolean coded on 1 byte]
 * 		[number of class files: int coded on 4 bytes]
 *		*[
 *			[length of class file: int coded on 4 bytes]
 *      	[class file: Java Class file format]
 *       ]
 * </pre>
 * This sequence is infinitely repeated until the input socket stream is closed.
 * <p>
 * The format from the socket output stream is the following:
 * <pre>
 * 		[has result flag: 1 if there is a result, 0 otherwise]
 * 		if there is a result:
 *		[fully qualified type name of result: utf8 encoded string]
 *      [toString representation of result: utf8 encoded string]
 * </pre>
 * This sequence is infinitely repeated until the output socket stream is closed.
 */
public class IDEInterface {
	/**
	 * Whether timing info should be printed to stdout
	 */
	static final boolean TIMING = false;
	long startTime;

	int portNumber = 0;
	Socket socket;
/**
 * Creates a new IDEInterface.
 */
IDEInterface(int portNumber) {
	this.portNumber = portNumber;
}
/**
 * Waits for a connection from the ide on the given port.
 * @throws IOException if the connection could not be established.
 */
void connect() throws IOException {
	ServerSocket server = new ServerSocket(this.portNumber);
	this.socket = server.accept();
	this.socket.setTcpNoDelay(true);
	server.close();
}
/**
 * Disconnects this interface from the IDE.
 */
void disconnect() {
	if (this.socket != null) {
		try {
			this.socket.close();
		} catch (IOException e2) {
			// Ignore
		}
		this.socket = null;
	}
}
/**
 * Returns the class definitions of the classes that compose the next code snippet to evaluate.
 */
protected byte[][] getNextClasses() {
	if (this.socket == null) {
		return new byte[0][];
	}
	if (TIMING) {
		this.startTime = System.currentTimeMillis();
	}
	try {
		DataInputStream in = new DataInputStream(this.socket.getInputStream());
		int numberOfClasses = in.readInt();
		byte[][] result = new byte[numberOfClasses][];
		for (int i = 0; i < numberOfClasses; i++) {
			int lengthOfClassFile = in.readInt();
			byte[] classFile = new byte[lengthOfClassFile];
			int read = 0;
			while (read < lengthOfClassFile && read != -1) {
				read += in.read(classFile, read, lengthOfClassFile - read);
			}
			result[i] = classFile;
		}
		return result;
	} catch (IOException e) {
		// The socket has likely been closed on the other end, close this end too.
		disconnect();
		return new byte[0][];
	}
}
/**
 * Returns whether the code snippet classes that follow should be run or just loaded.
 */
protected boolean getRunFlag() {
	if (this.socket == null) {
		return false;
	}
	if (TIMING) {
		this.startTime = System.currentTimeMillis();
	}
	try {
		DataInputStream in = new DataInputStream(this.socket.getInputStream());
		return in.readBoolean();
	} catch (IOException e) {
		// The socket has likely been closed on the other end, close this end too.
		disconnect();
		return false;
	}
}
/**
 * Returns whether this interface is connected to the IDE.
 */
boolean isConnected() {
	return this.socket != null;
}
/**
 * Sends the result of the evaluation to the IDE.
 */
protected void sendResult(Class resultType, Object resultValue) {
	if (this.socket == null) {
		return;
	}
	try {
		DataOutputStream out = new DataOutputStream(this.socket.getOutputStream());
		if (resultType == void.class) {
			out.writeBoolean(false);
		} else {
			out.writeBoolean(true);
			out.writeUTF(resultType.isPrimitive() ? resultType.toString() : resultType.getName());
			out.writeUTF(resultValue == null ? "null" : resultValue.toString());
		}
	} catch (IOException e) {
		// The socket has likely been closed on the other end, disconnect this end too
		disconnect();
	}
	if (TIMING) {
		System.out.println("Time to run on target is " + (System.currentTimeMillis() - this.startTime) + "ms");
	}
}
}

Back to the top