Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Goubet2013-06-20 06:50:00 -0400
committerGerrit Code Review @ Eclipse.org2013-06-20 11:01:59 -0400
commit099f3f702c577f1ee81b66680a2f81c548e5f031 (patch)
tree8a7219d788b917d4ef9c563d13577dd428100285
parent8d8cc5fad706d4e44d0e5528832655bb83a00837 (diff)
downloadorg.eclipse.emf.compare-099f3f702c577f1ee81b66680a2f81c548e5f031.tar.gz
org.eclipse.emf.compare-099f3f702c577f1ee81b66680a2f81c548e5f031.tar.xz
org.eclipse.emf.compare-099f3f702c577f1ee81b66680a2f81c548e5f031.zip
Prevent logical model from containing multiple starting points
During local comparisons, the logical model is computed for all three selected resources. If there is one resource in the workspace that reference (or "is referenced") by more than one of the compared resources, we'll end up with a logical model that will be identical for all of these resources. We now constrain the graph traversal to avoid iterating over other "compared resource" (say "R2") when we already started from one (R1). This keeps us out of R2's own dependency graph. Afterwards, we remove the intersection of the graphs before creating the actual comparison scope. Change-Id: I97438e644fdea423f3af08be1e09784c01423e91
-rw-r--r--plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/ide_ui_messages.properties6
-rw-r--r--plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/logical/DependencyResourceSet.java2
-rw-r--r--plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/logical/Graph.java227
-rw-r--r--plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/logical/ModelResolverRegistryListener.java4
-rw-r--r--plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/logical/ProjectModelResolver.java125
-rw-r--r--plugins/org.eclipse.emf.compare.ide/src/org/eclipse/emf/compare/ide/utils/ResourceUtil.java37
6 files changed, 337 insertions, 64 deletions
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/ide_ui_messages.properties b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/ide_ui_messages.properties
index cde0e4743..ac304cfce 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/ide_ui_messages.properties
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/ide_ui_messages.properties
@@ -13,5 +13,7 @@ EMFSynchronizationModel.resolving = Creating EMF Synchronization Model
EMFSynchronizationModel.minimizing = Minimizing synchronization model
EMFSynchronizationModel.creatingScope = Creating comparison scope
-ModelResolveRegistry.invalidResolver = Model resolver class ''{0}'' could not be instantiated.
-ModelResolveRegistry.invalidRanking = Ranking of resolver ''{0}'' was not a valid integer : ''{1}''. \ No newline at end of file
+ModelResolverRegistry.invalidResolver = Model resolver class ''{0}'' could not be instantiated.
+ModelResolverRegistry.invalidRanking = Ranking of resolver ''{0}'' was not a valid integer : ''{1}''.
+
+ModelResolver.coherenceWarning = Some models were accessible from multiple compared files and have been removed from the scope. This could break their references to the compared models as a result of merge operations. \ No newline at end of file
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/logical/DependencyResourceSet.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/logical/DependencyResourceSet.java
index a79d2f27f..bbd5993ca 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/logical/DependencyResourceSet.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/logical/DependencyResourceSet.java
@@ -76,7 +76,7 @@ public class DependencyResourceSet extends SyncResourceSet {
URI parent = resource.getURI();
URI child = ((InternalEObject)proxy).eProxyURI().trimFragment();
if (parent.isPlatformResource() && child.isPlatformResource()) {
- graph.createConnections(parent, Collections.singleton(child));
+ graph.addChildren(parent, Collections.singleton(child));
}
}
}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/logical/Graph.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/logical/Graph.java
index 549db90ad..2043e711e 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/logical/Graph.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/logical/Graph.java
@@ -10,7 +10,12 @@
*******************************************************************************/
package org.eclipse.emf.compare.ide.ui.internal.logical;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterators.concat;
+
+import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import java.util.Collections;
@@ -21,9 +26,15 @@ import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
+import org.eclipse.emf.common.util.AbstractTreeIterator;
+
/**
* This structure will be used to maintain a undirected graph of elements.
* <p>
+ * This boils down to maintaining a list of children and parents of each node, updating them in sync with each
+ * other.
+ * </p>
+ * <p>
* Take note that the elements of this graph are not necessarily all connected together. This can be used to
* represent a set of trees, a set of undirected graphs, a set of roots with no children...
* </p>
@@ -92,15 +103,15 @@ public final class Graph<E> {
}
/**
- * Connects the given set of elements to another. Note that nodes will be created for all new elements if
- * they do not exist yet.
+ * Connects the given set of elements to a given parent. Note that nodes will be created for all new
+ * elements if they do not exist yet.
*
* @param element
- * The element that is to be connected with others.
- * @param connections
+ * The element that is to be connected with new children.
+ * @param newChildren
* The set of elements to connect to the given parent.
*/
- public void createConnections(E element, Set<E> connections) {
+ public void addChildren(E element, Set<E> newChildren) {
synchronized(nodes) {
Node<E> node = nodes.get(element);
if (node == null) {
@@ -108,18 +119,49 @@ public final class Graph<E> {
nodes.put(element, node);
}
- for (E newConnection : connections) {
- Node<E> connectedNode = nodes.get(newConnection);
- if (connectedNode == null) {
- connectedNode = new Node<E>(newConnection);
- nodes.put(newConnection, connectedNode);
+ for (E newChild : newChildren) {
+ Node<E> childNode = nodes.get(newChild);
+ if (childNode == null) {
+ childNode = new Node<E>(newChild);
+ nodes.put(newChild, childNode);
}
- node.connectTo(connectedNode);
+ node.connectChild(childNode);
}
}
}
/**
+ * Checks if the given element is a parent of the given potential child, directly or not.
+ *
+ * @param parent
+ * Element that could be a parent of <code>potentialChild</code>.
+ * @param potentialChild
+ * The potential child of <code>parent</code>.
+ */
+ public boolean hasChild(E parent, E potentialChild) {
+ synchronized(nodes) {
+ final Node<E> node = nodes.get(potentialChild);
+ if (node != null) {
+ return Iterables.any(node.getAllParents(), is(parent));
+ }
+ return false;
+ }
+ }
+
+ /**
+ * This predicate will be used to check if a Node's element is the given one.
+ *
+ * @return The constructed predicate.
+ */
+ private Predicate<? super Node<E>> is(final E element) {
+ return new Predicate<Node<E>>() {
+ public boolean apply(Node<E> input) {
+ return input != null && input.getElement() == element;
+ }
+ };
+ }
+
+ /**
* Returns an iterable over all elements of the subgraph containing the given element.
*
* @param element
@@ -127,11 +169,30 @@ public final class Graph<E> {
* @return An iterable over all elements of the subgraph containing the given element, an empty list if
* that element is not present in this graph.
*/
- public Iterable<E> getSubgraphContaining(E element) {
+ public Iterable<E> getSubgraphOf(E element) {
+ return getBoundedSubgraphOf(element, Collections.<E> emptySet());
+ }
+
+ /**
+ * Returns an iterable over all elements of the subgraph containing the given element and ending at the
+ * given boundaries.
+ *
+ * @param element
+ * Element we need the subgraph of.
+ * @param endPoints
+ * Boundaries of the need subgraph.
+ * @return An iterable over all elements of the subgraph containing the given element, an empty list if
+ * that element is not present in this graph.
+ */
+ public Iterable<E> getBoundedSubgraphOf(E element, Set<E> endPoints) {
synchronized(nodes) {
final Node<E> node = nodes.get(element);
if (node != null) {
- return new SubgraphBuilder<E>(node).build();
+ Set<E> boundaries = endPoints;
+ if (boundaries == null) {
+ boundaries = Collections.emptySet();
+ }
+ return new SubgraphBuilder<E>(node, boundaries).build();
}
return Collections.emptyList();
}
@@ -148,8 +209,11 @@ public final class Graph<E> {
/** Underlying data of this Node. */
private final K element;
- /** Nodes that are connected with this one. */
- private final Set<Node<K>> connectedNodes;
+ /** Nodes that are connected with this one as a parent. */
+ private final Set<Node<K>> children;
+
+ /** Nodes that are connected with this one as a child. */
+ private final Set<Node<K>> parents;
/**
* Construct a new Node for the given element.
@@ -159,40 +223,60 @@ public final class Graph<E> {
*/
public Node(K element) {
this.element = element;
- this.connectedNodes = new LinkedHashSet<Node<K>>();
+ this.parents = new LinkedHashSet<Node<K>>();
+ this.children = new LinkedHashSet<Node<K>>();
}
/**
- * Returns all other Nodes connected to this one.
+ * Returns all children nodes of this one.
*
- * @return All other Nodes connected to this one.
+ * @return All children nodes of this one.
*/
- public Set<Node<K>> getConnections() {
- return Collections.unmodifiableSet(connectedNodes);
+ public Set<Node<K>> getChildren() {
+ return Collections.unmodifiableSet(children);
}
/**
- * Registers a link between the given Node and this one.
+ * Returns all parent nodes of this one.
*
- * @param other
- * The Node that is to be connected to this one.
+ * @return All parent nodes of this one.
+ */
+ public Set<Node<K>> getParents() {
+ return Collections.unmodifiableSet(parents);
+ }
+
+ /**
+ * Returns all direct and indirect parents of this node.
+ *
+ * @return All direct and indirect parents of this node.
*/
- public void connectTo(Node<K> other) {
- this.connectedNodes.add(other);
- other.connectedNodes.add(this);
+ public Iterable<Node<K>> getAllParents() {
+ return new ParentsIterable<K>(this);
}
/**
- * Breaks the connection from the given other node to this one.
+ * Registers the given element as a child of this one.
*
* @param other
- * The node which connection to this one is to be broken.
+ * The Node that is to be connected to this one.
+ */
+ public void connectChild(Node<K> child) {
+ this.children.add(child);
+ child.parents.add(this);
+ }
+
+ /**
+ * Breaks all connections of this node.
*/
public void breakConnections() {
- for (Node<K> connected : this.connectedNodes) {
- connected.connectedNodes.remove(this);
+ for (Node<K> parent : this.parents) {
+ parent.children.remove(this);
+ }
+ for (Node<K> child : this.children) {
+ child.parents.remove(this);
}
- this.connectedNodes.clear();
+ this.parents.clear();
+ this.children.clear();
}
/**
@@ -219,16 +303,24 @@ public final class Graph<E> {
/** Keeps track of the elements we've already iterated over. */
protected final Set<L> set;
+ /** Nodes that will be considered as boundaries for this subgraph. */
+ protected final Set<L> endPoints;
+
/**
- * Constructs a new iterable given the starting point in the target subgraph.
+ * Constructs a new iterable given the starting point the target subgraph and the elements that will
+ * be considered as (excluded) boundaries of that subgraph.
*
* @param start
* Starting point of the iteration.
+ * @param endPoints
+ * Excluded boundaries of the target subgraph. Iteration will be pruned on these, along
+ * with their own subgraphs.
*/
- public SubgraphBuilder(Node<L> start) {
+ public SubgraphBuilder(Node<L> start, Set<L> endPoints) {
this.start = start;
this.set = new LinkedHashSet<L>();
this.set.add(start.getElement());
+ this.endPoints = checkNotNull(endPoints);
}
/**
@@ -246,6 +338,10 @@ public final class Graph<E> {
* <p>
* This kind of iterator does not support {@link #remove() removal}.
* </p>
+ * <p>
+ * Note : this is not a static class as we're building the external SubgraphBuilder's set through this
+ * (and checking for already iterated over elements).
+ * </p>
*
* @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
*/
@@ -270,7 +366,7 @@ public final class Graph<E> {
*/
public NodeIterator(Node<L> node) {
this.next = node.getElement();
- this.nodesIterator = node.getConnections().iterator();
+ this.nodesIterator = concat(node.getParents().iterator(), node.getChildren().iterator());
prepareNextIterator();
}
@@ -328,10 +424,12 @@ public final class Graph<E> {
if (nodesIterator.hasNext()) {
Node<L> nextNode = nodesIterator.next();
while (SubgraphBuilder.this.set.contains(nextNode.getElement())
+ && !SubgraphBuilder.this.endPoints.contains(nextNode.getElement())
&& nodesIterator.hasNext()) {
nextNode = nodesIterator.next();
}
- if (SubgraphBuilder.this.set.add(nextNode.getElement())) {
+ if (!SubgraphBuilder.this.endPoints.contains(nextNode.getElement())
+ && SubgraphBuilder.this.set.add(nextNode.getElement())) {
nextNodeIterator = new NodeIterator(nextNode);
} else {
nextNodeIterator = Iterators.emptyIterator();
@@ -342,4 +440,63 @@ public final class Graph<E> {
}
}
}
+
+ /**
+ * A custom Iterable that will iterate over the Node->parent Node tree of a given Node.
+ *
+ * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
+ */
+ private static class ParentsIterable<M> implements Iterable<Node<M>> {
+ /** The leaf of the Node->parent tree for which this iterable has been constructed. */
+ private final Node<M> start;
+
+ /**
+ * Constructs an iterable given the root of its tree
+ *
+ * @param start
+ */
+ public ParentsIterable(Node<M> start) {
+ this.start = start;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Iterable#iterator()
+ */
+ public Iterator<Node<M>> iterator() {
+ return new ParentsIterator<M>(start);
+ }
+ }
+
+ /**
+ * A custom TreeIterator that will iterate over the Node->parent Node tree.
+ *
+ * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
+ */
+ private static class ParentsIterator<N> extends AbstractTreeIterator<Node<N>> {
+ /** Generated SUID. */
+ private static final long serialVersionUID = -4476850344598138970L;
+
+ /**
+ * Construct an iterator given the root (well, "leaf") of its tree.
+ *
+ * @param start
+ * Start node of the tree we'll iterate over.
+ */
+ public ParentsIterator(Node<N> start) {
+ super(start);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.common.util.AbstractTreeIterator#getChildren(java.lang.Object)
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ protected Iterator<? extends Node<N>> getChildren(Object obj) {
+ return ((Node<N>)obj).getParents().iterator();
+ }
+ }
}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/logical/ModelResolverRegistryListener.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/logical/ModelResolverRegistryListener.java
index 2c9a9f4e1..20812b5b1 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/logical/ModelResolverRegistryListener.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/logical/ModelResolverRegistryListener.java
@@ -69,7 +69,7 @@ public class ModelResolverRegistryListener extends AbstractRegistryEventListener
resolver = (IModelResolver)element.createExecutableExtension(ATTRIBUTE_CLASS);
} catch (CoreException e) {
final String message = EMFCompareIDEUIMessages.getString(
- "ModelResolveRegistry.invalidResolver", className); //$NON-NLS-1$
+ "ModelResolverRegistry.invalidResolver", className); //$NON-NLS-1$
log(element, message, e);
return false;
}
@@ -81,7 +81,7 @@ public class ModelResolverRegistryListener extends AbstractRegistryEventListener
ranking = Integer.parseInt(rankingStr);
} catch (NumberFormatException e) {
log(IStatus.ERROR, element, EMFCompareIDEUIMessages.getString(
- "ModelResolveRegistry.invalidRanking", className, rankingStr)); //$NON-NLS-1$
+ "ModelResolverRegistry.invalidRanking", className, rankingStr)); //$NON-NLS-1$
}
resolver.setRanking(ranking);
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/logical/ProjectModelResolver.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/logical/ProjectModelResolver.java
index fd6a8eedf..4abc3ab84 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/logical/ProjectModelResolver.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/logical/ProjectModelResolver.java
@@ -10,11 +10,14 @@
*******************************************************************************/
package org.eclipse.emf.compare.ide.ui.internal.logical;
+import static com.google.common.collect.Sets.difference;
+import static com.google.common.collect.Sets.intersection;
import static org.eclipse.emf.compare.ide.ui.internal.util.PlatformElementUtil.adaptAs;
import static org.eclipse.emf.compare.ide.utils.ResourceUtil.createURIFor;
import static org.eclipse.emf.compare.ide.utils.ResourceUtil.hasContentType;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import java.util.Collections;
@@ -34,8 +37,11 @@ import org.eclipse.core.resources.IStorage;
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.Path;
+import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.compare.ide.ui.internal.EMFCompareIDEUIMessages;
import org.eclipse.emf.compare.ide.ui.internal.EMFCompareIDEUIPlugin;
import org.eclipse.emf.compare.ide.ui.logical.IModelResolver;
import org.eclipse.emf.compare.ide.ui.logical.IStorageProvider;
@@ -122,17 +128,79 @@ public class ProjectModelResolver extends LogicalModelResolver {
updateDependencies((IFile)origin, monitor);
}
- final Set<IStorage> leftTraversal = resolveTraversal((IFile)left, monitor);
- final Set<IStorage> rightTraversal = resolveTraversal((IFile)right, monitor);
+ final Set<IFile> startingPoints;
+ if (origin != null) {
+ startingPoints = ImmutableSet.of((IFile)left, (IFile)right, (IFile)origin);
+ } else {
+ startingPoints = ImmutableSet.of((IFile)left, (IFile)right);
+ }
+
+ final Set<IStorage> leftTraversal = resolveTraversal((IFile)left, difference(startingPoints,
+ Collections.singleton(left)), monitor);
+ final Set<IStorage> rightTraversal = resolveTraversal((IFile)right, difference(startingPoints,
+ Collections.singleton(right)), monitor);
final Set<IStorage> originTraversal;
if (origin instanceof IFile) {
- originTraversal = resolveTraversal((IFile)origin, monitor);
+ originTraversal = resolveTraversal((IFile)origin, difference(startingPoints, Collections
+ .singleton(origin)), monitor);
} else {
originTraversal = Collections.emptySet();
}
- return new SynchronizationModel(new StorageTraversal(leftTraversal), new StorageTraversal(
- rightTraversal), new StorageTraversal(originTraversal));
+ /*
+ * If one resource of the logical model was pointing to both (or "all three") of our starting
+ * elements, we'll have way too many things in our traversal. We need to remove the intersection
+ * before going any further.
+ */
+ Set<IStorage> intersection = intersection(leftTraversal, rightTraversal);
+ if (!originTraversal.isEmpty()) {
+ intersection = intersection(intersection, originTraversal);
+ }
+ logCoherenceThreats(startingPoints, intersection);
+
+ final Set<IStorage> actualLeft = difference(leftTraversal, intersection);
+ final Set<IStorage> actualRight = difference(rightTraversal, intersection);
+ final Set<IStorage> actualOrigin = difference(originTraversal, intersection);
+ return new SynchronizationModel(new StorageTraversal(actualLeft), new StorageTraversal(actualRight),
+ new StorageTraversal(actualOrigin));
+ }
+
+ /**
+ * When executing local comparisons, we resolve the full logical model of both (or "all three of") the
+ * compared files.
+ * <p>
+ * If there is one resource in the scope that references all of these starting points, then we'll have
+ * perfectly identical logical models for all comparison sides. Because of that, we need to constrain the
+ * logical model of each starting point to only parts that are not accessible from other starting points.
+ * This might cause coherence issues as merging could thus "break" references from other files to our
+ * compared ones.
+ * </p>
+ * <p>
+ * This method will be used to browse the files that are removed from the logical model, and log a warning
+ * for the files that are removed even though they are "parents" of one of the starting points.
+ * </p>
+ *
+ * @param startingPoints
+ * Starting points of the comparison.
+ * @param removedFromModel
+ * All files that have been removed from the comparison scope.
+ */
+ private void logCoherenceThreats(Set<IFile> startingPoints, Set<IStorage> removedFromModel) {
+ final Set<URI> coherenceThreats = new LinkedHashSet<URI>();
+ for (IStorage start : startingPoints) {
+ final URI startURI = createURIFor(start);
+ for (IStorage removed : removedFromModel) {
+ final URI removedURI = createURIFor(removed);
+ if (dependencyGraph.hasChild(removedURI, startURI)) {
+ coherenceThreats.add(removedURI);
+ }
+ }
+ }
+
+ final String message = EMFCompareIDEUIMessages.getString("ModelResolver.coherenceWarning"); //$NON-NLS-1$
+ final String details = Iterables.toString(coherenceThreats);
+ EMFCompareIDEUIPlugin.getDefault().getLog().log(
+ new Status(IStatus.WARNING, EMFCompareIDEUIPlugin.PLUGIN_ID, message + '\n' + details));
}
/**
@@ -296,7 +364,37 @@ public class ProjectModelResolver extends LogicalModelResolver {
private Set<IStorage> resolveTraversal(IFile resource, IProgressMonitor monitor) {
final Set<IStorage> traversal = new LinkedHashSet<IStorage>();
final URI startURI = createURIFor(resource);
- final Iterable<URI> uris = dependencyGraph.getSubgraphContaining(startURI);
+
+ final Iterable<URI> uris = dependencyGraph.getSubgraphOf(startURI);
+ for (URI uri : uris) {
+ traversal.add(getFileAt(uri));
+ }
+ return traversal;
+ }
+
+ /**
+ * This will be used to resolve the traversal of a file's logical model, according to
+ * {@link #dependencyGraph}.
+ *
+ * @param resource
+ * The resource for which we need the full logical model.
+ * @param bounds
+ * The resources constituting starting points of "other" logical models. This will be used to
+ * constrain the dependency sub-graph.
+ * @param monitor
+ * Monitor on which to report progress to the user.
+ * @return The set of all storages that compose the logical model of <code>resource</code>.
+ */
+ private Set<IStorage> resolveTraversal(IFile resource, Set<IFile> bounds, IProgressMonitor monitor) {
+ final Set<IStorage> traversal = new LinkedHashSet<IStorage>();
+ final URI startURI = createURIFor(resource);
+
+ final Set<URI> uriBounds = new LinkedHashSet<URI>(bounds.size());
+ for (IFile bound : bounds) {
+ uriBounds.add(createURIFor(bound));
+ }
+
+ final Iterable<URI> uris = dependencyGraph.getBoundedSubgraphOf(startURI, uriBounds);
for (URI uri : uris) {
traversal.add(getFileAt(uri));
}
@@ -532,13 +630,14 @@ public class ProjectModelResolver extends LogicalModelResolver {
}
final IFile file = (IFile)delta.getResource();
- if (hasModelType(file)) {
- final URI fileURI = createURIFor(file);
- if (delta.getKind() == IResourceDelta.REMOVED) {
- synchronized(removedURIs) {
- removedURIs.add(fileURI);
- }
- } else if ((delta.getKind() & (IResourceDelta.CHANGED | IResourceDelta.ADDED)) != 0) {
+ final URI fileURI = createURIFor(file);
+ // We can't check the content type of a removed resource
+ if (delta.getKind() == IResourceDelta.REMOVED) {
+ synchronized(removedURIs) {
+ removedURIs.add(fileURI);
+ }
+ } else if (hasModelType(file)) {
+ if ((delta.getKind() & (IResourceDelta.CHANGED | IResourceDelta.ADDED)) != 0) {
synchronized(changedURIs) {
changedURIs.add(fileURI);
}
diff --git a/plugins/org.eclipse.emf.compare.ide/src/org/eclipse/emf/compare/ide/utils/ResourceUtil.java b/plugins/org.eclipse.emf.compare.ide/src/org/eclipse/emf/compare/ide/utils/ResourceUtil.java
index 9d24bebb0..61080c770 100644
--- a/plugins/org.eclipse.emf.compare.ide/src/org/eclipse/emf/compare/ide/utils/ResourceUtil.java
+++ b/plugins/org.eclipse.emf.compare.ide/src/org/eclipse/emf/compare/ide/utils/ResourceUtil.java
@@ -197,6 +197,18 @@ public final class ResourceUtil {
}
/**
+ * Create the URI with which we'll load the given IFile as an EMF resource.
+ *
+ * @param file
+ * The file for which we need an EMF URI.
+ * @return The created URI.
+ */
+ public static URI createURIFor(IFile file) {
+ // whether it exists or not (no longer), use platform:/resource
+ return URI.createPlatformResourceURI(file.getFullPath().toString(), true);
+ }
+
+ /**
* Create the URI with which we'll load the given IStorage as an EMF resource.
*
* @param storage
@@ -204,6 +216,10 @@ public final class ResourceUtil {
* @return The created URI.
*/
public static URI createURIFor(IStorage storage) {
+ if (storage instanceof IFile) {
+ return createURIFor((IFile)storage);
+ }
+
final String resourceName = storage.getName();
String path = storage.getFullPath().toString();
if (!path.endsWith(resourceName)) {
@@ -223,18 +239,17 @@ public final class ResourceUtil {
} else {
uri = URI.createFileURI(path);
}
- final IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
- if (root == null) {
- return uri;
- }
- if (root.getFile(new Path(path)).exists()) {
- uri = URI.createPlatformResourceURI(path, true);
- } else {
- // is it a file coming from a Git repository?
- final int indexOfSeparator = path.indexOf('/');
- if (indexOfSeparator > 0 && root.getFile(new Path(path.substring(indexOfSeparator))).exists()) {
- uri = URI.createPlatformResourceURI(path.substring(indexOfSeparator), true);
+ final IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ if (root != null) {
+ if (root.getFile(new Path(path)).exists()) {
+ uri = URI.createPlatformResourceURI(path, true);
+ } else {
+ // is it a file coming from a Git repository?
+ final int indexOfSeparator = path.indexOf('/');
+ if (indexOfSeparator > 0 && root.getFile(new Path(path.substring(indexOfSeparator))).exists()) {
+ uri = URI.createPlatformResourceURI(path.substring(indexOfSeparator), true);
+ }
}
}

Back to the top