blob: 682c386ad26e67399df7297aaf42b737724fae6c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* James Blackburn (Broadcom Corp.) - ongoing development
* Lars Vogel <Lars.Vogel@vogella.com> - Bug 473427
*******************************************************************************/
package org.eclipse.core.resources.mapping;
import java.util.ArrayList;
import org.eclipse.core.internal.resources.MarkerManager;
import org.eclipse.core.internal.resources.Workspace;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.CoreException;
/**
* A resource traversal is simply a set of resources and the depth to which
* each is to be traversed. A set of traversals is used to describe the
* resources that constitute a model element.
* <p>
* The flags of the traversal indicate which special resources should be
* included or excluded from the traversal. The flags used are the same as
* those passed to the {@link IResource#accept(IResourceVisitor, int, int)} method.
*
* <p>
* This class may be instantiated or subclassed by clients.
* </p>
* @see org.eclipse.core.resources.IResource
* @since 3.2
*/
public class ResourceTraversal {
private final int depth;
private final int flags;
private final IResource[] resources;
/**
* Creates a new resource traversal.
* @param resources The resources in the traversal
* @param depth The traversal depth
* @param flags the flags for this traversal. The traversal flags match those
* that are passed to the <code>IResource#accept</code> method.
*/
public ResourceTraversal(IResource[] resources, int depth, int flags) {
if (resources == null)
throw new NullPointerException();
this.resources = resources;
this.depth = depth;
this.flags = flags;
}
/**
* Visits all existing resources defined by this traversal.
*
* @param visitor a resource visitor
* @exception CoreException if this method fails. Reasons include:
* <ul>
* <li> The visitor failed with this exception.</li>
* </ul>
*/
public void accept(IResourceVisitor visitor) throws CoreException {
for (IResource resource : resources)
try {
if (resource.exists())
resource.accept(visitor, depth, flags);
} catch (CoreException e) {
//ignore failure in the case of concurrent deletion
if (e.getStatus().getCode() != IResourceStatus.RESOURCE_NOT_FOUND)
throw e;
}
}
/**
* Return whether the given resource is contained in or
* covered by this traversal, regardless of whether the resource
* currently exists.
*
* @param resource the resource to be tested
* @return <code>true</code> if the resource is in this traversal, and
* <code>false</code> otherwise.
*/
public boolean contains(IResource resource) {
for (IResource member : resources) {
if (contains(member, resource)) {
return true;
}
}
return false;
}
private boolean contains(IResource resource, IResource child) {
if (resource.equals(child))
return true;
if (depth == IResource.DEPTH_ZERO)
return false;
if (child.getParent().equals(resource))
return true;
if (depth == IResource.DEPTH_INFINITE)
return resource.getFullPath().isPrefixOf(child.getFullPath());
return false;
}
/**
* Efficient implementation of {@link #findMarkers(String, boolean)}, not
* available to clients because underlying non-API methods are used that
* may change.
*/
void doFindMarkers(ArrayList<IMarker> result, String type, boolean includeSubtypes) {
MarkerManager markerMan = ((Workspace) ResourcesPlugin.getWorkspace()).getMarkerManager();
for (IResource resource : resources)
markerMan.doFindMarkers(resource, result, type, includeSubtypes, depth);
}
/**
* Returns all markers of the specified type on existing resources in this traversal.
* If <code>includeSubtypes</code> is <code>false</code>, only markers
* whose type exactly matches the given type are returned. Returns an empty
* array if there are no matching markers.
*
* @param type the type of marker to consider, or <code>null</code> to indicate all types
* @param includeSubtypes whether or not to consider sub-types of the given type
* @return an array of markers
* @exception CoreException if this method fails.
* @see IResource#findMarkers(String, boolean, int)
*/
public IMarker[] findMarkers(String type, boolean includeSubtypes) throws CoreException {
if (resources.length == 0)
return new IMarker[0];
ArrayList<IMarker> result = new ArrayList<>();
doFindMarkers(result, type, includeSubtypes);
return result.toArray(new IMarker[result.size()]);
}
/**
* Returns the depth to which the resources should be traversed.
*
* @return the depth to which the physical resources are to be traversed
* (one of IResource.DEPTH_ZERO, IResource.DEPTH_ONE or
* IResource.DEPTH_INFINITE)
*/
public int getDepth() {
return depth;
}
/**
* Return the flags for this traversal.
* The flags of the traversal indicate which special resources should be
* included or excluded from the traversal. The flags used are the same as
* those passed to the <code>IResource#accept(IResourceVisitor, int, int)</code> method.
* Clients who traverse the resources manually (i.e. without calling <code>accept</code>)
* should respect the flags when determining which resources are included
* in the traversal.
*
* @return the flags for this traversal
*/
public int getFlags() {
return flags;
}
/**
* Returns the file system resource(s) for this traversal. The returned
* resources must be contained within the same project and need not exist in
* the local file system. The traversal of the returned resources should be
* done considering the flag returned by getDepth. If a resource returned by
* a traversal is a file, it should always be visited. If a resource of a
* traversal is a folder then files contained in the folder can only be
* visited if the folder is IResource.DEPTH_ONE or IResource.DEPTH_INFINITE.
* Child folders should only be visited if the depth is
* IResource.DEPTH_INFINITE.
*
* @return The resources in this traversal
*/
public IResource[] getResources() {
return resources;
}
}