org.chromium.sdk/src/org/chromium/sdk/internal/tools/v8/BreakpointManager.java
changeset 355 8726e95bcbba
parent 276 f2f4a1259de8
equal deleted inserted replaced
354:0bceeb415e7f 355:8726e95bcbba
       
     1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
       
     2 // Use of this source code is governed by a BSD-style license that can be
       
     3 // found in the LICENSE file.
       
     4 
     1 package org.chromium.sdk.internal.tools.v8;
     5 package org.chromium.sdk.internal.tools.v8;
     2 
     6 
       
     7 import java.util.Collections;
     3 import java.util.HashMap;
     8 import java.util.HashMap;
       
     9 import java.util.Iterator;
       
    10 import java.util.List;
     4 import java.util.Map;
    11 import java.util.Map;
     5 
    12 
     6 import org.chromium.sdk.Breakpoint;
    13 import org.chromium.sdk.Breakpoint;
     7 import org.chromium.sdk.BrowserTab;
    14 import org.chromium.sdk.JavascriptVm;
       
    15 import org.chromium.sdk.SyncCallback;
     8 import org.chromium.sdk.JavascriptVm.BreakpointCallback;
    16 import org.chromium.sdk.JavascriptVm.BreakpointCallback;
       
    17 import org.chromium.sdk.JavascriptVm.ListBreakpointsCallback;
     9 import org.chromium.sdk.internal.DebugSession;
    18 import org.chromium.sdk.internal.DebugSession;
    10 import org.chromium.sdk.internal.protocol.BreakpointBody;
    19 import org.chromium.sdk.internal.protocol.BreakpointBody;
       
    20 import org.chromium.sdk.internal.protocol.CommandResponseBody;
       
    21 import org.chromium.sdk.internal.protocol.ListBreakpointsBody;
    11 import org.chromium.sdk.internal.protocol.SuccessCommandResponse;
    22 import org.chromium.sdk.internal.protocol.SuccessCommandResponse;
       
    23 import org.chromium.sdk.internal.protocol.data.BreakpointInfo;
    12 import org.chromium.sdk.internal.protocolparser.JsonProtocolParseException;
    24 import org.chromium.sdk.internal.protocolparser.JsonProtocolParseException;
    13 import org.chromium.sdk.internal.tools.v8.request.DebuggerMessageFactory;
    25 import org.chromium.sdk.internal.tools.v8.request.DebuggerMessageFactory;
       
    26 import org.chromium.sdk.internal.tools.v8.request.ListBreakpointsMessage;
    14 
    27 
    15 public class BreakpointManager {
    28 public class BreakpointManager {
    16   /**
    29   /**
    17    * This map shall contain only breakpoints with valid IDs.
    30    * This map shall contain only breakpoints with valid IDs.
    18    */
    31    */
    19   private final Map<Long, Breakpoint> idToBreakpoint = new HashMap<Long, Breakpoint>();
    32   private final Map<Long, BreakpointImpl> idToBreakpoint = new HashMap<Long, BreakpointImpl>();
    20 
    33 
    21   private final DebugSession debugSession;
    34   private final DebugSession debugSession;
    22 
    35 
    23   public BreakpointManager(DebugSession debugSession) {
    36   public BreakpointManager(DebugSession debugSession) {
    24     this.debugSession = debugSession;
    37     this.debugSession = debugSession;
    25   }
    38   }
    26 
    39 
    27   public void setBreakpoint(final Breakpoint.Type type, String target, int line, int position,
    40   public void setBreakpoint(final Breakpoint.Type type, final String target,
    28       final boolean enabled, final String condition, final int ignoreCount,
    41       final int line, int position, final boolean enabled, final String condition,
    29       final BrowserTab.BreakpointCallback callback) {
    42       final int ignoreCount, final JavascriptVm.BreakpointCallback callback,
       
    43       SyncCallback syncCallback) {
       
    44 
       
    45     final String scriptName;
       
    46     final Long scriptId;
       
    47     Object targetObject;
       
    48     if (type == Breakpoint.Type.SCRIPT_ID) {
       
    49       scriptName = null;
       
    50       scriptId = Long.parseLong(target);
       
    51       targetObject = scriptId;
       
    52     } else if (type == Breakpoint.Type.SCRIPT_NAME) {
       
    53       scriptName = target;
       
    54       scriptId = null;
       
    55       targetObject = scriptName;
       
    56     } else {
       
    57       throw new IllegalArgumentException("Unsupported breakpoint type " + type);
       
    58     }
       
    59 
    30     debugSession.sendMessageAsync(
    60     debugSession.sendMessageAsync(
    31         DebuggerMessageFactory.setBreakpoint(type, target, toNullableInteger(line),
    61         DebuggerMessageFactory.setBreakpoint(type, targetObject, toNullableInteger(line),
    32             toNullableInteger(position), enabled, condition,
    62             toNullableInteger(position), enabled, condition,
    33             toNullableInteger(ignoreCount)),
    63             toNullableInteger(ignoreCount)),
    34         true,
    64         true,
    35         callback == null
    65         callback == null
    36             ? null
    66             ? null
    44                   throw new RuntimeException(e);
    74                   throw new RuntimeException(e);
    45                 }
    75                 }
    46                 long id = body.getBreakpoint();
    76                 long id = body.getBreakpoint();
    47 
    77 
    48                 final BreakpointImpl breakpoint =
    78                 final BreakpointImpl breakpoint =
    49                     new BreakpointImpl(type, id, enabled, ignoreCount,
    79                     new BreakpointImpl(type, id, scriptName, scriptId, line, enabled, ignoreCount,
    50                         condition, BreakpointManager.this);
    80                         condition, BreakpointManager.this);
    51 
    81 
    52                 callback.success(breakpoint);
    82                 callback.success(breakpoint);
    53                 idToBreakpoint.put(breakpoint.getId(), breakpoint);
    83                 idToBreakpoint.put(breakpoint.getId(), breakpoint);
    54               }
    84               }
    57                 if (callback != null) {
    87                 if (callback != null) {
    58                   callback.failure(message);
    88                   callback.failure(message);
    59                 }
    89                 }
    60               }
    90               }
    61             },
    91             },
    62             null);
    92             syncCallback);
    63   }
    93   }
    64 
    94 
    65   public Breakpoint getBreakpoint(Long id) {
    95   public Breakpoint getBreakpoint(Long id) {
    66     return idToBreakpoint.get(id);
    96     return idToBreakpoint.get(id);
    67   }
    97   }
    68 
    98 
    69   public void clearBreakpoint(
    99   public void clearBreakpoint(
    70       final BreakpointImpl breakpointImpl, final BreakpointCallback callback) {
   100       final BreakpointImpl breakpointImpl, final BreakpointCallback callback,
       
   101       SyncCallback syncCallback) {
    71     long id = breakpointImpl.getId();
   102     long id = breakpointImpl.getId();
    72     if (id == Breakpoint.INVALID_ID) {
   103     if (id == Breakpoint.INVALID_ID) {
    73       return;
   104       return;
    74     }
   105     }
    75     idToBreakpoint.remove(id);
   106     idToBreakpoint.remove(id);
    88             if (callback != null) {
   119             if (callback != null) {
    89               callback.failure(message);
   120               callback.failure(message);
    90             }
   121             }
    91           }
   122           }
    92         },
   123         },
    93         null);
   124         syncCallback);
    94   }
   125   }
    95 
   126 
    96   public void changeBreakpoint(final BreakpointImpl breakpointImpl,
   127   public void changeBreakpoint(final BreakpointImpl breakpointImpl,
    97       final BreakpointCallback callback) {
   128       final BreakpointCallback callback, SyncCallback syncCallback) {
    98     debugSession.sendMessageAsync(
   129     debugSession.sendMessageAsync(
    99         DebuggerMessageFactory.changeBreakpoint(breakpointImpl),
   130         DebuggerMessageFactory.changeBreakpoint(breakpointImpl),
   100         true,
   131         true,
   101         new V8CommandCallbackBase() {
   132         new V8CommandCallbackBase() {
   102           @Override
   133           @Override
   110             if (callback != null) {
   141             if (callback != null) {
   111               callback.failure(message);
   142               callback.failure(message);
   112             }
   143             }
   113           }
   144           }
   114         },
   145         },
   115         null);
   146         syncCallback);
       
   147   }
       
   148 
       
   149   /**
       
   150    * Reads a list of breakpoints from remote and updates local instances and the map.
       
   151    */
       
   152   public void reloadBreakpoints(final ListBreakpointsCallback callback, SyncCallback syncCallback) {
       
   153     V8CommandCallbackBase v8Callback = new V8CommandCallbackBase() {
       
   154       @Override
       
   155       public void failure(String message) {
       
   156         callback.failure(new Exception(message));
       
   157       }
       
   158       @Override
       
   159       public void success(SuccessCommandResponse successResponse) {
       
   160         CommandResponseBody body = successResponse.getBody();
       
   161         ListBreakpointsBody listBreakpointsBody;
       
   162         try {
       
   163           listBreakpointsBody = body.asListBreakpointsBody();
       
   164         } catch (JsonProtocolParseException e) {
       
   165           callback.failure(new Exception("Failed to read server response", e));
       
   166           return;
       
   167         }
       
   168         List<BreakpointInfo> infos = listBreakpointsBody.breakpoints();
       
   169         try {
       
   170           syncBreakpoints(infos);
       
   171         } catch (RuntimeException e) {
       
   172           callback.failure(new Exception("Failed to read server response", e));
       
   173           return;
       
   174         }
       
   175         callback.success(Collections.unmodifiableCollection(idToBreakpoint.values()));
       
   176       }
       
   177     };
       
   178     debugSession.sendMessageAsync(new ListBreakpointsMessage(), true, v8Callback, syncCallback);
   116   }
   179   }
   117 
   180 
   118   private static Integer toNullableInteger(int value) {
   181   private static Integer toNullableInteger(int value) {
   119     return value == Breakpoint.EMPTY_VALUE
   182     return value == Breakpoint.EMPTY_VALUE
   120         ? null
   183         ? null
   121         : value;
   184         : value;
   122   }
   185   }
       
   186 
       
   187   private void syncBreakpoints(List<BreakpointInfo> infoList) {
       
   188     Map<Long, BreakpointImpl> actualBreakpoints = new HashMap<Long, BreakpointImpl>();
       
   189     // Wrap all loaded BreakpointInfo as BreakpointImpl, possibly reusing old instances.
       
   190     // Also check that all breakpoint id's in loaded list are unique.
       
   191     for (BreakpointInfo info : infoList) {
       
   192       if (info.type() == BreakpointInfo.Type.function) {
       
   193         // We does not support function type breakpoints and ignore them.
       
   194         continue;
       
   195       }
       
   196       BreakpointImpl breakpoint = idToBreakpoint.get(info.number());
       
   197       if (breakpoint == null) {
       
   198         breakpoint = new BreakpointImpl(info, this);
       
   199       } else {
       
   200         breakpoint.updateFromRemote(info);
       
   201       }
       
   202       Object conflict = actualBreakpoints.put(info.number(), breakpoint);
       
   203       if (conflict != null) {
       
   204         throw new RuntimeException("Duplicated breakpoint number " + info.number());
       
   205       }
       
   206     }
       
   207 
       
   208     // Remove all obsolete breakpoints from the map.
       
   209     for (Iterator<Long> it = idToBreakpoint.keySet().iterator(); it.hasNext(); ) {
       
   210       Long id = it.next();
       
   211       if (!actualBreakpoints.containsKey(id)) {
       
   212         it.remove();
       
   213       }
       
   214     }
       
   215 
       
   216     // Add breakpoints that are not in the main map yet.
       
   217     for (BreakpointImpl breakpoint : actualBreakpoints.values()) {
       
   218       if (!idToBreakpoint.containsKey(breakpoint.getId())) {
       
   219         idToBreakpoint.put(breakpoint.getId(), breakpoint);
       
   220       }
       
   221     }
       
   222   }
   123 }
   223 }