Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.emf.compare-parent/codeStyle/EMFCompareCheckstyle5Configuration.xml12
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/AbstractMatchEngine.java170
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/eobject/IEObjectMatcher.java54
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/eobject/IdentifierEObjectMatcher.java36
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/ChainMatchingStrategy.java90
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/IResourceMatcher.java52
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/IResourceMatchingStrategy.java6
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/NameMatchingStrategy.java4
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/NameSimilarityMatchingStrategy.java16
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/ResourceMapping.java2
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/ResourceMatcher.java121
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/RootIDMatchingStrategy.java4
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/StrategyResourceMatcher.java127
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/scope/AbstractComparisonScope.java37
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/scope/DefaultComparisonScope.java43
15 files changed, 487 insertions, 287 deletions
diff --git a/org.eclipse.emf.compare-parent/codeStyle/EMFCompareCheckstyle5Configuration.xml b/org.eclipse.emf.compare-parent/codeStyle/EMFCompareCheckstyle5Configuration.xml
index 0c24f9681..b8b173081 100644
--- a/org.eclipse.emf.compare-parent/codeStyle/EMFCompareCheckstyle5Configuration.xml
+++ b/org.eclipse.emf.compare-parent/codeStyle/EMFCompareCheckstyle5Configuration.xml
@@ -1,13 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
-<!--
- This configuration file was written by the eclipse-cs plugin configuration editor
+<!--
+ This configuration file was written by the eclipse-cs plugin configuration editor
-->
-<!--
- Checkstyle-Configuration: Acceleo Checkstyle 5
- Description:
-Acceleo Checkstyle 5 Configuration
+<!--
+ Checkstyle-Configuration: EMF Compare
+ Description: none
-->
<module name="Checker">
<property name="severity" value="warning"/>
@@ -69,6 +68,7 @@ Acceleo Checkstyle 5 Configuration
</module>
<module name="ImportOrder">
<property name="severity" value="error"/>
+ <property name="option" value="top"/>
</module>
<module name="RedundantImport">
<property name="severity" value="error"/>
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/AbstractMatchEngine.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/AbstractMatchEngine.java
index b3118333f..59b3ce69c 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/AbstractMatchEngine.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/AbstractMatchEngine.java
@@ -10,21 +10,31 @@
*******************************************************************************/
package org.eclipse.emf.compare.match;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
+import com.google.common.collect.Iterators;
+
+import java.util.Iterator;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.compare.CompareFactory;
import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.Match;
import org.eclipse.emf.compare.MatchResource;
+import org.eclipse.emf.compare.match.eobject.IEObjectMatcher;
+import org.eclipse.emf.compare.match.eobject.IdentifierEObjectMatcher;
+import org.eclipse.emf.compare.match.resource.IResourceMatcher;
import org.eclipse.emf.compare.match.resource.ResourceMapping;
-import org.eclipse.emf.compare.match.resource.ResourceMatcher;
+import org.eclipse.emf.compare.match.resource.StrategyResourceMatcher;
import org.eclipse.emf.compare.scope.AbstractComparisonScope;
+import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
/**
- * This class defines the general contract of a match engine.
+ * The Match engine orchestrates the matching process : it takes a {@link AbstractComparisonScope scope} as
+ * input, iterates over its {@link AbstractComparisonScope#getLeft() left},
+ * {@link AbstractComparisonScope#getRight() right} and {@link AbstractComparisonScope#getOrigin() origin}
+ * root and delegates to {@link IResourceMatcher}s and {@link IEObjectMatcher}s in order to create the result
+ * {@link Comparison} model for this scope.
*
* @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
*/
@@ -80,9 +90,8 @@ public abstract class AbstractMatchEngine {
/**
* This will be used to match the given {@link ResourceSet}s. This default implementation will query the
- * comparison scope for these resource sets children, then delegate to a
- * {@link #createResourceMatcher(Iterable, Iterable, Iterable) ResourceMatcher} to determine the resource
- * mappings.
+ * comparison scope for these resource sets children, then delegate to an {@link IResourceMatcher} to
+ * determine the resource mappings.
*
* @param left
* The left {@link ResourceSet}.
@@ -92,28 +101,25 @@ public abstract class AbstractMatchEngine {
* The common ancestor of <code>left</code> and <code>right</code>. Can be <code>null</code>.
*/
protected void match(ResourceSet left, ResourceSet right, ResourceSet origin) {
- final Iterable<Notifier> leftChildren = getScope().getChildren(left);
- final Iterable<Notifier> rightChildren = getScope().getChildren(right);
- final Iterable<Notifier> originChildren;
+ final Iterator<? extends Resource> leftChildren = getScope().getChildren(left);
+ final Iterator<? extends Resource> rightChildren = getScope().getChildren(right);
+ final Iterator<? extends Resource> originChildren;
if (origin != null) {
originChildren = getScope().getChildren(origin);
} else {
- originChildren = Lists.newArrayList();
+ originChildren = Iterators.emptyIterator();
}
- final Iterable<Resource> leftResources = Iterables.filter(leftChildren, Resource.class);
- final Iterable<Resource> rightResources = Iterables.filter(rightChildren, Resource.class);
- final Iterable<Resource> originResources = Iterables.filter(originChildren, Resource.class);
-
- final ResourceMatcher matcher = createResourceMatcher(leftResources, rightResources, originResources);
- final Iterable<ResourceMapping> mappings = matcher.createMappings();
+ final IResourceMatcher matcher = getResourceMatcher();
+ final Iterable<ResourceMapping> mappings = matcher.createMappings(leftChildren, rightChildren,
+ originChildren);
for (ResourceMapping mapping : mappings) {
final MatchResource matchResource = CompareFactory.eINSTANCE.createMatchResource();
- if (mapping.getLeft().getURI() != null) {
+ if (mapping.getLeft() != null && mapping.getLeft().getURI() != null) {
matchResource.setLeftURI(mapping.getLeft().getURI().toString());
}
- if (mapping.getRight().getURI() != null) {
+ if (mapping.getRight() != null && mapping.getRight().getURI() != null) {
matchResource.setRightURI(mapping.getRight().getURI().toString());
}
if (mapping.getOrigin() != null && mapping.getOrigin().getURI() != null) {
@@ -126,35 +132,111 @@ public abstract class AbstractMatchEngine {
}
/**
- * This will only query the scope for the given Resources' children, then iterate over these children to
- * match them together.
+ * This will only query the scope for the given Resources' children, then delegate to an
+ * {@link IEObjectMatcher} to determine the EObject matches.
+ * <p>
+ * We expect at least two of the given resources not to be <code>null</code>.
+ * </p>
*
* @param left
- * The left {@link Resource}.
+ * The left {@link Resource}. Can be <code>null</code>.
* @param right
- * The right {@link Resource}.
+ * The right {@link Resource}. Can be <code>null</code>.
* @param origin
- * The common ancestor of <code>left</code> and <code>right</code>. can be <code>null</code>.
+ * The common ancestor of <code>left</code> and <code>right</code>. Can be <code>null</code>.
*/
protected void match(Resource left, Resource right, Resource origin) {
+ // We need at least two resources to match them
+ if (atLeastTwo(left == null, right == null, origin == null)) {
+ /*
+ * TODO But if we have only one resource, which is then unmatched, should we not still do
+ * something with it?
+ */
+ return;
+ }
+
+ final Iterator<? extends EObject> leftEObjects;
+ if (left != null) {
+ leftEObjects = getScope().getChildren(left);
+ } else {
+ leftEObjects = Iterators.emptyIterator();
+ }
+ final Iterator<? extends EObject> rightEObjects;
+ if (right != null) {
+ rightEObjects = getScope().getChildren(right);
+ } else {
+ rightEObjects = Iterators.emptyIterator();
+ }
+ final Iterator<? extends EObject> originEObjects;
+ if (origin != null) {
+ originEObjects = getScope().getChildren(origin);
+ } else {
+ originEObjects = Iterators.emptyIterator();
+ }
+
+ final IEObjectMatcher matcher = createEObjectMatcher();
+ final Iterable<Match> matches = matcher.createMatches(leftEObjects, rightEObjects, originEObjects);
+
+ // CODEME
+ }
+
+ /**
+ * This will query the scope for the given {@link EObject}s' children, then delegate to an
+ * {@link IEObjectMatcher} to compute the {@link Match}es.
+ * <p>
+ * We expect at least the <code>left</code> and <code>right</code> EObjects not to be <code>null</code>.
+ * </p>
+ *
+ * @param left
+ * The left {@link EObject}.
+ * @param right
+ * The right {@link EObject}.
+ * @param origin
+ * The common ancestor of <code>left</code> and <code>right</code>.
+ */
+ protected void match(EObject left, EObject right, EObject origin) {
+ if (left == null || right == null) {
+ // FIXME IAE or NPE?
+ throw new IllegalArgumentException();
+ }
+
+ final Iterator<? extends EObject> leftEObjects = getScope().getChildren(left);
+ final Iterator<? extends EObject> rightEObjects = getScope().getChildren(right);
+ final Iterator<? extends EObject> originEObjects;
+ if (origin != null) {
+ originEObjects = getScope().getChildren(origin);
+ } else {
+ originEObjects = Iterators.emptyIterator();
+ }
+
+ final IEObjectMatcher matcher = createEObjectMatcher();
+ final Iterable<Match> matches = matcher.createMatches(leftEObjects, rightEObjects, originEObjects);
+
// CODEME
}
/**
* This will be used to create the resource matcher that will be used by this match engine.
*
- * @param leftResources
- * The list of all resources from the left side.
- * @param rightResources
- * The list of all resources from the right side.
- * @param originResources
- * The list of all resources from the origin side.
- * @return A {@link ResourceMatcher} that can be used to retrieve the {@link MatchResource} corresponding
- * to the given input.
+ * @return An {@link IResourceMatcher} that can be used to retrieve the {@link MatchResource}s for this
+ * comparison.
*/
- protected ResourceMatcher createResourceMatcher(Iterable<Resource> leftResources,
- Iterable<Resource> rightResources, Iterable<Resource> originResources) {
- return new ResourceMatcher(leftResources, rightResources, originResources);
+ protected IResourceMatcher getResourceMatcher() {
+ return new StrategyResourceMatcher();
+ }
+
+ /**
+ * This will be used to create the EObject matcher that will be used by this match engine.
+ * <p>
+ * This default implementation uses an {@link IdentifierEObjectMatcher} to match EObjects through their ID
+ * only.
+ * </p>
+ *
+ * @return An {@link IEObjectMatcher} that can be used to retrieve the {@link Match}es for this
+ * comparison.
+ */
+ protected IEObjectMatcher createEObjectMatcher() {
+ return new IdentifierEObjectMatcher();
}
/**
@@ -178,4 +260,22 @@ public abstract class AbstractMatchEngine {
protected AbstractComparisonScope getScope() {
return scope;
}
+
+ /**
+ * This will check that at least two of the three given booleans are <code>true</code>.
+ *
+ * @param condition1
+ * First of the three booleans.
+ * @param condition2
+ * Second of the three booleans.
+ * @param condition3
+ * Third of the three booleans.
+ * @return <code>true</code> if at least two of the three given booleans are <code>true</code>,
+ * <code>false</code> otherwise.
+ */
+ protected static boolean atLeastTwo(boolean condition1, boolean condition2, boolean condition3) {
+ // CHECKSTYLE:OFF This expression is alone in its method, and documented.
+ return condition1 && (condition2 || condition3) || (condition2 && condition3);
+ // CHECKSTYLE:ON
+ }
}
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/eobject/IEObjectMatcher.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/eobject/IEObjectMatcher.java
new file mode 100644
index 000000000..2deacf573
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/eobject/IEObjectMatcher.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Obeo.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.match.eobject;
+
+import java.util.Iterator;
+
+import org.eclipse.emf.compare.Match;
+import org.eclipse.emf.ecore.EObject;
+
+/**
+ * An {@link IEObjectMatcher} will be used by the default implementation of the
+ * {@link org.eclipse.emf.compare.match.AbstractMatchEngine} in order to determine the mappings between three
+ * lists of EObjects coming from the left, right and origin sides.
+ * <p>
+ * Do take note that the match engine expects {@link IEObjectMatcher}s to return both matching and unmatching
+ * EObjects.
+ * </p>
+ * <p>
+ * A default implementation of this interface, matching EObjects through their identifier, can also be
+ * subclassed by clients. Sett {@link IdentifierEObjectMatcher}.
+ * </p>
+ *
+ * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
+ * @see IdentifierEObjectMatcher
+ */
+public interface IEObjectMatcher {
+ /**
+ * This will be called by the match engine to determine matches between EObjects.
+ * <p>
+ * The returned matches should include both matching and unmatchings EObjects (i.e. EObjects that can be
+ * matched in all three lists, EObjects that cna be matched in only two of the three lists, and EObjects
+ * that can only be found in one of the three.
+ * </p>
+ *
+ * @param leftEObjects
+ * An iterator over the EObjects that could be found in the left side.
+ * @param rightEObjects
+ * An iterator over the EObjects that could be found in the right side.
+ * @param originEObjects
+ * And iterator over the EObject that may be considered ancestors of the couples that can be
+ * detected in the left and right sides.
+ * @return The list of all detected matches. Should also include unmatching EObjects.
+ */
+ Iterable<Match> createMatches(Iterator<? extends EObject> leftEObjects,
+ Iterator<? extends EObject> rightEObjects, Iterator<? extends EObject> originEObjects);
+}
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/eobject/IdentifierEObjectMatcher.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/eobject/IdentifierEObjectMatcher.java
new file mode 100644
index 000000000..2c7732fbd
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/eobject/IdentifierEObjectMatcher.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Obeo.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.match.eobject;
+
+import java.util.Iterator;
+
+import org.eclipse.emf.compare.Match;
+import org.eclipse.emf.ecore.EObject;
+
+/**
+ * This implementation of an {@link IEObjectMatcher} will create {@link Match}es based on the input EObjects
+ * identifiers (either XMI:ID or attribute ID) alone.
+ *
+ * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
+ */
+public class IdentifierEObjectMatcher implements IEObjectMatcher {
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.compare.match.eobject.IEObjectMatcher#createMatches(java.util.Iterator,
+ * java.util.Iterator, java.util.Iterator)
+ */
+ public Iterable<Match> createMatches(Iterator<? extends EObject> leftEObjects,
+ Iterator<? extends EObject> rightEObjects, Iterator<? extends EObject> originEObjects) {
+ // CODEME
+ return null;
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/ChainMatchingStrategy.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/ChainMatchingStrategy.java
deleted file mode 100644
index a9ad2524c..000000000
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/ChainMatchingStrategy.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2012 Obeo.
- * 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:
- * Obeo - initial API and implementation
- *******************************************************************************/
-package org.eclipse.emf.compare.match.resource;
-
-import com.google.common.collect.Lists;
-
-import java.util.List;
-
-import org.eclipse.emf.ecore.resource.Resource;
-
-/**
- * This implementation of a matching strategy will simply delegate to a number of others in order. The
- * resources for which we found a match in a given strategy won't be passed on to the subsequent strategies of
- * the chain.
- *
- * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
- */
-public class ChainMatchingStrategy implements IResourceMatchingStrategy {
- /** The set of strategies we are to call through this chain. */
- private final IResourceMatchingStrategy[] strategies;
-
- /**
- * Instantiates a chaining strategy given the substrategies that it is to call.
- *
- * @param strategies
- * The strategies we are to delegate to, in the order they are to be called.
- */
- public ChainMatchingStrategy(IResourceMatchingStrategy... strategies) {
- this.strategies = strategies;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.eclipse.emf.compare.match.resource.IResourceMatchingStrategy#matchResources(java.lang.Iterable,
- * java.lang.Iterable, java.lang.Iterable)
- */
- public List<ResourceMapping> matchResources(Iterable<Resource> left, Iterable<Resource> right,
- Iterable<Resource> origin) {
- if (strategies.length == 1) {
- return strategies[0].matchResources(left, right, origin);
- }
-
- final List<ResourceMapping> mappings = Lists.newArrayList();
- final List<Resource> leftCopy = Lists.newArrayList(left);
- final List<Resource> rightCopy = Lists.newArrayList(right);
- final List<Resource> originCopy = Lists.newArrayList(origin);
-
- // Break this loop if we exhausted all strategies or if two of the lists are empty (no potential
- // match remaining)
- for (int i = 0; i < strategies.length
- && !atLeastTwo(leftCopy.isEmpty(), rightCopy.isEmpty(), originCopy.isEmpty()); i++) {
- final List<ResourceMapping> newMappings = strategies[i].matchResources(left, right, origin);
- for (ResourceMapping newMapping : newMappings) {
- leftCopy.remove(newMapping.getLeft());
- rightCopy.remove(newMapping.getRight());
- originCopy.remove(newMapping.getOrigin());
- }
- mappings.addAll(newMappings);
- }
-
- return mappings;
- }
-
- /**
- * This will check that at least two of the three given booleans are <code>true</code>.
- *
- * @param condition1
- * First of the three booleans.
- * @param condition2
- * Second of the three booleans.
- * @param condition3
- * Third of the three booleans.
- * @return <code>true</code> if at least two of the three given booleans are <code>true</code>,
- * <code>false</code> otherwise.
- */
- private static boolean atLeastTwo(boolean condition1, boolean condition2, boolean condition3) {
- // CHECKSTYLE:OFF This expression is alone in its method, and documented.
- return condition1 && (condition2 || condition3) || (condition2 && condition3);
- // CHECKSTYLE:ON
- }
-}
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/IResourceMatcher.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/IResourceMatcher.java
new file mode 100644
index 000000000..a83ba5842
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/IResourceMatcher.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Obeo.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.match.resource;
+
+import java.util.Iterator;
+
+import org.eclipse.emf.ecore.resource.Resource;
+
+/**
+ * An {@link IResourceMatcher} will be used to match two or three
+ * {@link org.eclipse.emf.ecore.resource.Resource}s together; depending on whether we are doing a two or three
+ * way comparison.
+ * <p>
+ * Do take note that the match engine expects IResourceMatchers to return matching resources as well as
+ * resources that do not match.
+ * </p>
+ * <p>
+ * A default implementation of the {@link IResourceMatcher}, based on strategies, can also be subclassed by
+ * clients, see {@link StrategyResourceMatcher}.
+ * </p>
+ *
+ * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
+ * @see StrategyResourceMatcher
+ */
+public interface IResourceMatcher {
+ /**
+ * This will be called by the engine in order to retrieve the mappings created by this matcher.
+ * <p>
+ * The returned mappings should include both "matching" resources and "not matching" resources (i.e.
+ * resources that are in either left or right ... but not in any of the two other lists).
+ * </p>
+ *
+ * @param leftResources
+ * An iterator over the resources we found on the left side.
+ * @param rightResources
+ * An iterator over the resources we found on the right side.
+ * @param originResources
+ * An iterator over the resources that may be considered as common ancestors of the couples
+ * detected on the left and right sides.
+ * @return The created resource mappings. Should include both matched and unmatched resources.
+ */
+ Iterable<ResourceMapping> createMappings(Iterator<? extends Resource> leftResources,
+ Iterator<? extends Resource> rightResources, Iterator<? extends Resource> originResources);
+}
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/IResourceMatchingStrategy.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/IResourceMatchingStrategy.java
index 0674e88aa..fe11394cf 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/IResourceMatchingStrategy.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/IResourceMatchingStrategy.java
@@ -15,7 +15,7 @@ import java.util.List;
import org.eclipse.emf.ecore.resource.Resource;
/**
- * A {@link ResourceMatcher} will be used to match two or three {@link Resource}s together; depending on
+ * A {@link StrategyResourceMatcher} will be used to match two or three {@link Resource}s together; depending on
* whether we are doing a two or three way comparison.
*
* @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
@@ -33,6 +33,6 @@ public interface IResourceMatchingStrategy {
* Resources we are to match in the origin.
* @return The list of mappings this strategy managed to determine.
*/
- List<ResourceMapping> matchResources(Iterable<Resource> left, Iterable<Resource> right,
- Iterable<Resource> origin);
+ List<ResourceMapping> matchResources(Iterable<? extends Resource> left,
+ Iterable<? extends Resource> right, Iterable<? extends Resource> origin);
}
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/NameMatchingStrategy.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/NameMatchingStrategy.java
index a822c3b83..76360601e 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/NameMatchingStrategy.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/NameMatchingStrategy.java
@@ -30,8 +30,8 @@ public class NameMatchingStrategy implements IResourceMatchingStrategy {
* @see org.eclipse.emf.compare.match.resource.IResourceMatchingStrategy#matchResources(java.lang.Iterable,
* java.lang.Iterable, java.lang.Iterable)
*/
- public List<ResourceMapping> matchResources(Iterable<Resource> left, Iterable<Resource> right,
- Iterable<Resource> origin) {
+ public List<ResourceMapping> matchResources(Iterable<? extends Resource> left,
+ Iterable<? extends Resource> right, Iterable<? extends Resource> origin) {
final List<ResourceMapping> mappings = Lists.newArrayList();
final List<Resource> rightCopy = Lists.newArrayList(right);
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/NameSimilarityMatchingStrategy.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/NameSimilarityMatchingStrategy.java
index 808bed937..53d67144e 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/NameSimilarityMatchingStrategy.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/NameSimilarityMatchingStrategy.java
@@ -40,8 +40,8 @@ public class NameSimilarityMatchingStrategy implements IResourceMatchingStrategy
* @see org.eclipse.emf.compare.match.resource.IResourceMatchingStrategy#matchResources(java.lang.Iterable,
* java.lang.Iterable, java.lang.Iterable)
*/
- public List<ResourceMapping> matchResources(Iterable<Resource> left, Iterable<Resource> right,
- Iterable<Resource> origin) {
+ public List<ResourceMapping> matchResources(Iterable<? extends Resource> left,
+ Iterable<? extends Resource> right, Iterable<? extends Resource> origin) {
final List<ResourceMapping> mappings = Lists.newArrayList();
final Set<List<Resource>> productLR = cartesianProductOf(left, right);
@@ -94,14 +94,16 @@ public class NameSimilarityMatchingStrategy implements IResourceMatchingStrategy
* First of the two iterables of which we need the cartesian product.
* @param iterable2
* Second of the two iterables of which we need the cartesian product.
+ * @param <T>
+ * Type of iterables' content.
* @return The cartesian product of the two given iterables.
* @see Sets#cartesianProduct(List)
*/
- private static Set<List<Resource>> cartesianProductOf(Iterable<Resource> iterable1,
- Iterable<Resource> iterable2) {
- Set<Resource> set1 = Sets.newLinkedHashSet(iterable1);
- Set<Resource> set2 = Sets.newLinkedHashSet(iterable2);
- List<Set<Resource>> input = ImmutableList.of(set1, set2);
+ private static <T> Set<List<T>> cartesianProductOf(Iterable<? extends T> iterable1,
+ Iterable<? extends T> iterable2) {
+ Set<T> set1 = Sets.newLinkedHashSet(iterable1);
+ Set<T> set2 = Sets.newLinkedHashSet(iterable2);
+ List<Set<T>> input = ImmutableList.of(set1, set2);
return Sets.cartesianProduct(input);
}
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/ResourceMapping.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/ResourceMapping.java
index 9648892d8..36e480a95 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/ResourceMapping.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/ResourceMapping.java
@@ -13,7 +13,7 @@ package org.eclipse.emf.compare.match.resource;
import org.eclipse.emf.ecore.resource.Resource;
/**
- * Simple structure that the {@link ResourceMatcher}s will use to map Resources together.
+ * Simple structure that the {@link StrategyResourceMatcher}s will use to map Resources together.
*
* @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
*/
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/ResourceMatcher.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/ResourceMatcher.java
deleted file mode 100644
index 990ab2cf6..000000000
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/ResourceMatcher.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2012 Obeo.
- * 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:
- * Obeo - initial API and implementation
- *******************************************************************************/
-package org.eclipse.emf.compare.match.resource;
-
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-
-import java.util.List;
-
-import org.eclipse.emf.ecore.resource.Resource;
-
-/**
- * A {@link ResourceMatcher} will be used to match two or three {@link Resource}s together; depending on
- * whether we are doing a two or three way comparison.
- * <p>
- * Do take note that the match engine expects ResourceMatchers to return matching resources as well as
- * resources that do not match.
- * </p>
- *
- * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
- */
-public class ResourceMatcher {
- /** Left resources we are to match. */
- protected final Iterable<Resource> leftResources;
-
- /** Right resources we are to match. */
- protected final Iterable<Resource> rightResources;
-
- /** Origin of the resources we are to match. */
- protected final Iterable<Resource> originResources;
-
- /**
- * Instantiates a {@link ResourceMatcher} given its target resources.
- *
- * @param leftResources
- * All resources from the left side.
- * @param rightResources
- * All resources from the right side.
- * @param originResources
- * All resources from the origin side.
- */
- public ResourceMatcher(Iterable<Resource> leftResources, Iterable<Resource> rightResources,
- Iterable<Resource> originResources) {
- this.leftResources = leftResources;
- this.rightResources = rightResources;
- this.originResources = originResources;
- }
-
- /**
- * This will be called by the engine in order to retrieve the mappings created by this matcher.
- * <p>
- * The returned mappings should include both "matching" resources and "not matching" resources (i.e.
- * resources that are in either left or right ... but not in any of the two other lists).
- * </p>
- *
- * @return The created resource mappings.
- */
- public Iterable<ResourceMapping> createMappings() {
- final List<ResourceMapping> mappings = Lists.newArrayList();
- // If there is only one of each resource, no need to go any further
- if (Iterables.size(leftResources) == 1 && Iterables.size(rightResources) == 1) {
- final Resource left = leftResources.iterator().next();
- final Resource right = rightResources.iterator().next();
- final ResourceMapping mapping;
- if (Iterables.isEmpty(originResources)) {
- mapping = new ResourceMapping(left, right, null);
- } else {
- mapping = new ResourceMapping(left, right, originResources.iterator().next());
- }
- mappings.add(mapping);
- } else if (!Iterables.isEmpty(leftResources) && !Iterables.isEmpty(rightResources)) {
- // We will try two ways of matching resources before considering them "unmatched" : equal name or
- // equals "roots" identifiers.
- final IResourceMatchingStrategy strategy = createResourceMatchingStrategy();
-
- mappings.addAll(strategy.matchResources(leftResources, rightResources, originResources));
-
- // Any resource that has not been matched by now is unmatched
- final List<Resource> leftUnmatch = Lists.newArrayList(leftResources);
- final List<Resource> rightUnmatch = Lists.newArrayList(rightResources);
- final List<Resource> originUnmatch = Lists.newArrayList(originResources);
-
- for (ResourceMapping mapping : mappings) {
- leftUnmatch.remove(mapping.getLeft());
- rightUnmatch.remove(mapping.getRight());
- originUnmatch.remove(mapping.getOrigin());
- }
-
- for (Resource left : leftUnmatch) {
- mappings.add(new ResourceMapping(left, null, null));
- }
- for (Resource right : rightUnmatch) {
- mappings.add(new ResourceMapping(null, right, null));
- }
- for (Resource origin : originUnmatch) {
- mappings.add(new ResourceMapping(null, null, origin));
- }
- }
-
- return mappings;
- }
-
- /**
- * Creates the resource matching strategy that should be used by this matcher.
- *
- * @return The resource matching strategy that should be used by this matcher.
- */
- protected IResourceMatchingStrategy createResourceMatchingStrategy() {
- final IResourceMatchingStrategy nameStrategy = new NameMatchingStrategy();
- final IResourceMatchingStrategy idStrategy = new RootIDMatchingStrategy();
- return new ChainMatchingStrategy(nameStrategy, idStrategy);
- }
-}
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/RootIDMatchingStrategy.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/RootIDMatchingStrategy.java
index 22607552b..8e7d6b5ca 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/RootIDMatchingStrategy.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/RootIDMatchingStrategy.java
@@ -35,8 +35,8 @@ public class RootIDMatchingStrategy implements IResourceMatchingStrategy {
* @see org.eclipse.emf.compare.match.resource.IResourceMatchingStrategy#matchResources(java.lang.Iterable,
* java.lang.Iterable, java.lang.Iterable)
*/
- public List<ResourceMapping> matchResources(Iterable<Resource> left, Iterable<Resource> right,
- Iterable<Resource> origin) {
+ public List<ResourceMapping> matchResources(Iterable<? extends Resource> left,
+ Iterable<? extends Resource> right, Iterable<? extends Resource> origin) {
final List<ResourceMapping> mappings = Lists.newArrayList();
final List<Resource> rightCopy = Lists.newArrayList(right);
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/StrategyResourceMatcher.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/StrategyResourceMatcher.java
new file mode 100644
index 000000000..8e124014f
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/StrategyResourceMatcher.java
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Obeo.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.match.resource;
+
+import com.google.common.collect.Lists;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.emf.ecore.resource.Resource;
+
+/**
+ * A {@link StrategyResourceMatcher} will be used to match two or three {@link Resource}s together; depending
+ * on whether we are doing a two or three way comparison.
+ * <p>
+ * Do take note that the match engine expects ResourceMatchers to return matching resources as well as
+ * resources that do not match.
+ * </p>
+ *
+ * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
+ */
+public class StrategyResourceMatcher implements IResourceMatcher {
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.compare.match.resource.IResourceMatcher#createMappings(java.util.Iterator,
+ * java.util.Iterator, java.util.Iterator)
+ */
+ public Iterable<ResourceMapping> createMappings(Iterator<? extends Resource> leftResources,
+ Iterator<? extends Resource> rightResources, Iterator<? extends Resource> originResources) {
+ final List<ResourceMapping> mappings;
+
+ // Copy the input Resource lists : we'll exhaust them as we go
+ final List<? extends Resource> leftCopy = Lists.newArrayList(leftResources);
+ final List<? extends Resource> rightCopy = Lists.newArrayList(rightResources);
+ final List<? extends Resource> originCopy = Lists.newArrayList(originResources);
+
+ // Detect matching resources
+ final IResourceMatchingStrategy[] strategies = getResourceMatchingStrategies();
+ if (strategies.length == 1) {
+ mappings = strategies[0].matchResources(leftCopy, rightCopy, originCopy);
+
+ // Remove all matched from the copies to leave only unmatched
+ for (ResourceMapping newMapping : mappings) {
+ leftCopy.remove(newMapping.getLeft());
+ rightCopy.remove(newMapping.getRight());
+ originCopy.remove(newMapping.getOrigin());
+ }
+ } else {
+ mappings = Lists.newArrayList();
+
+ // Break this loop if we exhausted all strategies or if two of the lists are empty (no potential
+ // match remaining)
+ for (int i = 0; i < strategies.length
+ && !atLeastTwo(leftCopy.isEmpty(), rightCopy.isEmpty(), originCopy.isEmpty()); i++) {
+ final List<ResourceMapping> newMappings = strategies[i].matchResources(leftCopy, rightCopy,
+ originCopy);
+ for (ResourceMapping newMapping : newMappings) {
+ leftCopy.remove(newMapping.getLeft());
+ rightCopy.remove(newMapping.getRight());
+ originCopy.remove(newMapping.getOrigin());
+ }
+ mappings.addAll(newMappings);
+ }
+ }
+
+ // Any resource that has not been matched by now is an unmatch. The "copies" list have been updated
+ // each time we found a
+ // match, they only contain the remaining unmatch resources now.
+ for (Resource left : leftCopy) {
+ mappings.add(new ResourceMapping(left, null, null));
+ }
+ for (Resource right : rightCopy) {
+ mappings.add(new ResourceMapping(null, right, null));
+ }
+ for (Resource origin : originCopy) {
+ mappings.add(new ResourceMapping(null, null, origin));
+ }
+
+ return mappings;
+ }
+
+ /**
+ * This will check that at least two of the three given booleans are <code>true</code>.
+ *
+ * @param condition1
+ * First of the three booleans.
+ * @param condition2
+ * Second of the three booleans.
+ * @param condition3
+ * Third of the three booleans.
+ * @return <code>true</code> if at least two of the three given booleans are <code>true</code>,
+ * <code>false</code> otherwise.
+ */
+ protected static boolean atLeastTwo(boolean condition1, boolean condition2, boolean condition3) {
+ // CHECKSTYLE:OFF This expression is alone in its method, and documented.
+ return condition1 && (condition2 || condition3) || (condition2 && condition3);
+ // CHECKSTYLE:ON
+ }
+
+ /**
+ * Returns the matching strategies that are to be used by this resource matcher.
+ * <p>
+ * This default implementation will try two ways of matching the resources before giving up : resources
+ * have equal name, then resources have roots with equal identifiers.
+ * </p>
+ * <p>
+ * Resource Matching Strategies are expected to map resources together, but not to detect resources that
+ * do not match.
+ * </p>
+ *
+ * @return The resource matching strategies that should be used by this matcher.
+ */
+ protected IResourceMatchingStrategy[] getResourceMatchingStrategies() {
+ final IResourceMatchingStrategy nameStrategy = new NameMatchingStrategy();
+ final IResourceMatchingStrategy idStrategy = new RootIDMatchingStrategy();
+ return new IResourceMatchingStrategy[] {nameStrategy, idStrategy, };
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/scope/AbstractComparisonScope.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/scope/AbstractComparisonScope.java
index 4c81f4a67..eb3d10cd1 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/scope/AbstractComparisonScope.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/scope/AbstractComparisonScope.java
@@ -10,7 +10,12 @@
*******************************************************************************/
package org.eclipse.emf.compare.scope;
+import java.util.Iterator;
+
import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
/**
* This class defines the expected contract of EMF Compare scopes.
@@ -80,13 +85,31 @@ public abstract class AbstractComparisonScope {
}
/**
- * This will be used by EMF Compare in order to retrieve the children of the given {@link Notifier}. Only
- * the children returned by this method will be matched with their other versions' counterparts.
+ * This will be used by EMF Compare in order to know which Resources are under the given ResourceSet.
+ *
+ * @param resourceSet
+ * The resource set for which we need all Resources.
+ * @return An iterator over the {@link Resource}s within the given {@link ResourceSet} which are part of
+ * this scope.
+ */
+ public abstract Iterator<? extends Resource> getChildren(ResourceSet resourceSet);
+
+ /**
+ * This will be used by EMF Compare in order to determine the EObjects that it should iterate over.
+ *
+ * @param resource
+ * The resource for which we need to determine the content.
+ * @return An iterator over the {@link EObject}s within the given {@link Resource} which are part of this
+ * scope.
+ */
+ public abstract Iterator<? extends EObject> getChildren(Resource resource);
+
+ /**
+ * This will be used by EMF Compare in order to know which EObjects are located under the given EObject.
*
- * @param notifier
- * The notifier which children should be returned.
- * @return The children of the given {@link Notifier} that should be matched. Should never be
- * <code>null</code>.
+ * @param eObject
+ * The EObject for which we need to determine the content.
+ * @return An iterator over the Resources within the given {@link EObject} which are part of this scope.
*/
- public abstract Iterable<Notifier> getChildren(Notifier notifier);
+ public abstract Iterator<? extends EObject> getChildren(EObject eObject);
}
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/scope/DefaultComparisonScope.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/scope/DefaultComparisonScope.java
index f23b8e6f4..b1799e54d 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/scope/DefaultComparisonScope.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/scope/DefaultComparisonScope.java
@@ -10,14 +10,15 @@
*******************************************************************************/
package org.eclipse.emf.compare.scope;
-import com.google.common.collect.Lists;
+import com.google.common.collect.Iterators;
-import java.util.List;
+import java.util.Iterator;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.util.EcoreUtil;
/**
* This implementation of an {@link AbstractComparisonScope} will return all of its Notifiers' contents
@@ -43,18 +44,34 @@ public class DefaultComparisonScope extends AbstractComparisonScope {
/**
* {@inheritDoc}
*
- * @see org.eclipse.emf.compare.scope.AbstractComparisonScope#getChildren(org.eclipse.emf.common.notify.Notifier)
+ * @see org.eclipse.emf.compare.scope.AbstractComparisonScope#getChildren(org.eclipse.emf.ecore.EObject)
*/
@Override
- public Iterable<Notifier> getChildren(Notifier notifier) {
- final List<Notifier> children = Lists.newArrayList();
- if (notifier instanceof ResourceSet) {
- children.addAll(((ResourceSet)notifier).getResources());
- } else if (notifier instanceof Resource) {
- children.addAll(((Resource)notifier).getContents());
- } else if (notifier instanceof EObject) {
- children.addAll(((EObject)notifier).eContents());
- }
- return children;
+ public Iterator<? extends EObject> getChildren(EObject eObject) {
+ final Iterator<EObject> properContent = Iterators.filter(EcoreUtil.getAllProperContents(eObject,
+ false), EObject.class);
+ return Iterators.unmodifiableIterator(properContent);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.compare.scope.AbstractComparisonScope#getChildren(org.eclipse.emf.ecore.resource.Resource)
+ */
+ @Override
+ public Iterator<? extends EObject> getChildren(Resource resource) {
+ final Iterator<EObject> properContent = Iterators.filter(EcoreUtil.getAllProperContents(resource,
+ false), EObject.class);
+ return Iterators.unmodifiableIterator(properContent);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.compare.scope.AbstractComparisonScope#getChildren(org.eclipse.emf.ecore.resource.ResourceSet)
+ */
+ @Override
+ public Iterator<? extends Resource> getChildren(ResourceSet resourceSet) {
+ return Iterators.unmodifiableIterator(resourceSet.getResources().iterator());
}
}

Back to the top