/******************************************************************************* * Copyright (c) 2000, 2014 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. */ @SuppressWarnings({ "rawtypes" }) 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"); } } }