org.eclipse.emf.compare.uml2.internal.postprocessor.util.UMLCompareUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.emf.compare.uml2.internal.postprocessor.util.UMLCompareUtil.java

Source

/*******************************************************************************
 * Copyright (c) 2013, 2014 Obeo 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:
 *     Obeo - initial API and implementation
 *     Philip Langer - adds helpers for opaque elements and opaque element changes
 *******************************************************************************/
package org.eclipse.emf.compare.uml2.internal.postprocessor.util;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;

import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.eclipse.emf.compare.AttributeChange;
import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Extension;
import org.eclipse.uml2.uml.OpaqueAction;
import org.eclipse.uml2.uml.OpaqueBehavior;
import org.eclipse.uml2.uml.OpaqueExpression;
import org.eclipse.uml2.uml.UMLPackage;
import org.eclipse.uml2.uml.util.UMLUtil;

/**
 * Some utility methods that may be tweaked to allow EMFCompare to scale.
 * 
 * @author <a href="mailto:mikael.barbero@obeo.fr">Mikael Barbero</a>
 */
public final class UMLCompareUtil {

    /** Constructor. */
    private UMLCompareUtil() {
    }

    /**
     * Retrieves the base element for the specified stereotype application, i.e. the element to which the
     * stereotype is applied.
     * <p>
     * It first calls {@link UMLUtil#getBaseElement(EObject)}. If it returns null, it then tries to find a
     * {@link EStructuralFeature} with a name starting with {@link Extension#METACLASS_ROLE_PREFIX}. It
     * <em>does not</em> verify if the the given {@code stereotypeApplication}'s eClass is defined as a
     * Stereotype within a Profile because it may lead to load the resource of the Profile.
     * 
     * @param stereotypeApplication
     *            The stereotype application.
     * @return The base element.
     */
    public static Element getBaseElement(EObject stereotypeApplication) {
        if (stereotypeApplication == null) {
            return null;
        }

        Element baseElement = UMLUtil.getBaseElement(stereotypeApplication);
        final Iterator<EStructuralFeature> features = stereotypeApplication.eClass().getEAllStructuralFeatures()
                .iterator();
        while (features.hasNext() && baseElement == null) {
            final EStructuralFeature feature = features.next();
            if (feature.getName().startsWith(Extension.METACLASS_ROLE_PREFIX)) {
                final Object value = stereotypeApplication.eGet(feature);
                if (value instanceof Element) {
                    baseElement = (Element) value;
                }
            }
        }

        return baseElement;
    }

    /**
     * From the given EReference, it returns the list of EReference which are superset and non union.
     * 
     * @param reference
     *            The EReference subset from which is requested the non union superset.
     * @return The list of EReference non union superset.
     */
    public static Iterable<EReference> getNonUnionSupersetReferences(EReference reference) {
        return Iterables.filter(getSupersetReferences(reference), isNonUnionReference());
    }

    private static Predicate<? super EReference> isNonUnionReference() {
        return new Predicate<EReference>() {
            public boolean apply(EReference input) {
                return input != null
                        && !Iterables.any(input.getEAnnotations(), UMLUtilForCompare.isUnionAnnotation());
            }
        };
    }

    /**
     * From the given EReference, it returns the list of EReference which are superset.
     * 
     * @param reference
     *            The EReference subset from which is requested the superset.
     * @return The list of EReference superset.
     */
    private static Iterable<EReference> getSupersetReferences(EReference reference) {
        EAnnotation subsetsAnnotation = Iterables.find(reference.getEAnnotations(),
                UMLUtilForCompare.isSubsetsAnnotation(), null);
        if (subsetsAnnotation != null) {
            return Iterables.filter(subsetsAnnotation.getReferences(), EReference.class);
        }
        return Collections.emptyList();
    }

    /**
     * This extends UMLUtil to get the name of the used annotations for subsets and unions.
     * 
     * @author <a href="mailto:cedric.notot@obeo.fr">Cedric Notot</a>
     */
    private static class UMLUtilForCompare extends UMLUtil {
        public static Predicate<? super EAnnotation> isSubsetsAnnotation() {
            return new Predicate<EAnnotation>() {
                public boolean apply(EAnnotation input) {
                    return input != null && input.getSource().equals(ANNOTATION__SUBSETS);
                }
            };
        }

        public static Predicate<? super EAnnotation> isUnionAnnotation() {
            return new Predicate<EAnnotation>() {
                public boolean apply(EAnnotation input) {
                    return input != null && input.getSource().equals(ANNOTATION__UNION);
                }
            };
        }
    }

    /**
     * Returns the bodies of the given {@code eObject}, which must be either an OpaqueAction, OpaqueBehavior,
     * or an OpaqueExpression.
     * 
     * @throws IllegalArgumentException
     *             If {@code eObject} is not a OpaqueAction, OpaqueBehavior, or an OpaqueExpression.
     * @param eObject
     *            The OpaqueAction, OpaqueBehavior, or an OpaqueExpression to get the bodies of.
     * @return The bodies of {@code eObject}.
     */
    public static List<String> getOpaqueElementBodies(EObject eObject) {
        final List<String> bodies;
        if (eObject instanceof OpaqueAction) {
            bodies = ((OpaqueAction) eObject).getBodies();
        } else if (eObject instanceof OpaqueBehavior) {
            bodies = ((OpaqueBehavior) eObject).getBodies();
        } else if (eObject instanceof OpaqueExpression) {
            bodies = ((OpaqueExpression) eObject).getBodies();
        } else {
            throw new IllegalArgumentException(eObject.eClass().getName()
                    + " has no bodies. Only OpaqueAction, OpaqueBehavior, and OpaqueExpression do."); //$NON-NLS-1$
        }
        return bodies;
    }

    /**
     * Returns the languages of the given {@code eObject}, which must be either an OpaqueAction,
     * OpaqueBehavior, or an OpaqueExpression.
     * 
     * @throws IllegalArgumentException
     *             If {@code eObject} is not a OpaqueAction, OpaqueBehavior, or an OpaqueExpression.
     * @param eObject
     *            The OpaqueAction, OpaqueBehavior, or an OpaqueExpression to get the languages of.
     * @return The bodies of {@code eObject}.
     */
    public static List<String> getOpaqueElementLanguages(EObject eObject) {
        final List<String> languages;
        if (eObject instanceof OpaqueAction) {
            languages = ((OpaqueAction) eObject).getLanguages();
        } else if (eObject instanceof OpaqueBehavior) {
            languages = ((OpaqueBehavior) eObject).getLanguages();
        } else if (eObject instanceof OpaqueExpression) {
            languages = ((OpaqueExpression) eObject).getLanguages();
        } else {
            throw new IllegalArgumentException(eObject.eClass().getName()
                    + " has no languages. Only OpaqueAction, OpaqueBehavior, and OpaqueExpression do."); //$NON-NLS-1$
        }
        return languages;
    }

    /**
     * Returns the body for the given {@code language} of the given {@code eObject}, which must be either an
     * OpaqueAction, OpaqueBehavior, or an OpaqueExpression.
     * 
     * @throws IllegalArgumentException
     *             If {@code eObject} is not a OpaqueAction, OpaqueBehavior, or an OpaqueExpression.
     * @param eObject
     *            The OpaqueAction, OpaqueBehavior, or an OpaqueExpression to get the body of.
     * @param language
     *            The language for which the body is requested.
     * @return The body for the given {@code language} of the given {@code eObject}.
     */
    public static String getOpaqueElementBody(EObject eObject, String language) {
        final List<String> languages = getOpaqueElementLanguages(eObject);
        final List<String> bodies = getOpaqueElementBodies(eObject);
        final int index = languages.indexOf(language);
        return bodies.get(index);
    }

    /**
     * Specifies whether the given {@code diff} is a change of the body attribute of {@link OpaqueAction},
     * {@link OpaqueBehavior}, or {@link OpaqueExpression}.
     * 
     * @param diff
     *            The difference to check.
     * @return <code>true</code> if it is a change of the body attribute, <code>false</code> otherwise.
     */
    public static boolean isChangeOfOpaqueElementBodyAttribute(Diff diff) {
        if (diff instanceof AttributeChange) {
            final EAttribute attribute = ((AttributeChange) diff).getAttribute();
            return UMLPackage.eINSTANCE.getOpaqueAction_Body().equals(attribute)
                    || UMLPackage.eINSTANCE.getOpaqueBehavior_Body().equals(attribute)
                    || UMLPackage.eINSTANCE.getOpaqueExpression_Body().equals(attribute);
        } else {
            return false;
        }
    }

    /**
     * Specifies whether the given {@code diff} is a change of the language attribute of {@link OpaqueAction},
     * {@link OpaqueBehavior}, or {@link OpaqueExpression}.
     * 
     * @param diff
     *            The difference to check.
     * @return <code>true</code> if it is a change of the language attribute, <code>false</code> otherwise.
     */
    public static boolean isChangeOfOpaqueElementLanguageAttribute(Diff diff) {
        if (diff instanceof AttributeChange) {
            final EAttribute attribute = ((AttributeChange) diff).getAttribute();
            return UMLPackage.eINSTANCE.getOpaqueAction_Language().equals(attribute)
                    || UMLPackage.eINSTANCE.getOpaqueBehavior_Language().equals(attribute)
                    || UMLPackage.eINSTANCE.getOpaqueExpression_Language().equals(attribute);
        } else {
            return false;
        }
    }
}