/* * Copyright (c) 2012, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.tools.debug.core.dartium; import com.google.dart.tools.debug.core.DartDebugCorePlugin; import com.google.dart.tools.debug.core.expr.IExpressionEvaluator; import com.google.dart.tools.debug.core.expr.WatchExpressionResult; import com.google.dart.tools.debug.core.util.DebuggerUtils; import com.google.dart.tools.debug.core.util.IDartDebugValue; import com.google.dart.tools.debug.core.webkit.WebkitCallback; import com.google.dart.tools.debug.core.webkit.WebkitPropertyDescriptor; import com.google.dart.tools.debug.core.webkit.WebkitRemoteObject; import com.google.dart.tools.debug.core.webkit.WebkitResult; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.model.IValue; import org.eclipse.debug.core.model.IVariable; import org.eclipse.debug.core.model.IWatchExpressionListener; import org.json.JSONObject; import java.io.IOException; import java.util.Collections; /** * The IValue implementation of Dartium Debug element. */ public class DartiumDebugValue extends DartiumDebugElement implements IValue, IDartDebugValue, IExpressionEvaluator { public static interface ValueCallback { public void detailComputed(String stringValue); } static DartiumDebugValue create(DartiumDebugTarget target, DartiumDebugVariable variable, WebkitRemoteObject value) { if (value == null) { return new DartiumEmptyValue(target, variable); } else if (value.isList()) { return new DartiumDebugIndexedValue(target, variable, value); } else { return new DartiumDebugValue(target, variable, value); } } private DartiumDebugVariable variable; protected WebkitRemoteObject value; protected VariableCollector variableCollector; protected DartiumDebugValue(DartiumDebugTarget target, DartiumDebugVariable variable, WebkitRemoteObject value) { super(target); this.variable = variable; this.value = value; } public void computeDetail(final ValueCallback callback) { // If the value is a primitive type, just return the display string. if (value.isPrimitive() || (variable != null && variable.isLibraryObject()) || !DartDebugCorePlugin.getPlugin().getInvokeToString()) { callback.detailComputed(getDisplayString()); return; } if (value.isNull()) { callback.detailComputed(getDisplayString()); return; } // Otherwise try and call the toString() method of the object. try { getConnection().getRuntime().callToString(value.getObjectId(), new WebkitCallback<String>() { @Override public void handleResult(WebkitResult<String> result) { if (result.isError()) { callback.detailComputed(result.getErrorMessage()); } else { callback.detailComputed(result.getResult()); } } }); } catch (IOException e) { DartDebugCorePlugin.logError(e); callback.detailComputed(null); } } @Override public void evaluateExpression(final String expression, final IWatchExpressionListener listener) { String exprText = expression; if (exprText.equals("this") || exprText.startsWith("this.")) { // do nothing } else if (exprText.startsWith("[")) { exprText = "this" + exprText; } String evalText = exprText; if (evalText.indexOf("return") == -1) { evalText = "return " + evalText + ";"; } evalText = "() {" + evalText + "}"; try { getConnection().getRuntime().callFunctionOn( value.getObjectId(), evalText, null, false, new WebkitCallback<WebkitRemoteObject>() { @Override public void handleResult(WebkitResult<WebkitRemoteObject> result) { if (result.isError()) { listener.watchEvaluationFinished(WatchExpressionResult.error( expression, result.getErrorMessage())); } else if (result.getResult().isUndefined()) { listener.watchEvaluationFinished(WatchExpressionResult.error( expression, "undefined")); } else if (result.getResult().isSyntaxError()) { evalOnGlobalContext(expression, result, listener); } else { listener.watchEvaluationFinished(WatchExpressionResult.value( expression, DartiumDebugValue.create(getTarget(), null, result.getResult()))); } } }); } catch (IOException e) { listener.watchEvaluationFinished(WatchExpressionResult.exception( expression, new DebugException(new Status( IStatus.ERROR, DartDebugCorePlugin.PLUGIN_ID, e.toString(), e)))); } } /** * Return the special '@staticFields' property on this object that represents the static fields. * * @return * @throws DebugException */ public IValue getClassValue() { if (variableCollector == null) { populate(); } try { for (WebkitPropertyDescriptor property : variableCollector.getWebkitProperties()) { if (WebkitPropertyDescriptor.STATIC_FIELDS_OBJECT.equals(property.getName())) { return DartiumDebugValue.create(getTarget(), null, property.getValue()); } } } catch (InterruptedException e) { } return null; } /** * @return a user-consumable string for the value object * @throws DebugException */ public String getDisplayString() { if (variable != null && variable.isLibraryObject()) { return ""; } if (value.isNull()) { return "null"; } if (value.isString()) { return DebuggerUtils.printString(value.getValue()); } if (isPrimitive()) { return value.getValue(); } if (isListValue()) { if (value.getClassName() != null) { return value.getClassName() + "[" + getListLength() + "]"; } else { return "List[" + getListLength() + "]"; } } return value.getDescription(); } @Override public String getId() { if (value == null || value.isNull()) { return null; } if (!value.isPrimitive() || value.isString()) { return parseObjectId(value.getObjectId()); } else { return null; } } public IValue getLibraryValue() { if (variableCollector == null) { populate(); } try { for (WebkitPropertyDescriptor property : variableCollector.getWebkitProperties()) { if (WebkitPropertyDescriptor.LIBRARY_OBJECT.equals(property.getName())) { return DartiumDebugValue.create(getTarget(), null, property.getValue()); } } } catch (InterruptedException e) { } return null; } @Override public int getListLength() { return value.getListLength(getConnection()); } @Override public String getReferenceTypeName() { return value.getClassName(); } @Override public String getValueString() throws DebugException { try { return getDisplayString(); } catch (Throwable t) { throw createDebugException(t); } } @Override public IVariable[] getVariables() throws DebugException { try { if (variableCollector == null) { populate(); } return variableCollector.getVariables(); } catch (Throwable t) { throw createDebugException(t); } } @Override public boolean hasVariables() throws DebugException { try { return value.hasObjectId() && !value.isNull() && !value.isPrimitive(); } catch (Throwable t) { throw createDebugException(t); } } @Override public boolean isAllocated() throws DebugException { return true; } @Override public boolean isListValue() { return false; } @Override public boolean isNull() { return value.isNull(); } @Override public boolean isPrimitive() { return value.isPrimitive(); } @Override public void reset() { variableCollector = null; fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CONTENT)); } protected void populate() { if (value.hasObjectId()) { variableCollector = VariableCollector.createCollector( getTarget(), variable, Collections.singletonList(value)); } else { variableCollector = VariableCollector.empty(); } } private void evalOnGlobalContext(final String expression, final WebkitResult<WebkitRemoteObject> originalResult, final IWatchExpressionListener listener) { try { getConnection().getRuntime().evaluate( expression, null, false, new WebkitCallback<WebkitRemoteObject>() { @Override public void handleResult(WebkitResult<WebkitRemoteObject> result) { if (result.isError()) { listener.watchEvaluationFinished(WatchExpressionResult.error( expression, originalResult.getErrorMessage())); } else if (result.getResult().isSyntaxError()) { listener.watchEvaluationFinished(WatchExpressionResult.value( expression, DartiumDebugValue.create(getTarget(), null, originalResult.getResult()))); } else { listener.watchEvaluationFinished(WatchExpressionResult.value( expression, DartiumDebugValue.create(getTarget(), null, result.getResult()))); } } }); } catch (IOException e) { listener.watchEvaluationFinished(WatchExpressionResult.exception( expression, new DebugException(new Status( IStatus.ERROR, DartDebugCorePlugin.PLUGIN_ID, e.toString(), e)))); } } private String parseObjectId(String objectId) { if (objectId == null) { return null; } try { JSONObject obj = new JSONObject(objectId); return obj.getString("id"); } catch (Throwable t) { return null; } } }