blob: c2fafe18a97505d67b3f42951bc2a73c2dfa22e0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 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.match.resource;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.compare.CompareFactory;
import org.eclipse.emf.compare.MatchResource;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.xmi.XMIResource;
/**
* This implementation of a matching strategy checks for the IDs of the resources' roots, and consider that
* resources match if the identifiers of their roots do.
*
* @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
*/
public class RootIDMatchingStrategy implements IResourceMatchingStrategy {
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.match.resource.IResourceMatchingStrategy#matchResources(java.lang.Iterable,
* java.lang.Iterable, java.lang.Iterable)
*/
public List<MatchResource> matchResources(Iterable<? extends Resource> left,
Iterable<? extends Resource> right, Iterable<? extends Resource> origin) {
final List<MatchResource> mappings = Lists.newArrayList();
final List<Resource> rightCopy = Lists.newArrayList(right);
final List<Resource> originCopy = Lists.newArrayList(origin);
// Can we find matches for the left resource in either left or origin?
for (Resource leftResource : left) {
final Resource matchingRight = findMatch(leftResource, rightCopy);
final Resource matchingOrigin = findMatch(leftResource, originCopy);
if (matchingRight != null || matchingOrigin != null) {
rightCopy.remove(matchingRight);
originCopy.remove(matchingOrigin);
mappings.add(createMatchResource(leftResource, matchingRight, matchingOrigin));
}
}
// We no longer have to check in the left, but we may have matches of the right resources in the
// origin list
for (Resource rightResource : rightCopy) {
final Resource matchingOrigin = findMatch(rightResource, originCopy);
originCopy.remove(matchingOrigin);
if (matchingOrigin != null) {
mappings.add(createMatchResource(null, rightResource, matchingOrigin));
}
}
return mappings;
}
/**
* Returns the first match of <code>reference</code> in <code>candidates</code>. This implementation will
* consider two Resources to be "matches" if their roots have IDs, and these IDs are the same.
*
* @param reference
* The reference resource.
* @param candidates
* The list of potential candidates that may match <code>reference</code>.
* @return The first match of <code>reference</code> in <code>candidates</code>. <code>null</code> if
* none.
*/
protected Resource findMatch(Resource reference, Iterable<Resource> candidates) {
final Set<String> referenceIDs = getResourceIdentifiers(reference);
if (referenceIDs.isEmpty()) {
return null;
}
Resource match = null;
final Iterator<Resource> candidateIterator = candidates.iterator();
while (candidateIterator.hasNext() && match == null) {
final Resource candidate = candidateIterator.next();
final Set<String> candidateIDs = getResourceIdentifiers(candidate);
if (!candidateIDs.isEmpty() && !Sets.intersection(candidateIDs, referenceIDs).isEmpty()) {
match = candidate;
}
}
return match;
}
/**
* Retrieves the set of identifiers for the given resource's root.
*
* @param resource
* The resource for which we need the identifiers.
* @return The identifiers (both XMI:ID and eAttribute ID) of the resource's roots, if any. May be empty
* if the resource has no roots or if they have no ID.
*/
protected Set<String> getResourceIdentifiers(Resource resource) {
final Set<String> identifiers = Sets.newHashSet();
for (EObject root : resource.getContents()) {
if (resource instanceof XMIResource) {
String resourceId = ((XMIResource)resource).getID(root);
if (resourceId != null) {
identifiers.add(resourceId);
}
}
String rootID = EcoreUtil.getID(root);
if (rootID != null) {
identifiers.add(rootID);
}
}
return identifiers;
}
/**
* Creates a {@link MatchResource} instance and sets all three resources of the mapping on it.
*
* @param left
* The left resource of this mapping.
* @param right
* The right resource of this mapping.
* @param origin
* The origin resource of this mapping.
* @return The create mapping.
*/
protected MatchResource createMatchResource(Resource left, Resource right, Resource origin) {
final MatchResource match = CompareFactory.eINSTANCE.createMatchResource();
match.setLeft(left);
match.setRight(right);
match.setOrigin(origin);
if (left != null && left.getURI() != null) {
match.setLeftURI(left.getURI().toString());
}
if (right != null && right.getURI() != null) {
match.setRightURI(right.getURI().toString());
}
if (origin != null && origin.getURI() != null) {
match.setOriginURI(origin.getURI().toString());
}
return match;
}
}