| /******************************************************************************* |
| * Copyright (c) 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.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.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.MultiStatus; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Status; |
| 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[])}, <code>null</code>, 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 <code>true</code>. 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 <code>null</code> |
| * @throws CoreException |
| * if an exception occurs while refreshing resources |
| */ |
| public static void refreshResources(IResource[] resources, int depth, IProgressMonitor monitor) throws CoreException { |
| if (monitor == null) { |
| monitor = new NullProgressMonitor(); |
| } |
| if (resources == null || resources.length == 0) { |
| return; |
| } |
| if (monitor.isCanceled()) { |
| return; |
| } |
| monitor.beginTask(DebugCoreMessages.RefreshingResources, resources.length); |
| MultiStatus status = new MultiStatus(DebugPlugin.getUniqueIdentifier(), 0, DebugCoreMessages.RefreshingResourcesError, null); |
| for (int i = 0; i < resources.length; i++) { |
| if (monitor.isCanceled()) |
| break; |
| if (resources[i] != null && resources[i].isAccessible()) { |
| try { |
| resources[i].refreshLocal(depth, null); |
| } catch (CoreException e) { |
| status.merge(e.getStatus()); |
| } |
| } |
| monitor.worked(1); |
| } |
| monitor.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 String[] { 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 String[]{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 (IResource[]) resourcesList.toArray(new IResource[resourcesList.size()]); |
| |
| } |
| |
| /** |
| * Returns whether the refresh scope specified by the given launch |
| * configuration is recursive. |
| * |
| * @param configuration |
| * @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 <code>null</code> |
| * @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); |
| } |
| } |
| } |
| } |