/******************************************************************************* * Copyright (c) 2004, 2009 QNX Software Systems 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: * QNX Software Systems - Initial API and implementation *******************************************************************************/ package org.eclipse.cdt.debug.internal.core.breakpoints; import com.ibm.icu.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.cdt.debug.core.CDIDebugModel; import org.eclipse.cdt.debug.core.CDebugCorePlugin; import org.eclipse.cdt.debug.core.model.ICBreakpoint; import org.eclipse.cdt.debug.core.model.ICBreakpointExtension; import org.eclipse.cdt.debug.core.model.ICBreakpointType; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.IDebugEventSetListener; import org.eclipse.debug.core.model.Breakpoint; /** * The base class for all C/C++ specific breakpoints. */ public abstract class CBreakpoint extends Breakpoint implements ICBreakpoint, ICBreakpointType, IDebugEventSetListener { /** * Map of breakpoint extensions. The keys to the map are debug model IDs * and values are arrays of breakpoint extensions. */ private Map fExtensions = new HashMap(1); /** * The number of debug targets the breakpoint is installed in. We don't use * the INSTALL_COUNT attribute to manage this property (see bugzilla 218194) * */ private int fInstallCount = 0; /** * Constructor for CBreakpoint. */ public CBreakpoint() { } /** * Constructor for CBreakpoint. */ public CBreakpoint( final IResource resource, final String markerType, final Map attributes, final boolean add ) throws CoreException { this(); IWorkspaceRunnable wr = new IWorkspaceRunnable() { public void run( IProgressMonitor monitor ) throws CoreException { // create the marker setMarker( resource.createMarker( markerType ) ); // set attributes ensureMarker().setAttributes( attributes ); //set the marker message setAttribute( IMarker.MESSAGE, getMarkerMessage() ); // add to breakpoint manager if requested register( add ); } }; run( wr ); } public void createMarker( final IResource resource, final String markerType, final Map attributes, final boolean add ) throws DebugException { IWorkspaceRunnable wr = new IWorkspaceRunnable() { public void run( IProgressMonitor monitor ) throws CoreException { // create the marker setMarker( resource.createMarker( markerType ) ); // set attributes ensureMarker().setAttributes( attributes ); //set the marker message setAttribute( IMarker.MESSAGE, getMarkerMessage() ); // add to breakpoint manager if requested register( add ); } }; run( wr ); } /* * (non-Javadoc) * * @see org.eclipse.debug.core.model.IBreakpoint#getModelIdentifier() */ public String getModelIdentifier() { return CDIDebugModel.getPluginIdentifier(); } /* * (non-Javadoc) * * @see org.eclipse.cdt.debug.core.ICBreakpoint#isInstalled() */ public boolean isInstalled() throws CoreException { return fInstallCount > 0; } /* * (non-Javadoc) * * @see org.eclipse.cdt.debug.core.ICBreakpoint#getCondition() */ public String getCondition() throws CoreException { return ensureMarker().getAttribute( CONDITION, "" ); //$NON-NLS-1$ } /* * (non-Javadoc) * * @see org.eclipse.cdt.debug.core.ICBreakpoint#setCondition(String) */ public void setCondition( String condition ) throws CoreException { setAttribute( CONDITION, condition ); setAttribute( IMarker.MESSAGE, getMarkerMessage() ); } /* * (non-Javadoc) * * @see org.eclipse.cdt.debug.core.ICBreakpoint#getIgnoreCount() */ public int getIgnoreCount() throws CoreException { return ensureMarker().getAttribute( IGNORE_COUNT, 0 ); } /* * (non-Javadoc) * * @see org.eclipse.cdt.debug.core.ICBreakpoint#setIgnoreCount(int) */ public void setIgnoreCount( int ignoreCount ) throws CoreException { setAttribute( IGNORE_COUNT, ignoreCount ); setAttribute( IMarker.MESSAGE, getMarkerMessage() ); } /* (non-Javadoc) * @see org.eclipse.cdt.debug.core.model.ICBreakpoint#getType() */ public int getType() throws CoreException { return ensureMarker().getAttribute( TYPE, 0 ); } /* (non-Javadoc) * @see org.eclipse.cdt.debug.core.model.ICBreakpoint#setType(int) */ public void setType(int type) throws CoreException { setAttribute( TYPE, type ); setAttribute( IMarker.MESSAGE, getMarkerMessage() ); } /* * (non-Javadoc) * * @see org.eclipse.cdt.debug.core.ICBreakpoint#getThreadId() */ public String getThreadId() throws CoreException { return ensureMarker().getAttribute( THREAD_ID, null ); } /* * (non-Javadoc) * * @see org.eclipse.cdt.debug.core.ICBreakpoint#setThreadId(String) */ public void setThreadId( String threadId ) throws CoreException { setAttribute( THREAD_ID, threadId ); } /* (non-Javadoc) * @see org.eclipse.cdt.debug.core.model.ICBreakpoint#getSourceHandle() */ public String getSourceHandle() throws CoreException { return ensureMarker().getAttribute( SOURCE_HANDLE, null ); } /* (non-Javadoc) * @see org.eclipse.cdt.debug.core.model.ICBreakpoint#setSourceHandle(java.lang.String) */ public void setSourceHandle( String sourceHandle ) throws CoreException { setAttribute( SOURCE_HANDLE, sourceHandle ); } /* * (non-Javadoc) * * @see org.eclipse.debug.core.IDebugEventSetListener#handleDebugEvents(DebugEvent[]) */ public void handleDebugEvents( DebugEvent[] events ) { } /** * Execute the given workspace runnable */ protected void run( IWorkspaceRunnable wr ) throws DebugException { try { ResourcesPlugin.getWorkspace().run( wr, null ); } catch( CoreException e ) { throw new DebugException( e.getStatus() ); } } /** * Add this breakpoint to the breakpoint manager, or sets it as * unregistered. */ public void register( boolean register ) throws CoreException { if ( register ) { DebugPlugin.getDefault().getBreakpointManager().addBreakpoint( this ); } /* * else { setRegistered( false ); } */ } abstract protected String getMarkerMessage() throws CoreException; /* (non-Javadoc) * @see org.eclipse.cdt.debug.core.model.ICBreakpoint#incrementInstallCount() */ public synchronized int incrementInstallCount() throws CoreException { ++fInstallCount; // cause the marker to update; will ultimately result in a blue checkmark // when install count > 0 setAttribute(INSTALL_COUNT, fInstallCount); return fInstallCount; } /** * Returns the <code>INSTALL_COUNT</code> attribute of this breakpoint or * 0 if the attribute is not set. */ public int getInstallCount() throws CoreException { return fInstallCount; } /* (non-Javadoc) * @see org.eclipse.cdt.debug.core.model.ICBreakpoint#decrementInstallCount() */ public synchronized int decrementInstallCount() throws CoreException { fInstallCount--; // cause the marker to update; will ultimately remove blue checkmark // when install count == 0 setAttribute(INSTALL_COUNT, fInstallCount); return fInstallCount; } /* (non-Javadoc) * @see org.eclipse.cdt.debug.core.model.ICBreakpoint#resetInstallCount() */ public synchronized void resetInstallCount() throws CoreException { if (fInstallCount != 0) { fInstallCount = 0; setAttribute(INSTALL_COUNT, fInstallCount); } } /* * (non-Javadoc) * * @see org.eclipse.debug.core.model.Breakpoint#ensureMarker() */ protected IMarker ensureMarker() throws DebugException { return super.ensureMarker(); } /* * (non-Javadoc) * * @see org.eclipse.debug.core.model.Breakpoint#setAttribute(String, Object) */ protected void setAttribute( String attributeName, Object value ) throws CoreException { super.setAttribute( attributeName, value ); } /* * (non-Javadoc) * * @see org.eclipse.cdt.debug.core.model.ICBreakpoint#isConditional() */ public boolean isConditional() throws CoreException { return ((getCondition() != null && getCondition().trim().length() > 0) || getIgnoreCount() > 0); } protected String getConditionText() throws CoreException { StringBuffer sb = new StringBuffer(); int ignoreCount = getIgnoreCount(); if ( ignoreCount > 0 ) { sb.append( MessageFormat.format( BreakpointMessages.getString( "CBreakpoint.1" ), new Integer[] { new Integer( ignoreCount ) } ) ); //$NON-NLS-1$ } String condition = getCondition(); if ( condition != null && condition.length() > 0 ) { sb.append( MessageFormat.format( BreakpointMessages.getString( "CBreakpoint.2" ), new String[] { condition } ) ); //$NON-NLS-1$ } return sb.toString(); } /** * Change notification when there are no marker changes. If the marker * does not exist, do not fire a change notificaiton (the marker may not * exist if the associated project was closed). */ public void fireChanged() { if ( markerExists() ) { DebugPlugin.getDefault().getBreakpointManager().fireBreakpointChanged( this ); } } /* (non-Javadoc) * @see org.eclipse.cdt.debug.core.model.ICBreakpoint#getModule() */ public String getModule() throws CoreException { return ensureMarker().getAttribute( MODULE, null ); } /* (non-Javadoc) * @see org.eclipse.cdt.debug.core.model.ICBreakpoint#setModule(java.lang.String) */ public void setModule( String module ) throws CoreException { setAttribute( MODULE, module ); } public ICBreakpointExtension getExtension(String debugModelId, Class extensionType) throws CoreException { ICBreakpointExtension[] extensions = getExtensionsForModelId(debugModelId); for (int i = 0; i < extensions.length; i++) { if ( extensionType.isAssignableFrom(extensions[i].getClass()) ) { return extensions[i]; } } throw new CoreException(new Status(IStatus.ERROR, CDebugCorePlugin.getUniqueIdentifier(), DebugPlugin.ERROR, "Extension " + extensionType + " not defined for breakpoint " + this, null)); //$NON-NLS-1$ //$NON-NLS-2$ } /** * Reads platform extension registry for breakpoint extensions registered * for the given debug model. * @param debugModelId Requested debug model that the extensions were * registerd for. * @return Breakpoint extensions. * @throws CoreException Throws exception in case the breakpoint marker * cannot be accessed. */ private ICBreakpointExtension[] getExtensionsForModelId(String debugModelId) throws CoreException { if (!fExtensions.containsKey(debugModelId)) { // Check to make sure that a marker is present. Extensions can only be created // once the marker type is known. IMarker marker = ensureMarker(); // Read the extension registry and create applicable extensions. List extensions = new ArrayList(4); IExtensionPoint ep = Platform.getExtensionRegistry().getExtensionPoint(CDebugCorePlugin.getUniqueIdentifier(), CDebugCorePlugin.BREAKPOINT_EXTENSION_EXTENSION_POINT_ID); IConfigurationElement[] elements = ep.getConfigurationElements(); for (int i= 0; i < elements.length; i++) { if ( elements[i].getName().equals(CDebugCorePlugin.BREAKPOINT_EXTENSION_ELEMENT) ) { String elementDebugModelId = elements[i].getAttribute("debugModelId"); //$NON-NLS-1$ String elementMarkerType = elements[i].getAttribute("markerType"); //$NON-NLS-1$ if (elementDebugModelId == null) { CDebugCorePlugin.log(new Status(IStatus.ERROR, CDebugCorePlugin.getUniqueIdentifier(), DebugPlugin.INTERNAL_ERROR, "Extension " + elements[i].getDeclaringExtension().getUniqueIdentifier() + " missing required attribute: markerType", null)); //$NON-NLS-1$ //$NON-NLS-2$ } else if (elementMarkerType == null){ CDebugCorePlugin.log(new Status(IStatus.ERROR, CDebugCorePlugin.getUniqueIdentifier(), DebugPlugin.INTERNAL_ERROR, "Extension " + elements[i].getDeclaringExtension().getUniqueIdentifier() + " missing required attribute: debugModelId", null)); //$NON-NLS-1$ //$NON-NLS-2$ } else if ( debugModelId.equals(elementDebugModelId) && marker.isSubtypeOf(elementMarkerType)) { String className = elements[i].getAttribute("class"); //$NON-NLS-1$ if (className == null){ CDebugCorePlugin.log(new Status(IStatus.ERROR, CDebugCorePlugin.getUniqueIdentifier(), DebugPlugin.INTERNAL_ERROR, "Extension " + elements[i].getDeclaringExtension().getUniqueIdentifier() + " missing required attribute: className", null)); //$NON-NLS-1$ //$NON-NLS-2$ } else { ICBreakpointExtension extension; try { extension = (ICBreakpointExtension)elements[i].createExecutableExtension("class"); //$NON-NLS-1$ extension.initialize(this); extensions.add(extension); } catch (CoreException e) { CDebugCorePlugin.log(new Status(IStatus.ERROR, CDebugCorePlugin.getUniqueIdentifier(), DebugPlugin.INTERNAL_ERROR, "Extension " + elements[i].getDeclaringExtension().getUniqueIdentifier() + " contains an invalid value for attribute: className", e)); //$NON-NLS-1$ //$NON-NLS-2$ } } } } } fExtensions.put(debugModelId, extensions.toArray(new ICBreakpointExtension[extensions.size()])); } return (ICBreakpointExtension[])fExtensions.get(debugModelId); } }