/*******************************************************************************
* Copyright (c) 2016 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.boot.launch;
import java.util.ArrayList;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IDebugEventFilter;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.jdt.debug.core.IJavaExceptionBreakpoint;
import org.eclipse.jdt.debug.core.IJavaThread;
import org.springframework.ide.eclipse.boot.core.BootActivator;
import org.springsource.ide.eclipse.commons.livexp.ui.Disposable;
/**
* An instance of this type causes a given type of exception to be 'ignored' by the debug UI.
*
* @author Kris De Volder
*/
public class IgnoreExceptionOfType implements IDebugEventFilter, Disposable {
//This class works as follows:
// - an 'EventFilter is attached to the debug model.
// - if an event is detected that corresponds to suspending on an exception breakpoint of the 'ignored' type.
// => a) the event is'filtered' (so that it won't cause a popup to swithc to debugging perspective
// b) the suspended thread is automatically resumed (so that it looks to the user as if the breakpoint wasn't hit)
// Why such a strange way of doing things?
// Because these methods do not work:
//
// a) try to use a BreakPointListener instead. It didn't seem possible to suppress a breakpoint from being installed
// or the breakpoint from causing a suspension. (There's a voting mechanism, but its not possible to override a
// vote to install / suspend cast by another existing listener)
// b) use a DebugEventListener (instead of a filter). This does work, but it has the annoying effect that,
// because breakpoint is actually triggered and then auto-resumed, the debug UI still pops up a dialog
// to switch into the debug perspective. The filter allows us to 'hide' that event. (note that just filtering
// the event isn't enough as this only stops the debug ui from reacting to the breakpoint being hit, but
// the thread still ends up suspended nevertheless)
// private static final boolean DEBUG = true;
//
// private static void debug(String string) {
// if (DEBUG) {
// System.out.println(string);
// }
// }
private ILaunch launch;
private String exceptionToIgnore;
/**
* Create an instance and register it as a listened of the debug model.
*/
public IgnoreExceptionOfType(ILaunch launch, String exceptionToIgnore) {
this.launch = launch;
this.exceptionToIgnore = exceptionToIgnore;
DebugPlugin.getDefault().addDebugEventFilter(this);
}
@Override
public void dispose() {
DebugPlugin.getDefault().removeDebugEventFilter(this);
}
@Override
public DebugEvent[] filterDebugEvents(DebugEvent[] events) {
ArrayList<DebugEvent> filtered = new ArrayList<>(events.length);
for (DebugEvent e : events) {
if (select(e)) {
filtered.add(e);
}
}
if (!filtered.isEmpty()) {
return filtered.toArray(new DebugEvent[filtered.size()]);
}
return null;
}
private boolean select(DebugEvent e) {
if (e.getKind()==DebugEvent.SUSPEND && e.getDetail()==DebugEvent.BREAKPOINT) {
IJavaThread source = (IJavaThread) e.getSource();
if (launch==null || launch.equals(source.getLaunch())) {
IBreakpoint[] bps = source.getBreakpoints();
if (bps!=null) {
for (IBreakpoint bp : bps) {
if (bp instanceof IJavaExceptionBreakpoint) {
IJavaExceptionBreakpoint ebp = (IJavaExceptionBreakpoint) bp;
if (exceptionToIgnore.equals(ebp.getExceptionTypeName())) {
resume(source);
return false;
}
}
}
}
}
}
return true;
}
private void resume(IJavaThread source) {
try {
source.resume();
} catch (DebugException e) {
BootActivator.log(e);
}
}
}