BreakpointManager.loadState: avoid exception from TaskVcsTest tearDown
[idea/community.git] / java / debugger / impl / src / com / intellij / debugger / ui / breakpoints / BreakpointManager.java
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*
18  * Class BreakpointManager
19  * @author Jeka
20  */
21 package com.intellij.debugger.ui.breakpoints;
22
23 import com.intellij.debugger.DebuggerBundle;
24 import com.intellij.debugger.DebuggerInvocationUtil;
25 import com.intellij.debugger.engine.BreakpointStepMethodFilter;
26 import com.intellij.debugger.engine.DebugProcessImpl;
27 import com.intellij.debugger.engine.requests.RequestManagerImpl;
28 import com.intellij.debugger.impl.DebuggerContextImpl;
29 import com.intellij.debugger.impl.DebuggerContextListener;
30 import com.intellij.debugger.impl.DebuggerManagerImpl;
31 import com.intellij.debugger.impl.DebuggerSession;
32 import com.intellij.debugger.ui.JavaDebuggerSupport;
33 import com.intellij.openapi.application.ApplicationManager;
34 import com.intellij.openapi.diagnostic.Logger;
35 import com.intellij.openapi.editor.Document;
36 import com.intellij.openapi.editor.Editor;
37 import com.intellij.openapi.editor.markup.GutterIconRenderer;
38 import com.intellij.openapi.editor.markup.RangeHighlighter;
39 import com.intellij.openapi.fileEditor.FileDocumentManager;
40 import com.intellij.openapi.project.Project;
41 import com.intellij.openapi.startup.StartupManager;
42 import com.intellij.openapi.ui.MessageType;
43 import com.intellij.openapi.util.Comparing;
44 import com.intellij.openapi.util.Computable;
45 import com.intellij.openapi.util.InvalidDataException;
46 import com.intellij.openapi.util.Key;
47 import com.intellij.openapi.vfs.VirtualFile;
48 import com.intellij.openapi.vfs.VirtualFileManager;
49 import com.intellij.psi.PsiField;
50 import com.intellij.util.containers.ContainerUtil;
51 import com.intellij.xdebugger.XDebuggerManager;
52 import com.intellij.xdebugger.XDebuggerUtil;
53 import com.intellij.xdebugger.XSourcePosition;
54 import com.intellij.xdebugger.breakpoints.*;
55 import com.intellij.xdebugger.impl.DebuggerSupport;
56 import com.intellij.xdebugger.impl.XDebugSessionImpl;
57 import com.intellij.xdebugger.impl.breakpoints.XBreakpointBase;
58 import com.intellij.xdebugger.impl.breakpoints.XBreakpointManagerImpl;
59 import com.intellij.xdebugger.impl.breakpoints.XDependentBreakpointManager;
60 import com.intellij.xdebugger.impl.breakpoints.XLineBreakpointImpl;
61 import com.sun.jdi.InternalException;
62 import com.sun.jdi.ThreadReference;
63 import com.sun.jdi.request.*;
64 import gnu.trove.THashMap;
65 import org.jdom.Element;
66 import org.jetbrains.annotations.NonNls;
67 import org.jetbrains.annotations.NotNull;
68 import org.jetbrains.annotations.Nullable;
69 import org.jetbrains.java.debugger.breakpoints.properties.JavaExceptionBreakpointProperties;
70
71 import javax.swing.*;
72 import java.util.LinkedHashMap;
73 import java.util.List;
74 import java.util.Map;
75
76 public class BreakpointManager {
77   private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.breakpoints.BreakpointManager");
78
79   @NonNls private static final String MASTER_BREAKPOINT_TAG_NAME = "master_breakpoint";
80   @NonNls private static final String SLAVE_BREAKPOINT_TAG_NAME = "slave_breakpoint";
81   @NonNls private static final String DEFAULT_SUSPEND_POLICY_ATTRIBUTE_NAME = "default_suspend_policy";
82   @NonNls private static final String DEFAULT_CONDITION_STATE_ATTRIBUTE_NAME = "default_condition_enabled";
83
84   @NonNls private static final String RULES_GROUP_NAME = "breakpoint_rules";
85   private static final String CONVERTED_PARAM = "converted";
86
87   private final Project myProject;
88   private final Map<String, String> myUIProperties = new LinkedHashMap<>();
89
90   private final StartupManager myStartupManager;
91
92   public BreakpointManager(@NotNull Project project, @NotNull StartupManager startupManager, @NotNull DebuggerManagerImpl debuggerManager) {
93     myProject = project;
94     myStartupManager = startupManager;
95     debuggerManager.getContextManager().addListener(new DebuggerContextListener() {
96       private DebuggerSession myPreviousSession;
97
98       @Override
99       public void changeEvent(@NotNull DebuggerContextImpl newContext, DebuggerSession.Event event) {
100         if (event == DebuggerSession.Event.ATTACHED) {
101           for (XBreakpoint breakpoint : getXBreakpointManager().getAllBreakpoints()) {
102             if (checkAndNotifyPossiblySlowBreakpoint(breakpoint)) break;
103           }
104         }
105         if (newContext.getDebuggerSession() != myPreviousSession || event == DebuggerSession.Event.DETACHED) {
106           updateBreakpointsUI();
107           myPreviousSession = newContext.getDebuggerSession();
108         }
109       }
110     });
111   }
112
113   private static boolean checkAndNotifyPossiblySlowBreakpoint(XBreakpoint breakpoint) {
114     if (breakpoint.isEnabled() &&
115         (breakpoint.getType() instanceof JavaMethodBreakpointType || breakpoint.getType() instanceof JavaWildcardMethodBreakpointType)) {
116       Breakpoint bpt = getJavaBreakpoint(breakpoint);
117       if (bpt instanceof MethodBreakpoint && ((MethodBreakpoint)bpt).isEmulated()) {
118         return false;
119       }
120       XDebugSessionImpl.NOTIFICATION_GROUP
121         .createNotification(DebuggerBundle.message("method.breakpoints.slowness.warning"), MessageType.WARNING)
122         .notify(((XBreakpointBase)breakpoint).getProject());
123       return true;
124     }
125     return false;
126   }
127
128   public void init() {
129     XBreakpointManager manager = XDebuggerManager.getInstance(myProject).getBreakpointManager();
130     manager.addBreakpointListener(new XBreakpointAdapter<XBreakpoint<?>>() {
131       @Override
132       public void breakpointAdded(@NotNull XBreakpoint<?> xBreakpoint) {
133         Breakpoint breakpoint = getJavaBreakpoint(xBreakpoint);
134         if (breakpoint != null) {
135           addBreakpoint(breakpoint);
136         }
137       }
138
139       @Override
140       public void breakpointChanged(@NotNull XBreakpoint xBreakpoint) {
141         Breakpoint breakpoint = getJavaBreakpoint(xBreakpoint);
142         if (breakpoint != null) {
143           fireBreakpointChanged(breakpoint);
144         }
145       }
146     });
147   }
148
149   private XBreakpointManager getXBreakpointManager() {
150     return XDebuggerManager.getInstance(myProject).getBreakpointManager();
151   }
152
153   public void editBreakpoint(final Breakpoint breakpoint, final Editor editor) {
154     DebuggerInvocationUtil.swingInvokeLater(myProject, () -> {
155       XBreakpoint xBreakpoint = breakpoint.myXBreakpoint;
156       if (xBreakpoint instanceof XLineBreakpointImpl) {
157         RangeHighlighter highlighter = ((XLineBreakpointImpl)xBreakpoint).getHighlighter();
158         if (highlighter != null) {
159           GutterIconRenderer renderer = highlighter.getGutterIconRenderer();
160           if (renderer != null) {
161             DebuggerSupport.getDebuggerSupport(JavaDebuggerSupport.class).getEditBreakpointAction().editBreakpoint(
162               myProject, editor, breakpoint.myXBreakpoint, renderer
163             );
164           }
165         }
166       }
167     });
168   }
169
170   public void setBreakpointDefaults(Key<? extends Breakpoint> category, BreakpointDefaults defaults) {
171     Class typeCls = null;
172     if (LineBreakpoint.CATEGORY.toString().equals(category.toString())) {
173       typeCls = JavaLineBreakpointType.class;
174     }
175     else if (MethodBreakpoint.CATEGORY.toString().equals(category.toString())) {
176       typeCls = JavaMethodBreakpointType.class;
177     }
178     else if (FieldBreakpoint.CATEGORY.toString().equals(category.toString())) {
179       typeCls = JavaFieldBreakpointType.class;
180     }
181     else if (ExceptionBreakpoint.CATEGORY.toString().equals(category.toString())) {
182       typeCls = JavaExceptionBreakpointType.class;
183     }
184     if (typeCls != null) {
185       XBreakpointType type = XDebuggerUtil.getInstance().findBreakpointType(typeCls);
186       ((XBreakpointManagerImpl)getXBreakpointManager()).getBreakpointDefaults(type).setSuspendPolicy(Breakpoint.transformSuspendPolicy(defaults.getSuspendPolicy()));
187     }
188   }
189
190   @Nullable
191   public RunToCursorBreakpoint addRunToCursorBreakpoint(@NotNull XSourcePosition position, final boolean ignoreBreakpoints) {
192     return RunToCursorBreakpoint.create(myProject, position, ignoreBreakpoints);
193   }
194
195   @Nullable
196   public StepIntoBreakpoint addStepIntoBreakpoint(@NotNull BreakpointStepMethodFilter filter) {
197     return StepIntoBreakpoint.create(myProject, filter);
198   }
199
200   @Nullable
201   public LineBreakpoint addLineBreakpoint(Document document, int lineIndex) {
202     ApplicationManager.getApplication().assertIsDispatchThread();
203     if (!LineBreakpoint.canAddLineBreakpoint(myProject, document, lineIndex)) {
204       return null;
205     }
206     XLineBreakpoint xLineBreakpoint = addXLineBreakpoint(JavaLineBreakpointType.class, document, lineIndex);
207     Breakpoint breakpoint = getJavaBreakpoint(xLineBreakpoint);
208     if (breakpoint instanceof LineBreakpoint) {
209       addBreakpoint(breakpoint);
210       return ((LineBreakpoint)breakpoint);
211     }
212     return null;
213   }
214
215   @Nullable
216   public FieldBreakpoint addFieldBreakpoint(@NotNull Document document, int offset) {
217     PsiField field = FieldBreakpoint.findField(myProject, document, offset);
218     if (field == null) {
219       return null;
220     }
221
222     int line = document.getLineNumber(offset);
223
224     if (document.getLineNumber(field.getNameIdentifier().getTextOffset()) < line) {
225       return null;
226     }
227
228     return addFieldBreakpoint(document, line, field.getName());
229   }
230
231   @Nullable
232   public FieldBreakpoint addFieldBreakpoint(Document document, int lineIndex, String fieldName) {
233     ApplicationManager.getApplication().assertIsDispatchThread();
234     XLineBreakpoint xBreakpoint = addXLineBreakpoint(JavaFieldBreakpointType.class, document, lineIndex);
235     Breakpoint javaBreakpoint = getJavaBreakpoint(xBreakpoint);
236     if (javaBreakpoint instanceof FieldBreakpoint) {
237       FieldBreakpoint fieldBreakpoint = (FieldBreakpoint)javaBreakpoint;
238       fieldBreakpoint.setFieldName(fieldName);
239       addBreakpoint(javaBreakpoint);
240       return fieldBreakpoint;
241     }
242     return null;
243   }
244
245   @NotNull
246   public ExceptionBreakpoint addExceptionBreakpoint(@NotNull final String exceptionClassName, final String packageName) {
247     ApplicationManager.getApplication().assertIsDispatchThread();
248     final JavaExceptionBreakpointType type = XDebuggerUtil.getInstance().findBreakpointType(JavaExceptionBreakpointType.class);
249     return ApplicationManager.getApplication().runWriteAction((Computable<ExceptionBreakpoint>)() -> {
250       XBreakpoint<JavaExceptionBreakpointProperties> xBreakpoint = XDebuggerManager.getInstance(myProject).getBreakpointManager()
251         .addBreakpoint(type, new JavaExceptionBreakpointProperties(exceptionClassName, packageName));
252       Breakpoint javaBreakpoint = getJavaBreakpoint(xBreakpoint);
253       if (javaBreakpoint instanceof ExceptionBreakpoint) {
254         ExceptionBreakpoint exceptionBreakpoint = (ExceptionBreakpoint)javaBreakpoint;
255         exceptionBreakpoint.setQualifiedName(exceptionClassName);
256         exceptionBreakpoint.setPackageName(packageName);
257         addBreakpoint(exceptionBreakpoint);
258         LOG.debug("ExceptionBreakpoint Added");
259         return exceptionBreakpoint;
260       }
261       return null;
262     });
263   }
264
265   @Nullable
266   public MethodBreakpoint addMethodBreakpoint(Document document, int lineIndex) {
267     ApplicationManager.getApplication().assertIsDispatchThread();
268
269     XLineBreakpoint xBreakpoint = addXLineBreakpoint(JavaMethodBreakpointType.class, document, lineIndex);
270     Breakpoint javaBreakpoint = getJavaBreakpoint(xBreakpoint);
271     if (javaBreakpoint instanceof MethodBreakpoint) {
272       addBreakpoint(javaBreakpoint);
273       return (MethodBreakpoint)javaBreakpoint;
274     }
275     return null;
276   }
277
278   private <B extends XBreakpoint<?>> XLineBreakpoint addXLineBreakpoint(Class<? extends XBreakpointType<B,?>> typeCls, Document document, final int lineIndex) {
279     final XBreakpointType<B, ?> type = XDebuggerUtil.getInstance().findBreakpointType(typeCls);
280     final VirtualFile file = FileDocumentManager.getInstance().getFile(document);
281     return ApplicationManager.getApplication().runWriteAction((Computable<XLineBreakpoint>)() -> XDebuggerManager.getInstance(myProject).getBreakpointManager()
282       .addLineBreakpoint((XLineBreakpointType)type, file.getUrl(), lineIndex,
283                          ((XLineBreakpointType)type).createBreakpointProperties(file, lineIndex)));
284   }
285
286   /**
287    * @param category breakpoint category, null if the category does not matter
288    */
289   @Nullable
290   public <T extends BreakpointWithHighlighter> T findBreakpoint(final Document document, final int offset, @Nullable final Key<T> category) {
291     for (final Breakpoint breakpoint : getBreakpoints()) {
292       if (breakpoint instanceof BreakpointWithHighlighter && ((BreakpointWithHighlighter)breakpoint).isAt(document, offset)) {
293         if (category == null || category.equals(breakpoint.getCategory())) {
294           //noinspection CastConflictsWithInstanceof,unchecked
295           return (T)breakpoint;
296         }
297       }
298     }
299     return null;
300   }
301
302   private final Map<String, Element> myOriginalBreakpointsNodes = new LinkedHashMap<>();
303
304   public void readExternal(@NotNull final Element parentNode) {
305     myOriginalBreakpointsNodes.clear();
306     // save old breakpoints
307     for (Element element : parentNode.getChildren()) {
308       myOriginalBreakpointsNodes.put(element.getName(), element.clone());
309     }
310     myStartupManager.runWhenProjectIsInitialized(() -> doRead(parentNode));
311   }
312
313   private void doRead(@NotNull final Element parentNode) {
314     ApplicationManager.getApplication().runReadAction(() -> {
315       final Map<String, Breakpoint> nameToBreakpointMap = new THashMap<>();
316       try {
317         final List groups = parentNode.getChildren();
318         for (final Object group1 : groups) {
319           final Element group = (Element)group1;
320           if (group.getName().equals(RULES_GROUP_NAME)) {
321             continue;
322           }
323           // skip already converted
324           if (group.getAttribute(CONVERTED_PARAM) != null) {
325             continue;
326           }
327           final String categoryName = group.getName();
328           final Key<Breakpoint> breakpointCategory = BreakpointCategory.lookup(categoryName);
329           final String defaultPolicy = group.getAttributeValue(DEFAULT_SUSPEND_POLICY_ATTRIBUTE_NAME);
330           final boolean conditionEnabled = Boolean.parseBoolean(group.getAttributeValue(DEFAULT_CONDITION_STATE_ATTRIBUTE_NAME, "true"));
331           setBreakpointDefaults(breakpointCategory, new BreakpointDefaults(defaultPolicy, conditionEnabled));
332           Element anyExceptionBreakpointGroup;
333           if (!AnyExceptionBreakpoint.ANY_EXCEPTION_BREAKPOINT.equals(breakpointCategory)) {
334             // for compatibility with previous format
335             anyExceptionBreakpointGroup = group.getChild(AnyExceptionBreakpoint.ANY_EXCEPTION_BREAKPOINT.toString());
336             //final BreakpointFactory factory = BreakpointFactory.getInstance(breakpointCategory);
337             //if (factory != null) {
338               for (Element breakpointNode : group.getChildren("breakpoint")) {
339                 //Breakpoint breakpoint = factory.createBreakpoint(myProject, breakpointNode);
340                 Breakpoint breakpoint = createBreakpoint(categoryName, breakpointNode);
341                 breakpoint.readExternal(breakpointNode);
342                 nameToBreakpointMap.put(breakpoint.getDisplayName(), breakpoint);
343               }
344             //}
345           }
346           else {
347             anyExceptionBreakpointGroup = group;
348           }
349
350           if (anyExceptionBreakpointGroup != null) {
351             final Element breakpointElement = group.getChild("breakpoint");
352             if (breakpointElement != null) {
353               XBreakpointManager manager = XDebuggerManager.getInstance(myProject).getBreakpointManager();
354               JavaExceptionBreakpointType type = XDebuggerUtil.getInstance().findBreakpointType(JavaExceptionBreakpointType.class);
355               XBreakpoint<JavaExceptionBreakpointProperties> xBreakpoint = manager.getDefaultBreakpoint(type);
356               Breakpoint breakpoint = getJavaBreakpoint(xBreakpoint);
357               if (breakpoint != null) {
358                 breakpoint.readExternal(breakpointElement);
359                 addBreakpoint(breakpoint);
360               }
361             }
362           }
363         }
364       }
365       catch (InvalidDataException ignored) {
366       }
367
368       final Element rulesGroup = parentNode.getChild(RULES_GROUP_NAME);
369       if (rulesGroup != null) {
370         final List<Element> rules = rulesGroup.getChildren("rule");
371         for (Element rule : rules) {
372           // skip already converted
373           if (rule.getAttribute(CONVERTED_PARAM) != null) {
374             continue;
375           }
376           final Element master = rule.getChild(MASTER_BREAKPOINT_TAG_NAME);
377           if (master == null) {
378             continue;
379           }
380           final Element slave = rule.getChild(SLAVE_BREAKPOINT_TAG_NAME);
381           if (slave == null) {
382             continue;
383           }
384           final Breakpoint masterBreakpoint = nameToBreakpointMap.get(master.getAttributeValue("name"));
385           if (masterBreakpoint == null) {
386             continue;
387           }
388           final Breakpoint slaveBreakpoint = nameToBreakpointMap.get(slave.getAttributeValue("name"));
389           if (slaveBreakpoint == null) {
390             continue;
391           }
392
393           boolean leaveEnabled = "true".equalsIgnoreCase(rule.getAttributeValue("leaveEnabled"));
394           XDependentBreakpointManager dependentBreakpointManager = ((XBreakpointManagerImpl)getXBreakpointManager()).getDependentBreakpointManager();
395           dependentBreakpointManager.setMasterBreakpoint(slaveBreakpoint.myXBreakpoint, masterBreakpoint.myXBreakpoint, leaveEnabled);
396           //addBreakpointRule(new EnableBreakpointRule(BreakpointManager.this, masterBreakpoint, slaveBreakpoint, leaveEnabled));
397         }
398       }
399
400       DebuggerInvocationUtil.invokeLater(myProject, this::updateBreakpointsUI);
401     });
402
403     myUIProperties.clear();
404     final Element props = parentNode.getChild("ui_properties");
405     if (props != null) {
406       final List children = props.getChildren("property");
407       for (Object child : children) {
408         Element property = (Element)child;
409         final String name = property.getAttributeValue("name");
410         final String value = property.getAttributeValue("value");
411         if (name != null && value != null) {
412           myUIProperties.put(name, value);
413         }
414       }
415     }
416   }
417
418   private Breakpoint createBreakpoint(String category, Element breakpointNode) throws InvalidDataException {
419     XBreakpoint xBreakpoint = null;
420     if (category.equals(LineBreakpoint.CATEGORY.toString())) {
421       xBreakpoint = createXLineBreakpoint(JavaLineBreakpointType.class, breakpointNode);
422     }
423     else if (category.equals(MethodBreakpoint.CATEGORY.toString())) {
424       if (breakpointNode.getAttribute("url") != null) {
425         xBreakpoint = createXLineBreakpoint(JavaMethodBreakpointType.class, breakpointNode);
426       }
427       else {
428         xBreakpoint = createXBreakpoint(JavaWildcardMethodBreakpointType.class);
429       }
430     }
431     else if (category.equals(FieldBreakpoint.CATEGORY.toString())) {
432       xBreakpoint = createXLineBreakpoint(JavaFieldBreakpointType.class, breakpointNode);
433     }
434     else if (category.equals(ExceptionBreakpoint.CATEGORY.toString())) {
435       xBreakpoint = createXBreakpoint(JavaExceptionBreakpointType.class);
436     }
437     if (xBreakpoint == null) {
438       throw new IllegalStateException("Unknown breakpoint category " + category);
439     }
440     return getJavaBreakpoint(xBreakpoint);
441   }
442
443   private <B extends XBreakpoint<?>> XBreakpoint createXBreakpoint(Class<? extends XBreakpointType<B, ?>> typeCls) {
444     final XBreakpointType<B, ?> type = XDebuggerUtil.getInstance().findBreakpointType(typeCls);
445     return ApplicationManager.getApplication().runWriteAction((Computable<XBreakpoint>)() -> XDebuggerManager.getInstance(myProject).getBreakpointManager().addBreakpoint((XBreakpointType)type, type.createProperties()));
446   }
447
448   private <B extends XBreakpoint<?>> XLineBreakpoint createXLineBreakpoint(Class<? extends XBreakpointType<B, ?>> typeCls,
449                                                                            Element breakpointNode) throws InvalidDataException {
450     final String url = breakpointNode.getAttributeValue("url");
451     VirtualFile vFile = VirtualFileManager.getInstance().findFileByUrl(url);
452     if (vFile == null) {
453       throw new InvalidDataException(DebuggerBundle.message("error.breakpoint.file.not.found", url));
454     }
455     final Document doc = FileDocumentManager.getInstance().getDocument(vFile);
456     if (doc == null) {
457       throw new InvalidDataException(DebuggerBundle.message("error.cannot.load.breakpoint.file", url));
458     }
459
460     final int line;
461     try {
462       //noinspection HardCodedStringLiteral
463       line = Integer.parseInt(breakpointNode.getAttributeValue("line"));
464     }
465     catch (Exception e) {
466       throw new InvalidDataException("Line number is invalid for breakpoint");
467     }
468     return addXLineBreakpoint(typeCls, doc, line);
469   }
470
471   public static void addBreakpoint(@NotNull Breakpoint breakpoint) {
472     assert breakpoint.myXBreakpoint.getUserData(Breakpoint.DATA_KEY) == breakpoint;
473     breakpoint.updateUI();
474     checkAndNotifyPossiblySlowBreakpoint(breakpoint.myXBreakpoint);
475   }
476
477   public void removeBreakpoint(@Nullable final Breakpoint breakpoint) {
478     if (breakpoint == null) {
479       return;
480     }
481     ApplicationManager.getApplication().runWriteAction(() -> getXBreakpointManager().removeBreakpoint(breakpoint.myXBreakpoint));
482   }
483
484   public void writeExternal(@NotNull final Element parentNode) {
485     // restore old breakpoints
486     for (Element group : myOriginalBreakpointsNodes.values()) {
487       if (group.getAttribute(CONVERTED_PARAM) == null) {
488         group.setAttribute(CONVERTED_PARAM, "true");
489       }
490       parentNode.addContent(group.clone());
491     }
492   }
493
494   @NotNull
495   public List<Breakpoint> getBreakpoints() {
496     return ApplicationManager.getApplication().runReadAction((Computable<List<Breakpoint>>)() ->
497       ContainerUtil.mapNotNull(getXBreakpointManager().getAllBreakpoints(), BreakpointManager::getJavaBreakpoint));
498   }
499
500   @Nullable
501   public static Breakpoint getJavaBreakpoint(@Nullable final XBreakpoint xBreakpoint) {
502     if (xBreakpoint == null) {
503       return null;
504     }
505     Breakpoint breakpoint = xBreakpoint.getUserData(Breakpoint.DATA_KEY);
506     if (breakpoint == null && xBreakpoint.getType() instanceof JavaBreakpointType) {
507       Project project = ((XBreakpointBase)xBreakpoint).getProject();
508       breakpoint = ((JavaBreakpointType)xBreakpoint.getType()).createJavaBreakpoint(project, xBreakpoint);
509       xBreakpoint.putUserData(Breakpoint.DATA_KEY, breakpoint);
510     }
511     return breakpoint;
512   }
513
514   //interaction with RequestManagerImpl
515   public void disableBreakpoints(@NotNull final DebugProcessImpl debugProcess) {
516     final List<Breakpoint> breakpoints = getBreakpoints();
517     if (!breakpoints.isEmpty()) {
518       final RequestManagerImpl requestManager = debugProcess.getRequestsManager();
519       for (Breakpoint breakpoint : breakpoints) {
520         breakpoint.markVerified(requestManager.isVerified(breakpoint));
521         requestManager.deleteRequest(breakpoint);
522       }
523       SwingUtilities.invokeLater(this::updateBreakpointsUI);
524     }
525   }
526
527   public void enableBreakpoints(final DebugProcessImpl debugProcess) {
528     final List<Breakpoint> breakpoints = getBreakpoints();
529     if (!breakpoints.isEmpty()) {
530       for (Breakpoint breakpoint : breakpoints) {
531         breakpoint.markVerified(false); // clean cached state
532         breakpoint.createRequest(debugProcess);
533       }
534       SwingUtilities.invokeLater(this::updateBreakpointsUI);
535     }
536   }
537
538   public void applyThreadFilter(@NotNull final DebugProcessImpl debugProcess, @Nullable ThreadReference newFilterThread) {
539     final RequestManagerImpl requestManager = debugProcess.getRequestsManager();
540     final ThreadReference oldFilterThread = requestManager.getFilterThread();
541     if (Comparing.equal(newFilterThread, oldFilterThread)) {
542       // the filter already added
543       return;
544     }
545     requestManager.setFilterThread(newFilterThread);
546     if (newFilterThread == null || oldFilterThread != null) {
547       final List<Breakpoint> breakpoints = getBreakpoints();
548       for (Breakpoint breakpoint : breakpoints) {
549         if (LineBreakpoint.CATEGORY.equals(breakpoint.getCategory()) || MethodBreakpoint.CATEGORY.equals(breakpoint.getCategory())) {
550           requestManager.deleteRequest(breakpoint);
551           breakpoint.createRequest(debugProcess);
552         }
553       }
554     }
555     else {
556       // important! need to add filter to _existing_ requests, otherwise Requestor->Request mapping will be lost
557       // and debugger trees will not be restored to original state
558       abstract class FilterSetter <T extends EventRequest> {
559          void applyFilter(@NotNull final List<T> requests, final ThreadReference thread) {
560           for (T request : requests) {
561             try {
562               final boolean wasEnabled = request.isEnabled();
563               if (wasEnabled) {
564                 request.disable();
565               }
566               addFilter(request, thread);
567               if (wasEnabled) {
568                 request.enable();
569               }
570             }
571             catch (InternalException e) {
572               LOG.info(e);
573             }
574             catch (InvalidRequestStateException e) {
575               LOG.info(e);
576             }
577           }
578         }
579         protected abstract void addFilter(final T request, final ThreadReference thread);
580       }
581
582       final EventRequestManager eventRequestManager = requestManager.getVMRequestManager();
583       if (eventRequestManager != null) {
584         new FilterSetter<BreakpointRequest>() {
585           @Override
586           protected void addFilter(@NotNull final BreakpointRequest request, final ThreadReference thread) {
587             request.addThreadFilter(thread);
588           }
589         }.applyFilter(eventRequestManager.breakpointRequests(), newFilterThread);
590
591         new FilterSetter<MethodEntryRequest>() {
592           @Override
593           protected void addFilter(@NotNull final MethodEntryRequest request, final ThreadReference thread) {
594             request.addThreadFilter(thread);
595           }
596         }.applyFilter(eventRequestManager.methodEntryRequests(), newFilterThread);
597
598         new FilterSetter<MethodExitRequest>() {
599           @Override
600           protected void addFilter(@NotNull final MethodExitRequest request, final ThreadReference thread) {
601             request.addThreadFilter(thread);
602           }
603         }.applyFilter(eventRequestManager.methodExitRequests(), newFilterThread);
604       }
605     }
606   }
607
608   public void updateBreakpointsUI() {
609     ApplicationManager.getApplication().assertIsDispatchThread();
610     getBreakpoints().forEach(Breakpoint::updateUI);
611   }
612
613   public void reloadBreakpoints() {
614     ApplicationManager.getApplication().assertIsDispatchThread();
615     getBreakpoints().forEach(Breakpoint::reload);
616   }
617
618   public void fireBreakpointChanged(Breakpoint breakpoint) {
619     breakpoint.reload();
620     breakpoint.updateUI();
621   }
622
623   public void setBreakpointEnabled(@NotNull final Breakpoint breakpoint, final boolean enabled) {
624     if (breakpoint.isEnabled() != enabled) {
625       breakpoint.setEnabled(enabled);
626     }
627   }
628
629   @Nullable
630   public Breakpoint findMasterBreakpoint(@NotNull Breakpoint dependentBreakpoint) {
631     XDependentBreakpointManager dependentBreakpointManager = ((XBreakpointManagerImpl)getXBreakpointManager()).getDependentBreakpointManager();
632     return getJavaBreakpoint(dependentBreakpointManager.getMasterBreakpoint(dependentBreakpoint.myXBreakpoint));
633   }
634
635   public String getProperty(String name) {
636     return myUIProperties.get(name);
637   }
638   
639   public String setProperty(String name, String value) {
640     return myUIProperties.put(name, value);
641   }
642 }