From 60cb898c865ce54df19dcd4850e533f197d80b08 Mon Sep 17 00:00:00 2001 From: Francois Chouinard Date: Fri, 7 Mar 2008 19:33:00 +0000 Subject: [PATCH] Breakpoint action for DSF --- .../service/MIBreakpointsActionManager.java | 185 ------------------ .../dd/mi/service/MIBreakpointsManager.java | 85 +++++++- .../actions/BreakpointActionAdapter.java | 44 +++++ .../actions/MILogActionEnabler.java | 82 ++++++++ .../actions/MIResumeActionEnabler.java | 44 +++++ 5 files changed, 247 insertions(+), 193 deletions(-) delete mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointsActionManager.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/breakpoint/actions/BreakpointActionAdapter.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/breakpoint/actions/MILogActionEnabler.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/breakpoint/actions/MIResumeActionEnabler.java diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointsActionManager.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointsActionManager.java deleted file mode 100644 index 9cc46e6c481..00000000000 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointsActionManager.java +++ /dev/null @@ -1,185 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007 Ericsson and others. - * 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: - * Ericsson - Initial API and implementation - *******************************************************************************/ - -package org.eclipse.dd.mi.service; - -import java.io.StringReader; -import java.util.ArrayList; -import java.util.Iterator; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - -import org.eclipse.cdt.debug.core.CDebugCorePlugin; -import org.eclipse.cdt.debug.core.breakpointactions.IBreakpointAction; -import org.eclipse.core.resources.IMarker; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.core.runtime.IConfigurationElement; -import org.eclipse.core.runtime.IExtension; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.debug.core.model.IBreakpoint; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; -import org.xml.sax.helpers.DefaultHandler; - -public class MIBreakpointsActionManager { - - public static final String BREAKPOINT_ACTION_ATTRIBUTE = "BREAKPOINT_ACTIONS"; //$NON-NLS-1$ - private static final String BREAKPOINT_ACTION_DATA = "BreakpointActionManager.actionData"; //$NON-NLS-1$ - - private ArrayList breakpointActions = null; - - public MIBreakpointsActionManager() { - } - - public void executeActions(final IBreakpoint breakpoint, final IAdaptable context) { - if (breakpoint != null) { - IMarker marker = breakpoint.getMarker(); - String actionNames = marker.getAttribute(BREAKPOINT_ACTION_ATTRIBUTE, ""); //$NON-NLS-1$ - final String[] actions = actionNames.split(","); - if (actions.length > 0){ - Job job = new Job("Execute breakpoint actions") { - public IStatus run(final IProgressMonitor monitor) { - return doExecuteActions(breakpoint, context, actions, monitor); - } - }; - job.schedule(); - try { - // wait for actions to execute - job.join(); - } - catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } - - private IStatus doExecuteActions(final IBreakpoint breakpoint, final IAdaptable context, String[] actions, IProgressMonitor monitor) { - try { - for (int i = 0; i < actions.length && !monitor.isCanceled(); i++) { - String actionName = actions[i]; - IBreakpointAction action = findBreakpointAction(actionName); - if (action != null) { - monitor.setTaskName(action.getSummary()); - IStatus status = action.execute(breakpoint, context, monitor); - if (status.getCode() != IStatus.OK) { - // do not log status if user canceled. - if (status.getCode() != IStatus.CANCEL) - CDebugCorePlugin.log(status); - return status; - } - } - monitor.worked(1); - } - } catch (Exception e) { - return new Status( IStatus.ERROR, CDebugCorePlugin.getUniqueIdentifier(), CDebugCorePlugin.INTERNAL_ERROR, "Internal Error", e ); - } - return monitor.isCanceled() ? Status.CANCEL_STATUS : Status.OK_STATUS; - } - - public IBreakpointAction findBreakpointAction(String name) { - for (Iterator iter = getBreakpointActions().iterator(); iter.hasNext();) { - IBreakpointAction action = (IBreakpointAction) iter.next(); - if (action.getName().equals(name)) - return action; - } - return null; - } - - public ArrayList getBreakpointActions() { - if (breakpointActions == null) { - breakpointActions = new ArrayList(); - loadActionData(); - } - return breakpointActions; - } - - private void loadActionData() { - - String actionData = CDebugCorePlugin.getDefault().getPluginPreferences().getString(BREAKPOINT_ACTION_DATA); - - if (actionData == null || actionData.length() == 0) - return; - - Element root = null; - DocumentBuilder parser; - try { - parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - parser.setErrorHandler(new DefaultHandler()); - root = parser.parse(new InputSource(new StringReader(actionData))).getDocumentElement(); - - NodeList nodeList = root.getChildNodes(); - int entryCount = nodeList.getLength(); - - for (int i = 0; i < entryCount; i++) { - Node node = nodeList.item(i); - short type = node.getNodeType(); - if (type == Node.ELEMENT_NODE) { - Element subElement = (Element) node; - String nodeName = subElement.getNodeName(); - if (nodeName.equalsIgnoreCase("actionEntry")) { //$NON-NLS-1$ - String name = subElement.getAttribute("name"); //$NON-NLS-1$ - if (name == null) - throw new Exception(); - String value = subElement.getAttribute("value"); //$NON-NLS-1$ - if (value == null) - throw new Exception(); - String className = subElement.getAttribute("class"); //$NON-NLS-1$ - if (className == null) - throw new Exception(); - - IBreakpointAction action = createActionFromClassName(name, className); - action.initializeFromMemento(value); - } - } - } - - } catch (Exception e) { - e.printStackTrace(); - } - } - - private IBreakpointAction createActionFromClassName(String name, String className) { - - IBreakpointAction action = null; - IExtension[] actionExtensions = CDebugCorePlugin.getDefault().getBreakpointActionManager().getBreakpointActionExtensions(); - - try { - - for (int i = 0; i < actionExtensions.length && action == null; i++) { - IConfigurationElement[] elements = actionExtensions[i].getConfigurationElements(); - for (int j = 0; j < elements.length && action == null; j++) { - IConfigurationElement element = elements[j]; - if (element.getName().equals(CDebugCorePlugin.ACTION_TYPE_ELEMENT)) { - if (element.getAttribute("class").equals(className)) { //$NON-NLS-1$ - action = (IBreakpointAction) element.createExecutableExtension("class"); //$NON-NLS-1$ - action.setName(name); - CDebugCorePlugin.getDefault().getBreakpointActionManager().addAction(action); - } - } - } - } - - } catch (CoreException e) { - e.printStackTrace(); - } - - return action; - } - -} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointsManager.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointsManager.java index 2246915bdd4..044e384a6e9 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointsManager.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointsManager.java @@ -9,7 +9,8 @@ * Wind River - Initial API and implementation * Ericsson - High-level breakpoints integration * Ericsson - Added breakpoint filter support - * Ericsson - Re-factored the service and put a few comments + * Ericsson - Re-factored the service and put a few comments + * Ericsson - Added Action support *******************************************************************************/ package org.eclipse.dd.mi.service; @@ -24,6 +25,8 @@ import java.util.Set; import java.util.Vector; import java.util.concurrent.RejectedExecutionException; +import org.eclipse.cdt.debug.core.CDebugCorePlugin; +import org.eclipse.cdt.debug.core.breakpointactions.BreakpointActionManager; import org.eclipse.cdt.debug.core.model.ICBreakpoint; import org.eclipse.cdt.debug.core.model.ICBreakpointExtension; import org.eclipse.cdt.debug.core.model.ICLineBreakpoint; @@ -65,10 +68,13 @@ import org.eclipse.dd.mi.internal.MIPlugin; import org.eclipse.dd.mi.service.MIBreakpoints.BreakpointAddedEvent; import org.eclipse.dd.mi.service.MIBreakpoints.BreakpointRemovedEvent; import org.eclipse.dd.mi.service.MIBreakpoints.BreakpointUpdatedEvent; +import org.eclipse.dd.mi.service.MIBreakpoints.MIBreakpointDMContext; import org.eclipse.dd.mi.service.MIRunControl.MIExecutionDMC; +import org.eclipse.dd.mi.service.breakpoint.actions.BreakpointActionAdapter; import org.eclipse.dd.mi.service.command.events.MIBreakpointHitEvent; import org.eclipse.dd.mi.service.command.events.MIGDBExitEvent; import org.eclipse.dd.mi.service.command.events.MIWatchpointScopeEvent; +import org.eclipse.dd.mi.service.command.events.MIWatchpointTriggerEvent; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.IBreakpointListener; import org.eclipse.debug.core.IBreakpointManager; @@ -98,7 +104,7 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo ISourceLookup fSourceLookup; IBreakpoints fBreakpoints; IBreakpointManager fBreakpointManager; // Platform breakpoint manager (not this!) - // FIXME: MIBreakpointsActionManager fBreakpointActionManager; + BreakpointActionManager fBreakpointActionManager; /////////////////////////////////////////////////////////////////////////// // Breakpoints tracking @@ -159,7 +165,6 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo /////////////////////////////////////////////////////////////////////////// // String constants - // FIXME: Extract to some centralized location /////////////////////////////////////////////////////////////////////////// private static final String NULL_STRING = ""; //$NON-NLS-1$ @@ -230,7 +235,7 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo fSourceLookup = getServicesTracker().getService(ISourceLookup.class); fBreakpoints = getServicesTracker().getService(IBreakpoints.class); fBreakpointManager = DebugPlugin.getDefault().getBreakpointManager(); - // FIXME: fBreakpointActionManager = new MIBreakpointsActionManager(); + fBreakpointActionManager = CDebugCorePlugin.getDefault().getBreakpointActionManager(); // Register to the useful events getSession().addServiceEventListener(this, null); @@ -1134,20 +1139,23 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo // IServiceEventListener /////////////////////////////////////////////////////////////////////////// + //------------------------------------------------------------------------- + // Breakpoints + //------------------------------------------------------------------------- + @DsfServiceEventHandler public void eventDispatched(BreakpointAddedEvent e) { + // Nothing to do - already handled by breakpointAdded() } @DsfServiceEventHandler public void eventDispatched(BreakpointUpdatedEvent e) { + // Nothing to do - already handled by breakpointChanged() } @DsfServiceEventHandler public void eventDispatched(BreakpointRemovedEvent e) { - } - - @DsfServiceEventHandler - public void eventDispatched(MIBreakpointHitEvent e) { + // Nothing to do - already handled by breakpointRemoved() } /* @@ -1160,6 +1168,67 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo public void eventDispatched(MIWatchpointScopeEvent e) { } + //------------------------------------------------------------------------- + // Breakpoint actions + //------------------------------------------------------------------------- + + @DsfServiceEventHandler + public void eventDispatched(MIBreakpointHitEvent e) { + performBreakpointAction(e.getNumber()); + } + + @DsfServiceEventHandler + public void eventDispatched(MIWatchpointTriggerEvent e) { + performBreakpointAction(e.getNumber()); + } + + private void performBreakpointAction(int number) { + // Identify the platform breakpoint + final ICBreakpoint breakpoint = findPlatformBreakpoint(number); + + // FIXME: Temporary hack to have a context + Object[] contexts = fTargetBPs.keySet().toArray(); + final IBreakpointsTargetDMContext context = (IBreakpointsTargetDMContext) contexts[0]; + + // Perform the actions asynchronously (otherwise we can have a deadlock...) + new Job("Breakpoint action") { //$NON-NLS-1$ + { setSystem(true); } + @Override + protected IStatus run(IProgressMonitor monitor) { + // FIXME: Rename MyAdaptableType to something more relevant + fBreakpointActionManager.executeActions(breakpoint, new BreakpointActionAdapter(getExecutor(), getServicesTracker(), context)); + return Status.OK_STATUS; + }; + }.schedule(); + } + + // Helper function to locate the platform breakpoint corresponding + // to the target breakpoint/watchpoint that was just hit + // FIXME: Need a way to identify the correct context where the BP was hit + // because it impacts the action (expression evaluation and resume delay). + // This means that the Breakpoint/WatchpointHitEvent will need to + // provide some extra info... + private ICBreakpoint findPlatformBreakpoint(int targetBreakpointID) { + Set targets = fTargetBPs.keySet(); + for (IBreakpointsTargetDMContext target : targets) { + Map bps = fTargetBPs.get(target); + Set contexts = bps.keySet(); + for (IBreakpointDMContext context : contexts) { + if (context instanceof MIBreakpointDMContext) { + MIBreakpointDMContext ctx = (MIBreakpointDMContext) context; + if (ctx.getReference() == targetBreakpointID) { + return bps.get(context); + } + } + } + } + return null; + } + + //------------------------------------------------------------------------- + // Session exit + //------------------------------------------------------------------------- + @DsfServiceEventHandler public void eventDispatched(MIGDBExitEvent e) { terminated(); diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/breakpoint/actions/BreakpointActionAdapter.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/breakpoint/actions/BreakpointActionAdapter.java new file mode 100644 index 00000000000..745820ca899 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/breakpoint/actions/BreakpointActionAdapter.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2008 Ericsson and others. + * 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: + * Ericsson - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.breakpoint.actions; + +import org.eclipse.cdt.debug.core.breakpointactions.ILogActionEnabler; +import org.eclipse.cdt.debug.core.breakpointactions.IResumeActionEnabler; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.dd.dsf.concurrent.DsfExecutor; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.service.DsfServicesTracker; + +public class BreakpointActionAdapter implements IAdaptable { + + private final DsfExecutor fExecutor; + private final DsfServicesTracker fServiceTracker; + private final IDMContext fContext; + + public BreakpointActionAdapter(DsfExecutor executor, DsfServicesTracker serviceTracker, IDMContext context) { + fExecutor = executor; + fServiceTracker = serviceTracker; + fContext = context; + } + + @SuppressWarnings("unchecked") + public Object getAdapter(Class adapter) { + if (adapter.equals(ILogActionEnabler.class)) { + return new MILogActionEnabler(fExecutor, fServiceTracker, fContext); + } + if (adapter.equals(IResumeActionEnabler.class)) { + return new MIResumeActionEnabler(fExecutor, fServiceTracker, fContext); + } + return null; + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/breakpoint/actions/MILogActionEnabler.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/breakpoint/actions/MILogActionEnabler.java new file mode 100644 index 00000000000..8b9c509bedb --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/breakpoint/actions/MILogActionEnabler.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2008 Ericsson and others. + * 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: + * Ericsson - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.breakpoint.actions; + +import java.util.concurrent.ExecutionException; + +import org.eclipse.cdt.debug.core.breakpointactions.ILogActionEnabler; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.DsfExecutor; +import org.eclipse.dd.dsf.concurrent.Query; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.IExpressions; +import org.eclipse.dd.dsf.debug.service.IFormattedValues; +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMData; +import org.eclipse.dd.dsf.service.DsfServicesTracker; + +public class MILogActionEnabler implements ILogActionEnabler { + + private final DsfExecutor fExecutor; + private final DsfServicesTracker fServiceTracker; + private final IBreakpointsTargetDMContext fContext; + + public MILogActionEnabler(DsfExecutor executor, DsfServicesTracker serviceTracker, IDMContext context) { + fExecutor = executor; + fServiceTracker = serviceTracker; + // FIXME: Although it looks optimistic, we know it works + // How can we guarantee that it always will? + fContext = (IBreakpointsTargetDMContext) context; + } + + public String evaluateExpression(final String expression) throws Exception { + // Use a Query to synchronize the call + Query query = new Query() { + @Override + protected void execute(final DataRequestMonitor drm) { + final IExpressions expressionService = fServiceTracker.getService(IExpressions.class); + if (expressionService != null) { + final IExpressionDMContext expressionDMC = expressionService.createExpression(fContext, expression); + String formatId = IFormattedValues.NATURAL_FORMAT; + FormattedValueDMContext valueDmc = expressionService.getFormattedValueContext(expressionDMC, formatId); + expressionService.getFormattedExpressionValue( + valueDmc, + new DataRequestMonitor(fExecutor, drm) { + @Override + protected void handleCompleted() { + String result = expression + ": evaluation failed."; //$NON-NLS-1$ + if (getStatus().isOK()) { + result = getData().getFormattedValue(); + } + drm.setData(result); + drm.done(); + } + } + ); + } + } + }; + fExecutor.execute(query); + + try { + // The happy case + return query.get(); + } catch (InterruptedException e) { + return "Error evaluating \"" + expression + "\" (InterruptedException)."; //$NON-NLS-1$ //$NON-NLS-2$ + } catch (ExecutionException e) { + return "Error evaluating \"" + expression + "\" (ExecutionException)."; //$NON-NLS-1$ //$NON-NLS-2$ + } + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/breakpoint/actions/MIResumeActionEnabler.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/breakpoint/actions/MIResumeActionEnabler.java new file mode 100644 index 00000000000..1334f9e167f --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/breakpoint/actions/MIResumeActionEnabler.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2008 Ericsson and others. + * 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: + * Ericsson - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.breakpoint.actions; + +import org.eclipse.cdt.debug.core.breakpointactions.IResumeActionEnabler; +import org.eclipse.dd.dsf.concurrent.DsfExecutor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.dsf.service.DsfServicesTracker; + +public class MIResumeActionEnabler implements IResumeActionEnabler { + + @SuppressWarnings("unused") + private final DsfExecutor fExecutor; + private final DsfServicesTracker fServiceTracker; + private final IExecutionDMContext fContext; + + public MIResumeActionEnabler(DsfExecutor executor, DsfServicesTracker serviceTracker, IDMContext context) { + fExecutor = executor; + fServiceTracker = serviceTracker; + // FIXME: Although it looks optimistic, we know it works + // How can we guarantee that it always will? + fContext = (IExecutionDMContext) context; + } + + public void resume() throws Exception { + final IRunControl runControlService = fServiceTracker.getService(IRunControl.class); + if (runControlService != null) { + runControlService.resume(fContext, new RequestMonitor(fExecutor, null)); + } + } + +}