blob: c0834d8ccbc6894b8193b8829ccb0ab69e6f6ce6 [file] [log] [blame]
/*******************************************************************************
* 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.internal;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.compare.match.eobject.WeightProvider;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EParameter;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.impl.EStringToStringMapEntryImpl;
/**
* Default implementation which is parameterized to set weights based on features, to ignore features and
* consider "name" features as more important.
*
* @author <a href="mailto:cedric.brun@obeo.fr">Cedric Brun</a>
*/
public class ReflectiveWeightProvider implements WeightProvider {
/***
* Something not impacting the object identity unless it adds up a lot.
*/
private static final int SMALL = 5;
/**
* A normal change in an object.
*/
private static final int NORMAL = 10;
/**
* Likely to impact the object identity.
*/
private static final int SIGNIFICANT = 20;
/**
* Quite important regarding the Object identity.
*/
private static final int MAJOR = 150;
/**
* Very important regarding the Object identity.
*/
private static final int MASSIVE = 350;
/**
* It is very unlikely the elements are matching if they have differences of this magnitude.
*/
private static final int UNLIKELY_TO_MATCH = 1000;
/**
* The list of specific weight to apply on specific Features.
*/
private Map<EStructuralFeature, Integer> weights;
/**
* The list of features to ignore during the distance computation.
*/
private Set<EStructuralFeature> toBeIgnored;
/**
* Weight coefficient of a change on a reference.
*/
private int referenceChangeCoef = NORMAL;
/**
* Weight coefficient of a change on an attribute.
*/
private int attributeChangeCoef = SIGNIFICANT;
/**
* Create the weight provider.
*/
public ReflectiveWeightProvider() {
weights = Maps.newHashMap();
toBeIgnored = Sets.newLinkedHashSet();
}
/**
* {@inheritDoc}
*/
public int getWeight(EStructuralFeature feature) {
if (irrelevant(feature) || toBeIgnored.contains(feature)) {
return 0;
}
Integer found = weights.get(feature);
if (found == null) {
found = Integer.valueOf(SMALL);
/*
* This is worst than empirical but it works in many cases, if your feature is a "name" its likely
* that it's important for matching the element. At some point I'll have to come up with something
* which is more extensible..
*/
if ("name".equals(feature.getName()) || "id".equals(feature.getName())) { //$NON-NLS-1$
found = Integer.valueOf(SIGNIFICANT);
}
if (feature instanceof EReference && ((EReference)feature).isContainment()) {
found = Integer.valueOf(NORMAL);
}
}
if (feature instanceof EReference) {
found = referenceChangeCoef * found.intValue();
} else {
found = attributeChangeCoef * found.intValue();
}
return found;
}
/**
* return true i the feature is irrelevant for the comparison.
*
* @param feat
* any feature.
* @return true i the feature is irrelevant for the comparison.
*/
protected boolean irrelevant(EStructuralFeature feat) {
boolean irrelevantFeature = feat.isDerived() || feat.isTransient();
if (!irrelevantFeature && feat instanceof EReference) {
EReference ref = (EReference)feat;
irrelevantFeature = ref.isContainment() || ref.isContainer();
}
return irrelevantFeature;
}
/**
* {@inheritDoc}
*/
// CHECKSTYLE:OFF
public int getParentWeight(EObject a) {
/*
* these should belong to an Ecore specific class
*/
if (a instanceof EStructuralFeature) {
return MASSIVE;
} else if (a instanceof EAnnotation) {
return UNLIKELY_TO_MATCH;
} else if (a instanceof EOperation) {
return MAJOR;
} else if (a instanceof EParameter) {
return UNLIKELY_TO_MATCH;
} else if (a instanceof EStringToStringMapEntryImpl) {
return UNLIKELY_TO_MATCH;
}
return SIGNIFICANT;
}
// CHECKSTYLE:ON
/**
* {@inheritDoc}
*/
public int getContainingFeatureWeight(EObject a) {
/*
* these should belong to an ECore specific class
*/
if (a instanceof EStructuralFeature || a instanceof EAnnotation || a instanceof EOperation) {
return MAJOR;
}
return SIGNIFICANT;
}
}