Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCedric Notot2012-05-22 07:15:50 -0400
committerCedric Notot2012-05-30 05:31:36 -0400
commit75f51818620f9a47b5499ef732712d72f2864a0f (patch)
tree38e9c2fd6ca4996a0071f9477afabd998a716827
parente26fbe664b89492304bc037a6dfdeaac81828e88 (diff)
downloadorg.eclipse.emf.compare-75f51818620f9a47b5499ef732712d72f2864a0f.tar.gz
org.eclipse.emf.compare-75f51818620f9a47b5499ef732712d72f2864a0f.tar.xz
org.eclipse.emf.compare-75f51818620f9a47b5499ef732712d72f2864a0f.zip
Use of EcoreUtil.CrossReferencer and equivalence computing development
-rw-r--r--plugins/org.eclipse.emf.compare.tests/model/nodes.ecore18
-rw-r--r--plugins/org.eclipse.emf.compare.tests/model/nodes.genmodel12
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/equi/EquiComputingTest.java83
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/equi/data/EquiInputData.java16
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/equi/data/a1/left.nodes9
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/equi/data/a1/right.nodes9
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/equi/data/useCases9
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/suite/AllTests.java9
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/EMFCompare.java12
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/equi/DefaultEquiEngine.java103
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/equi/IEquiEngine.java34
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/req/DefaultReqEngine.java40
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/ReferenceUtil.java58
13 files changed, 377 insertions, 35 deletions
diff --git a/plugins/org.eclipse.emf.compare.tests/model/nodes.ecore b/plugins/org.eclipse.emf.compare.tests/model/nodes.ecore
index dd1a4c0d0..0a9ad7160 100644
--- a/plugins/org.eclipse.emf.compare.tests/model/nodes.ecore
+++ b/plugins/org.eclipse.emf.compare.tests/model/nodes.ecore
@@ -34,4 +34,22 @@
<eStructuralFeatures xsi:type="ecore:EReference" name="multiValuedReference" upperBound="-1"
eType="#//Node"/>
</eClassifiers>
+ <eClassifiers xsi:type="ecore:EClass" name="NodeOppositeRefOneToOne" eSuperTypes="#//Node">
+ <eStructuralFeatures xsi:type="ecore:EReference" name="source" eType="#//NodeOppositeRefOneToOne"
+ eOpposite="#//NodeOppositeRefOneToOne/destination"/>
+ <eStructuralFeatures xsi:type="ecore:EReference" name="destination" eType="#//NodeOppositeRefOneToOne"
+ eOpposite="#//NodeOppositeRefOneToOne/source"/>
+ </eClassifiers>
+ <eClassifiers xsi:type="ecore:EClass" name="NodeOppositeRefOneToMany" eSuperTypes="#//Node">
+ <eStructuralFeatures xsi:type="ecore:EReference" name="source" eType="#//NodeOppositeRefOneToMany"
+ eOpposite="#//NodeOppositeRefOneToMany/destination"/>
+ <eStructuralFeatures xsi:type="ecore:EReference" name="destination" upperBound="-1"
+ eType="#//NodeOppositeRefOneToMany" eOpposite="#//NodeOppositeRefOneToMany/source"/>
+ </eClassifiers>
+ <eClassifiers xsi:type="ecore:EClass" name="NodeOppositeRefManyToMany" eSuperTypes="#//Node">
+ <eStructuralFeatures xsi:type="ecore:EReference" name="source" upperBound="-1"
+ eType="#//NodeOppositeRefManyToMany" eOpposite="#//NodeOppositeRefManyToMany/destination"/>
+ <eStructuralFeatures xsi:type="ecore:EReference" name="destination" upperBound="-1"
+ eType="#//NodeOppositeRefManyToMany" eOpposite="#//NodeOppositeRefManyToMany/source"/>
+ </eClassifiers>
</ecore:EPackage>
diff --git a/plugins/org.eclipse.emf.compare.tests/model/nodes.genmodel b/plugins/org.eclipse.emf.compare.tests/model/nodes.genmodel
index cc57fd36f..50c4129e2 100644
--- a/plugins/org.eclipse.emf.compare.tests/model/nodes.genmodel
+++ b/plugins/org.eclipse.emf.compare.tests/model/nodes.genmodel
@@ -31,5 +31,17 @@
<genClasses ecoreClass="nodes.ecore#//NodeMultiValueReference">
<genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference nodes.ecore#//NodeMultiValueReference/multiValuedReference"/>
</genClasses>
+ <genClasses ecoreClass="nodes.ecore#//NodeOppositeRefOneToOne">
+ <genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference nodes.ecore#//NodeOppositeRefOneToOne/source"/>
+ <genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference nodes.ecore#//NodeOppositeRefOneToOne/destination"/>
+ </genClasses>
+ <genClasses ecoreClass="nodes.ecore#//NodeOppositeRefOneToMany">
+ <genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference nodes.ecore#//NodeOppositeRefOneToMany/source"/>
+ <genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference nodes.ecore#//NodeOppositeRefOneToMany/destination"/>
+ </genClasses>
+ <genClasses ecoreClass="nodes.ecore#//NodeOppositeRefManyToMany">
+ <genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference nodes.ecore#//NodeOppositeRefManyToMany/source"/>
+ <genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference nodes.ecore#//NodeOppositeRefManyToMany/destination"/>
+ </genClasses>
</genPackages>
</genmodel:GenModel>
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/equi/EquiComputingTest.java b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/equi/EquiComputingTest.java
new file mode 100644
index 000000000..a3dac6a28
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/equi/EquiComputingTest.java
@@ -0,0 +1,83 @@
+package org.eclipse.emf.compare.tests.equi;
+
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertSame;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.addedToReference;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.changedReference;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterators;
+
+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.tests.equi.data.EquiInputData;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.junit.Test;
+
+public class EquiComputingTest {
+
+ private EquiInputData input = new EquiInputData();
+
+ @Test
+ public void testA1UseCase() throws IOException {
+ final Resource left = input.getA1Left();
+ final Resource right = input.getA1Right();
+
+ final Comparison comparison = EMFCompare.compare(left, right);
+
+ List<Diff> differences = comparison.getDifferences();
+
+ // We should have no less and no more than 6 differences
+ assertSame(Integer.valueOf(6), Integer.valueOf(differences.size()));
+
+ Predicate<? super Diff> changeRefA2BDiffDescription = changedReference("Requirements.A",
+ "destination", null, "Requirements.B");
+ Predicate<? super Diff> changeRefB2ADiffDescription = changedReference("Requirements.B", "source",
+ null, "Requirements.A");
+ Predicate<? super Diff> changeRefC2DDiffDescription = addedToReference("Requirements.C",
+ "destination", "Requirements.D");
+ Predicate<? super Diff> changeRefD2CDiffDescription = changedReference("Requirements.D", "source",
+ null, "Requirements.C");
+ Predicate<? super Diff> changeRefE2FDiffDescription = addedToReference("Requirements.E",
+ "destination", "Requirements.F");
+ Predicate<? super Diff> changeRefF2EDiffDescription = addedToReference("Requirements.F", "source",
+ "Requirements.E");
+
+ final Diff changeRefA2BDiff = Iterators.find(differences.iterator(), changeRefA2BDiffDescription);
+ final Diff changeRefB2ADiff = Iterators.find(differences.iterator(), changeRefB2ADiffDescription);
+ final Diff changeRefC2DDiff = Iterators.find(differences.iterator(), changeRefC2DDiffDescription);
+ final Diff changeRefD2CDiff = Iterators.find(differences.iterator(), changeRefD2CDiffDescription);
+ final Diff changeRefE2FDiff = Iterators.find(differences.iterator(), changeRefE2FDiffDescription);
+ final Diff changeRefF2EDiff = Iterators.find(differences.iterator(), changeRefF2EDiffDescription);
+
+ assertNotNull(changeRefA2BDiff);
+ assertNotNull(changeRefB2ADiff);
+ assertNotNull(changeRefC2DDiff);
+ assertNotNull(changeRefD2CDiff);
+ assertNotNull(changeRefE2FDiff);
+ assertNotNull(changeRefF2EDiff);
+
+ // CHECK EQUIVALENCE
+ assertNotNull(changeRefA2BDiff.getEquivalence());
+ assertSame(Integer.valueOf(2), changeRefA2BDiff.getEquivalence().getDifferences().size());
+ assertTrue(changeRefA2BDiff.getEquivalence().getDifferences().contains(changeRefA2BDiff));
+ assertTrue(changeRefA2BDiff.getEquivalence().getDifferences().contains(changeRefB2ADiff));
+
+ assertNotNull(changeRefC2DDiff.getEquivalence());
+ assertSame(Integer.valueOf(2), changeRefC2DDiff.getEquivalence().getDifferences().size());
+ assertTrue(changeRefC2DDiff.getEquivalence().getDifferences().contains(changeRefC2DDiff));
+ assertTrue(changeRefC2DDiff.getEquivalence().getDifferences().contains(changeRefD2CDiff));
+
+ assertNotNull(changeRefE2FDiff.getEquivalence());
+ assertSame(Integer.valueOf(2), changeRefE2FDiff.getEquivalence().getDifferences().size());
+ assertTrue(changeRefE2FDiff.getEquivalence().getDifferences().contains(changeRefE2FDiff));
+ assertTrue(changeRefE2FDiff.getEquivalence().getDifferences().contains(changeRefF2EDiff));
+
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/equi/data/EquiInputData.java b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/equi/data/EquiInputData.java
new file mode 100644
index 000000000..9f1af3860
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/equi/data/EquiInputData.java
@@ -0,0 +1,16 @@
+package org.eclipse.emf.compare.tests.equi.data;
+
+import java.io.IOException;
+
+import org.eclipse.emf.compare.tests.framework.AbstractInputData;
+import org.eclipse.emf.ecore.resource.Resource;
+
+public class EquiInputData extends AbstractInputData {
+ public Resource getA1Left() throws IOException {
+ return loadFromClassloader("a1/left.nodes"); //$NON-NLS-1$
+ }
+
+ public Resource getA1Right() throws IOException {
+ return loadFromClassloader("a1/right.nodes"); //$NON-NLS-1$
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/equi/data/a1/left.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/equi/data/a1/left.nodes
new file mode 100644
index 000000000..d3a7808e6
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/equi/data/a1/left.nodes
@@ -0,0 +1,9 @@
+<?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="_yWc_0JUeEeGiestbncRZoQ" name="Requirements">
+ <containmentRef1 xsi:type="nodes:NodeOppositeRefOneToOne" xmi:id="_ZB0jcJtsEeGMQeoeefOsHA" name="A" destination="_dRiFIJtsEeGMQeoeefOsHA"/>
+ <containmentRef1 xsi:type="nodes:NodeOppositeRefOneToOne" xmi:id="_dRiFIJtsEeGMQeoeefOsHA" name="B" source="_ZB0jcJtsEeGMQeoeefOsHA"/>
+ <containmentRef1 xsi:type="nodes:NodeOppositeRefOneToMany" xmi:id="_m5FOMJtsEeGMQeoeefOsHA" name="C" destination="_njLUEJtsEeGMQeoeefOsHA"/>
+ <containmentRef1 xsi:type="nodes:NodeOppositeRefOneToMany" xmi:id="_njLUEJtsEeGMQeoeefOsHA" name="D" source="_m5FOMJtsEeGMQeoeefOsHA"/>
+ <containmentRef1 xsi:type="nodes:NodeOppositeRefManyToMany" xmi:id="_xjrvsJtsEeGMQeoeefOsHA" name="E" destination="_zbOgIJtsEeGMQeoeefOsHA"/>
+ <containmentRef1 xsi:type="nodes:NodeOppositeRefManyToMany" xmi:id="_zbOgIJtsEeGMQeoeefOsHA" name="F" source="_xjrvsJtsEeGMQeoeefOsHA"/>
+</nodes:Node>
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/equi/data/a1/right.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/equi/data/a1/right.nodes
new file mode 100644
index 000000000..c2295d20e
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/equi/data/a1/right.nodes
@@ -0,0 +1,9 @@
+<?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="_yWc_0JUeEeGiestbncRZoQ" name="Requirements">
+ <containmentRef1 xsi:type="nodes:NodeOppositeRefOneToOne" xmi:id="_ZB0jcJtsEeGMQeoeefOsHA" name="A"/>
+ <containmentRef1 xsi:type="nodes:NodeOppositeRefOneToOne" xmi:id="_dRiFIJtsEeGMQeoeefOsHA" name="B"/>
+ <containmentRef1 xsi:type="nodes:NodeOppositeRefOneToMany" xmi:id="_m5FOMJtsEeGMQeoeefOsHA" name="C"/>
+ <containmentRef1 xsi:type="nodes:NodeOppositeRefOneToMany" xmi:id="_njLUEJtsEeGMQeoeefOsHA" name="D"/>
+ <containmentRef1 xsi:type="nodes:NodeOppositeRefManyToMany" xmi:id="_xjrvsJtsEeGMQeoeefOsHA" name="E"/>
+ <containmentRef1 xsi:type="nodes:NodeOppositeRefManyToMany" xmi:id="_zbOgIJtsEeGMQeoeefOsHA" name="F"/>
+</nodes:Node>
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/equi/data/useCases b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/equi/data/useCases
new file mode 100644
index 000000000..e32370424
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/equi/data/useCases
@@ -0,0 +1,9 @@
+This will try and list all possible "dependence" cases that can happen in a model comparison. For each use case, we will consider
+two models, "left" and "right".
+
+a - 2-ways comparison
+ a1 - 1-1 relation
+ a2 - 1-n relation
+ a3 - n-1 relation
+ a4 - n-n relation
+
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 2af7311a7..81675f989 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
@@ -16,8 +16,9 @@ import junit.textui.TestRunner;
import org.eclipse.emf.compare.ComparePackage;
import org.eclipse.emf.compare.internal.spec.CompareFactorySpec;
-import org.eclipse.emf.compare.tests.conflict.ConflictDetectionTest;
-import org.eclipse.emf.compare.tests.diff.DiffEngineTest;
+import org.eclipse.emf.compare.tests.conflict.ConflictDetectionTest;
+import org.eclipse.emf.compare.tests.diff.DiffEngineTest;
+import org.eclipse.emf.compare.tests.equi.EquiComputingTest;
import org.eclipse.emf.compare.tests.fullcomparison.IdentifierComparisonTest;
import org.eclipse.emf.compare.tests.model.CompareModelTestSuite;
import org.eclipse.emf.compare.tests.nodes.NodesPackage;
@@ -38,8 +39,8 @@ import org.junit.runners.Suite.SuiteClasses;
* @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
*/
@RunWith(Suite.class)
-@SuiteClasses({CompareModelTestSuite.class, DefaultComparisonScopeTest.class, IdentifierComparisonTest.class,
- ConflictDetectionTest.class, ReqComputingTest.class, DiffEngineTest.class, })
+@SuiteClasses({CompareModelTestSuite.class, DefaultComparisonScopeTest.class, IdentifierComparisonTest.class,
+ ConflictDetectionTest.class, ReqComputingTest.class, EquiComputingTest.class, DiffEngineTest.class })
public class AllTests {
/**
* Standalone launcher for all of compare's tests.
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/EMFCompare.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/EMFCompare.java
index 991cd4d2e..7eb781888 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/EMFCompare.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/EMFCompare.java
@@ -15,12 +15,16 @@ import org.eclipse.emf.compare.conflict.DefaultConflictDetector;
import org.eclipse.emf.compare.conflict.IConflictDetector;
import org.eclipse.emf.compare.diff.DefaultDiffEngine;
import org.eclipse.emf.compare.diff.IDiffEngine;
+import org.eclipse.emf.compare.equi.DefaultEquiEngine;
+import org.eclipse.emf.compare.equi.IEquiEngine;
import org.eclipse.emf.compare.match.DefaultMatchEngine;
import org.eclipse.emf.compare.match.IMatchEngine;
import org.eclipse.emf.compare.req.DefaultReqEngine;
import org.eclipse.emf.compare.req.IReqEngine;
import org.eclipse.emf.compare.scope.DefaultComparisonScope;
import org.eclipse.emf.compare.scope.IComparisonScope;
+import org.eclipse.emf.compare.utils.ReferenceUtil;
+import org.eclipse.emf.ecore.util.EcoreUtil;
// FIXME progress monitor!
/**
@@ -90,10 +94,16 @@ public final class EMFCompare {
final IDiffEngine diffEngine = new DefaultDiffEngine();
diffEngine.diff(comparison);
+ EcoreUtil.CrossReferencer crossReferencer = ReferenceUtil.initializeCrossReferencer(comparison);
+
// TODO allow extension of the default requirements engine
- final IReqEngine reqEngine = new DefaultReqEngine();
+ final IReqEngine reqEngine = new DefaultReqEngine(crossReferencer);
reqEngine.computeRequirements(comparison);
+ // TODO allow extension of the default equivalences engine
+ final IEquiEngine equiEngine = new DefaultEquiEngine(crossReferencer);
+ equiEngine.computeEquivalences(comparison);
+
// TODO allow extension of the default conflict detector
if (comparison.isThreeWay()) {
final IConflictDetector conflictDetector = new DefaultConflictDetector();
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/equi/DefaultEquiEngine.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/equi/DefaultEquiEngine.java
new file mode 100644
index 000000000..05166fcee
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/equi/DefaultEquiEngine.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * 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.equi;
+
+import java.util.Set;
+
+import org.eclipse.emf.compare.CompareFactory;
+import org.eclipse.emf.compare.ComparePackage;
+import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.Equivalence;
+import org.eclipse.emf.compare.ReferenceChange;
+import org.eclipse.emf.compare.utils.ReferenceUtil;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+/**
+ * The requirements engine is in charge of actually computing the equivalences between the differences.
+ * <p>
+ * This default implementation aims at being generic enough to be used for any model, whatever the metamodel.
+ * However, specific requirements might be necessary.
+ * </p>
+ * TODO document available extension possibilities.
+ *
+ * @author <a href="mailto:cedric.notot@obeo.fr">Cedric Notot</a>
+ */
+public class DefaultEquiEngine implements IEquiEngine {
+
+ /**
+ * Cross referencer which links business model objects to the related differences.
+ */
+ private EcoreUtil.CrossReferencer crossReferencerModelObjectsToDiffs;
+
+ /**
+ * Constructor.
+ */
+ public DefaultEquiEngine() {
+ }
+
+ /**
+ * Constructor with a cross referencer.
+ *
+ * @param crossReferencer
+ * The cross referencer.
+ */
+ public DefaultEquiEngine(EcoreUtil.CrossReferencer crossReferencer) {
+ this.crossReferencerModelObjectsToDiffs = crossReferencer;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.compare.equi.IEquiEngine#computeEquivalences(org.eclipse.emf.compare.Comparison)
+ */
+ public void computeEquivalences(Comparison comparison) {
+ if (crossReferencerModelObjectsToDiffs == null) {
+ crossReferencerModelObjectsToDiffs = ReferenceUtil.initializeCrossReferencer(comparison);
+ }
+
+ for (Diff difference : comparison.getDifferences()) {
+ checkForEquivalences(comparison, difference);
+ }
+ }
+
+ /**
+ * Checks the potential equivalence from the given <code>difference</code>.
+ *
+ * @param comparison
+ * The comparison this engine is expected to complete.
+ * @param difference
+ * The difference that is to be checked
+ */
+ protected void checkForEquivalences(Comparison comparison, Diff difference) {
+ if (difference instanceof ReferenceChange) {
+ ReferenceChange diff = (ReferenceChange)difference;
+ if (diff.getReference().getEOpposite() != null) {
+ Equivalence equivalence = diff.getEquivalence();
+ if (equivalence == null) {
+ equivalence = CompareFactory.eINSTANCE.createEquivalence();
+ comparison.getEquivalences().add(equivalence);
+ equivalence.getDifferences().add(difference);
+ // Find the opposite difference to reference it from the equivalence:
+ EReference oppositeReference = diff.getReference().getEOpposite();
+ Set<Diff> equivalentDifferences = ReferenceUtil.getCrossReferences(
+ crossReferencerModelObjectsToDiffs, oppositeReference, ComparePackage.eINSTANCE
+ .getReferenceChange_Reference(), Diff.class);
+ for (Diff eqDiff : equivalentDifferences) {
+ equivalence.getDifferences().add(eqDiff);
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/equi/IEquiEngine.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/equi/IEquiEngine.java
new file mode 100644
index 000000000..f03dfaef4
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/equi/IEquiEngine.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * 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.equi;
+
+import org.eclipse.emf.compare.Comparison;
+
+/**
+ * .
+ *
+ * @author <a href="mailto:cedric.notot@obeo.fr">Cedric Notot</a>
+ */
+public interface IEquiEngine {
+
+ /**
+ * This is the entry point of the equivalence computing process.
+ * <p>
+ * It will complete the input <code>comparison</code> by iterating over the
+ * {@link org.eclipse.emf.compare.Diff differences} it contain, filling in the equivalence it can detect
+ * for each distinct Diff.
+ * </p>
+ *
+ * @param comparison
+ * The comparison this engine is expected to complete.
+ */
+ void computeEquivalences(Comparison comparison);
+}
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/req/DefaultReqEngine.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/req/DefaultReqEngine.java
index 4567678ab..977722d9a 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/req/DefaultReqEngine.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/req/DefaultReqEngine.java
@@ -11,19 +11,20 @@
package org.eclipse.emf.compare.req;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
import java.util.Set;
+import org.eclipse.emf.compare.ComparePackage;
import org.eclipse.emf.compare.Comparison;
import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.DifferenceKind;
import org.eclipse.emf.compare.Match;
import org.eclipse.emf.compare.ReferenceChange;
+import org.eclipse.emf.compare.utils.ReferenceUtil;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.util.EcoreUtil;
/**
* The requirements engine is in charge of actually computing the requirements between the differences.
@@ -40,7 +41,7 @@ public class DefaultReqEngine implements IReqEngine {
/**
* Cross referencer which links business model objects to the related differences.
*/
- private Map<EObject, Set<Diff>> crossReferencerModelObjectsToDiffs = new HashMap<EObject, Set<Diff>>();
+ private EcoreUtil.CrossReferencer crossReferencerModelObjectsToDiffs;
/**
* Constructor.
@@ -54,7 +55,7 @@ public class DefaultReqEngine implements IReqEngine {
* @param crossReferencerModelObjectsToDiffs
* The cross referencer.
*/
- public DefaultReqEngine(Map<EObject, Set<Diff>> crossReferencerModelObjectsToDiffs) {
+ public DefaultReqEngine(EcoreUtil.CrossReferencer crossReferencerModelObjectsToDiffs) {
this.crossReferencerModelObjectsToDiffs = crossReferencerModelObjectsToDiffs;
}
@@ -64,8 +65,8 @@ public class DefaultReqEngine implements IReqEngine {
* @see org.eclipse.emf.compare.diff.IDiffEngine#computeRequirements(org.eclipse.emf.compare.Comparison)
*/
public void computeRequirements(Comparison comparison) {
- if (crossReferencerModelObjectsToDiffs.isEmpty()) {
- fillCrossReferencerDifferences(comparison);
+ if (crossReferencerModelObjectsToDiffs == null) {
+ crossReferencerModelObjectsToDiffs = ReferenceUtil.initializeCrossReferencer(comparison);
}
for (Diff difference : comparison.getDifferences()) {
@@ -74,29 +75,6 @@ public class DefaultReqEngine implements IReqEngine {
}
/**
- * Initialize the cross referencer with mapping between mode objects and differences from the result of
- * the given <code>comparison</code>. Mapping created through ReferenceChange(ADD/CHANGE/DELETE).value.
- *
- * @param comparison
- * The result of the comparison.
- */
- protected void fillCrossReferencerDifferences(Comparison comparison) {
- for (Diff difference : comparison.getDifferences()) {
- if (isConcernedByRequirements(difference)) {
- ReferenceChange diff = (ReferenceChange)difference;
- if (difference instanceof ReferenceChange) {
- Set<Diff> crossedDifferences = crossReferencerModelObjectsToDiffs.get(diff.getValue());
- if (crossedDifferences == null) {
- crossedDifferences = new HashSet<Diff>();
- crossReferencerModelObjectsToDiffs.put(diff.getValue(), crossedDifferences);
- }
- crossedDifferences.add(diff);
- }
- }
- }
- }
-
- /**
* Checks the potential required differences from the given <code>difference</code>. If the given
* <code>difference</code> is an ADD/CHANGE or DELETE of a business model object and this object
* references other business model objects, respectively added or deleted too, then the related
@@ -115,7 +93,9 @@ public class DefaultReqEngine implements IReqEngine {
// For each of them, look for existing other equivalent differences
for (EObject modelObj : referencedObjects) {
- Set<Diff> requiredDifferences = crossReferencerModelObjectsToDiffs.get(modelObj);
+ Set<Diff> requiredDifferences = ReferenceUtil.getCrossReferences(
+ crossReferencerModelObjectsToDiffs, modelObj, ComparePackage.eINSTANCE
+ .getReferenceChange_Value(), Diff.class);
if (requiredDifferences != null) {
for (Diff diff : requiredDifferences) {
if (isConcernedByRequirements(diff)
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/ReferenceUtil.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/ReferenceUtil.java
index 58e24788d..e6b0ab72b 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/ReferenceUtil.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/ReferenceUtil.java
@@ -2,15 +2,19 @@ package org.eclipse.emf.compare.utils;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
+import org.eclipse.emf.compare.Comparison;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.EStructuralFeature.Setting;
+import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.FeatureMap;
import org.eclipse.emf.ecore.util.FeatureMapUtil;
@@ -28,6 +32,60 @@ public final class ReferenceUtil {
}
/**
+ * Initialize a cross referencer between business model objects and differences for a given
+ * <code>comparison</code>.
+ *
+ * @param comparison
+ * The comparison.
+ * @return The cross referencer.
+ */
+ public static EcoreUtil.CrossReferencer initializeCrossReferencer(Comparison comparison) {
+ EcoreUtil.CrossReferencer crossReferencer = new EcoreUtil.CrossReferencer(comparison) {
+ /** Generic Serial ID. */
+ private static final long serialVersionUID = 1L;
+
+ {
+ crossReference();
+ }
+ };
+ return crossReferencer;
+ }
+
+ /**
+ * Get the objects which reference the given <code>referencedObject</code> through the given
+ * <code>feature</code> thanks to the given <code>crossreferencer</code>. The given <code>clazz</code>
+ * enables to specify the expected kind of objects.
+ *
+ * @param crossReferencer
+ * The cross referencer.
+ * @param referencedEObject
+ * The concerned object.
+ * @param feature
+ * The structural feature.
+ * @param clazz
+ * The expected kind of objects.
+ * @param <T>
+ * The expected kind.
+ * @return A set of referencing objects.
+ */
+ public static <T extends EObject> Set<T> getCrossReferences(EcoreUtil.CrossReferencer crossReferencer,
+ EObject referencedEObject, EStructuralFeature feature, Class<T> clazz) {
+ final Set<T> result = new HashSet<T>();
+ final Collection<Setting> settings = crossReferencer.get(referencedEObject);
+ if (settings != null) {
+ for (Setting setting : settings) {
+ if (feature == null || setting.getEStructuralFeature().equals(feature)) {
+ final EObject crossElt = setting.getEObject();
+ if (clazz == null || clazz.isInstance(crossElt)) {
+ result.add((T)crossElt);
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
* Returns the list of references that should be taken into account when copying an EObject : EReferences
* that are neither {@link EReference#isContainer() container} nor {@link EReference#isContainment()}; or
* that contain feature maps.

Back to the top