// Copyright (c) 2009 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.tools.v8;
import org.chromium.sdk.Breakpoint;
import org.chromium.sdk.JavascriptVm;
import org.chromium.sdk.SyncCallback;
import org.chromium.sdk.internal.protocol.data.BreakpointInfo;
/**
* A generic implementation of the Breakpoint interface.
*/
public class BreakpointImpl implements Breakpoint {
/**
* The breakpoint type.
*/
private final Type type;
/**
* The breakpoint id as reported by the JavaScript VM.
*/
private long id;
/**
* The corresponding script name as reported by the JavaScript VM. May be null.
*/
private String scriptName;
/**
* The corresponding script id as reported by the JavaScript VM. May be null.
*/
private Long scriptId;
/**
* Breakpoint line number. May become invalidated by LiveEdit actions.
*/
private long lineNumber;
/**
* Whether the breakpoint is enabled.
*/
private boolean isEnabled;
/**
* The number of times the breakpoint should be ignored
* by the JavaScript VM until it fires.
*/
private int ignoreCount;
/**
* The breakpoint condition (plain JavaScript) that should be {@code true}
* for the breakpoint to fire.
*/
private String condition;
/**
* The breakpoint manager that manages this breakpoint.
*/
private final BreakpointManager breakpointManager;
/**
* Whether the breakpoint data have changed with respect
* to the JavaScript VM data.
*/
private volatile boolean isDirty = false;
public BreakpointImpl(Type type, long id, String scriptName, Long scriptId, long lineNumber,
boolean enabled, int ignoreCount, String condition, BreakpointManager breakpointManager) {
this.type = type;
this.scriptName = scriptName;
this.scriptId = scriptId;
this.id = id;
this.isEnabled = enabled;
this.ignoreCount = ignoreCount;
this.condition = condition;
this.lineNumber = lineNumber;
this.breakpointManager = breakpointManager;
}
public BreakpointImpl(BreakpointInfo info, BreakpointManager breakpointManager) {
this.type = getType(info);
this.id = info.number();
this.breakpointManager = breakpointManager;
updateFromRemote(info);
}
public void updateFromRemote(BreakpointInfo info) {
if (this.type != getType(info)) {
throw new IllegalArgumentException();
}
if (this.id != info.number()) {
throw new IllegalArgumentException();
}
this.lineNumber = info.line();
this.isEnabled = info.active();
this.ignoreCount = (int) info.ignoreCount();
this.condition = info.condition();
this.scriptName = info.script_name();
this.scriptId = info.script_id();
}
public boolean isEnabled() {
return isEnabled;
}
public Type getType() {
return type;
}
public long getId() {
return id;
}
public String getScriptName() {
return scriptName;
}
public Long getScriptId() {
return scriptId;
}
public int getIgnoreCount() {
return ignoreCount;
}
public String getCondition() {
return condition;
}
public long getLineNumber() {
return lineNumber;
}
public void setEnabled(boolean enabled) {
if (this.isEnabled != enabled) {
setDirty(true);
}
this.isEnabled = enabled;
}
public void setIgnoreCount(int ignoreCount) {
if (this.ignoreCount != ignoreCount) {
setDirty(true);
}
this.ignoreCount = ignoreCount;
}
public void setCondition(String condition) {
if (!eq(this.condition, condition)) {
setDirty(true);
}
this.condition = condition;
}
private boolean eq(Object left, Object right) {
return left == right || (left != null && left.equals(right));
}
public void clear(JavascriptVm.BreakpointCallback callback, SyncCallback syncCallback) {
breakpointManager.clearBreakpoint(this, callback, syncCallback);
// The order must be preserved, otherwise the breakpointProcessor will not be able
// to identify the original breakpoint ID.
this.id = INVALID_ID;
}
public void flush(final JavascriptVm.BreakpointCallback callback, SyncCallback syncCallback) {
if (!isDirty()) {
if (callback != null) {
callback.success(this);
}
return;
}
breakpointManager.changeBreakpoint(this, callback, syncCallback);
setDirty(false);
}
private void setDirty(boolean isDirty) {
this.isDirty = isDirty;
}
private boolean isDirty() {
return isDirty;
}
private static Type getType(BreakpointInfo info) {
BreakpointInfo.Type infoType = info.type();
switch (infoType) {
case scriptId: return Type.SCRIPT_ID;
case scriptName: return Type.SCRIPT_NAME;
case function: return Type.FUNCTION;
}
throw new RuntimeException("Unknown type: " + infoType);
}
}