org.eclipse.emf.compare.diagram.sirius.internal.SiriusDiffPostProcessor.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.emf.compare.diagram.sirius.internal.SiriusDiffPostProcessor.java

Source

/*******************************************************************************
 * Copyright (c) 2015 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.diagram.sirius.internal;

import static com.google.common.collect.Collections2.filter;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.CONTAINMENT_REFERENCE_CHANGE;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.fromSide;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Sets;

import java.util.Iterator;
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.ReferenceChange;
import org.eclipse.emf.compare.diagram.internal.extensions.DiagramDiff;
import org.eclipse.emf.compare.postprocessor.IPostProcessor;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gmf.runtime.notation.NotationPackage;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.sirius.diagram.DNode;
import org.eclipse.sirius.diagram.DiagramPackage;
import org.eclipse.sirius.diagram.description.NodeMapping;
import org.eclipse.sirius.viewpoint.DSemanticDecorator;
import org.eclipse.sirius.viewpoint.ViewpointPackage;

/**
 * A post processor to refine the differences found on a Sirius model.
 * 
 * @author <a href="mailto:cedric.brun@obeo.fr">Cedric Brun</a>
 */
@SuppressWarnings("restriction")
public class SiriusDiffPostProcessor implements IPostProcessor {
    /**
     * Create a new predicate to check whether the value of a {@link ReferenceChange} is of a given type.
     * 
     * @param clazz
     *            an EClass.
     * @return true if the value of the {@link ReferenceChange} is of the given type.
     */
    private static Predicate<ReferenceChange> valueIsKindOf(final EClass clazz) {
        return new Predicate<ReferenceChange>() {
            public boolean apply(ReferenceChange diff) {
                return clazz.isSuperTypeOf(diff.getValue().eClass());
            }
        };
    }

    private static Function<? super ReferenceChange, EObject> getReferenceChangeValue() {
        return new Function<ReferenceChange, EObject>() {
            public EObject apply(ReferenceChange diff) {
                return diff.getValue();
            }
        };
    }

    /**
     * {@inheritDoc}
     */
    public void postMatch(Comparison comparison, Monitor monitor) {

    }

    /**
     * {@inheritDoc}
     */
    public void postDiff(Comparison comparison, Monitor monitor) {

    }

    /**
     * {@inheritDoc}
     */
    public void postRequirements(Comparison comparison, Monitor monitor) {
        /*
         * Any added/deleted DSemanticDecorator must require the corresponding getTarget() addition/removal
         */
        Iterable<ReferenceChange> allContainmentRefChanges = Iterables.filter(
                Iterables.filter(comparison.getDifferences(), ReferenceChange.class), CONTAINMENT_REFERENCE_CHANGE);

        Iterable<ReferenceChange> addedOrRemovedSemanticDecorators = Iterables.filter(allContainmentRefChanges,
                valueIsKindOf(ViewpointPackage.eINSTANCE.getDSemanticDecorator()));

        Multimap<EObject, ReferenceChange> diffsByValue = Multimaps.index(allContainmentRefChanges,
                getReferenceChangeValue());

        /*
         * Any added or removed semantic decorator should have a dependency to the corresponding
         * addition/removal of semantic element.
         */
        for (ReferenceChange referenceChange : addedOrRemovedSemanticDecorators) {
            DSemanticDecorator value = (DSemanticDecorator) referenceChange.getValue();
            if (value.getTarget() != null) {
                EObject semanticTarget = value.getTarget();
                addRequiresToDecoratedElement(diffsByValue, referenceChange, semanticTarget);
            }
            /*
             * A DNode should always have its actualMapping reference set.
             */
            if (value instanceof DNode) {
                NodeMapping map = ((DNode) value).getActualMapping();
                if (map != null) {
                    for (ReferenceChange actualMappingChange : Iterables.filter(comparison.getDifferences(map),
                            ReferenceChange.class)) {
                        if (actualMappingChange.getReference() == DiagramPackage.eINSTANCE.getDNode_ActualMapping()
                                && fromSide(referenceChange.getSource()).apply(actualMappingChange)) {
                            referenceChange.getRequires().add(actualMappingChange);
                        }
                    }
                }
            }
        }
        /*
         * Any added or removed gmf Node should have a dependency to the corresponding addition/removal of a
         * DSemantic decorator.
         */

        Iterable<ReferenceChange> addedOrRemovedGmfView = Iterables.filter(allContainmentRefChanges,
                valueIsKindOf(NotationPackage.eINSTANCE.getView()));

        for (ReferenceChange referenceChange : addedOrRemovedGmfView) {
            View value = (View) referenceChange.getValue();

            /*
             * beware here, GMF do som trick in getElement() and will return it's container element if the
             * element is null..
             */
            if (value.getElement() != null) {
                EObject semanticTarget = value.getElement();
                addRequiresToDecoratedElement(diffsByValue, referenceChange, semanticTarget);
            }
        }
    }

    /**
     * Add diff requires for every change related to the semantic target.
     * 
     * @param diffsByValue
     *            {@link ReferenceChange} differences indexed by value.
     * @param referenceChange
     *            a given {@link ReferenceChange}.
     * @param semanticTarget
     *            the semantic target.
     */
    private void addRequiresToDecoratedElement(Multimap<EObject, ReferenceChange> diffsByValue,
            ReferenceChange referenceChange, EObject semanticTarget) {
        for (Diff valueDiff : diffsByValue.get(semanticTarget)) {
            if (referenceChange.getKind() == DifferenceKind.ADD) {
                if (valueDiff.getKind() == DifferenceKind.ADD
                        && fromSide(referenceChange.getSource()).apply(valueDiff)) {
                    referenceChange.getRequires().add(valueDiff);
                }

            } else if (referenceChange.getKind() == DifferenceKind.DELETE) {
                if (valueDiff.getKind() == DifferenceKind.DELETE
                        && fromSide(referenceChange.getSource()).apply(valueDiff)) {
                    referenceChange.getRequires().add(valueDiff);
                }
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public void postEquivalences(Comparison comparison, Monitor monitor) {

    }

    /**
     * {@inheritDoc}
     */
    public void postConflicts(Comparison comparison, Monitor monitor) {

    }

    /**
     * {@inheritDoc}
     */
    public void postComparison(Comparison comparison, Monitor monitor) {
        /*
         * We re-refine the refinements already setup by
         * org.eclipse.emf.compare.diagram.internal.CompareDiagramPostProcessor
         */
        Iterator<DiagramDiff> it = Iterators.filter(comparison.eAllContents(), DiagramDiff.class);
        while (it.hasNext()) {
            DiagramDiff next = it.next();
            Set<Diff> refinesToAdd = Sets.newLinkedHashSet();
            for (Diff refined : next.getRefinedBy()) {
                collectDifferenceRefines(comparison, refinesToAdd, refined.getMatch().getLeft());
                collectDifferenceRefines(comparison, refinesToAdd, refined.getMatch().getRight());
            }
            next.getRefinedBy().addAll(filter(refinesToAdd, fromSide(next.getSource())));
        }
    }

    /**
     * Collect the differences which have to be added as a refinment of the current DiagramDiff.
     * 
     * @param comparison
     *            the current comparison.
     * @param refinesToAdd
     *            the set of differences to add as refinement.
     * @param changedEObject
     *            any changed EObject.
     */
    private void collectDifferenceRefines(Comparison comparison, Set<Diff> refinesToAdd, EObject changedEObject) {
        if (changedEObject instanceof View) {
            View gmfView = (View) changedEObject;
            if (gmfView.getElement() instanceof DSemanticDecorator) {
                for (Diff diffOnSemanticDecorator : comparison.getDifferences(gmfView.getElement())) {
                    refinesToAdd.add(diffOnSemanticDecorator);
                }
            }
        }
    }

}