/*******************************************************************************
* Copyright (c) 2009 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
* Zend Technologies
*******************************************************************************/
package org.eclipse.php.internal.debug.core.zend.debugger;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.preferences.IDebugPreferenceConstants;
import org.eclipse.debug.internal.ui.views.console.ProcessConsole;
import org.eclipse.php.internal.debug.core.IPHPDebugConstants;
import org.eclipse.php.internal.debug.core.launching.PHPProcess;
import org.eclipse.php.internal.debug.core.preferences.PHPDebugCorePreferenceNames;
import org.eclipse.php.internal.debug.core.zend.communication.DebuggerCommunicationDaemon;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.IConsoleListener;
import org.eclipse.ui.console.IOConsoleOutputStream;
/**
* A process crash detector is a {@link Runnable} that hooks a PHP process error
* stream and blocks until the process terminates. Then, the detector determines
* if the process terminated as a result of an abnormal crash, or as a result of
* a normal termination or a PHP fatal termination. The PHP termination codes
* are between 0 - 255, so any other exit value is considered as a program
* crash. The crash detector displays a message to the user in case of a crash.
*
* @author shalom
* @since PDT 1.0.1
*/
public class ProcessCrashDetector implements Runnable, IConsoleListener {
private ILaunch launch;
private Process process;
private ProcessConsole console;
/**
* Constructs a process detector on a given {@link Process}.
*
* @param launch
* {@link ILaunch}
* @param p
* {@link Process}.
*/
public ProcessCrashDetector(ILaunch launch, Process p) {
this.launch = launch;
this.process = p;
}
/*
* (non-Javadoc)
*
* @see java.lang.Runnable#run()
*/
public void run() {
try {
boolean streamerReqd = false;
try {
ILaunchConfiguration config = launch.getLaunchConfiguration();
if (config.getAttribute(
PHPDebugCorePreferenceNames.PHP_DEBUGGER_ID, "") //$NON-NLS-1$
.equals(DebuggerCommunicationDaemon.ZEND_DEBUGGER_ID)) {
streamerReqd = config.getAttribute(
IPHPDebugConstants.RUN_WITH_DEBUG_INFO, true)
|| launch.getLaunchMode().equals(
ILaunchManager.DEBUG_MODE);
}
} catch (CoreException e) {
}
if (streamerReqd) {
StreamGobbler errorGobbler = new StreamGobbler(
process.getErrorStream(), true);
StreamGobbler inputGobbler = new StreamGobbler(
process.getInputStream(), false);
ConsolePlugin.getDefault().getConsoleManager()
.addConsoleListener(this);
errorGobbler.start();
inputGobbler.start();
}
int exitValue = process.waitFor();
IDebugTarget debugTarget = launch.getDebugTarget();
if (debugTarget != null) {
IProcess p = debugTarget.getProcess();
if (p instanceof PHPProcess) {
((PHPProcess) p).setExitValue(exitValue);
}
}
} catch (Throwable t) {
} finally {
ConsolePlugin.getDefault().getConsoleManager()
.removeConsoleListener(this);
}
}
class StreamGobbler extends Thread {
InputStream is;
StringBuilder buf;
boolean isError;
private IOConsoleOutputStream os;
StreamGobbler(InputStream is, boolean isError) {
this.is = is;
this.buf = new StringBuilder();
this.isError = isError;
}
public void run() {
try {
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
if (!isError) {
continue;
}
if (console != null) {
if (os == null) {
os = console.newOutputStream();
if (isError) {
Display.getDefault().syncExec(new Runnable() {
public void run() {
os.setColor(DebugUIPlugin
.getPreferenceColor(IDebugPreferenceConstants.CONSOLE_SYS_ERR_COLOR));
}
});
}
}
os.write(buf.toString());
os.write(line + '\n');
buf.delete(0, buf.length());
} else {
buf.append(line).append('\n');
}
}
} catch (IOException ioe) {
// PHPDebugPlugin.log(ioe);
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
// PHPDebugPlugin.log(e);
}
}
}
}
}
public void consolesAdded(IConsole[] consoles) {
for (IConsole console : consoles) {
if (console instanceof ProcessConsole) {
this.console = (ProcessConsole) console;
}
}
}
public void consolesRemoved(IConsole[] consoles) {
}
}