EmulatorRunner.java
| Index Score | ||
|---|---|---|
![]() |
![]() |
eclipseme.core.internal.launching |
![]() |
![]() |
EclipseME |
View: Reasons, Metrics, Source Code
These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.
/**
* Copyright (c) 2003-2005 Craig Setera
* All Rights Reserved.
* Licensed under the Eclipse Public License - v 1.0
* For more information see http://www.eclipse.org/legal/epl-v10.html
*/
package eclipseme.core.internal.launching;
import java.io.File;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.text.DateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Preferences;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.IStatusHandler;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.jdi.Bootstrap;
import org.eclipse.jdt.debug.core.JDIDebugModel;
import org.eclipse.jdt.launching.AbstractVMRunner;
import org.eclipse.jdt.launching.ExecutionArguments;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.jdt.launching.SocketUtil;
import org.eclipse.jdt.launching.VMRunnerConfiguration;
import com.sun.jdi.VirtualMachine;
import com.sun.jdi.connect.AttachingConnector;
import com.sun.jdi.connect.Connector;
import com.sun.jdi.connect.IllegalConnectorArgumentsException;
import com.sun.jdi.connect.ListeningConnector;
import eclipseme.core.EclipseMECoreStrings;
import eclipseme.core.IEclipseMECoreConstants;
import eclipseme.core.internal.EclipseMECorePlugin;
import eclipseme.core.internal.utils.Utils;
import eclipseme.core.model.IMidletSuiteProject;
import eclipseme.core.model.LaunchEnvironment;
import eclipseme.core.model.device.IDevice;
import eclipseme.core.model.device.IDevice2;
/**
* A VMRunner implementation that debugs against a wireless
* toolkit emulator. Places the standard VM debug arguments
* as program arguments when in debug mode. Otherwise, does
* not mess with that when not in debug mode.
* <p />
* Copyright (c) 2003-2005 Craig Setera<br>
* All Rights Reserved.<br>
* Licensed under the Eclipse Public License - v 1.0<p/>
* <br>
* $Revision: 1.8 $
* <br>
* $Date: 2006/02/11 21:26:57 $
* <br>
* @author Craig Setera
*/
public class EmulatorRunner extends AbstractVMRunner {
/**
* Used to attach to a VM in a seperate thread, to allow for cancellation
* and detect that the associated System process died before the connect
* occurred.
*/
static class ConnectRunnable implements Runnable {
private VirtualMachine fVirtualMachine = null;
private ListeningConnector fConnector = null;
private Map fConnectionMap = null;
private Exception fException = null;
/**
* Constructs a runnable to connect to a VM via the given connector
* with the given connection arguments.
*
* @param connector
* @param map
*/
public ConnectRunnable(ListeningConnector connector, Map map) {
fConnector = connector;
fConnectionMap = map;
}
/**
* Thread entrypoint.
* @see java.lang.Runnable#run()
*/
public void run() {
try {
fVirtualMachine = fConnector.accept(fConnectionMap);
} catch (IOException e) {
fException = e;
} catch (IllegalConnectorArgumentsException e) {
fException = e;
}
}
/**
* Returns the VM that was attached to, or <code>null</code> if none.
*
* @return the VM that was attached to, or <code>null</code> if none
*/
public VirtualMachine getVirtualMachine() {
return fVirtualMachine;
}
/**
* Returns any exception that occurred while attaching, or <code>null</code>.
*
* @return IOException or IllegalConnectorArgumentsException
*/
public Exception getException() {
return fException;
}
}
/**
* Render the debug target string.
*
* @param classToRun
* @param host
* @return
*/
private static String renderDebugTarget(String classToRun, int host) {
return EclipseMECoreStrings.getString(
"debugvmrunner.debug_target_string",
new String[] { classToRun, String.valueOf(host) });
}
/**
* Render the process label string.
*
* @param commandLine
* @return
*/
public static String renderProcessLabel(String[] commandLine) {
String timestamp =
DateFormat.getInstance().format(
new Date(System.currentTimeMillis()));
return EclipseMECoreStrings.getString(
"debugvmrunner.process_label_string",
new String[] { commandLine[0], timestamp });
}
/**
* Render the command line string.
*
* @param commandLine
* @return
*/
private static String renderCommandLine(String[] commandLine) {
StringBuffer buf = new StringBuffer();
if (commandLine.length > 1) {
for (int i = 0; i < commandLine.length; i++) {
if (i > 0) buf.append(' ');
buf.append(commandLine[i]);
}
}
return buf.toString();
}
private IMidletSuiteProject suite;
private IDevice device;
private boolean debugMode;
/**
* Construct an VM runner instance for an executable emulator.
*
* @param emulator
*/
public EmulatorRunner(IMidletSuiteProject suite, IDevice device, String mode)
{
this.suite = suite;
this.device = device;
debugMode = ILaunchManager.DEBUG_MODE.equals(mode);
}
/**
* @see org.eclipse.jdt.launching.IVMRunner#run(org.eclipse.jdt.launching.VMRunnerConfiguration, org.eclipse.debug.core.ILaunch, org.eclipse.core.runtime.IProgressMonitor)
*/
public void run(
VMRunnerConfiguration vmRunnerConfig,
ILaunchConfiguration launchConfig,
ILaunch launch,
IProgressMonitor monitor)
throws CoreException
{
if (debugMode) {
runInDebug(vmRunnerConfig, launchConfig, launch, monitor);
} else {
runWithoutDebug(vmRunnerConfig, launchConfig, launch, monitor);
}
}
/**
* Run the emulator with debugging.
*
* @param vmRunnerConfig
* @param launchConfig
* @param launch
* @param monitor
* @throws CoreException
*/
public void runInDebug(
VMRunnerConfiguration vmRunnerConfig,
ILaunchConfiguration launchConfig,
ILaunch launch,
IProgressMonitor monitor)
throws CoreException
{
if (monitor == null) {
monitor = new NullProgressMonitor();
}
IProgressMonitor subMonitor = new SubProgressMonitor(monitor, 1);
subMonitor.beginTask(EclipseMECoreStrings.getString("debugvmrunner.launching_vm"), 4);
subMonitor.subTask(EclipseMECoreStrings.getString("debugvmrunner.finding_free_socket"));
int port = SocketUtil.findFreePort();
if (port == -1) {
abort(
EclipseMECoreStrings.getString("debugvmrunner.no_free_socket"),
null, IJavaLaunchConfigurationConstants.ERR_NO_SOCKET_AVAILABLE);
}
subMonitor.worked(1);
// check for cancellation
if (monitor.isCanceled()) {
return;
}
subMonitor.subTask(EclipseMECoreStrings.getString("debugvmrunner.constructing_cmd_line"));
String[] cmdLine = getCommandLine(launchConfig, port, monitor);
Utils.dumpCommandLine(cmdLine);
// check for cancellation
if (monitor.isCanceled()) {
return;
}
subMonitor.worked(1);
subMonitor.subTask(EclipseMECoreStrings.getString("debugvmrunner.starting_VM"));
Connector connector = getConnector();
if (connector == null) {
abort(
EclipseMECoreStrings.getString("debugvmrunner.no_connector"),
null,
IJavaLaunchConfigurationConstants.ERR_CONNECTOR_NOT_AVAILABLE);
}
Map map = connector.defaultArguments();
specifyArguments(map, port);
Process p = null;
try {
try {
// check for cancellation
if (monitor.isCanceled()) {
return;
}
if (!device.isDebugServer()) {
((ListeningConnector) connector).startListening(map);
}
File workingDir = getWorkingDir(vmRunnerConfig);
p = exec(cmdLine, workingDir);
if (p == null) {
return;
}
// check for cancellation
if (monitor.isCanceled()) {
p.destroy();
return;
}
IProcess process = DebugPlugin.newProcess(
launch, p,
renderProcessLabel(cmdLine),
getDefaultProcessMap());
process.setAttribute(
IProcess.ATTR_CMDLINE,
renderCommandLine(cmdLine));
subMonitor.worked(1);
subMonitor.subTask(
EclipseMECoreStrings.getString("debugvmrunner.establishing_debug_conn"));
VirtualMachine vm =
createVirtualMachine(connector, map, p, process, monitor);
JDIDebugModel.newDebugTarget(
launch, vm,
renderDebugTarget(vmRunnerConfig.getClassToLaunch(), port),
process, true, false);
subMonitor.worked(1);
subMonitor.done();
return;
} finally {
if (!device.isDebugServer()) {
((ListeningConnector) connector).stopListening(map);
}
}
} catch (IOException e) {
abort(
EclipseMECoreStrings.getString("debugvmrunner.couldnt_connect_to_vm"),
e, IJavaLaunchConfigurationConstants.ERR_CONNECTION_FAILED);
} catch (IllegalConnectorArgumentsException e) {
abort(
EclipseMECoreStrings.getString("debugvmrunner.couldnt_connect_to_vm"),
e, IJavaLaunchConfigurationConstants.ERR_CONNECTION_FAILED);
}
if (p != null) {
p.destroy();
}
}
/**
* Create a new VirtualMachine instances for the specified
* Connector and associated information.
*
* @param connector
* @param map
* @param p
* @param process
* @param monitor
* @return
* @throws IOException
* @throws IllegalConnectorArgumentsException
* @throws CoreException
*/
private VirtualMachine createVirtualMachine(
Connector connector, Map map,
Process p, IProcess process,
IProgressMonitor monitor)
throws IOException,
IllegalConnectorArgumentsException,
CoreException
{
VirtualMachine vm = (device.isDebugServer()) ?
(waitForRemoteDebugger((AttachingConnector)connector, map)):
waitForDebuggerConnection(
(ListeningConnector) connector, p, process, map, monitor);
return vm;
}
/**
* Get the appropriate Connector dependent on what
* the IEmulator instance requires.
*
* @return
*/
private Connector getConnector() {
Connector connector = (device.isDebugServer()) ?
(Connector) getAttachingConnector() :
(Connector) getListeningConnector();
return connector;
}
/**
*
* Connect to the remote VM debugger and
* return a new VirtualMachine. Will retry until
* launch timeout is reached.
*
* @param connector
* @param map
* @return
* @throws IOException
* @throws IllegalConnectorArgumentsException
* @throws CoreException
*/
private VirtualMachine waitForRemoteDebugger(
AttachingConnector connector,
Map map)
throws IOException, IllegalConnectorArgumentsException, CoreException
{
Preferences preferences =
EclipseMECorePlugin.getDefault().getPluginPreferences();
VirtualMachine vm = null;
int launchTimeout = preferences.getInt(IEclipseMECoreConstants.PREF_RMTDBG_TIMEOUT);
int launchRetryInterval = preferences.getInt(IEclipseMECoreConstants.PREF_RMTDBG_INTERVAL);
long launchEndTime = System.currentTimeMillis() + launchTimeout;
boolean retry = true;
do {
try {
vm = connector.attach(map);
retry=false;
} catch (IOException e) {
if (System.currentTimeMillis() > launchEndTime) {
throw new IOException("Debugger launch time-out exceeded");
} else {
try {
Thread.sleep(launchRetryInterval);
} catch(InterruptedException ex) {
// No action, re-try immediately in this case.
}
}
}
} while (retry);
return vm;
}
/**
* Wait for the debugger to connect to our connector
* and return the new VirtualMachine.
*
* @param connector
* @param p
* @param process
* @param map
* @param monitor
* @return
* @throws CoreException
* @throws IOException
* @throws IllegalConnectorArgumentsException
*/
private VirtualMachine waitForDebuggerConnection(
ListeningConnector connector,
Process p,
IProcess process,
Map map,
IProgressMonitor monitor)
throws CoreException, IOException,
IllegalConnectorArgumentsException
{
VirtualMachine vm = null;
boolean retry = false;
do {
try {
ConnectRunnable runnable =
new ConnectRunnable(connector, map);
Thread connectThread =
new Thread(runnable, "Listening Connector");
connectThread.start();
while (connectThread.isAlive()) {
if (monitor.isCanceled()) {
connector.stopListening(map);
p.destroy();
break;
}
try {
p.exitValue();
// process has terminated - stop waiting for a connection
try {
connector.stopListening(map);
} catch (IOException e) {
// expected
}
checkErrorMessage(process);
} catch (IllegalThreadStateException e) {
// expected while process is alive
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
Exception ex = runnable.getException();
if (ex instanceof IllegalConnectorArgumentsException) {
throw (IllegalConnectorArgumentsException)ex;
}
if (ex instanceof InterruptedIOException) {
throw (InterruptedIOException)ex;
}
if (ex instanceof IOException) {
throw (IOException)ex;
}
vm = runnable.getVirtualMachine();
break;
} catch (InterruptedIOException e) {
checkErrorMessage(process);
// timeout, consult status handler if there is one
IStatus status = new Status(
IStatus.ERROR,
IEclipseMECoreConstants.PLUGIN_ID,
IJavaLaunchConfigurationConstants.ERR_VM_CONNECT_TIMEOUT,
"", e);
IStatusHandler handler = DebugPlugin.getDefault().getStatusHandler(status);
retry = false;
if (handler == null) {
// if there is no handler, throw the exception
throw new CoreException(status);
} else {
Object result = handler.handleStatus(status, this);
if (result instanceof Boolean) {
retry = ((Boolean)result).booleanValue();
}
}
}
} while (retry);
return vm;
}
/**
* Run the emulator without debugging.
*
* @param vmRunnerConfig
* @param launchConfig
* @param launch
* @param monitor
* @throws CoreException
*/
public void runWithoutDebug(
VMRunnerConfiguration vmRunnerConfig,
ILaunchConfiguration launchConfig,
ILaunch launch,
IProgressMonitor monitor)
throws CoreException
{
if (monitor == null) {
monitor = new NullProgressMonitor();
}
IProgressMonitor subMonitor = new SubProgressMonitor(monitor, 1);
subMonitor.beginTask(EclipseMECoreStrings.getString("debugvmrunner.launching_vm"), 3);
// check for cancellation
if (monitor.isCanceled()) {
return;
}
subMonitor.subTask(EclipseMECoreStrings.getString("debugvmrunner.constructing_cmd_line"));
String[] cmdLine = getCommandLine(launchConfig, -1, monitor);
Utils.dumpCommandLine(cmdLine);
// check for cancellation
if (monitor.isCanceled()) {
return;
}
subMonitor.worked(1);
subMonitor.subTask(EclipseMECoreStrings.getString("debugvmrunner.starting_VM"));
// check for cancellation
if (monitor.isCanceled()) {
return;
}
File workingDir = getWorkingDir(vmRunnerConfig);
Process p = exec(cmdLine, workingDir);
if (p == null) {
return;
}
// check for cancellation
if (monitor.isCanceled()) {
p.destroy();
return;
}
IProcess process = DebugPlugin.newProcess(
launch, p,
renderProcessLabel(cmdLine),
getDefaultProcessMap());
process.setAttribute(
IProcess.ATTR_CMDLINE,
renderCommandLine(cmdLine));
subMonitor.worked(1);
}
/**
* @see org.eclipse.jdt.launching.AbstractVMRunner#getPluginIdentifier()
*/
protected String getPluginIdentifier() {
return IEclipseMECoreConstants.PLUGIN_ID;
}
/**
* Add the specified arguments array to the list of arguments.
*
* @param args
* @param allArgs
*/
protected void addArguments(String[] args, List allArgs) {
if (args != null) {
for (int i= 0; i < args.length; i++) {
allArgs.add(args[i]);
}
}
}
/**
* Check for an error message and throw an exception as necessary.
*
* @param process
* @throws CoreException
*/
protected void checkErrorMessage(IProcess process) throws CoreException {
String errorMessage = process.getStreamsProxy().getErrorStreamMonitor().getContents();
if (errorMessage.length() == 0) {
errorMessage = process.getStreamsProxy().getOutputStreamMonitor().getContents();
}
if (errorMessage.length() != 0) {
abort(errorMessage, null, IJavaLaunchConfigurationConstants.ERR_VM_LAUNCH_ERROR);
}
}
/**
* Get the appropriate JDI AttachingConnector instance.
*
* @return
*/
private AttachingConnector getAttachingConnector() {
AttachingConnector connector = null;
List connectors =
Bootstrap.virtualMachineManager().attachingConnectors();
for (int i= 0; i < connectors.size(); i++) {
AttachingConnector c = (AttachingConnector) connectors.get(i);
if ("com.sun.jdi.SocketAttach".equals(c.name()))
connector = c;
}
return connector;
}
/**
* Get the appropriate JDI ListenerConnector instance.
*
* @return
*/
private ListeningConnector getListeningConnector() {
ListeningConnector connector = null;
List connectors = Bootstrap.virtualMachineManager().listeningConnectors();
for (int i= 0; i < connectors.size(); i++) {
ListeningConnector c = (ListeningConnector) connectors.get(i);
if ("com.sun.jdi.SocketListen".equals(c.name()))
connector = c;
}
return connector;
}
/**
* Returns the working directory to use for the launched VM,
* or <code>null</code> if the working directory is to be inherited
* from the current process.
*
* @return the working directory to use
* @exception CoreException if the working directory specified by
* the configuration does not exist or is not a directory
*/
private File getWorkingDir(VMRunnerConfiguration config)
throws CoreException
{
File dir = null;
String path = null;
if (device instanceof IDevice2) {
File deviceWorkingDirectory = ((IDevice2) device).getWorkingDirectory();
if ((deviceWorkingDirectory != null) && deviceWorkingDirectory.exists()) {
path = deviceWorkingDirectory.getPath();
}
}
if (path == null) {
path = config.getWorkingDirectory();
}
if (path != null) {
dir = new File(path);
if (!dir.isDirectory()) {
abort(EclipseMECoreStrings.getString(
"debugvmrunner.workingdir_not_dir",
new String[] {path}),
null,
IJavaLaunchConfigurationConstants.ERR_WORKING_DIRECTORY_DOES_NOT_EXIST);
}
}
return dir;
}
/**
* Specify new connector arguments to the JDI connector.
*
* @param map
* @param portNumber
*/
private void specifyArguments(Map map, int portNumber) {
Connector.IntegerArgument port =
(Connector.IntegerArgument) map.get("port");
port.setValue(portNumber);
Connector.IntegerArgument timeoutArg =
(Connector.IntegerArgument) map.get("timeout");
if (timeoutArg != null) {
int timeout =
JavaRuntime.getPreferences().getInt(JavaRuntime.PREF_CONNECT_TIMEOUT);
timeoutArg.setValue(timeout);
}
}
/**
* @param monitor
* @see eclipseme.core.internal.launching.EmulatorRunner#getCommandLine(org.eclipse.jdt.launching.VMRunnerConfiguration, int)
*/
protected String[] getCommandLine(ILaunchConfiguration config, int port, IProgressMonitor monitor)
throws CoreException
{
LaunchEnvironment launchEnvironment = new LaunchEnvironment();
launchEnvironment.setDebugLaunch(debugMode);
launchEnvironment.setDebugListenerPort(port);
launchEnvironment.setLaunchConfiguration(config);
launchEnvironment.setMidletSuite(suite);
String commandLineString = device.getLaunchCommand(launchEnvironment, monitor);
ExecutionArguments execArgs = new ExecutionArguments("", commandLineString);
String[] cmdLine = execArgs.getProgramArgumentsArray();
return cmdLine;
}
/**
* @see org.eclipse.jdt.launching.IVMRunner#run(org.eclipse.jdt.launching.VMRunnerConfiguration, org.eclipse.debug.core.ILaunch, org.eclipse.core.runtime.IProgressMonitor)
*/
public void run(VMRunnerConfiguration configuration, ILaunch launch, IProgressMonitor monitor)
throws CoreException
{
// Method provided to meet the superclass requirement. Is not called.
}
}
The table below shows all metrics for EmulatorRunner.java.




