/******************************************************************************* * Copyright (c) 2009, 2013 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.core; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.util.ArrayList; import java.util.List; import org.eclipse.core.resources.IResource; 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.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.variables.IStringVariableManager; import org.eclipse.core.variables.VariablesPlugin; import org.eclipse.debug.internal.core.DebugCoreMessages; import org.eclipse.debug.internal.core.IMementoConstants; import org.eclipse.debug.internal.core.ResourceFactory; import org.eclipse.debug.internal.core.XMLMemento; import com.ibm.icu.text.MessageFormat; /** * Utilities for launch configurations that persist, restore, and refresh * collections of resources. * * @since 3.6 * @noextend This class is not intended to be subclassed by clients. * @noinstantiate This class is not intended to be instantiated by clients. */ public class RefreshUtil { /** * String attribute identifying a scope of resources that should be * refreshed - for example, after an external tool is run. The value is either * a resource memento constant by this class, a resource memento created * via {@link RefreshUtil#toMemento(IResource[])}, null, indicating no * refresh. */ public static final String ATTR_REFRESH_SCOPE = DebugPlugin.getUniqueIdentifier() + ".ATTR_REFRESH_SCOPE"; //$NON-NLS-1$ /** * Boolean attribute indicating if a refresh scope is recursive. Default * value is true. When a refresh is recursive, resources are * refreshed to an infinite depth, otherwise they are refreshed to a depth * of one. */ public static final String ATTR_REFRESH_RECURSIVE = DebugPlugin.getUniqueIdentifier() + ".ATTR_REFRESH_RECURSIVE"; //$NON-NLS-1$ /** * Resource memento referring to the selected resource's project. * Only works when the debug user interface is running. * * @see #toResources(String) */ public static final String MEMENTO_SELECTED_PROJECT = "${project}"; //$NON-NLS-1$ /** * Resource memento referring to the selected resource's container. * Only works when the debug user interface is running. * * @see #toResources(String) */ public static final String MEMENTO_SELECTED_CONTAINER = "${container}"; //$NON-NLS-1$ /** * Resource memento referring to the selected resource. * Only works when the debug user interface is running. * * @see #toResources(String) */ public static final String MEMENTO_SELECTED_RESOURCE = "${resource}"; //$NON-NLS-1$ /** * Resource memento referring to the workspace root. * * @see #toResources(String) */ public static final String MEMENTO_WORKSPACE = "${workspace}"; //$NON-NLS-1$ /** * Indicates no working set has been selected (for backwards compatibility). * The new format uses an empty working set */ private static final String NO_WORKING_SET = "NONE"; //$NON-NLS-1$ /** * Refreshes the resources as specified by the given launch configuration. * * @param resources * resources to refresh * @param depth one of {@link IResource#DEPTH_INFINITE}, {@link IResource#DEPTH_ONE}, * or {@link IResource#DEPTH_ZERO} * @param monitor * progress monitor which may be null * @throws CoreException * if an exception occurs while refreshing resources */ public static void refreshResources(IResource[] resources, int depth, IProgressMonitor monitor) throws CoreException { if (resources == null || resources.length == 0) { return; } SubMonitor lmonitor = SubMonitor.convert(monitor, DebugCoreMessages.RefreshingResources, resources.length); if (lmonitor.isCanceled()) { return; } MultiStatus status = new MultiStatus(DebugPlugin.getUniqueIdentifier(), 0, DebugCoreMessages.RefreshingResourcesError, null); try { for (int i = 0; i < resources.length; i++) { if (lmonitor.isCanceled()) { break; } if (resources[i] != null && resources[i].isAccessible()) { try { resources[i].refreshLocal(depth, null); } catch (CoreException e) { status.merge(e.getStatus()); } } lmonitor.worked(1); } } finally { lmonitor.done(); } if (!status.isOK()) { throw new CoreException(status); } } /** * Returns a collection of resources referred to by the specified * memento generated via {@link #toMemento(IResource[])}. * * @param memento * resource memento generated by this manager * @return collection of resources referred to by the memento * @throws CoreException * if unable to resolve a set of resources */ public static IResource[] toResources(String memento) throws CoreException { if (memento.startsWith("${resource:")) { //$NON-NLS-1$ // This is an old format that is replaced with 'working_set' String pathString = memento.substring(11, memento.length() - 1); Path path = new Path(pathString); IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(path); if (resource == null) { throw new CoreException(new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), IStatus.ERROR, MessageFormat.format(DebugCoreMessages.RefreshUtil_1, new Object[] { pathString }), null)); } return new IResource[] { resource }; } else if (memento.startsWith("${working_set:")) { //$NON-NLS-1$ String ws = memento.substring(14, memento.length() - 1); return getResources(ws); } else if (memento.equals(MEMENTO_WORKSPACE)) { return new IResource[] { ResourcesPlugin.getWorkspace().getRoot() }; } else { // result the selected resource for backwards compatibility IStringVariableManager manager = VariablesPlugin.getDefault().getStringVariableManager(); IResource resource = null; try { String pathString = manager.performStringSubstitution("${selected_resource_path}"); //$NON-NLS-1$ resource = ResourcesPlugin.getWorkspace().getRoot().findMember(new Path(pathString)); } catch (CoreException e) { // unable to resolve a resource } if (resource == null) { // empty selection return new IResource[]{}; } else { if (memento.equals(MEMENTO_SELECTED_RESOURCE)) { return new IResource[] { resource }; } else if (memento.equals(MEMENTO_SELECTED_CONTAINER)) { return new IResource[] {resource.getParent()}; } else if (memento.equals(MEMENTO_SELECTED_PROJECT)) { return new IResource[] {resource.getProject()}; } } } throw new CoreException(new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), MessageFormat.format(DebugCoreMessages.RefreshUtil_0, new Object[] { memento }))); } /** * Returns a memento for a collection of resources that can be restored * via {@link #toResources(String)}. * * @param resources resources to create a memento for * @return memento for the given resources */ public static String toMemento(IResource[] resources) { XMLMemento memento = XMLMemento.createWriteRoot("resources"); //$NON-NLS-1$ for (int i = 0; i < resources.length; i++) { final XMLMemento itemMemento = memento.createChild(IMementoConstants.MEMENTO_ITEM); ResourceFactory.saveState(itemMemento, resources[i]); } StringWriter writer = new StringWriter(); try { memento.save(writer); } catch (IOException e) { DebugPlugin.log(e); } StringBuffer buf = new StringBuffer(); buf.append("${working_set:"); //$NON-NLS-1$ buf.append(writer.toString()); buf.append("}"); //$NON-NLS-1$ return buf.toString(); } /** * Restores a collection of resources from a working set memento, for backwards * compatibility. * * @param wsMemento working set memento * @return resource collection, possibly empty */ private static IResource[] getResources(String wsMemento) { if (NO_WORKING_SET.equals(wsMemento)) { return null; } List resourcesList = new ArrayList(); StringReader reader = new StringReader(wsMemento); XMLMemento memento = null; try { memento = XMLMemento.createReadRoot(reader); } catch (Exception e) { DebugPlugin.log(e); return null; } XMLMemento[] mementos = memento.getChildren(IMementoConstants.MEMENTO_ITEM); for (int i = 0; i < mementos.length; i++) { resourcesList.add(ResourceFactory.createElement(mementos[i])); } return resourcesList.toArray(new IResource[resourcesList.size()]); } /** * Returns whether the refresh scope specified by the given launch * configuration is recursive. * * @param configuration the {@link ILaunchConfiguration} * @return whether the refresh scope is recursive * @throws CoreException * if unable to access the associated attribute */ public static boolean isRefreshRecursive(ILaunchConfiguration configuration) throws CoreException { return configuration.getAttribute(ATTR_REFRESH_RECURSIVE, true); } /** * Refreshes the resources as specified by the given launch configuration via its * {@link RefreshUtil#ATTR_REFRESH_SCOPE} and {@link #ATTR_REFRESH_RECURSIVE} attributes. * * @param configuration launch configuration * @param monitor progress monitor which may be null * @throws CoreException * if an exception occurs while refreshing resources or accessing launch * configuration attributes */ public static void refreshResources(ILaunchConfiguration configuration, IProgressMonitor monitor) throws CoreException { String scope = configuration.getAttribute(ATTR_REFRESH_SCOPE, (String) null); if (scope != null) { IResource[] resources = toResources(scope); if (resources != null && resources.length > 0) { int depth = IResource.DEPTH_ONE; if (isRefreshRecursive(configuration)) { depth = IResource.DEPTH_INFINITE; } refreshResources(resources, depth, monitor); } } } }