/******************************************************************************* * Copyright (c) 2000, 2008 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.runtime; import org.eclipse.jdt.internal.compiler.ClassFile; import org.eclipse.jdt.internal.compiler.util.Util; import java.io.*; import java.net.*; /** * This is the interface to the target VM. It connects to an IDEInterface on the target side * using TCP/IO to send request for code snippet evaluation and to get the result back. * * @see org.eclipse.jdt.core.tests.eval.target.IDEInterface for details about the protocol. */ public class TargetInterface { /** * Whether class files should be written in d:\eval\ instead of sending them to the target * NB: d:\eval should contain a batch file TestCodeSnippet.bat with the following contents: * SET JDK=c:\jdk1.2.2 * SET EVAL=d:\eval * %JDK%\bin\java -Xbootclasspath:%JDK%\jre\lib\rt.jar;%EVAL%\javaClasses; -classpath c:\temp;%EVAL%\snippets;%EVAL%\classes;"d:\ide\project_resources\Eclipse Java Evaluation\CodeSnippetSupport.jar" CodeSnippetTester %1 */ static final boolean DEBUG = false; String codeSnippetClassName; /** * Whether timing info should be printed to stdout */ static final boolean TIMING = false; long sentTime; /** * The connection to the target's ide interface. */ Socket socket; public class Result { public char[] displayString; public char[] typeName; } /** * (PRIVATE API) * Connects this interface to the target. * Try as long as the given time (in ms) has not expired. * Use isConnected() to find out if the connection was successful. */ public void connect(String targetAddress, int portNumber, int timeout) { if (isConnected()) { return; } if (portNumber > 0) { long startTime = System.currentTimeMillis(); do { try { this.socket = new Socket(targetAddress, portNumber); this.socket.setTcpNoDelay(true); break; } catch (UnknownHostException e) { } catch (IOException e) { } if (this.socket == null) { try { Thread.sleep(100); } catch (InterruptedException e) { } } } while (!isConnected() && (System.currentTimeMillis() - startTime) < timeout); } } /** * (PRIVATE API) * Disconnects this interface from the target. */ public void disconnect() { if (this.socket != null) { try { this.socket.close(); } catch (IOException e) { // Already closed. Nothing more to do } this.socket = null; } } /** * Returns the result of the evaluation sent previously to the target. */ public Result getResult() { boolean hasValue = false; String typeName = null; String toString = null; if (DEBUG) { hasValue = true; typeName = "TargetInterface in debug mode. Run d:\\eval\\TestCodeSnippet.bat d:\\eval\\snippets\\" + this.codeSnippetClassName; toString = ""; } else { if (isConnected()) { // TBD: Read type name and toString as a character array try { DataInputStream in = new DataInputStream(this.socket.getInputStream()); hasValue = in.readBoolean(); if (hasValue) { typeName = in.readUTF(); toString = in.readUTF(); } else { typeName = null; toString = null; } } catch (IOException e) { // The socket has likely been closed on the other end. So the code snippet runner has stopped. hasValue = true; typeName = e.getMessage(); toString = ""; disconnect(); } } else { hasValue = true; typeName = "Connection has been lost"; toString = ""; } } if (TIMING) { System.out.println("Time to send compiled classes, run on target and get result is " + (System.currentTimeMillis() - this.sentTime) + "ms"); } Result result = new Result(); result.displayString = toString == null ? null : toString.toCharArray(); result.typeName = typeName == null ? null : typeName.toCharArray(); return result; } /** * Returns whether this interface is connected to the target. */ boolean isConnected() { return this.socket != null; } /** * Sends the given class definitions to the target for loading and (if specified) for running. */ public void sendClasses(boolean mustRun, ClassFile[] classes) throws TargetException { if (DEBUG) { for (int i = 0; i < classes.length; i++) { String className = new String(classes[i].fileName()).replace('/', '\\') + ".class"; if ((i == 0) && (className.indexOf("CodeSnippet") != -1)) { this.codeSnippetClassName = className; try { Util.writeToDisk(true, "d:\\eval\\snippets", className, classes[0]); } catch(IOException e) { } } else { String dirName; if (className.startsWith("java")) { dirName = "d:\\eval\\" + LocalVMLauncher.BOOT_CLASSPATH_DIRECTORY; } else { dirName = "d:\\eval\\" + LocalVMLauncher.REGULAR_CLASSPATH_DIRECTORY; } try { Util.writeToDisk(true, dirName, className, classes[i]); } catch(IOException e) { } } } } else { if (TIMING) { this.sentTime = System.currentTimeMillis(); } if (!isConnected()) { throw new TargetException("Connection to the target VM has been lost"); } try { DataOutputStream out = new DataOutputStream(this.socket.getOutputStream()); out.writeBoolean(mustRun); out.writeInt(classes.length); for (int i = 0; i < classes.length; i++) { byte[] classDefinition = classes[i].getBytes(); out.writeInt(classDefinition.length); out.write(classDefinition); } } catch (IOException e) { // The socket has likely been closed on the other end. So the code snippet runner has stopped. disconnect(); } } } }