📄 abstractshell.java
字号:
}
/**
* This method creates the python server process and starts the sockets, so that we
* can talk with the server.
*
* @param milisSleep: time to wait after creating the process.
* @throws IOException is some error happens creating the sockets - the process is terminated.
* @throws JDTNotAvailableException
* @throws CoreException
* @throws CoreException
*/
protected synchronized void startIt(int milisSleep) throws IOException, JDTNotAvailableException, CoreException {
if(inStart || isConnected){
//it is already in the process of starting, so, if we are in another thread, just forget about it.
return;
}
inStart = true;
try {
if (finishedForGood) {
throw new RuntimeException(
"Shells are already finished for good, so, it is an invalid state to try to restart it.");
}
try {
int pWrite = SocketUtil.findUnusedLocalPort("127.0.0.1", 50000, 55000);
int pRead = SocketUtil.findUnusedLocalPort("127.0.0.1", 55001, 60000);
if (process != null) {
endIt(); //end the current process
}
String execMsg = createServerProcess(pWrite, pRead);
dbg("executing " + execMsg,1);
sleepALittle(200);
String osName = System.getProperty("os.name");
if (process == null) {
String msg = "Error creating python process - got null process(" + execMsg + ") - os:" + osName;
dbg(msg, 1);
PydevPlugin.log(msg);
throw new CoreException(PydevPlugin.makeStatus(IStatus.ERROR, msg, new Exception(msg)));
}
try {
int exitVal = process.exitValue(); //should throw exception saying that it still is not terminated...
String msg = "Error creating python process - exited before creating sockets - exitValue = ("+ exitVal + ")(" + execMsg + ") - os:" + osName;
dbg(msg, 1);
PydevPlugin.log(msg);
throw new CoreException(PydevPlugin.makeStatus(IStatus.ERROR, msg, new Exception(msg)));
} catch (IllegalThreadStateException e2) { //this is ok
}
dbg("afterCreateProcess ",1);
//ok, process validated, so, let's get its output and store it for further use.
afterCreateProcess();
boolean connected = false;
int attempts = 0;
dbg("connecting... ",1);
sleepALittle(milisSleep);
socketToWrite = null;
serverSocket = new ServerSocket(pRead); //read in this port
int maxAttempts = PyCodeCompletionPreferencesPage.getNumberOfConnectionAttempts();
while (!connected && attempts < maxAttempts && !finishedForGood) {
attempts += 1;
dbg("connecting attept..."+attempts,1);
try {
if (socketToWrite == null || socketToWrite.isConnected() == false) {
socketToWrite = new Socket("127.0.0.1", pWrite); //we should write in this port
}
if (socketToWrite != null || socketToWrite.isConnected()) {
serverSocket.setSoTimeout(milisSleep * 2); //let's give it a higher timeout, as we're already half - connected
try {
socketToRead = serverSocket.accept();
socketToRead.setSoTimeout(5000);
connected = true;
dbg("connected! ",1);
} catch (SocketTimeoutException e) {
//that's ok, timeout for waiting connection expired, let's check it again in the next loop
}
}
} catch (IOException e1) {
if (socketToWrite != null && socketToWrite.isConnected() == true) {
String msg = "Attempt: " + attempts + " of " + maxAttempts +
" failed, trying again...(socketToWrite already binded)";
dbg(msg,1);
PydevPlugin.log(IStatus.ERROR, msg, e1);
}
if (socketToWrite != null && !socketToWrite.isConnected() == true) {
String msg = "Attempt: " + attempts + " of " + maxAttempts +
" failed, trying again...(socketToWrite still not binded)";
dbg(msg,1);
PydevPlugin.log(IStatus.ERROR, msg, e1);
}
}
//if not connected, let's sleep a little for another attempt
if (!connected) {
sleepALittle(milisSleep);
}
}
if (!connected && !finishedForGood) {
dbg("NOT connected ",1);
//what, after all this trouble we are still not connected????!?!?!?!
//let's communicate this to the user...
String isAlive;
try {
int exitVal = process.exitValue(); //should throw exception saying that it still is not terminated...
isAlive = " - the process in NOT ALIVE anymore (output=" + exitVal + ") - ";
} catch (IllegalThreadStateException e2) { //this is ok
isAlive = " - the process in still alive (killing it now)- ";
process.destroy();
}
String output = getProcessOutput();
String msg = "Error connecting to python process (" + execMsg + ") " +
isAlive + " the output of the process is: " + output;
RuntimeException exception = new RuntimeException(msg);
dbg(msg, 1);
PydevPlugin.log(exception);
throw exception;
}
} catch (IOException e) {
if (process != null) {
process.destroy();
process = null;
}
throw e;
}
} finally {
this.inStart = false;
}
//if it got here, everything went ok (otherwise we would have gotten an exception).
isConnected = true;
}
private synchronized void afterCreateProcess() {
try {
process.getOutputStream().close(); //we won't write to it...
} catch (IOException e2) {
}
//will print things if we are debugging or just get it (and do nothing except emptying it)
stdReader = new ThreadStreamReader(process.getInputStream());
errReader = new ThreadStreamReader(process.getErrorStream());
stdReader.setName("Shell reader (stdout)");
errReader.setName("Shell reader (stderr)");
stdReader.start();
errReader.start();
}
/**
* @return the current output of the process
*/
protected synchronized String getProcessOutput(){
try {
String output = "";
output += "Std output:\n" + stdReader.contents.toString();
output += "\n\nErr output:\n" + errReader.contents.toString();
return output;
} catch (Exception e) {
return "Unable to get output";
}
}
/**
* @param pWrite the port where we should write
* @param pRead the port where we should read
* @return the command line that was used to create the process
*
* @throws IOException
* @throws JDTNotAvailableException
*/
protected abstract String createServerProcess(int pWrite, int pRead) throws IOException, JDTNotAvailableException;
protected synchronized void communicateWork(String desc, IProgressMonitor monitor) {
if(monitor != null){
monitor.setTaskName(desc);
monitor.worked(1);
}
}
public synchronized void clearSocket() throws IOException {
while(true){ //clear until we get no message...
byte[] b = new byte[AbstractShell.BUFFER_SIZE];
if(this.socketToRead != null){
this.socketToRead.getInputStream().read(b);
String s = new String(b);
s = s.replaceAll((char)0+"",""); //python sends this char as payload.
if(s.length() == 0){
return;
}
}
}
}
/**
* @param operation
* @return
* @throws IOException
*/
public synchronized String read(IProgressMonitor monitor) throws IOException {
if(finishedForGood){
throw new RuntimeException("Shells are already finished for good, so, it is an invalid state to try to read from it.");
}
if(inStart){
throw new RuntimeException("The shell is still not completely started, so, it is an invalid state to try to read from it..");
}
if(!isConnected){
throw new RuntimeException("The shell is still not connected, so, it is an invalid state to try to read from it..");
}
if(isInRead){
throw new RuntimeException("The shell is already in read mode, so, it is an invalid state to try to read from it..");
}
if(isInWrite){
throw new RuntimeException("The shell is already in write mode, so, it is an invalid state to try to read from it..");
}
isInRead = true;
try {
StringBuffer str = new StringBuffer();
int j = 0;
while (j < 200) {
byte[] b = new byte[AbstractShell.BUFFER_SIZE];
this.socketToRead.getInputStream().read(b);
String s = new String(b);
//processing without any status to present to the user
if (s.indexOf("@@PROCESSING_END@@") != -1) { //each time we get a processing message, reset j to 0.
s = s.replaceAll("@@PROCESSING_END@@", "");
j = 0;
communicateWork("Processing...", monitor);
}
//processing with some kind of status
if (s.indexOf("@@PROCESSING:") != -1) { //each time we get a processing message, reset j to 0.
s = s.replaceAll("@@PROCESSING:", "");
s = s.replaceAll("END@@", "");
j = 0;
s = URLDecoder.decode(s, ENCODING_UTF_8);
if (s.trim().equals("") == false) {
communicateWork("Processing: " + s, monitor);
} else {
communicateWork("Processing...", monitor);
}
s = "";
}
s = s.replaceAll((char) 0 + "", ""); //python sends this char as payload.
str.append(s);
if (str.indexOf("END@@") != -1) {
break;
} else {
if (s.length() == 0) { //only raise if nothing was received.
j++;
} else {
j = 0; //we are receiving, even though that may take a long time if the namespace is really polluted...
}
sleepALittle(10);
}
}
String ret = str.toString().replaceFirst("@@COMPLETIONS", "");
//remove END@@
try {
if (ret.indexOf("END@@") != -1) {
ret = ret.substring(0, ret.indexOf("END@@"));
return ret;
} else {
throw new RuntimeException("Couldn't find END@@ on received string.");
}
} catch (RuntimeException e) {
e.printStackTrace();
if (ret.length() > 500) {
ret = ret.substring(0, 499) + "...(continued)...";//if the string gets too big, it can crash Eclipse...
}
PydevPlugin.log(IStatus.ERROR, "ERROR WITH STRING:" + ret, e);
return "";
}
} finally{
isInRead = false;
}
}
/**
* @return s string with the contents read.
* @throws IOException
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -