Java tutorial
// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package org.chromium.sdk.internal.v8native.value; import java.util.EnumSet; import java.util.Set; import org.chromium.sdk.JsValue; import org.chromium.sdk.JsValue.Type; import org.chromium.sdk.internal.v8native.V8Helper; import org.chromium.sdk.internal.v8native.protocol.input.data.FunctionValueHandle; import org.chromium.sdk.internal.v8native.protocol.input.data.ObjectValueHandle; import org.chromium.sdk.internal.v8native.protocol.input.data.RefWithDisplayData; import org.chromium.sdk.internal.v8native.protocol.input.data.ValueHandle; import org.chromium.sdk.internal.v8native.value.LoadableString.Factory; import org.json.simple.JSONObject; import org.json.simple.JSONValue; import org.json.simple.parser.JSONParser; /** * A representation of a datum (value) in the remote JavaScript VM. The class must be immutable. * When additional (or more recent) data arrives, new instance should be put into * {@link ValueLoader} map. */ public abstract class ValueMirror { /** * Merges to {@link ValueMirror}s into one. Since {@link ValueMirror} is immutable * this is the right way to gather data. * @return possibly new {@link ValueMirror}, or any of the old ones, making a preference for * 'base' parameter. */ static ValueMirror merge(ValueMirror base, ValueMirror alternative) { if (base.hasProperties()) { if (alternative.hasProperties()) { // Fall through. } else { return base; } } else { if (alternative.hasProperties()) { return alternative; } else { // Fall through. } } int lenDiff = base.getStringLength() - alternative.getStringLength(); if (lenDiff < 0) { return alternative; } else { return base; } } /** * Tries to construct the full {@link ValueMirror} from V8 debugger display data (preview) * if it's possible. */ public static ValueMirror createIfSure(final RefWithDisplayData refWithDisplayData) { long ref = refWithDisplayData.ref(); final Type type = V8Helper.calculateType(refWithDisplayData.type(), refWithDisplayData.className(), false); if (!TYPES_WITH_ACCURATE_DISPLAY.contains(type)) { return null; } return new ValueMirror(ref) { @Override public Type getType() { return type; } @Override public String getClassName() { return refWithDisplayData.className(); } @Override public LoadableString getStringValue() { // try another format Object valueObj = refWithDisplayData.value(); String valueStr; if (valueObj == null) { valueStr = refWithDisplayData.type(); // e.g. "undefined" } else { // Works poorly for strings, but we do not allow strings here. valueStr = JSONValue.toJSONString(valueObj); if (type == Type.TYPE_NUMBER && valueStr.lastIndexOf('E') != -1) { // Make accurate rendering of what V8 does. valueStr = valueStr.toLowerCase(); } } return new LoadableString.Immutable(valueStr); } @Override public boolean hasProperties() { return false; } @Override public SubpropertiesMirror getProperties() { return null; } }; } /** * Lists types that we can accept in 'display data' form (preview property format). * Object types are not here because we cannot get either proper class name or * string representation. String isn't here because it may be truncated and we * have no clue about it (well, we can check that it ends like truncated string * ends, but it's not too robust). */ private static final Set<Type> TYPES_WITH_ACCURATE_DISPLAY = EnumSet.of(Type.TYPE_NUMBER, Type.TYPE_BOOLEAN, Type.TYPE_NULL, Type.TYPE_UNDEFINED); /** * Constructs a ValueMirror given a V8 debugger object specification. * @param valueHandle containing the object specification from the V8 debugger */ public static ValueMirror create(final ValueHandle valueHandle, final Factory factory) { Long ref = valueHandle.handle(); final Type type = V8Helper.calculateType(valueHandle.type(), valueHandle.className(), true); return new ValueMirror(ref) { @Override public Type getType() { return type; } @Override public LoadableString getStringValue() { return V8Helper.createLoadableString(valueHandle, factory); } @Override public SubpropertiesMirror getProperties() { ObjectValueHandle objectValueHandle = valueHandle.asObject(); if (objectValueHandle == null) { return SubpropertiesMirror.EMPTY; } int refId = (int) valueHandle.handle(); SubpropertiesMirror subpropertiesMirror; if (type == Type.TYPE_FUNCTION) { FunctionValueHandle functionValueHandle = objectValueHandle.asFunction(); subpropertiesMirror = new SubpropertiesMirror.FunctionValueBased(functionValueHandle); } else { subpropertiesMirror = new SubpropertiesMirror.ObjectValueBased(objectValueHandle); } return subpropertiesMirror; } @Override public boolean hasProperties() { return true; } @Override public String getClassName() { return valueHandle.className(); } }; } public static ValueMirror create(Long ref, final Type type, final String className, final LoadableString loadableString, final SubpropertiesMirror subpropertiesMirror) { return new ValueMirror(ref) { @Override public JsValue.Type getType() { return type; } @Override public String getClassName() { return className; } @Override public LoadableString getStringValue() { return loadableString; } @Override public SubpropertiesMirror getProperties() { return subpropertiesMirror; } @Override public boolean hasProperties() { return getProperties() != null; } }; } private final Long ref; protected ValueMirror(Long ref) { assert ref != null; this.ref = ref; } public abstract JsValue.Type getType(); public abstract SubpropertiesMirror getProperties(); public Long getRef() { return ref; } public abstract LoadableString getStringValue(); public abstract String getClassName(); public abstract boolean hasProperties(); int getStringLength() { LoadableString loadableString = getStringValue(); if (loadableString == null) { return 0; } return loadableString.getCurrentString().length(); } }