org.search.niem.uml.merge.NamespaceMergeUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.search.niem.uml.merge.NamespaceMergeUtil.java

Source

/*
 * 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:
 *   SEARCH Group, Incorporated - initial API and implementation
 *
 */
package org.search.niem.uml.merge;

import static org.apache.commons.lang.StringUtils.isBlank;
import static org.eclipse.uml2.uml.util.UMLUtil.findNamedElements;
import static org.eclipse.uml2.uml.util.UMLUtil.getBaseElement;
import static org.search.niem.uml.util.CollectionExt.allAreNull;
import static org.search.niem.uml.util.CollectionExt.anyIsNull;
import static org.search.niem.uml.util.EcoreExt.get;
import static org.search.niem.uml.util.EcoreExt.getEClass;
import static org.search.niem.uml.util.EcoreExt.getNsURI;
import static org.search.niem.uml.util.EcoreExt.getPackage;
import static org.search.niem.uml.util.NIEMUmlExt.findNearestNiemNamespacePackage;
import static org.search.niem.uml.util.NIEMUmlExt.getTargetNamespace;
import static org.search.niem.uml.util.NIEMUmlExt.isNiemNamespace;
import static org.search.niem.uml.util.NIEMUmlExt.isXmlPrimitiveType;
import static org.search.niem.uml.util.NIEMUmlExt.namesMatch;
import static org.search.niem.uml.util.UMLExt.getBody;
import static org.search.niem.uml.util.UMLExt.getClients;
import static org.search.niem.uml.util.UMLExt.getGeneral;
import static org.search.niem.uml.util.UMLExt.getMemberEnds;
import static org.search.niem.uml.util.UMLExt.getName;
import static org.search.niem.uml.util.UMLExt.getOwner;
import static org.search.niem.uml.util.UMLExt.getSuppliers;
import static org.search.niem.uml.util.UMLExt.getType;
import static org.search.niem.uml.util.UMLExt.isStereotypeApplication;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.lang.ObjectUtils;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Namespace;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Type;
import org.search.niem.uml.util.EcoreExt;
import org.search.niem.uml.util.UMLExt;

public class NamespaceMergeUtil {
    public static Collection<Element> mapEquivalents(final Collection<EObject> referenceLibraryElements,
            final Package inThePIM) {
        final Collection<Element> pimEquivalents = new ArrayList<>();

        Namespace theCurrentOwner = null;
        Namespace theEquivalentOwnerInThePIM = null;
        for (final EObject visibleElement : referenceLibraryElements) {
            final Namespace theOwner = getOwner(visibleElement);
            if (theOwner != theCurrentOwner) {
                theCurrentOwner = theOwner;
                theEquivalentOwnerInThePIM = findEquivalent(theOwner, inThePIM);
            }
            if (theEquivalentOwnerInThePIM == null) {
                continue;
            }
            final NamedElement theElement = theEquivalentOwnerInThePIM.getMember(getName(visibleElement), false,
                    getEClass(visibleElement));
            if (theElement != null) {
                pimEquivalents.add(theElement);
            }
        }

        return pimEquivalents;
    }

    public static <T extends EObject> T findEquivalent(final T referenceLibraryElement, final Package inThePIM) {
        if (referenceLibraryElement == null) {
            return null;
        }
        if (isStereotypeApplication(referenceLibraryElement)) {
            @SuppressWarnings("unchecked")
            final T equivalentStereotypeApplication = (T) findEquivalentStereotypeApplication(
                    referenceLibraryElement, inThePIM);
            return equivalentStereotypeApplication;
        }
        if (!isBlank(UMLExt.getName(referenceLibraryElement))) {
            final NamedElement ne = (NamedElement) referenceLibraryElement;
            if (theNameIsUnique(ne)) {
                return findEquivalentNamedElement(ne, inThePIM);
            }
        }
        final EObject inTheEquivalentParent = findEquivalent(getOwner(referenceLibraryElement), inThePIM);
        if (inTheEquivalentParent == null) {
            return null;
        }
        return findImmediatelyContainedEquivalent(referenceLibraryElement, inTheEquivalentParent, inThePIM);
    }

    private static <T extends EObject> T findEquivalentNamedElement(final NamedElement referenceLibraryElement,
            final Package inThePIM) {
        // first find the target namespace of the referenceLibraryElement
        final Package namespaceInTheReferenceLibrary = findNearestNiemNamespacePackage(
                referenceLibraryElement.getNearestPackage());
        if (namespaceInTheReferenceLibrary == null) {
            return null;
        }
        // find the Package with the same targetNamespace in the PIM
        final Package namespaceInThePIM = findPackageWithTargetNamespace(inThePIM,
                getTargetNamespace(namespaceInTheReferenceLibrary));
        if (namespaceInThePIM == null) {
            return null;
        }
        final LinkedList<Element> pathToReferenceLibraryElement = new LinkedList<>();
        NamedElement next = referenceLibraryElement;
        while (next != namespaceInTheReferenceLibrary) {
            pathToReferenceLibraryElement.addFirst(next);
            next = next.getNamespace();
        }
        return findNamedElement(namespaceInThePIM, pathToReferenceLibraryElement);
    }

    public static Element findMatching(final EObject referenceLibraryElement, final Element inTheNamespace) {
        for (final Element member : EcoreUtil.<Element>getObjectsByType(inTheNamespace.getOwnedElements(),
                referenceLibraryElement.eClass())) {
            if (namesMatch(referenceLibraryElement, member)) {
                return member;
            }
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    private static <T extends EObject> T findNamedElement(final Package inTheNamespace,
            final Iterable<Element> withThePath) {
        // foreach path element, look for an element in the namespace with either a matching NIEMName, a matching name or, if
        // the path element ends with 'Type', the name without the 'Type' suffix
        Element nextNamespaceElement = inTheNamespace;
        for (final Element nextPathElement : withThePath) {
            final Element match = findMatching(nextPathElement, nextNamespaceElement);
            if (match == null) {
                return null;
            }
            nextNamespaceElement = match;
        }
        return (T) nextNamespaceElement;
    }

    private static Package findPackageWithTargetNamespace(final Package inThePackage,
            final String targetNamespace) {
        if (isNiemNamespace(inThePackage) && areEqual(getTargetNamespace(inThePackage), targetNamespace)) {
            return inThePackage;
        }
        for (final Package p : inThePackage.getNestedPackages()) {
            final Package packageWithTargetNamespace = findPackageWithTargetNamespace(p, targetNamespace);
            if (packageWithTargetNamespace != null) {
                return packageWithTargetNamespace;
            }
        }
        return null;
    }

    private static EObject findEquivalentStereotypeApplication(final EObject referenceLibraryElement,
            final Package inThePIM) {
        final Element pimEquivalentBaseElement = findEquivalent(getBaseElement(referenceLibraryElement), inThePIM);
        if (pimEquivalentBaseElement == null) {
            return null;
        }
        final Collection<EObject> equivalencies = new ArrayList<>();
        for (final EObject pimStereotypeApplication : pimEquivalentBaseElement.getStereotypeApplications()) {
            if (classesAreTheSame(referenceLibraryElement, pimStereotypeApplication)) {
                equivalencies.add(pimStereotypeApplication);
            }
        }
        if (equivalencies.isEmpty()) {
            return null;
        }
        if (equivalencies.size() > 1) {
            Activator.INSTANCE.log("Ambiguous matches found for stereotype application " + referenceLibraryElement);
        }
        return equivalencies.iterator().next();
    }

    private static <T extends EObject> T findEquivalent(final T referenceLibraryElement,
            final Collection<T> inThePIMContents, final Package inThePIM) {
        final Collection<T> equivalencies = new ArrayList<>();
        for (final T aPIMElement : EcoreUtil.<T>getObjectsByType(inThePIMContents,
                referenceLibraryElement.eClass())) {
            if (areEquivalent(referenceLibraryElement, aPIMElement, inThePIM)) {
                equivalencies.add(aPIMElement);
            }
        }
        if (equivalencies.isEmpty()) {
            return null;
        }
        if (equivalencies.size() > 1) {
            Activator.INSTANCE.log("Ambiguous matches found for element " + referenceLibraryElement);
        }
        return equivalencies.iterator().next();
    }

    private static <T extends EObject> T findImmediatelyContainedEquivalent(final T referenceLibraryElement,
            final EObject inThePIMElement, final Package inThePIM) {
        final EStructuralFeature feature = referenceLibraryElement.eContainingFeature();
        if (!inThePIMElement.eIsSet(feature)) {
            return null;
        }
        if (feature.isMany()) {
            return findEquivalent(referenceLibraryElement, EcoreExt.<T>getMany(feature, inThePIMElement), inThePIM);
        }
        final T child = get(feature, inThePIMElement);
        if (areEquivalent(referenceLibraryElement, child, inThePIM)) {
            return child;
        }
        return null;
    }

    private static boolean areEquivalent(final EObject aReferenceLibraryElement, final EObject aPIMElement,
            final Package inThePIM) {
        /* @formatter:off */
        return allAreNull(aReferenceLibraryElement, aPIMElement)
                || !anyIsNull(aReferenceLibraryElement, aPIMElement)
                        && classesAreTheSame(aReferenceLibraryElement, aPIMElement)
                        && namesAreTheSame(aReferenceLibraryElement, aPIMElement)
                        && bodiesAreTheSame(aReferenceLibraryElement, aPIMElement)
                        && typesAreEquivalent(aReferenceLibraryElement, aPIMElement, inThePIM)
                        && memberEndsAreEquivalent(aReferenceLibraryElement, aPIMElement, inThePIM)
                        && clientsAreEquivalent(aReferenceLibraryElement, aPIMElement, inThePIM)
                        && suppliersAreEquivalent(aReferenceLibraryElement, aPIMElement, inThePIM)
                        && generalsAreEquivalent(aReferenceLibraryElement, aPIMElement, inThePIM);
        /* @formatter:on */
    }

    private static boolean generalsAreEquivalent(final EObject aReferenceLibraryElement, final EObject aPIMElement,
            final Package inThePIM) {
        final Classifier referenceLibraryGeneral = getGeneral(aReferenceLibraryElement);
        final Classifier pimElementGeneral = getGeneral(aPIMElement);
        return isXmlPrimitiveType(referenceLibraryGeneral)
                ? areEqual(UMLExt.getName(referenceLibraryGeneral), UMLExt.getName(pimElementGeneral))
                : findEquivalent(referenceLibraryGeneral, inThePIM) == pimElementGeneral;
    }

    private static boolean clientsAreEquivalent(final EObject aReferenceLibraryElement, final EObject aPIMElement,
            final Package inThePIM) {
        final List<NamedElement> referenceLibraryClients = getClients(aReferenceLibraryElement);
        final List<NamedElement> pimClients = getClients(aPIMElement);
        if (referenceLibraryClients.size() != pimClients.size()) {
            return false;
        }
        for (int i = 0; i < referenceLibraryClients.size(); i++) {
            if (findEquivalent(referenceLibraryClients.get(i), inThePIM) != pimClients.get(i)) {
                return false;
            }
        }
        return true;
    }

    private static boolean suppliersAreEquivalent(final EObject aReferenceLibraryElement, final EObject aPIMElement,
            final Package inThePIM) {
        final List<NamedElement> referenceLibrarySuppliers = getSuppliers(aReferenceLibraryElement);
        final List<NamedElement> pimSuppliers = getSuppliers(aPIMElement);
        if (referenceLibrarySuppliers.size() != pimSuppliers.size()) {
            return false;
        }
        for (int i = 0; i < referenceLibrarySuppliers.size(); i++) {
            if (findEquivalent(referenceLibrarySuppliers.get(i), inThePIM) != pimSuppliers.get(i)) {
                return false;
            }
        }
        return true;
    }

    private static boolean memberEndsAreEquivalent(final EObject aReferenceLibraryElement,
            final EObject aPIMElement, final Package inThePIM) {
        final List<Property> referenceLibraryMemberEnds = getMemberEnds(aReferenceLibraryElement);
        final List<Property> pimMemberEnds = getMemberEnds(aPIMElement);
        if (referenceLibraryMemberEnds.size() != pimMemberEnds.size()) {
            return false;
        }
        for (int i = 0; i < referenceLibraryMemberEnds.size(); i++) {
            if (!areEquivalent(referenceLibraryMemberEnds.get(i), pimMemberEnds.get(i), inThePIM)) {
                return false;
            }
        }
        return true;
    }

    private static boolean typesAreEquivalent(final EObject aReferenceLibraryElement, final EObject aPIMElement,
            final Package inThePIM) {
        final Type referenceLibraryType = getType(aReferenceLibraryElement);
        final Type pimType = getType(aPIMElement);
        return isXmlPrimitiveType(referenceLibraryType)
                ? areEqual(UMLExt.getName(referenceLibraryType), UMLExt.getName(pimType))
                : findEquivalent(referenceLibraryType, inThePIM) == pimType;
    }

    private static boolean bodiesAreTheSame(final EObject left, final EObject right) {
        return ObjectUtils.equals(getBody(left), getBody(right));
    }

    private static boolean classesAreTheSame(final EObject left, final EObject right) {
        final EClass leftClass = getEClass(left);
        final EClass rightClass = getEClass(right);
        return areEqual(EcoreExt.getName(leftClass), EcoreExt.getName(rightClass))
                && packagesAreTheSame(getPackage(leftClass), getPackage(rightClass));
    }

    private static boolean packagesAreTheSame(final EPackage left, final EPackage right) {
        return areEqual(EcoreExt.getName(left), EcoreExt.getName(right))
                && areEqual(getNsURI(left), getNsURI(right));
    }

    private static boolean namesAreTheSame(final EObject aReferenceLibraryElement, final EObject aPIMElement) {
        if (isNiemNamespace(aReferenceLibraryElement) && isNiemNamespace(aPIMElement)) {
            return areEqual(getTargetNamespace((Element) aReferenceLibraryElement),
                    getTargetNamespace((Element) aPIMElement));
        }
        return namesMatch(aReferenceLibraryElement, aPIMElement);
    }

    private static boolean areEqual(final Object left, final Object right) {
        return ObjectUtils.equals(left, right);
    }

    private static boolean theNameIsUnique(final NamedElement e) {
        return findNamedElements(e.eResource(), e.getQualifiedName()).size() == 1;
    }
}