Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Dirix2015-03-03 10:54:28 +0000
committerAxel RICHARD2015-03-09 08:11:25 +0000
commitbf9717a69a20da626b1d8955c8c371973396b531 (patch)
treeeceaa735f8cdacfce4b03d79b1f7e053735f40bd
parent0cd4336875072986b52723da20b0baadf7d893b7 (diff)
downloadorg.eclipse.emf.compare-bf9717a69a20da626b1d8955c8c371973396b531.tar.gz
org.eclipse.emf.compare-bf9717a69a20da626b1d8955c8c371973396b531.tar.xz
org.eclipse.emf.compare-bf9717a69a20da626b1d8955c8c371973396b531.zip
[461291] Avoid matching proxies with actual objects in
IdentifierEObjectMatcher Differentiates between identifiers for proxies and identifiers for actual objects within the IdentifierEObjectMachter. This avoids matching proxies with actual objects while still allowing themselves to be matched. Includes testcases. Bug: 461291 Signed-off-by: Stefan Dirix <sdirix@eclipsesource.com> Change-Id: Ib1a6553bfd0a682652de728f727a21607c6cc6c6
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/ProxyMatchingTest.java113
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/MatchInputData.java37
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/proxy/a1/left.nodes11
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/proxy/a1/right.nodes13
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/proxy/a2/left.nodes11
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/proxy/a2/other.nodes9
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/proxy/a2/right.nodes13
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/suite/AllTests.java7
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/eobject/IdentifierEObjectMatcher.java88
9 files changed, 291 insertions, 11 deletions
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/ProxyMatchingTest.java b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/ProxyMatchingTest.java
new file mode 100644
index 000000000..98ec6c334
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/ProxyMatchingTest.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2015 EclipseSource Muenchen GmbH 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:
+ * Stefan Dirix - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.tests.match;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.EMFCompare;
+import org.eclipse.emf.compare.Match;
+import org.eclipse.emf.compare.ResourceAttachmentChange;
+import org.eclipse.emf.compare.scope.DefaultComparisonScope;
+import org.eclipse.emf.compare.scope.IComparisonScope;
+import org.eclipse.emf.compare.tests.match.data.MatchInputData;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.junit.Test;
+
+/**
+ * Tests the matching behavior when unresolvable proxies exist.
+ *
+ * @author Stefan Dirix <sdirix@eclipsesource.com>
+ */
+public class ProxyMatchingTest {
+
+ private MatchInputData input = new MatchInputData();
+
+ /**
+ * Tests a scenario in which the elements are identified via xmi:ids and the left side uses an
+ * unresolvable proxy.
+ *
+ * @throws IOException
+ * if {@link MatchInputData} fails to load the test models.
+ */
+ @Test
+ public void testProxyA1() throws IOException {
+ final Resource left = input.getProxyMatchingA1Left();
+ final Resource right = input.getProxyMatchingA1Right();
+
+ final ResourceSet leftResourceSet = left.getResourceSet();
+ final ResourceSet rightResourceSet = right.getResourceSet();
+
+ EcoreUtil.resolveAll(leftResourceSet);
+ EcoreUtil.resolveAll(rightResourceSet);
+
+ final IComparisonScope scope = new DefaultComparisonScope(leftResourceSet, rightResourceSet, null);
+ final Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+ final List<Match> matches = comparison.getMatches();
+
+ // There should be one root match
+ assertEquals(1, matches.size());
+
+ // The root match should have two submatches since the proxy can not be matched to the "real" object
+ final Match rootMatch = matches.get(0);
+ final List<Match> subMatches = rootMatch.getSubmatches();
+ assertEquals(2, subMatches.size());
+
+ // Based on the matches two differences should be determined (add/delete)
+ final List<Diff> differences = comparison.getDifferences();
+ assertEquals(2, differences.size());
+ }
+
+ /**
+ * Tests a scenario in which the elements are identified via xmi:ids and the left side uses a resolvable
+ * proxy.
+ *
+ * @throws IOException
+ * if {@link MatchInputData} fails to load the test models.
+ */
+ @Test
+ public void testProxyA2() throws IOException {
+ final Resource left = input.getProxyMatchingA2Left();
+ final Resource right = input.getProxyMatchingA2Right();
+
+ final ResourceSet leftResourceSet = left.getResourceSet();
+ final ResourceSet rightResourceSet = right.getResourceSet();
+
+ EcoreUtil.resolveAll(leftResourceSet);
+ EcoreUtil.resolveAll(rightResourceSet);
+
+ final IComparisonScope scope = new DefaultComparisonScope(leftResourceSet, rightResourceSet, null);
+ final Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+ final List<Match> matches = comparison.getMatches();
+
+ // There should be one root match
+ assertEquals(1, matches.size());
+
+ // The root match should have one submatch
+ final Match rootMatch = matches.get(0);
+ final List<Match> subMatches = rootMatch.getSubmatches();
+ assertEquals(1, subMatches.size());
+
+ // There should be one ResourceAttachmentChange
+ final List<Diff> differences = comparison.getDifferences();
+ assertEquals(1, differences.size());
+ assertTrue(differences.get(0) instanceof ResourceAttachmentChange);
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/MatchInputData.java b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/MatchInputData.java
new file mode 100644
index 000000000..7dcd0cf3d
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/MatchInputData.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2015 EclipseSource Muenchen GmbH 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:
+ * Stefan Dirix - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.tests.match.data;
+
+import java.io.IOException;
+
+import org.eclipse.emf.compare.tests.framework.AbstractInputData;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+
+@SuppressWarnings("nls")
+public class MatchInputData extends AbstractInputData {
+
+ public Resource getProxyMatchingA1Left() throws IOException {
+ return loadFromClassLoader("proxy/a1/left.nodes", new ResourceSetImpl());
+ }
+
+ public Resource getProxyMatchingA1Right() throws IOException {
+ return loadFromClassLoader("proxy/a1/right.nodes", new ResourceSetImpl());
+ }
+
+ public Resource getProxyMatchingA2Left() throws IOException {
+ return loadFromClassLoader("proxy/a2/left.nodes", new ResourceSetImpl());
+ }
+
+ public Resource getProxyMatchingA2Right() throws IOException {
+ return loadFromClassLoader("proxy/a2/right.nodes", new ResourceSetImpl());
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/proxy/a1/left.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/proxy/a1/left.nodes
new file mode 100644
index 000000000..77902c7f2
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/proxy/a1/left.nodes
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<nodes:Node
+ xmi:version="2.0"
+ xmlns:xmi="http://www.omg.org/XMI"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes"
+ xmi:id="_root"
+ name="root">
+ <containmentRef1
+ href="nonexisting.nodes#_a"/>
+</nodes:Node>
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/proxy/a1/right.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/proxy/a1/right.nodes
new file mode 100644
index 000000000..9691e3a67
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/proxy/a1/right.nodes
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<nodes:Node
+ xmi:version="2.0"
+ xmlns:xmi="http://www.omg.org/XMI"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes"
+ xmi:id="_root"
+ name="root">
+ <containmentRef1
+ xsi:type="nodes:NodeSingleValueAttribute"
+ xmi:id="_a"
+ singleValuedAttribute="attribute1"/>
+</nodes:Node>
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/proxy/a2/left.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/proxy/a2/left.nodes
new file mode 100644
index 000000000..7f89b5406
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/proxy/a2/left.nodes
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<nodes:Node
+ xmi:version="2.0"
+ xmlns:xmi="http://www.omg.org/XMI"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes"
+ xmi:id="_root"
+ name="root">
+ <containmentRef1
+ href="other.nodes#_a"/>
+</nodes:Node>
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/proxy/a2/other.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/proxy/a2/other.nodes
new file mode 100644
index 000000000..53a8b0b4c
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/proxy/a2/other.nodes
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<nodes:NodeSingleValueAttribute
+ xmi:version="2.0"
+ xmlns:xmi="http://www.omg.org/XMI"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes"
+ xmi:id="_a"
+ singleValuedAttribute="attribute1">
+</nodes:NodeSingleValueAttribute>
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/proxy/a2/right.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/proxy/a2/right.nodes
new file mode 100644
index 000000000..9691e3a67
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/match/data/proxy/a2/right.nodes
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<nodes:Node
+ xmi:version="2.0"
+ xmlns:xmi="http://www.omg.org/XMI"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes"
+ xmi:id="_root"
+ name="root">
+ <containmentRef1
+ xsi:type="nodes:NodeSingleValueAttribute"
+ xmi:id="_a"
+ singleValuedAttribute="attribute1"/>
+</nodes:Node>
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/suite/AllTests.java b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/suite/AllTests.java
index 75261b04d..37308ddd6 100644
--- a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/suite/AllTests.java
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/suite/AllTests.java
@@ -8,6 +8,7 @@
* Contributors:
* Obeo - initial API and implementation
* Philip Langer - Adds additional test classes
+ * Stefan Dirix - Add additional test class
*******************************************************************************/
package org.eclipse.emf.compare.tests.suite;
@@ -35,6 +36,7 @@ import org.eclipse.emf.compare.tests.fullcomparison.IdentifierComparisonTest;
import org.eclipse.emf.compare.tests.fullcomparison.ProximityComparisonTest;
import org.eclipse.emf.compare.tests.match.MatchEngineFactoryRegistryTest;
import org.eclipse.emf.compare.tests.match.ProximityIndexTest;
+import org.eclipse.emf.compare.tests.match.ProxyMatchingTest;
import org.eclipse.emf.compare.tests.merge.ConflictMergeTest;
import org.eclipse.emf.compare.tests.merge.ExtensionMergeTest;
import org.eclipse.emf.compare.tests.merge.FeatureMaps2wayMergeTest;
@@ -76,8 +78,9 @@ import org.junit.runners.Suite.SuiteClasses;
ExtensionMergeTest.class, IndividualMergeOutOfScopeValuesTest.class, ProximityComparisonTest.class,
DynamicInstanceComparisonTest.class, URIDistanceTest.class, FragmentationTest.class,
AllEditTests.class, CommandStackTestSuite.class, MatchEngineFactoryRegistryTest.class,
- ConflictMergeTest.class, PseudoConflictMergeTest.class, ProximityIndexTest.class, AllRCPTests.class,
- FeatureMaps2wayMergeTest.class, FeatureMaps3wayMergeTest.class, FeatureMapsConflictsMergeTest.class,
+ ProxyMatchingTest.class, ConflictMergeTest.class, PseudoConflictMergeTest.class,
+ ProximityIndexTest.class, AllRCPTests.class, FeatureMaps2wayMergeTest.class,
+ FeatureMaps3wayMergeTest.class, FeatureMapsConflictsMergeTest.class,
FeatureMapsPseudoConflictsMergeTest.class, TwoWayBatchMergingTest.class, EqualityHelperTest.class,
FeatureFilterTest.class, ThreeWayBatchMergingTest.class,
MultiLineAttributeConflictDetectionTest.class, ThreeWayTextDiffTest.class,
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
index aec5d4502..9b0d306ef 100644
--- 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
@@ -9,7 +9,7 @@
* Obeo - initial API and implementation
* Alexandra Buzila - Bug 450360
* Philip Langer - Bug 460778
- * Stefan Dirix - Bug 461011
+ * Stefan Dirix - Bugs 461011 and 461291
*******************************************************************************/
package org.eclipse.emf.compare.match.eobject;
@@ -211,7 +211,8 @@ public class IdentifierEObjectMatcher implements IEObjectMatcher {
final Set<Match> matches = Sets.newLinkedHashSet();
// This lookup map will be used by iterations on right and origin to find the match in which they
// should add themselves
- final Map<String, Match> idToMatch = Maps.newHashMap();
+
+ SwitchMap<String, Match> idProxyMap = new SwitchMap<String, Match>();
// We will try and mimic the structure of the input model.
// These map do not need to be ordered, we only need fast lookup.
@@ -236,10 +237,11 @@ public class IdentifierEObjectMatcher implements IEObjectMatcher {
} else {
matches.add(match);
}
- if (idToMatch.containsKey(identifier)) {
+
+ final boolean isAlreadyContained = idProxyMap.put(left.eIsProxy(), identifier, match);
+ if (isAlreadyContained) {
reportDuplicateID(Side.LEFT, left);
}
- idToMatch.put(identifier, match);
leftEObjectsToMatch.put(left, match);
} else {
leftEObjectsNoID.add(left);
@@ -252,13 +254,12 @@ public class IdentifierEObjectMatcher implements IEObjectMatcher {
// Do we have an existing match?
final String identifier = idComputation.apply(right);
if (identifier != null) {
- Match match = idToMatch.get(identifier);
+ Match match = idProxyMap.get(right.eIsProxy(), identifier);
if (match != null) {
if (match.getRight() != null) {
reportDuplicateID(Side.RIGHT, right);
}
match.setRight(right);
-
rightEObjectsToMatch.put(right, match);
} else {
// Otherwise, create and place it.
@@ -275,7 +276,7 @@ public class IdentifierEObjectMatcher implements IEObjectMatcher {
}
rightEObjectsToMatch.put(right, match);
- idToMatch.put(identifier, match);
+ idProxyMap.put(right.eIsProxy(), identifier, match);
}
} else {
rightEObjectsNoID.add(right);
@@ -288,7 +289,7 @@ public class IdentifierEObjectMatcher implements IEObjectMatcher {
// Do we have an existing match?
final String identifier = idComputation.apply(origin);
if (identifier != null) {
- Match match = idToMatch.get(identifier);
+ Match match = idProxyMap.get(origin.eIsProxy(), identifier);
if (match != null) {
if (match.getOrigin() != null) {
reportDuplicateID(Side.ORIGIN, origin);
@@ -310,7 +311,7 @@ public class IdentifierEObjectMatcher implements IEObjectMatcher {
matches.add(match);
}
- idToMatch.put(identifier, match);
+ idProxyMap.put(origin.eIsProxy(), identifier, match);
originEObjectsToMatch.put(origin, match);
}
} else {
@@ -366,6 +367,7 @@ public class IdentifierEObjectMatcher implements IEObjectMatcher {
* </p>
*
* @param eObject
+ * The {@link EObject} for which's resource the string representation of its URI is determined.
* @return A String representation of the given {@code eObject}'s resource URI.
*/
private String getUriString(EObject eObject) {
@@ -431,4 +433,72 @@ public class IdentifierEObjectMatcher implements IEObjectMatcher {
return identifier;
}
}
+
+ /**
+ * Helper class to manage two different maps within one class based on a switch boolean.
+ *
+ * @param <K>
+ * The class used as key in the internal maps.
+ * @param <V>
+ * The class used as value in the internal maps.
+ */
+ private class SwitchMap<K, V> {
+
+ /**
+ * Map used when the switch boolean is true.
+ */
+ final Map<K, V> trueMap = Maps.newHashMap();
+
+ /**
+ * Map used when the switch boolean is false.
+ */
+ final Map<K, V> falseMap = Maps.newHashMap();
+
+ /**
+ * Puts the key-value pair in the map corresponding to the switch.
+ *
+ * @param switcher
+ * The boolean variable defining which map is to be used.
+ * @param key
+ * The key which is to be put into a map.
+ * @param value
+ * The value which is to be put into a map.
+ * @return {@code true} if the key was already contained in the chosen map, {@code false} otherwise.
+ */
+ public boolean put(boolean switcher, K key, V value) {
+ final Map<K, V> selectedMap = getMap(switcher);
+ final boolean isContained = selectedMap.containsKey(key);
+ selectedMap.put(key, value);
+ return isContained;
+ }
+
+ /**
+ * Returns the value mapped to key.
+ *
+ * @param switcher
+ * The boolean variable defining which map is to be used.
+ * @param key
+ * The key for which the value is looked up.
+ * @return The value {@link V} if it exists, {@code null} otherwise.
+ */
+ public V get(boolean switcher, K key) {
+ final Map<K, V> selectedMap = getMap(switcher);
+ return selectedMap.get(key);
+ }
+
+ /**
+ * Selects the map based on the given boolean.
+ *
+ * @param switcher
+ * Defined which map is to be used.
+ * @return {@link #trueMap} if {@code switcher} is true, {@link #falseMap} otherwise.
+ */
+ private Map<K, V> getMap(boolean switcher) {
+ if (switcher) {
+ return falseMap;
+ } else {
+ return trueMap;
+ }
+ }
+ }
}

Back to the top