org.eclipse.emf.compare.match.eobject.IdentifierEObjectMatcher.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.emf.compare.match.eobject.IdentifierEObjectMatcher.java

Source

/*******************************************************************************
 * 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.match.eobject;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.eclipse.emf.compare.CompareFactory;
import org.eclipse.emf.compare.Match;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.xmi.XMIResource;

/**
 * This implementation of an {@link IEObjectMatcher} will create {@link Match}es based on the input EObjects
 * identifiers (either XMI:ID or attribute ID) alone.
 * 
 * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
 */
public class IdentifierEObjectMatcher implements IEObjectMatcher {
    /**
     * {@inheritDoc}
     * 
     * @see org.eclipse.emf.compare.match.eobject.IEObjectMatcher#createMatches(java.util.Iterator,
     *      java.util.Iterator, java.util.Iterator)
     */
    public Iterable<Match> createMatches(Iterator<? extends EObject> leftEObjects,
            Iterator<? extends EObject> rightEObjects, Iterator<? extends EObject> originEObjects) {
        final Set<Match> matches = Sets.newLinkedHashSet();

        // This lookup map will be used by iterations on right and origin to find the match in which they
        // should add themselves
        final Map<String, Match> idToMatch = Maps.newHashMap();

        // We will try and mimic the structure of the input model.
        // These map do not need to be ordered, we only need fast lookup.
        final Map<EObject, Match> leftEObjectsToMatch = Maps.newHashMap();
        final Map<EObject, Match> rightEObjectsToMatch = Maps.newHashMap();
        final Map<EObject, Match> originEObjectsToMatch = Maps.newHashMap();

        // We'll only iterate once on each of the three sides, building the matches as we go
        while (leftEObjects.hasNext()) {
            final EObject left = leftEObjects.next();

            final Match match = CompareFactory.eINSTANCE.createMatch();
            match.setLeft(left);

            // Can we find a parent? Assume we're iterating in containment order
            final EObject parentEObject = left.eContainer();
            final Match parent = leftEObjectsToMatch.get(parentEObject);
            if (parent != null) {
                parent.getSubmatches().add(match);
            } else {
                matches.add(match);
            }

            final String identifier = getID(left);
            if (identifier != null) {
                idToMatch.put(identifier, match);
            }
            leftEObjectsToMatch.put(left, match);
        }

        while (rightEObjects.hasNext()) {
            final EObject right = rightEObjects.next();

            // Do we have an existing match?
            final String identifier = getID(right);
            Match match = idToMatch.get(identifier);
            if (match != null) {
                match.setRight(right);

                rightEObjectsToMatch.put(right, match);
            } else {
                // Otherwise, create and place it.
                match = CompareFactory.eINSTANCE.createMatch();
                match.setRight(right);

                // Can we find a parent?
                final EObject parentEObject = right.eContainer();
                final Match parent = rightEObjectsToMatch.get(parentEObject);
                if (parent != null) {
                    parent.getSubmatches().add(match);
                } else {
                    matches.add(match);
                }

                if (identifier != null) {
                    idToMatch.put(identifier, match);
                }
                rightEObjectsToMatch.put(right, match);
            }
        }

        while (originEObjects.hasNext()) {
            final EObject origin = originEObjects.next();

            // Do we have an existing match?
            final String identifier = getID(origin);
            Match match = idToMatch.get(identifier);
            if (match != null) {
                match.setOrigin(origin);

                originEObjectsToMatch.put(origin, match);
            } else {
                // Otherwise, create and place it.
                match = CompareFactory.eINSTANCE.createMatch();
                match.setOrigin(origin);

                // Can we find a parent?
                final EObject parentEObject = origin.eContainer();
                final Match parent = originEObjectsToMatch.get(parentEObject);
                if (parent != null) {
                    parent.getSubmatches().add(match);
                } else {
                    matches.add(match);
                }

                if (identifier != null) {
                    idToMatch.put(identifier, match);
                }
                originEObjectsToMatch.put(origin, match);
            }
        }

        return matches;
    }

    /**
     * This will be used to determine what represents the "identifier" of an EObject. By default, we will use
     * the following logic, in order (i.e. if condition 1 is fulfilled, we will not try conditions 2 and 3) :
     * <ol>
     * <li>If the given eObject is a proxy, it is uniquely identified by its URI fragment.</li>
     * <li>If the eObject's EClass has an eIdAttribute set, use this attribute's value.</li>
     * <li>If the eObject is located in an XMI resource and has an XMI ID, use this as its unique identifier.</li>
     * </ol>
     * 
     * @param eObject
     *            The EObject for which we need an identifier.
     * @return The identifier for that EObject if we could determine one. <code>null</code> if no condition
     *         (see description above) is fulfilled for the given eObject.
     */
    protected String getID(EObject eObject) {
        if (eObject.eIsProxy()) {
            return ((InternalEObject) eObject).eProxyURI().fragment();
        }
        String identifier = EcoreUtil.getID(eObject);
        if (identifier == null) {
            final Resource eObjectResource = eObject.eResource();
            if (eObjectResource instanceof XMIResource) {
                identifier = ((XMIResource) eObjectResource).getID(eObject);
            }
        }
        return identifier;
    }
}