blob: 96c2e7c01829581dc199b3b6670566ac9e6284e4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2010 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
*******************************************************************************/
package org.eclipse.e4.languages.javascript.jsdi.rhino;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.e4.languages.javascript.debug.connect.DisconnectException;
import org.eclipse.e4.languages.javascript.debug.connect.JSONConstants;
import org.eclipse.e4.languages.javascript.debug.connect.Request;
import org.eclipse.e4.languages.javascript.debug.connect.Response;
import org.eclipse.e4.languages.javascript.debug.connect.TimeoutException;
import org.eclipse.e4.languages.javascript.jsdi.Location;
import org.eclipse.e4.languages.javascript.jsdi.StackFrameReference;
import org.eclipse.e4.languages.javascript.jsdi.Value;
import org.eclipse.e4.languages.javascript.jsdi.Variable;
/**
* Rhino implementation of {@link StackFrameReference}
*
* @see Location
* @see MirrorImpl
* @see StackFrameReference
* @since 1.0
*/
public class StackFrameReferenceImpl extends MirrorImpl implements StackFrameReference {
private final Number frameId;
private final Number threadId;
private final Number contextId;
private final Number ref;
private final Location location;
private List variables;
private VariableImpl thisVariable;
private HashMap cache = new HashMap();
/**
* Constructor
*
* @param vm
* @param jsonFrame
*/
public StackFrameReferenceImpl(VirtualMachineImpl vm, Map jsonFrame) {
super(vm);
this.threadId = (Number) jsonFrame.get(JSONConstants.THREAD_ID);
this.frameId = (Number) jsonFrame.get(JSONConstants.FRAME_ID);
this.contextId = (Number) jsonFrame.get(JSONConstants.CONTEXT_ID);
this.ref = (Number) jsonFrame.get(JSONConstants.REF);
Long scriptId = new Long(((Number) jsonFrame.get(JSONConstants.SCRIPT_ID)).longValue());
ScriptReferenceImpl script = vm.script(scriptId);
String function = (String) jsonFrame.get(JSONConstants.FUNCTION);
if (function != null) {
this.location = script.functionLocation(function);
} else {
Number line = (Number) jsonFrame.get(JSONConstants.LINE);
Location lineLocation = script.lineLocation(line.intValue());
this.location = lineLocation != null ? lineLocation : new LocationImpl(vm, function, line.intValue(), script);
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.e4.languages.javascript.jsdi.StackFrame#evaluate(java.lang .String)
*/
public Value evaluate(String expression) {
Request request = new Request(JSONConstants.EVALUATE);
request.getArguments().put(JSONConstants.THREAD_ID, threadId);
request.getArguments().put(JSONConstants.FRAME_ID, frameId);
request.getArguments().put(JSONConstants.EXPRESSION, expression);
try {
Response response = vm.sendRequest(request, 30000);
return createValue(response.getBody(), true);
} catch (DisconnectException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
return null;
}
/**
* Utility method to look up the {@link Value} with the given reference id <br>
* or <code>null</code> if there is no {@link Value} with the given id
*
* @param ref
* @return the {@link Value} or <code>null</code>
*/
public Value lookupValue(Number ref) {
Value value = (Value) this.cache.get(ref);
if (value == null) {
Request request = new Request(JSONConstants.LOOKUP);
request.getArguments().put(JSONConstants.THREAD_ID, threadId);
request.getArguments().put(JSONConstants.FRAME_ID, frameId);
request.getArguments().put(JSONConstants.HANDLE, ref);
try {
Response response = vm.sendRequest(request, 30000);
value = createValue(response.getBody(), false);
this.cache.put(ref, value);
return value;
} catch (DisconnectException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
return value;
}
/**
* Creates a new type value for the given type description in the map
*
* @param body
* @param iseval
* @return the new type
* @throws IllegalStateException
* if the type description in the map is unknown
*/
private Value createValue(Map body, boolean iseval) throws IllegalStateException {
Map value = (Map) body.get((iseval ? JSONConstants.EVALUATE : JSONConstants.LOOKUP));
String type = (String) value.get(JSONConstants.TYPE);
// "undefined", "null", "boolean", "number", "string", "object",
// "function"
if (type.equals(JSONConstants.UNDEFINED)) {
return vm.undefinedValue;
} else if (type.equals(JSONConstants.NULL)) {
return vm.nullValue;
} else if (type.equals(JSONConstants.BOOLEAN)) {
return new BooleanValueImpl(vm, value);
} else if (type.equals(JSONConstants.NUMBER)) {
return new NumberValueImpl(vm, value);
} else if (type.equals(JSONConstants.STRING)) {
return new StringValueImpl(vm, value);
} else if (type.equals(JSONConstants.OBJECT)) {
return new ObjectReferenceImpl(vm, value, this);
} else if (type.equals(JSONConstants.FUNCTION)) {
return new FunctionReferenceImpl(vm, value, this);
} else if (type.equals(JSONConstants.ARRAY)) {
return new ArrayReferenceImpl(vm, value, this);
}
throw new IllegalStateException();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.e4.languages.javascript.jsdi.StackFrame#location()
*/
public Location location() {
return location;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.e4.languages.javascript.jsdi.StackFrame#thisObject()
*/
public synchronized Variable thisObject() {
initializeVariables();
return thisVariable;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.e4.languages.javascript.jsdi.StackFrame#variables()
*/
public synchronized List variables() {
initializeVariables();
return variables;
}
/**
* Initializes and caches the live set of variables
*/
private void initializeVariables() {
if (variables != null) {
return;
}
Request request = new Request(JSONConstants.LOOKUP);
request.getArguments().put(JSONConstants.THREAD_ID, threadId);
request.getArguments().put(JSONConstants.FRAME_ID, frameId);
request.getArguments().put(JSONConstants.HANDLE, ref);
try {
Response response = vm.sendRequest(request, 30000);
Map lookup = (Map) response.getBody().get(JSONConstants.LOOKUP);
List properties = (List) lookup.get(JSONConstants.PROPERTIES);
variables = new ArrayList();
for (Iterator iterator = properties.iterator(); iterator.hasNext();) {
Map property = (Map) iterator.next();
String name = (String) property.get(JSONConstants.NAME);
Number ref = (Number) property.get(JSONConstants.REF);
VariableImpl variable = new VariableImpl(vm, this, name, ref);
if (name.equals(JSONConstants.THIS))
thisVariable = variable;
else
variables.add(variable);
}
} catch (DisconnectException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
/**
* Returns if this stack frame is visible
*
* @param variable
* @return true if this frame is visible, false otherwise
*/
public synchronized boolean isVisible(VariableImpl variable) {
return variables != null && (thisVariable == variable || variables.contains(variable));
}
/**
* @return the context id for this frame
*/
public Number getContextId() {
return contextId;
}
}