org.eclipse.emf.compare.match.eobject.internal.ReflectiveWeightProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.emf.compare.match.eobject.internal.ReflectiveWeightProvider.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.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;
    }

}