blob: 4676564bf060d36d90033cec9653ff5ff53b64ef [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2012 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.jsdt.debug.internal.chrome.jsdi;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.osgi.util.NLS;
import org.eclipse.wst.jsdt.debug.core.breakpoints.IJavaScriptBreakpoint;
import org.eclipse.wst.jsdt.debug.core.jsdi.BooleanValue;
import org.eclipse.wst.jsdt.debug.core.jsdi.NullValue;
import org.eclipse.wst.jsdt.debug.core.jsdi.NumberValue;
import org.eclipse.wst.jsdt.debug.core.jsdi.StringValue;
import org.eclipse.wst.jsdt.debug.core.jsdi.UndefinedValue;
import org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine;
import org.eclipse.wst.jsdt.debug.core.jsdi.event.EventQueue;
import org.eclipse.wst.jsdt.debug.core.jsdi.request.EventRequestManager;
import org.eclipse.wst.jsdt.debug.internal.chrome.ChromePlugin;
import org.eclipse.wst.jsdt.debug.internal.chrome.Tracing;
import org.eclipse.wst.jsdt.debug.internal.chrome.event.EventQueueImpl;
import org.eclipse.wst.jsdt.debug.internal.chrome.request.EventReqManager;
import org.eclipse.wst.jsdt.debug.internal.chrome.transport.Attributes;
import org.eclipse.wst.jsdt.debug.internal.chrome.transport.EventPacketImpl;
import org.eclipse.wst.jsdt.debug.internal.chrome.transport.RequestPacketImpl;
import org.eclipse.wst.jsdt.debug.internal.chrome.transport.Commands;
import org.eclipse.wst.jsdt.debug.internal.chrome.transport.JSON;
import org.eclipse.wst.jsdt.debug.transport.DebugSession;
import org.eclipse.wst.jsdt.debug.transport.exception.DisconnectedException;
import org.eclipse.wst.jsdt.debug.transport.exception.TimeoutException;
import org.eclipse.wst.jsdt.debug.transport.packet.Event;
import org.eclipse.wst.jsdt.debug.transport.packet.Request;
import org.eclipse.wst.jsdt.debug.transport.packet.Response;
/**
* Default implementation of a {@link VirtualMachine} for Chrome
*
* @since 1.0
*/
public class VMImpl extends MirrorImpl implements VirtualMachine {
public static int RUNNING = 1;
public static int SUSPENDED = 2;
public static int TERMINATED = 3;
public static int DISPOSED = 4;
public static int DISCONNECTED = 5;
/**
* The current state
*/
private int state = 0;
/**
* The singleton {@link NullValue}
*/
private static NullValue nullValue = null;
/**
* The singleton {@link UndefinedValue}
*/
private static UndefinedValue undefinedValue = null;
private EventRequestManager ermanager = new EventReqManager(this);
private EventQueue queue = new EventQueueImpl(this, ermanager);
private final DebugSession session;
private Map threads = null;
private Map scripts = null;
private String version = null;
/**
* Constructor
*
* @param session the backing {@link DebugSession}
*/
public VMImpl(DebugSession session) {
super();
this.session = session;
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine#resume()
*/
public synchronized void resume() {
if(state == SUSPENDED) {
//TODO
state = RUNNING;
}
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine#suspend()
*/
public synchronized void suspend() {
if(state == RUNNING) {
//TODO
state = SUSPENDED;
}
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine#terminate()
*/
public synchronized void terminate() {
if(state != TERMINATED) {
//TODO
state = TERMINATED;
}
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine#name()
*/
public String name() {
return NLS.bind(Messages.chrome_vm, version());
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine#description()
*/
public String description() {
return Messages.vm_description;
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine#version()
*/
public synchronized String version() {
if(version == null) {
RequestPacketImpl request = new RequestPacketImpl(Commands.VERSION, Attributes.TOOL_DEVTOOLSRVC, null);
Response response = sendRequest(request);
if(response.isSuccess()) {
version = (String) response.getBody().get(Attributes.DATA);
}
else if(TRACE) {
Tracing.writeString("VM [failed version request]" + JSON.serialize(request)); //$NON-NLS-1$
}
}
return version;
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine#allThreads()
*/
public synchronized List allThreads() {
if(threads == null) {
threads = Collections.synchronizedMap(new HashMap(4));
RequestPacketImpl request = new RequestPacketImpl(Commands.LIST_TABS, Attributes.TOOL_DEVTOOLSRVC, null);
Response response = sendRequest(request);
if(response.isSuccess()) {
List tabs = (List) response.getBody().get(Attributes.DATA);
if(tabs != null) {
ArrayList values = null;
for(Iterator i = tabs.iterator(); i.hasNext();) {
values = (ArrayList) i.next();
String url = (String)values.get(1);
Number id = (Number)values.get(0);
ThreadImpl thread = new ThreadImpl(this, id, url);
threads.put(id, thread);
attach(thread);
}
}
}
else if(TRACE) {
Tracing.writeString("VM [failed all_tabs request]" + JSON.serialize(request)); //$NON-NLS-1$
}
}
return new ArrayList(threads.values());
}
/**
* Try to attach the debugger to the v8 debugger service for the given thread (tab)
*
* @param thread
*/
void attach(ThreadImpl thread) {
RequestPacketImpl request = new RequestPacketImpl(Commands.ATTACH, Attributes.TOOL_DEVTOOLSRVC, thread.id());
Response response = sendRequest(request);
if(response.isSuccess()) {
}
else if(TRACE) {
Tracing.writeString("VM [failed attach request] " + JSON.serialize(request)); //$NON-NLS-1$
}
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine#allScripts()
*/
public synchronized List allScripts() {
if(this.scripts == null) {
this.scripts = Collections.synchronizedMap(new HashMap(4));
}
return new ArrayList(scripts.values());
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine#dispose()
*/
public synchronized void dispose() {
if(state != DISPOSED) {
//TODO
try {
if(threads != null) {
threads.clear();
threads = null;
}
if(scripts != null) {
scripts.clear();
scripts = null;
}
}
finally {
state = DISPOSED;
}
}
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine#mirrorOfUndefined()
*/
public UndefinedValue mirrorOfUndefined() {
synchronized (this) {
if(undefinedValue == null) {
undefinedValue = new UndefinedImpl(this);
}
}
return undefinedValue;
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine#mirrorOfNull()
*/
public NullValue mirrorOfNull() {
synchronized (this) {
if(nullValue == null) {
nullValue = new NullImpl(this);
}
}
return nullValue;
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine#mirrorOf(boolean)
*/
public BooleanValue mirrorOf(boolean bool) {
return new BooleanImpl(this, bool);
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine#mirrorOf(java.lang.Number)
*/
public NumberValue mirrorOf(Number number) {
return new NumberImpl(this, number);
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine#mirrorOf(java.lang.String)
*/
public StringValue mirrorOf(String string) {
return new StringImpl(this, string);
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine#eventRequestManager()
*/
public EventRequestManager eventRequestManager() {
return ermanager;
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine#eventQueue()
*/
public EventQueue eventQueue() {
return queue;
}
/**
* Sends a request to the underlying {@link DebugSession}, waiting
* for the {@link VirtualMachine#DEFAULT_TIMEOUT}.
*
* @param request
* @return the {@link CFResponse} for the request
*/
public Response sendRequest(Request request) {
try {
session.send(request);
return session.receiveResponse(request.getSequence(), 3000);
}
catch(DisconnectedException de) {
disconnectVM();
handleException(de.getMessage(), de.getCause());
}
catch(TimeoutException te) {
ChromePlugin.log(te);
}
return null;
}
/**
* Receives an {@link EventPacket} from the underlying {@link DebugSession},
* waiting for the {@link VirtualMachine#DEFAULT_TIMEOUT}.
*
* @return the next {@link EventPacket} never <code>null</code>
* @throws TimeoutException
* @throws DisconnectedException
*/
public Event receiveEvent() throws TimeoutException, DisconnectedException {
return (Event) session.receive(EventPacketImpl.EVENT, DEFAULT_TIMEOUT);
}
/**
* Receives an {@link EventPacket} from the underlying {@link DebugSession},
* waiting for the {@link VirtualMachine#DEFAULT_TIMEOUT}.
* @param timeout
* @return the next {@link EventPacket} never <code>null</code>
* @throws TimeoutException
* @throws DisconnectedException
*/
public Event receiveEvent(int timeout) throws TimeoutException, DisconnectedException {
return (Event) session.receive(EventPacketImpl.EVENT, timeout);
}
/**
* disconnects the VM
*/
public synchronized void disconnectVM() {
if (state == DISCONNECTED) {
if(TRACE) {
Tracing.writeString("VM [already disconnected]"); //$NON-NLS-1$
}
return;
}
if(TRACE) {
Tracing.writeString("VM [disconnecting]"); //$NON-NLS-1$
}
try {
if(threads != null) {
threads.clear();
}
if(scripts != null) {
scripts.clear();
}
this.session.dispose();
} finally {
state = DISCONNECTED;
}
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine#canUpdateBreakpoints()
*/
public boolean canUpdateBreakpoints() {
return true;
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine#updateBreakpoint(org.eclipse.wst.jsdt.debug.core.breakpoints.IJavaScriptBreakpoint)
*/
public void updateBreakpoint(IJavaScriptBreakpoint breakpoint) {
}
}