blob: 712f8f2b525e05ba4d59ead8e0916916cb3e1fc9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2009 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.debug.ui.actions;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.debug.core.model.IBreakpointImportParticipant;
import org.eclipse.debug.internal.core.BreakpointManager;
import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
import org.eclipse.debug.internal.ui.importexport.breakpoints.IImportExportConstants;
import org.eclipse.debug.internal.ui.importexport.breakpoints.ImportExportMessages;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.IWorkingSetManager;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.XMLMemento;
import com.ibm.icu.text.MessageFormat;
/**
* Imports breakpoints from a file or string buffer into the workspace.
* <p>
* This class may be instantiated.
* <p>
* @since 3.2
* @noextend This class is not intended to be subclassed by clients.
*/
public class ImportBreakpointsOperation implements IRunnableWithProgress {
private boolean fOverwriteAll = false;
private String fFileName = null;
private boolean fCreateWorkingSets = false;
private ArrayList fAdded = new ArrayList();
private String fCurrentWorkingSetProperty = null;
private BreakpointManager fManager = (BreakpointManager) DebugPlugin.getDefault().getBreakpointManager();
/**
* When a buffer is specified, a file is not used.
*/
private StringBuffer fBuffer = null;
/**
* Constructs an operation to import breakpoints.
*
* @param fileName the file to read breakpoints from - the file should have been
* created from an export operation
* @param overwrite whether imported breakpoints will overwrite existing equivalent breakpoints
* @param createWorkingSets whether breakpoint working sets should be created. Breakpoints
* are exported with information about the breakpoint working sets they belong to. Those
* working sets can be optionally re-created on import if they do not already exist in the
* workspace.
*/
public ImportBreakpointsOperation(String fileName, boolean overwrite, boolean createWorkingSets) {
fFileName = fileName;
fOverwriteAll = overwrite;
fCreateWorkingSets = createWorkingSets;
}
/**
* Constructs an operation to import breakpoints from a string buffer. The buffer
* must contain a memento created an {@link ExportBreakpointsOperation}.
*
* @param buffer the string buffer to read breakpoints from - the file should have been
* created from an export operation
* @param overwrite whether imported breakpoints will overwrite existing equivalent breakpoints
* @param createWorkingSets whether breakpoint working sets should be created. Breakpoints
* are exported with information about the breakpoint working sets they belong to. Those
* working sets can be optionally re-created on import if they do not already exist in the
* workspace.
* @since 3.5
*/
public ImportBreakpointsOperation(StringBuffer buffer, boolean overwrite, boolean createWorkingSets) {
fBuffer = buffer;
fOverwriteAll = overwrite;
fCreateWorkingSets = createWorkingSets;
}
/* (non-Javadoc)
* @see org.eclipse.core.resources.IWorkspaceRunnable#run(org.eclipse.core.runtime.IProgressMonitor)
*/
public void run(final IProgressMonitor monitor) throws InvocationTargetException {
SubMonitor localmonitor = SubMonitor.convert(monitor, ImportExportMessages.ImportOperation_0, 1);
Reader reader = null;
try {
if (fBuffer == null) {
reader = new InputStreamReader(new FileInputStream(fFileName), "UTF-8"); //$NON-NLS-1$
} else {
reader = new StringReader(fBuffer.toString());
}
XMLMemento memento = XMLMemento.createReadRoot(reader);
IMemento[] nodes = memento.getChildren(IImportExportConstants.IE_NODE_BREAKPOINT);
IWorkspaceRoot workspace = ResourcesPlugin.getWorkspace().getRoot();
localmonitor.setWorkRemaining(nodes.length);
Map attributes = null;
IBreakpointImportParticipant[] participants = null;
for(int i = 0; i < nodes.length; i++) {
if(localmonitor.isCanceled()) {
return;
}
attributes = collectBreakpointProperties(nodes[i]);
IResource resource = workspace.findMember((String) attributes.get(IImportExportConstants.IE_NODE_PATH));
// filter resource breakpoints that do not exist in this workspace
if(resource != null) {
try {
participants = fManager.getImportParticipants((String) attributes.get(IImportExportConstants.IE_NODE_TYPE));
}
catch(CoreException ce) {}
IMarker marker = findExistingMarker(attributes, participants);
if(marker == null) {
marker = resource.createMarker((String) attributes.get(IImportExportConstants.IE_NODE_TYPE));
restoreBreakpoint(marker, attributes, participants);
}
else {
if(fOverwriteAll) {
marker.setAttributes(null);
restoreBreakpoint(marker, attributes, participants);
}
}
}
fCurrentWorkingSetProperty = null;
localmonitor.worked(1);
}
fManager.addBreakpoints((IBreakpoint[])fAdded.toArray(new IBreakpoint[fAdded.size()]));
}
catch(FileNotFoundException e) {
throw new InvocationTargetException(e,
MessageFormat.format("Breakpoint import file not found: {0}", new String[]{fFileName})); //$NON-NLS-1$
}
catch (UnsupportedEncodingException e) {
throw new InvocationTargetException(e,
MessageFormat.format("The import file was written in non-UTF-8 encoding.", new String[]{fFileName})); //$NON-NLS-1$
}
catch(CoreException ce) {
throw new InvocationTargetException(ce,
MessageFormat.format("There was a problem importing breakpoints from: {0}", new String[] {fFileName})); //$NON-NLS-1$
}
finally {
localmonitor.done();
if(reader != null) {
try {
reader.close();
}
catch (IOException e) {
throw new InvocationTargetException(e);
}
}
}
}
/**
* Returns a marker backing an existing breakpoint based on the given set of breakpoint attributes
* @param attributes
* @param participants
* @return the marker for an existing breakpoint or <code>null</code> if one could not be located
* @since 3.5
*/
protected IMarker findExistingMarker(Map attributes, IBreakpointImportParticipant[] participants) {
IBreakpoint[] bps = fManager.getBreakpoints();
for(int i = 0; i < bps.length; i++) {
for(int j = 0; j < participants.length; j++) {
try {
if(participants[j].matches(attributes, bps[i])) {
return bps[i].getMarker();
}
}
catch(CoreException ce) {}
}
}
return null;
}
/**
* Collects all of the properties for a breakpoint from the memento describing it.
* The values in the map will be one of:
* <ul>
* <li>{@link String}</li>
* <li>{@link Integer}</li>
* <li>{@link Boolean}</li>
* </ul>
* @param memento
* @return a new map of all of the breakpoint attributes from the given memento.
* @since 3.5
*/
protected Map collectBreakpointProperties(IMemento memento) {
HashMap map = new HashMap();
//collect attributes from the 'breakpoint' node
map.put(IImportExportConstants.IE_BP_ENABLED, memento.getBoolean(IImportExportConstants.IE_BP_ENABLED));
map.put(IImportExportConstants.IE_BP_PERSISTANT, memento.getBoolean(IImportExportConstants.IE_BP_PERSISTANT));
map.put(IImportExportConstants.IE_BP_REGISTERED, memento.getBoolean(IImportExportConstants.IE_BP_REGISTERED));
//collect attributes from the 'marker' node
IMemento child = memento.getChild(IImportExportConstants.IE_NODE_MARKER);
map.put(IImportExportConstants.IE_NODE_TYPE, child.getString(IImportExportConstants.IE_NODE_TYPE));
map.put(IMarker.LINE_NUMBER, child.getInteger(IMarker.LINE_NUMBER));
//copy all the marker attributes to the map
IMemento[] children = child.getChildren(IImportExportConstants.IE_NODE_ATTRIB);
for(int i = 0; i < children.length; i++) {
readAttribute(children[i], map);
}
//collect attributes from the 'resource' node
child = memento.getChild(IImportExportConstants.IE_NODE_RESOURCE);
map.put(IImportExportConstants.IE_NODE_PATH, child.getString(IImportExportConstants.IE_NODE_PATH));
return map;
}
/**
* Collects the 'name' and 'value' key / attribute from the given memento and places it in the specified map
* @param memento
* @param map
*/
private void readAttribute(IMemento memento, Map map) {
String name = memento.getString(IImportExportConstants.IE_NODE_NAME),
value = memento.getString(IImportExportConstants.IE_NODE_VALUE);
if (value != null && name != null) {
if (name.equals(IInternalDebugUIConstants.WORKING_SET_NAME)) {
fCurrentWorkingSetProperty = value;
}
Object val = value;
try {
val = Integer.valueOf(value);
} catch (NumberFormatException e) {
if (value.equalsIgnoreCase("false") || value.equalsIgnoreCase("true")) { //$NON-NLS-1$ //$NON-NLS-2$
val = Boolean.valueOf(value);
}
}
if(val != null) {
map.put(name, val);
}
}
}
/**
* restores all of the attributes back into the given marker, recreates the breakpoint in the
* breakpoint manager, and optionally recreates any working set(s) the breakpoint belongs to.
* @param marker
* @param attributes
* @param participants
* @since 3.5
*/
protected void restoreBreakpoint(IMarker marker, final Map attributes, IBreakpointImportParticipant[] participants) {
String key = null;
for(Iterator iter = attributes.keySet().iterator(); iter.hasNext();) {
key = (String) iter.next();
try {
marker.setAttribute(key, attributes.get(key));
}
catch(CoreException ce) {}
}
try {
// create the breakpoint
IBreakpoint breakpoint = fManager.createBreakpoint(marker);
breakpoint.setEnabled(((Boolean)attributes.get(IImportExportConstants.IE_BP_ENABLED)).booleanValue());
breakpoint.setPersisted(((Boolean)attributes.get(IImportExportConstants.IE_BP_PERSISTANT)).booleanValue());
breakpoint.setRegistered(((Boolean)attributes.get(IImportExportConstants.IE_BP_REGISTERED)).booleanValue());
fAdded.add(breakpoint);
if (fCreateWorkingSets && fCurrentWorkingSetProperty != null) {
String[] names = fCurrentWorkingSetProperty.split("\\" + IImportExportConstants.DELIMITER); //$NON-NLS-1$
updateWorkingSets(names, breakpoint);
}
if(participants != null) {
for(int i = 0; i < participants.length; i++) {
participants[i].verify(breakpoint);
}
}
}
catch(CoreException ce) {}
}
/**
* Updates the working sets the given breakpoint belongs to
* @param wsnames
* @param breakpoint
* @since 3.5
*/
private void updateWorkingSets(String[] wsnames, IBreakpoint breakpoint) {
IWorkingSetManager mgr = PlatformUI.getWorkbench().getWorkingSetManager();
IWorkingSet set = null;
ArrayList sets = new ArrayList();
collectContainingWorkingsets(breakpoint, sets);
for (int i = 0; i < wsnames.length; i++) {
if("".equals(wsnames[i])) { //$NON-NLS-1$
continue;
}
set = mgr.getWorkingSet(wsnames[i]);
if(set == null) {
//create working set
set = mgr.createWorkingSet(wsnames[i], new IAdaptable[] {});
set.setId(IDebugUIConstants.BREAKPOINT_WORKINGSET_ID);
mgr.addWorkingSet(set);
}
if(!sets.contains(set)) {
IAdaptable[] elements = set.getElements();
IAdaptable[] newElements = new IAdaptable[elements.length + 1];
newElements[newElements.length - 1] = breakpoint;
System.arraycopy(elements, 0, newElements, 0, elements.length);
set.setElements(newElements);
}
sets.remove(set);
}
ArrayList items = null;
for(Iterator iter = sets.iterator(); iter.hasNext();) {
set = (IWorkingSet) iter.next();
items = new ArrayList(Arrays.asList(set.getElements()));
if(items.remove(breakpoint)) {
set.setElements((IAdaptable[]) items.toArray(new IAdaptable[items.size()]));
}
}
}
/**
* Collects all of the breakpoint working sets that contain the given {@link IBreakpoint}
* in the given list
*
* @param breakpoint
* @param collector
* @since 3.5
*/
private void collectContainingWorkingsets(IBreakpoint breakpoint, List collector) {
IWorkingSetManager mgr = PlatformUI.getWorkbench().getWorkingSetManager();
IWorkingSet[] sets = mgr.getWorkingSets();
for (int i = 0; i < sets.length; i++) {
if(IDebugUIConstants.BREAKPOINT_WORKINGSET_ID.equals(sets[i].getId()) &&
containsBreakpoint(sets[i], breakpoint)) {
collector.add(sets[i]);
}
}
}
/**
* Method to ensure markers and breakpoints are not both added to the working set
* @param set the set to check
* @param breakpoint the breakpoint to check for existence
* @return true if it is present false otherwise
*/
private boolean containsBreakpoint(IWorkingSet set, IBreakpoint breakpoint) {
IAdaptable[] elements = set.getElements();
for (int i = 0; i < elements.length; i++) {
if (elements[i].equals(breakpoint)) {
return true;
}
}
return false;
}
/**
* Returns the breakpoints that were imported by this operation, possibly
* an empty list.
*
* @return breakpoints imported by this operation
* @since 3.5
*/
public IBreakpoint[] getImportedBreakpoints() {
return (IBreakpoint[])fAdded.toArray(new IBreakpoint[fAdded.size()]);
}
}