org.chromium.debug.core/src/org/chromium/debug/core/model/BreakpointRegistry.java
changeset 2 e4420d2515f1
equal deleted inserted replaced
1:ef76fc2ac88c 2:e4420d2515f1
       
     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 
       
     5 package org.chromium.debug.core.model;
       
     6 
       
     7 import java.util.Collection;
       
     8 import java.util.Collections;
       
     9 import java.util.HashMap;
       
    10 import java.util.HashSet;
       
    11 import java.util.LinkedList;
       
    12 import java.util.Map;
       
    13 
       
    14 import org.chromium.sdk.Breakpoint;
       
    15 import org.chromium.sdk.Script;
       
    16 
       
    17 /**
       
    18  * A registry of existing breakpoints associated with their script locations. It
       
    19  * is used to restore
       
    20  */
       
    21 public class BreakpointRegistry {
       
    22 
       
    23   /**
       
    24    * Script identifier for a breakpoint location.
       
    25    */
       
    26   public static class ScriptIdentifier {
       
    27     private final String name;
       
    28 
       
    29     private final long id;
       
    30 
       
    31     private final int startLine;
       
    32 
       
    33     private final int endLine;
       
    34 
       
    35     public static ScriptIdentifier forScript(Script script) {
       
    36       String name = script.getName();
       
    37       return new ScriptIdentifier(
       
    38           name,
       
    39           name != null ? -1 : script.getId(),
       
    40           script.getStartLine(),
       
    41           script.getEndLine());
       
    42     }
       
    43 
       
    44     private ScriptIdentifier(String name, long id, int startLine, int endLine) {
       
    45       this.name = name;
       
    46       this.id = id;
       
    47       this.startLine = startLine;
       
    48       this.endLine = endLine;
       
    49     }
       
    50 
       
    51     @Override
       
    52     public int hashCode() {
       
    53       final int prime = 31;
       
    54       int result = 1;
       
    55       result = prime * result + (int) (id ^ (id >>> 32));
       
    56       result = prime * result + ((name == null) ? 0 : name.hashCode());
       
    57       result = prime * result + 17 * startLine + 19 * endLine;
       
    58       return result;
       
    59     }
       
    60 
       
    61     @Override
       
    62     public boolean equals(Object obj) {
       
    63       if (!(obj instanceof ScriptIdentifier)) {
       
    64         return false;
       
    65       }
       
    66       ScriptIdentifier that = (ScriptIdentifier) obj;
       
    67       if (this.startLine != that.startLine || this.endLine != that.endLine) {
       
    68         return false;
       
    69       }
       
    70       if (name == null) {
       
    71         // an unnamed script, only id is known
       
    72         return that.name == null && this.id == that.id;
       
    73       }
       
    74       // a named script
       
    75       return this.name.equals(that.name);
       
    76     }
       
    77   }
       
    78 
       
    79   static class BreakpointLocation {
       
    80     private final ScriptIdentifier scriptIdentifier;
       
    81 
       
    82     private final int line;
       
    83 
       
    84     public BreakpointLocation(ScriptIdentifier scriptIdentifier, int line) {
       
    85       this.scriptIdentifier = scriptIdentifier;
       
    86       this.line = line;
       
    87     }
       
    88 
       
    89     public ScriptIdentifier getScriptIdentifier() {
       
    90       return scriptIdentifier;
       
    91     }
       
    92 
       
    93     public int getLine() {
       
    94       return line;
       
    95     }
       
    96 
       
    97     @Override
       
    98     public int hashCode() {
       
    99       final int prime = 31;
       
   100       int result = 1;
       
   101       result = prime * result + line;
       
   102       result = prime * result + ((scriptIdentifier == null)
       
   103           ? 0
       
   104           : scriptIdentifier.hashCode());
       
   105       return result;
       
   106     }
       
   107 
       
   108     @Override
       
   109     public boolean equals(Object obj) {
       
   110       if (!(obj instanceof BreakpointLocation)) {
       
   111         return false;
       
   112       }
       
   113       BreakpointLocation that = (BreakpointLocation) obj;
       
   114       return (this.line == that.line && eq(this.scriptIdentifier, that.scriptIdentifier));
       
   115     }
       
   116   }
       
   117 
       
   118   /**
       
   119    * A breakpoint accompanied by its line number in the corresponding enclosing
       
   120    * resource.
       
   121    */
       
   122   public static class BreakpointEntry {
       
   123     public final Breakpoint breakpoint;
       
   124 
       
   125     public final int line;
       
   126 
       
   127     private BreakpointEntry(Breakpoint breakpoint, int line) {
       
   128       this.breakpoint = breakpoint;
       
   129       this.line = line;
       
   130     }
       
   131 
       
   132     boolean isWithinScriptRange(Script script) {
       
   133       return line >= script.getStartLine() && line <= script.getEndLine();
       
   134     }
       
   135 
       
   136     @Override
       
   137     public int hashCode() {
       
   138       return 31 * line + 17 * breakpoint.hashCode();
       
   139     }
       
   140 
       
   141     @Override
       
   142     public boolean equals(Object obj) {
       
   143       if (!(obj instanceof BreakpointEntry)) {
       
   144         return false;
       
   145       }
       
   146       BreakpointEntry that = (BreakpointEntry) obj;
       
   147       return this.line == that.line && this.breakpoint.equals(that.breakpoint);
       
   148     }
       
   149   }
       
   150 
       
   151   private final Map<ScriptIdentifier, Collection<BreakpointEntry>> scriptIdToBreakpointEntries =
       
   152       new HashMap<ScriptIdentifier, Collection<BreakpointEntry>>();
       
   153 
       
   154   /**
       
   155    * Adds the given line breakpoint.
       
   156    *
       
   157    * @param script where the breakpoint is set
       
   158    * @param line (0-based, like in V8) in the script
       
   159    * @param breakpoint
       
   160    */
       
   161   public void add(Script script, int line, Breakpoint breakpoint) {
       
   162     ScriptIdentifier scriptId = ScriptIdentifier.forScript(script);
       
   163     Collection<BreakpointEntry> entries = scriptIdToBreakpointEntries.get(scriptId);
       
   164     if (entries == null) {
       
   165       entries = new HashSet<BreakpointEntry>();
       
   166       scriptIdToBreakpointEntries.put(scriptId, entries);
       
   167     }
       
   168     entries.add(new BreakpointEntry(breakpoint, line));
       
   169   }
       
   170 
       
   171   /**
       
   172    * Gets breakpoint entries for the given script. An empty collection for a
       
   173    * {@code null} script.
       
   174    *
       
   175    * @param script to extract the breakpoints for
       
   176    * @return the breakpoints that fall within the given script line range
       
   177    */
       
   178   public Collection<? extends BreakpointEntry> getBreakpointEntries(Script script) {
       
   179     if (script == null) {
       
   180       return Collections.emptySet();
       
   181     }
       
   182     Collection<BreakpointEntry> entries =
       
   183         scriptIdToBreakpointEntries.get(ScriptIdentifier.forScript(script));
       
   184     if (entries == null) {
       
   185       return Collections.emptySet();
       
   186     }
       
   187     Collection<BreakpointEntry> scriptBreakpoints = new LinkedList<BreakpointEntry>();
       
   188     // Linear search should work fairly well for a reasonable number of
       
   189     // breakpoints per script
       
   190     for (BreakpointEntry entry : entries) {
       
   191       if (entry.isWithinScriptRange(script)) {
       
   192         scriptBreakpoints.add(entry);
       
   193       }
       
   194     }
       
   195     return scriptBreakpoints;
       
   196   }
       
   197 
       
   198   /**
       
   199    * Removes the given line breakpoint in the given script. Does nothing for a
       
   200    * {@code null} script (which may be the case after a navigation + disconnect
       
   201    * when the resource referenced by the breakpoint marker is absent.)
       
   202    *
       
   203    * @param script where the breakpoint is set
       
   204    * @param line (0-based, like in V8) in the script
       
   205    * @param breakpoint
       
   206    */
       
   207   public void remove(Script script, int line, Breakpoint breakpoint) {
       
   208     if (script == null) {
       
   209       return;
       
   210     }
       
   211     ScriptIdentifier scriptId = ScriptIdentifier.forScript(script);
       
   212     Collection<BreakpointEntry> entries = scriptIdToBreakpointEntries.get(scriptId);
       
   213     if (entries == null) {
       
   214       return;
       
   215     }
       
   216     if (entries.size() == 1) {
       
   217       scriptIdToBreakpointEntries.remove(scriptId);
       
   218     } else {
       
   219       entries.remove(new BreakpointEntry(breakpoint, line));
       
   220     }
       
   221   }
       
   222 
       
   223   protected static boolean eq(Object left, Object right) {
       
   224     return left == right || (left != null && left.equals(right));
       
   225   }
       
   226 
       
   227 }