Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/UMLPostProcessor.java')
-rw-r--r--plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/UMLPostProcessor.java245
1 files changed, 36 insertions, 209 deletions
diff --git a/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/UMLPostProcessor.java b/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/UMLPostProcessor.java
index 7259a3645..b5b712aab 100644
--- a/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/UMLPostProcessor.java
+++ b/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/UMLPostProcessor.java
@@ -10,68 +10,36 @@
*******************************************************************************/
package org.eclipse.emf.compare.uml2.internal.postprocessor;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-import com.google.common.primitives.Ints;
+import static org.eclipse.emf.compare.internal.utils.ComparisonUtil.isAddOrSetDiff;
+import static org.eclipse.emf.compare.internal.utils.ComparisonUtil.isDeleteOrUnsetDiff;
-import java.lang.reflect.Field;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.util.Monitor;
import org.eclipse.emf.compare.Comparison;
import org.eclipse.emf.compare.Diff;
-import org.eclipse.emf.compare.DifferenceKind;
-import org.eclipse.emf.compare.DifferenceSource;
import org.eclipse.emf.compare.Match;
import org.eclipse.emf.compare.ReferenceChange;
import org.eclipse.emf.compare.internal.postprocessor.factories.IChangeFactory;
import org.eclipse.emf.compare.postprocessor.IPostProcessor;
import org.eclipse.emf.compare.uml2.internal.UMLDiff;
import org.eclipse.emf.compare.uml2.internal.postprocessor.extension.UMLExtensionFactoryRegistry;
-import org.eclipse.emf.compare.utils.ReferenceUtil;
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.util.EcoreUtil;
-import org.eclipse.uml2.common.util.SubsetSupersetEObjectEList;
+import org.eclipse.emf.compare.uml2.internal.postprocessor.util.UMLCompareUtil;
+import org.eclipse.emf.ecore.EReference;
+/**
+ * Post-processor to create the UML difference extensions.
+ *
+ * @author <a href="mailto:cedric.notot@obeo.fr">Cedric Notot</a>
+ */
public class UMLPostProcessor implements IPostProcessor {
/** UML2 extensions factories. */
private Set<IChangeFactory> uml2ExtensionFactories;
/**
- * UML has notions of "subset" and "superset" features, which can be multiply derived but can also hold
- * values of their own.
- * <p>
- * For example, Association#memberEnds is a superset of Association#ownedEnds which in turn is a superset
- * of Association#navigableOwnedEnds.
- * </p>
- * <p>
- * If we add a value to "ownedEnds", it will automatically be added to "memberEnds" but not to
- * "navigableOwnedEnds". EMF Compare will detect two differences : 'value has been added to ownedEnds' and
- * 'value has been added to memberEnds'. We need to ignore the diff on memberEnds, but not the one on
- * ownedEnds (otherwise, and since these are not simple equivalences, the value would be added twice to
- * memberEnds, and once in ownedEnds).
- * </p>
- * <p>
- * Likewise, if we add a value to navigableOwnedEnds, we must still ignore the diff on memberEnds, but
- * this time and for that value we also need to ignore the diff on ownedEnds, lest we end up post-merge
- * with three identical values in memberEnds, two in ownedEnds and one in navigableOwnedEnds.
- * </p>
- * <p>
- * Since there is no API way to determine which references are subsets of another, we will have to resort
- * to casting the reference's value in {@link SubsetSupersetEObjectEList} and reflexively access its
- * "subsetFeatureIDs" protected field.
- * </p>
- */
- private static final Field SUBSET_FEATURES_FIELD = getSubsetField();
-
- /**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.postprocessor.IPostProcessor#postMatch(org.eclipse.emf.compare.Comparison,
@@ -91,101 +59,6 @@ public class UMLPostProcessor implements IPostProcessor {
// Not needed here.
}
- private void removeDuplicateDiffs(Comparison comparison) {
- final Set<Diff> removeMe = Sets.newLinkedHashSet();
- for (Diff input : comparison.getDifferences()) {
- if (!(input instanceof ReferenceChange && ((ReferenceChange)input).getReference().isMany())) {
- // Nothing to see here
- continue;
- }
-
- final EObject matchSide = getSourceSide(input);
- final Object value = ReferenceUtil.safeEGet(matchSide, ((ReferenceChange)input).getReference());
- // The only diffs that can be duplicated are those that can have subsets
- if (value instanceof SubsetSupersetEObjectEList<?>) {
- final int[] subsetsFeatures = getSubsetFeatures((SubsetSupersetEObjectEList<?>)value);
-
- // If we have subsets and this is a MOVE, ignore the Diff altogether
- if (subsetsFeatures.length > 0 && input.getKind() == DifferenceKind.MOVE) {
- removeMe.add(input);
- } else {
- // Check each subset : if it contains the same value as the input then it is a duplicate
- final Diff duplicate = findDuplicatedDiffOnLowestSubset(input, matchSide, subsetsFeatures);
- if (duplicate != null) {
- // We have a duplicate on a subset. This diff will be removed from the comparison
- // model, but before that we need to copy all of its requires and refines
- removeMe.add(input);
- copyRequirements(input, duplicate);
- }
- }
- }
- }
-
- for (Diff sentenced : removeMe) {
- EcoreUtil.delete(sentenced);
- }
- }
-
- private void copyRequirements(Diff source, Diff target) {
- for (Diff requiredBy : source.getRequiredBy()) {
- if (requiredBy != target) {
- target.getRequiredBy().add(requiredBy);
- }
- }
- for (Diff requires : source.getRequires()) {
- if (requires != target) {
- target.getRequires().add(requires);
- }
- }
- if (source.getEquivalence() != null) {
- source.getEquivalence().getDifferences().add(target);
- }
- }
-
- private Diff findDuplicatedDiffOnLowestSubset(Diff input, EObject matchSide, int[] subsetsFeatures) {
- final EClass clazz = matchSide.eClass();
- final Object diffValue = ((ReferenceChange)input).getValue();
- final int[] actualIDs = convertFeatureIDs(clazz, subsetsFeatures);
-
- Diff lowestDuplicate = null;
- final Iterator<ReferenceChange> siblings = Iterables.filter(input.getMatch().getDifferences(),
- ReferenceChange.class).iterator();
- while (siblings.hasNext() && lowestDuplicate == null) {
- final ReferenceChange sibling = siblings.next();
- final int refID = sibling.getReference().getFeatureID();
- final Object siblingValue = sibling.getValue();
-
- if (sibling.getKind() == input.getKind() && Ints.contains(actualIDs, refID)
- && siblingValue == diffValue) {
- // This is a duplicate... but it may be a duplicate itself.
- // We have to go down to the lowest level.
- final Object subset = matchSide.eGet(clazz.getEStructuralFeature(refID), false);
- if (subset instanceof SubsetSupersetEObjectEList<?>) {
- final int[] lowerSubsets = getSubsetFeatures((SubsetSupersetEObjectEList<?>)subset);
- final Diff lowerDuplicate = findDuplicatedDiffOnLowestSubset(sibling, matchSide,
- lowerSubsets);
- if (lowerDuplicate != null) {
- lowestDuplicate = lowerDuplicate;
- } else {
- lowestDuplicate = sibling;
- }
- } else {
- lowestDuplicate = sibling;
- }
- }
- }
-
- return lowestDuplicate;
- }
-
- private int[] convertFeatureIDs(EClass clazz, int[] ids) {
- int[] result = new int[ids.length];
- for (int i = 0; i < ids.length; i++) {
- result[i] = clazz.getEStructuralFeature(ids[i]).getFeatureID();
- }
- return result;
- }
-
/**
* {@inheritDoc}
*
@@ -222,7 +95,6 @@ public class UMLPostProcessor implements IPostProcessor {
* org.eclipse.emf.common.util.Monitor)
*/
public void postComparison(Comparison comparison, Monitor monitor) {
- removeDuplicateDiffs(comparison);
final Map<Class<? extends Diff>, IChangeFactory> mapUml2ExtensionFactories = UMLExtensionFactoryRegistry
.createExtensionFactories();
@@ -243,6 +115,14 @@ public class UMLPostProcessor implements IPostProcessor {
}
}
}
+
+ // Filling implications with subsets
+ for (Diff diff : comparison.getDifferences()) {
+ if (diff instanceof ReferenceChange) {
+ fillImplicationsWithUMLSubsets((ReferenceChange)diff);
+ }
+ }
+
}
/**
@@ -250,8 +130,6 @@ public class UMLPostProcessor implements IPostProcessor {
*
* @param element
* The input {@link DiffElement}.
- * @param diffModelCrossReferencer
- * The cross referencer.
*/
private void applyManagedTypes(Diff element) {
for (IChangeFactory factory : uml2ExtensionFactories) {
@@ -273,80 +151,29 @@ public class UMLPostProcessor implements IPostProcessor {
}
/**
- * Retrieves the value of the <i>subsetFeatureIDs</i> field of the given list. Note that this will never
- * return <code>null</code>, but an empty array instead.
+ * Fill the implication links ({@link Diff#getImplies()}, {@link Diff#getImpliedBy()}) on the given
+ * reference change.
*
- * @param list
- * The list for which we need the subset feature IDs.
- * @return The IDs of the subsets from which the given lists derives its values.
- * @see #SUBSET_FEATURES_FIELD
+ * @param diff
+ * The reference change.
*/
- private static int[] getSubsetFeatures(SubsetSupersetEObjectEList<?> list) {
- Object value = null;
- try {
- value = SUBSET_FEATURES_FIELD.get(list);
- } catch (IllegalArgumentException e) {
- // Ignore, cannot happen
- } catch (IllegalAccessException e) {
- // Ignore, cannot happen
- }
- if (value instanceof int[]) {
- return (int[])value;
- }
- return new int[0];
- }
-
- /**
- * This will allow us to retrieve the "subsetFeatureIDs" protected field of the
- * {@link SubsetSupersetEObjectEList} class and set it accessible for further reflexive access. More on
- * this on the {@link #SUBSET_FEATURES_FIELD field}'s description.
- *
- * @return The {@link SubsetSupersetEObjectEList#subsetFeatureIDs} field, after having made it accessible.
- * @see #SUBSET_FEATURES_FIELD
- */
- private static Field getSubsetField() {
- try {
- final Field subsetIDs = SubsetSupersetEObjectEList.class.getDeclaredField("subsetFeatureIDs"); //$NON-NLS-1$
- AccessController.doPrivileged(new PrivilegedAction<Object>() {
- public Object run() {
- subsetIDs.setAccessible(true);
- return null;
+ private void fillImplicationsWithUMLSubsets(ReferenceChange diff) {
+ EReference reference = diff.getReference();
+ // ADD implies ADD on non union supersets
+ // DELETE is implied by DEL on non union supersets
+ for (EReference superSet : UMLCompareUtil.getNonUnionSupersetReferences(reference)) {
+ Comparison comparison = diff.getMatch().getComparison();
+ for (Diff superSetDiff : comparison.getDifferences(superSet)) {
+ if (superSetDiff instanceof ReferenceChange
+ && ((ReferenceChange)superSetDiff).getReference() == superSet
+ && ((ReferenceChange)superSetDiff).getValue() == diff.getValue()) {
+ if (isAddOrSetDiff(diff) && isAddOrSetDiff(superSetDiff)) {
+ diff.getImplies().add(superSetDiff);
+ } else if (isDeleteOrUnsetDiff(diff) && isDeleteOrUnsetDiff(superSetDiff)) {
+ diff.getImpliedBy().add(superSetDiff);
+ }
}
- });
- return subsetIDs;
- } catch (SecurityException e) {
- // Ignore, cannot happen
- } catch (NoSuchFieldException e) {
- // Ignore, cannot happen
- }
- return null;
- }
-
- /**
- * Retrieves the EObject holding the reference on which we detected a difference.
- *
- * @param input
- * The difference for which we need a "holder" object.
- * @return The EObject holding the reference on which we detected a difference.
- */
- private static EObject getSourceSide(Diff input) {
- // Note that we know this diff is not a "CHANGE" as its reference is multi-valued
- final Match match = input.getMatch();
- final EObject matchSide;
- if (input.getKind() == DifferenceKind.DELETE) {
- if (match.getOrigin() != null) {
- matchSide = match.getOrigin();
- } else if (input.getSource() == DifferenceSource.LEFT) {
- matchSide = match.getRight();
- } else {
- // Should never happen
- matchSide = match.getLeft();
}
- } else if (input.getSource() == DifferenceSource.LEFT) {
- matchSide = match.getLeft();
- } else {
- matchSide = match.getRight();
}
- return matchSide;
}
}

Back to the top