blob: ac1c2dcb2b8743d2e80d5154b23d77640263dd97 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.core.tests.runtime;
import org.eclipse.jdt.internal.compiler.ClassFile;
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\\" + codeSnippetClassName;
toString = "";
} else {
if (this.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 = "";
this.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)) {
codeSnippetClassName = className;
try {
ClassFile.writeToDisk(true, "d:\\eval\\snippets", className, classes[0].getBytes());
} 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 {
ClassFile.writeToDisk(true, dirName, className, classes[i].getBytes());
} 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.
this.disconnect();
}
}
}
}