Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/org.eclipse.emf.compare.match/src/org/eclipse/emf/compare/match/engine/GenericMatchEngine.java')
-rw-r--r--plugins/org.eclipse.emf.compare.match/src/org/eclipse/emf/compare/match/engine/GenericMatchEngine.java1875
1 files changed, 0 insertions, 1875 deletions
diff --git a/plugins/org.eclipse.emf.compare.match/src/org/eclipse/emf/compare/match/engine/GenericMatchEngine.java b/plugins/org.eclipse.emf.compare.match/src/org/eclipse/emf/compare/match/engine/GenericMatchEngine.java
deleted file mode 100644
index 83060aae5..000000000
--- a/plugins/org.eclipse.emf.compare.match/src/org/eclipse/emf/compare/match/engine/GenericMatchEngine.java
+++ /dev/null
@@ -1,1875 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2006, 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.engine;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.eclipse.emf.common.EMFPlugin;
-import org.eclipse.emf.common.notify.Notifier;
-import org.eclipse.emf.common.util.BasicEList;
-import org.eclipse.emf.common.util.BasicMonitor;
-import org.eclipse.emf.common.util.Monitor;
-import org.eclipse.emf.compare.EMFComparePlugin;
-import org.eclipse.emf.compare.FactoryException;
-import org.eclipse.emf.compare.match.EMFCompareMatchMessages;
-import org.eclipse.emf.compare.match.engine.internal.DistinctEcoreSimilarityChecker;
-import org.eclipse.emf.compare.match.engine.internal.EcoreIDSimilarityChecker;
-import org.eclipse.emf.compare.match.engine.internal.GenericMatchEngineToCheckerBridge;
-import org.eclipse.emf.compare.match.engine.internal.StatisticBasedSimilarityChecker;
-import org.eclipse.emf.compare.match.engine.internal.XMIIDSimilarityChecker;
-import org.eclipse.emf.compare.match.internal.statistic.NameSimilarity;
-import org.eclipse.emf.compare.match.metamodel.Match2Elements;
-import org.eclipse.emf.compare.match.metamodel.Match3Elements;
-import org.eclipse.emf.compare.match.metamodel.MatchElement;
-import org.eclipse.emf.compare.match.metamodel.MatchFactory;
-import org.eclipse.emf.compare.match.metamodel.MatchModel;
-import org.eclipse.emf.compare.match.metamodel.Side;
-import org.eclipse.emf.compare.match.metamodel.UnmatchElement;
-import org.eclipse.emf.compare.match.statistic.MetamodelFilter;
-import org.eclipse.emf.compare.util.EFactory;
-import org.eclipse.emf.compare.util.EMFCompareMap;
-import org.eclipse.emf.compare.util.EclipseModelUtils;
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.EPackage;
-import org.eclipse.emf.ecore.EReference;
-import org.eclipse.emf.ecore.EStructuralFeature;
-import org.eclipse.emf.ecore.resource.Resource;
-import org.eclipse.emf.ecore.util.EcoreUtil;
-
-/**
- * These services are useful when one wants to compare models more precisely using the method modelDiff.
- *
- * @author <a href="mailto:cedric.brun@obeo.fr">Cedric Brun</a>
- */
-public class GenericMatchEngine implements IMatchEngine {
- /** Containment reference for the matched elements root. */
- private static final String MATCH_ELEMENT_NAME = "matchedElements"; //$NON-NLS-1$
-
- /** Containment reference for {@link MatchElement}s' submatches. */
- private static final String SUBMATCH_ELEMENT_NAME = "subMatchElements"; //$NON-NLS-1$
-
- /** Containment reference for the {@link MatchModel}'s unmatched elements. */
- private static final String UNMATCH_ELEMENT_NAME = "unmatchedElements"; //$NON-NLS-1$
-
- /**
- * {@link MetamodelFilter} used for filtering unused features of the objects we're computing the
- * similarity for.
- */
- protected MetamodelFilter filter = new MetamodelFilter();
-
- /**
- * Contains the options given to the match procedure. This method is deprecated, if you want to handle
- * specific options for your match engine you should override the updateSettings() method.
- */
- @Deprecated
- protected Map<String, Object> options = new EMFCompareMap<String, Object>();
-
- /** Contains the options given to the match procedure. */
- private MatchSettings structuredOptions;
-
- /**
- * This list allows us to memorize the unmatched elements for a three-way comparison.<br/>
- * <p>
- * More specifically, we will populate this list with the {@link UnmatchElement}s created by the
- * comparison between the left and the ancestor model, followed by the {@link UnmatchElement}s created by
- * the comparison between the right and the ancestor model.<br/>
- * Those {@link UnmatchElement}s will then be filtered to retain only those that actually cannot be
- * matched.
- * </p>
- */
- private final Set<EObject> remainingUnmatchedElements = new LinkedHashSet<EObject>();
-
- /**
- * This list will be intensively used while matching elements to keep track of the unmatched ones from the
- * left model.
- */
- private final List<EObject> stillToFindFromModel1 = new ArrayList<EObject>();
-
- /**
- * This list will be intensively used while matching elements to keep track of the unmatched ones from the
- * right model.
- */
- private final List<EObject> stillToFindFromModel2 = new ArrayList<EObject>();
-
- /**
- * Current checker used by the engine to determine whether an element has the same identity as another one
- * or not.
- */
- private AbstractSimilarityChecker checker;
-
- /**
- * This list is used while matching elements to keep track of matched reference targets, being outside the
- * provided match scope.
- */
- private List<Match2Elements> externalRefMappings = new ArrayList<Match2Elements>();
-
- /**
- * The options map must be initialized to avoid potential NPEs. This initializer will take care of this
- * issue.
- */
- {
- structuredOptions = new MatchSettings();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.eclipse.emf.compare.match.engine.IMatchEngine#contentMatch(org.eclipse.emf.ecore.EObject,
- * org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EObject, java.util.Map)
- */
- public MatchModel contentMatch(EObject leftObject, EObject rightObject, EObject ancestor,
- Map<String, Object> optionMap) {
- updateSettings(structuredOptions, optionMap);
- checker = prepareChecker();
-
- // see if scope provider was passed in via option, otherwise create default one
- final IMatchScopeProvider scopeProvider = MatchScopeProviderUtil.getScopeProvider(optionMap,
- leftObject, rightObject, ancestor);
-
- final IMatchScope leftScope = scopeProvider.getLeftScope();
- final IMatchScope rightScope = scopeProvider.getRightScope();
- final IMatchScope ancestorScope = scopeProvider.getAncestorScope();
-
- MatchModel result = null;
- if (leftScope.isInScope(leftObject) && rightScope.isInScope(rightObject)
- && ancestorScope.isInScope(ancestor)) {
- result = doContentMatch(leftObject, leftScope, rightObject, rightScope, ancestor, ancestorScope);
- }
- return result;
- }
-
- /**
- * This method will compare three {@link EObject}s and their direct content, ignoring the given objects'
- * siblings and parents, as well as all objects not being part of the scope (indeed the given ones will
- * also not be compared, if they are not included in the scope), for the match. It will however compute
- * external mappings for all those objects outside the scope, being referenced from those that are
- * processed.
- *
- * @param leftObject
- * Left of the two objects to get compared.
- * @param leftScope
- * The scope to restrict which content of the left object is processed.
- * @param rightObject
- * Right of the two objects to compare.
- * @param rightScope
- * The scope to restrict which content of the left object is processed.
- * @param ancestor
- * Common ancestor of the two others.
- * @param ancestorScope
- * The scope to restrict which content of the ancestor is processed.
- * @return {@link MatchModel} for these two objects' comparison.
- */
- private MatchModel doContentMatch(EObject leftObject, IMatchScope leftScope, EObject rightObject,
- IMatchScope rightScope, EObject ancestor, IMatchScope ancestorScope) {
- MatchModel root = null;
-
- // proceed if input elements are within scope
- if (leftScope.isInScope(leftObject) && rightScope.isInScope(rightObject)
- && ancestorScope.isInScope(ancestor)) {
- root = MatchFactory.eINSTANCE.createMatchModel();
-
- setModelRoots(root, leftObject, leftScope, rightObject, rightScope, ancestor, ancestorScope);
-
- final Monitor monitor = createProgressMonitor();
-
- // perform content match
- final MatchModel leftObjectAncestorMatch = doContentMatch(leftObject, leftScope, ancestor,
- ancestorScope);
- // remove those external mappings added by call to contentMatch
- leftObjectAncestorMatch.getMatchedElements().removeAll(externalRefMappings);
- final List<Match2Elements> leftExternal2WayMappings = new ArrayList<Match2Elements>(
- externalRefMappings);
-
- // perform content match
- final MatchModel rightObjectAncestorMatch = doContentMatch(rightObject, rightScope, ancestor,
- ancestorScope);
- // remove those external mappings added by call to contentMatch
- rightObjectAncestorMatch.getMatchedElements().removeAll(externalRefMappings);
- final List<Match2Elements> rightExternal2WayMappings = new ArrayList<Match2Elements>(
- externalRefMappings);
-
- final List<MatchElement> leftObjectMatchedElements = new ArrayList<MatchElement>(
- leftObjectAncestorMatch.getMatchedElements());
- final List<MatchElement> rightObjectMatchedElements = new ArrayList<MatchElement>(
- rightObjectAncestorMatch.getMatchedElements());
-
- // populates the unmatched elements list for later use
- for (final UnmatchElement unmatch : leftObjectAncestorMatch.getUnmatchedElements()) {
- remainingUnmatchedElements.add(unmatch);
- }
- for (final UnmatchElement unmatch : rightObjectAncestorMatch.getUnmatchedElements()) {
- remainingUnmatchedElements.add(unmatch);
- }
- try {
- Match3Elements subMatchRoot = null;
- if (leftObjectMatchedElements.size() > 0 && rightObjectMatchedElements.size() > 0) {
- final Match2Elements leftObjectMatchRoot = (Match2Elements)leftObjectMatchedElements
- .get(0);
- final Match2Elements rightObjectMatchRoot = (Match2Elements)rightObjectMatchedElements
- .get(0);
- subMatchRoot = MatchFactory.eINSTANCE.createMatch3Elements();
-
- subMatchRoot.setSimilarity(set3WaySimilarity(leftObjectMatchRoot.getLeftElement(),
- rightObjectMatchRoot.getLeftElement(), rightObjectMatchRoot.getRightElement()));
- subMatchRoot.setLeftElement(leftObjectMatchRoot.getLeftElement());
- subMatchRoot.setRightElement(rightObjectMatchRoot.getLeftElement());
- subMatchRoot.setOriginElement(rightObjectMatchRoot.getRightElement());
- redirectedAdd(root, MATCH_ELEMENT_NAME, subMatchRoot);
- createSub3Match(root, subMatchRoot, leftObjectMatchRoot, rightObjectMatchRoot);
- } else {
- for (final EObject left : leftObjectMatchedElements) {
- stillToFindFromModel1.add(left);
- }
- for (final EObject right : rightObjectMatchedElements) {
- stillToFindFromModel2.add(right);
- }
- }
- // We will now check through the unmatched object for matches.
- processNotFoundElements(root, subMatchRoot);
- // #createSub3Match(MatchModel, Match3Element, Match2Elements,
- // Match2Elements) will have updated "remainingUnmatchedElements"
- processSingleUnmatchedElements(leftObject, rightObject, root, subMatchRoot, monitor);
- processUnmatchedMatch2Elements(leftObject, rightObject, root, subMatchRoot);
- } catch (final FactoryException e) {
- EMFComparePlugin.log(e, false);
- } catch (final InterruptedException e) {
- // Cannot be thrown since we have no monitor
- }
-
- // create mappings for external references
- create3WayMatches(leftExternal2WayMappings, rightExternal2WayMappings);
-
- }
- return root;
- }
-
- /**
- * Build the best checker depending on the options.
- *
- * @since 1.1
- */
- protected AbstractSimilarityChecker prepareChecker() {
- AbstractSimilarityChecker checker = null;
- GenericMatchEngineToCheckerBridge bridge = new GenericMatchEngineToCheckerBridge() {
-
- @Override
- public double nameSimilarity(EObject obj1, EObject obj2) {
- return GenericMatchEngine.this.nameSimilarity(obj1, obj2);
- }
-
- @Override
- public double contentSimilarity(EObject obj1, EObject obj2) throws FactoryException {
- return GenericMatchEngine.this.contentSimilarity(obj1, obj2);
- }
- };
- if (!structuredOptions.shouldMatchDistinctMetamodels()) {
- checker = new DistinctEcoreSimilarityChecker(filter, bridge);
- } else {
- checker = new StatisticBasedSimilarityChecker(filter, bridge);
- }
- if (!structuredOptions.isIgnoringID()) {
- checker = new EcoreIDSimilarityChecker(filter, checker);
- disableMetamodelFilter();
- }
- if (!structuredOptions.isIgnoringXMIID()) {
- checker = new XMIIDSimilarityChecker(filter, checker);
- disableMetamodelFilter();
- }
- return checker;
-
- }
-
- /**
- * replace the metamodel filter with one doing nothing.
- */
- private void disableMetamodelFilter() {
- filter = new MetamodelFilter() {
-
- @Override
- public void analyseModel(EObject root) {
- /*
- * do nothing
- */
- }
-
- @Override
- public List<EStructuralFeature> getFilteredFeatures(EObject eObj) {
- return new ArrayList<EStructuralFeature>(eObj.eClass().getEAllStructuralFeatures());
- }
- };
-
- }
-
- /**
- * prepare the engine with the options.
- *
- * @param settings
- * the settings to update.
- * @param optionMap
- * the match options.
- * @since 1.1
- */
- protected void updateSettings(MatchSettings settings, Map<String, Object> optionMap) {
- if (optionMap != null && optionMap.size() > 0) {
- settings.update(optionMap);
- }
-
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.eclipse.emf.compare.match.engine.IMatchEngine#contentMatch(org.eclipse.emf.ecore.EObject,
- * org.eclipse.emf.ecore.EObject, java.util.Map)
- */
- public MatchModel contentMatch(EObject leftObject, EObject rightObject, Map<String, Object> optionMap) {
- externalRefMappings.clear();
- updateSettings(structuredOptions, optionMap);
- checker = prepareChecker();
-
- // see if scope provider was passed in via option, otherwise create default one
- final IMatchScopeProvider scopeProvider = MatchScopeProviderUtil.getScopeProvider(optionMap,
- leftObject, rightObject);
-
- final IMatchScope leftScope = scopeProvider.getLeftScope();
- final IMatchScope rightScope = scopeProvider.getRightScope();
-
- MatchModel result = null;
- if (leftScope.isInScope(leftObject) && rightScope.isInScope(rightObject)) {
- result = doContentMatch(leftObject, leftScope, rightObject, rightScope);
- }
- return result;
- }
-
- /**
- * This method will compare two {@link EObject}s and their direct content, ignoring the given objects'
- * siblings and parents, as well as all objects not being part of the scope (indeed the given ones will
- * also not be compared, if they are not included in the scope), for the match. It will however compute
- * external mappings for all those objects outside the scope, being referenced from those that are
- * processed.
- *
- * @param leftObject
- * Left of the two objects to get compared.
- * @param leftScope
- * The scope to restrict which content of the left object is processed.
- * @param rightObject
- * Right of the two objects to compare.
- * @param rightScope
- * The scope to restrict which content of the left object is processed.
- * @return {@link MatchModel} for these two objects' comparison.
- */
- private MatchModel doContentMatch(EObject leftObject, IMatchScope leftScope, EObject rightObject,
- IMatchScope rightScope) {
- final Monitor monitor = createProgressMonitor();
-
- MatchModel root = null;
- if (leftScope.isInScope(leftObject) && rightScope.isInScope(rightObject)) {
- root = MatchFactory.eINSTANCE.createMatchModel();
-
- setModelRoots(root, leftObject, leftScope, rightObject, rightScope, null, null);
- /*
- * As we could very well be passed two EClasses (as opposed to modelMatch which compares all roots
- * of a resource), we cannot filter the model.
- */
-
- final Set<EObject> still1 = new LinkedHashSet<EObject>();
- final Set<EObject> still2 = new LinkedHashSet<EObject>();
-
- // navigate through both objects at the same time and realize mappings..
- try {
- checker.init(leftObject, rightObject);
- if (isSimilar(leftObject, rightObject)) {
- stillToFindFromModel1.clear();
- stillToFindFromModel2.clear();
- final Match2Elements matchModelRoot = recursiveMappings(leftObject, leftScope,
- rightObject, rightScope, monitor);
- redirectedAdd(root, MATCH_ELEMENT_NAME, matchModelRoot);
- createSubMatchElements(matchModelRoot, new ArrayList<EObject>(stillToFindFromModel1),
- leftScope, new ArrayList<EObject>(stillToFindFromModel2), rightScope, monitor);
- still1.addAll(stillToFindFromModel1);
- still2.addAll(stillToFindFromModel2);
- createUnmatchElements(root, still1, true, false);
- createUnmatchElements(root, still2, false, false);
- } else {
- // The two objects passed as this method's parameters are not
- // similar. Creates unmatch root.
- still1.add(leftObject);
- still2.add(rightObject);
- createUnmatchElements(root, still1, true, false);
- createUnmatchElements(root, still2, false, false);
- }
- } catch (final FactoryException e) {
- EMFComparePlugin.log(e, false);
- } catch (final InterruptedException e) {
- // Cannot be thrown since we have no monitor
- }
-
- root.getMatchedElements().addAll(externalRefMappings);
- }
- return root;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.eclipse.emf.compare.match.engine.IMatchEngine#modelMatch(org.eclipse.emf.ecore.EObject,
- * org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EObject, java.util.Map)
- */
- public MatchModel modelMatch(EObject leftRoot, EObject rightRoot, EObject ancestor,
- Map<String, Object> optionMap) throws InterruptedException {
- updateSettings(structuredOptions, optionMap);
- checker = prepareChecker();
-
- MatchModel result = null;
- // Creates and sizes progress monitor
- final Monitor monitor = createProgressMonitor();
- int size = 1;
- if (leftRoot.eResource() != null && rightRoot.eResource() != null) {
- for (final EObject root : leftRoot.eResource().getContents()) {
- final Iterator<EObject> rootContent = root.eAllContents();
- while (rootContent.hasNext()) {
- rootContent.next();
- size++;
- }
- }
- startMonitor(monitor, size);
-
- // see if scope provider was passed in via option, otherwise create default one
- final IMatchScopeProvider scopeProvider = MatchScopeProviderUtil.getScopeProvider(optionMap,
- leftRoot.eResource(), rightRoot.eResource(), ancestor.eResource());
-
- final IMatchScope leftScope = scopeProvider.getLeftScope();
- final IMatchScope rightScope = scopeProvider.getRightScope();
- final IMatchScope ancestorScope = scopeProvider.getAncestorScope();
-
- if (leftScope.isInScope(leftRoot.eResource()) && rightScope.isInScope(rightRoot.eResource())
- && ancestorScope.isInScope(ancestor.eResource())) {
- result = doMatch(leftRoot.eResource(), leftScope, rightRoot.eResource(), rightScope,
- ancestor.eResource(), ancestorScope, monitor);
- }
- } else {
- final Iterator<EObject> rootContent = leftRoot.eAllContents();
- while (rootContent.hasNext()) {
- rootContent.next();
- size++;
- }
- startMonitor(monitor, size);
- IMatchScope alwaysInScope = new IMatchScope() {
- public boolean isInScope(Resource resource) {
- return true;
- }
-
- public boolean isInScope(EObject eObject) {
- return true;
- }
- };
- result = doContentMatch(leftRoot, alwaysInScope, rightRoot, alwaysInScope, ancestor,
- alwaysInScope);
- }
-
- return result;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.eclipse.emf.compare.match.engine.IMatchEngine#modelMatch(org.eclipse.emf.ecore.EObject,
- * org.eclipse.emf.ecore.EObject, java.util.Map)
- */
- public MatchModel modelMatch(EObject leftRoot, EObject rightRoot, Map<String, Object> optionMap)
- throws InterruptedException {
- updateSettings(structuredOptions, optionMap);
- checker = prepareChecker();
-
- MatchModel result = null;
- // Creates and sizes progress monitor
- final Monitor monitor = createProgressMonitor();
- int size = 1;
- if (leftRoot.eResource() != null && rightRoot.eResource() != null) {
- for (final EObject root : leftRoot.eResource().getContents()) {
- final Iterator<EObject> rootContent = root.eAllContents();
- while (rootContent.hasNext()) {
- rootContent.next();
- size++;
- }
- }
-
- startMonitor(monitor, size);
-
- // see if scope provider was passed in via option, otherwise create default one
- final IMatchScopeProvider scopeProvider = MatchScopeProviderUtil.getScopeProvider(optionMap,
- leftRoot.eResource(), rightRoot.eResource());
- final IMatchScope leftScope = scopeProvider.getLeftScope();
- final IMatchScope rightScope = scopeProvider.getRightScope();
-
- if (leftScope.isInScope(leftRoot.eResource()) && rightScope.isInScope(rightRoot.eResource())) {
- result = doMatch(leftRoot.eResource(), leftScope, rightRoot.eResource(), rightScope, monitor);
- }
- } else {
- final Iterator<EObject> rootContent = leftRoot.eAllContents();
- while (rootContent.hasNext()) {
- rootContent.next();
- size++;
- }
- startMonitor(monitor, size);
- IMatchScope alwaysInScope = new IMatchScope() {
- public boolean isInScope(Resource resource) {
- return true;
- }
-
- public boolean isInScope(EObject eObject) {
- return true;
- }
- };
- result = doContentMatch(leftRoot, alwaysInScope, rightRoot, alwaysInScope);
-
- }
-
- return result;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.eclipse.emf.compare.match.engine.IMatchEngine#reset()
- */
- public void reset() {
- filter.clear();
- filter = new MetamodelFilter();
- checker = null;
-
- remainingUnmatchedElements.clear();
- stillToFindFromModel1.clear();
- stillToFindFromModel2.clear();
- externalRefMappings.clear();
- structuredOptions = new MatchSettings();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.eclipse.emf.compare.match.engine.IMatchEngine#resourceMatch(org.eclipse.emf.ecore.resource.Resource,
- * org.eclipse.emf.ecore.resource.Resource, java.util.Map)
- */
- public MatchModel resourceMatch(Resource leftResource, Resource rightResource,
- Map<String, Object> optionMap) throws InterruptedException {
- updateSettings(structuredOptions, optionMap);
- checker = prepareChecker();
-
- MatchModel result = null;
- // Creates and sizes progress monitor
- final Monitor monitor = createProgressMonitor();
- int size = 1;
- for (final EObject root : leftResource.getContents()) {
- final Iterator<EObject> rootContent = root.eAllContents();
- while (rootContent.hasNext()) {
- rootContent.next();
- size++;
- }
- }
-
- // see if scope provider was passed in via option, otherwise create default one
- final IMatchScopeProvider scopeProvider = MatchScopeProviderUtil.getScopeProvider(optionMap,
- leftResource, rightResource);
-
- final IMatchScope leftScope = scopeProvider.getLeftScope();
- final IMatchScope rightScope = scopeProvider.getRightScope();
-
- startMonitor(monitor, size);
-
- if (leftScope.isInScope(leftResource) && rightScope.isInScope(rightResource)) {
- result = doMatch(leftResource, leftScope, rightResource, rightScope, monitor);
- }
- return result;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.eclipse.emf.compare.match.engine.IMatchEngine#resourceMatch(org.eclipse.emf.ecore.resource.Resource,
- * org.eclipse.emf.ecore.resource.Resource, org.eclipse.emf.ecore.resource.Resource, java.util.Map)
- */
- public MatchModel resourceMatch(Resource leftResource, Resource rightResource, Resource ancestorResource,
- Map<String, Object> optionMap) throws InterruptedException {
- updateSettings(structuredOptions, optionMap);
- checker = prepareChecker();
-
- MatchModel result = null;
- // Creates and sizes progress monitor
- final Monitor monitor = createProgressMonitor();
- int size = 1;
- for (final EObject root : leftResource.getContents()) {
- final Iterator<EObject> rootContent = root.eAllContents();
- while (rootContent.hasNext()) {
- rootContent.next();
- size++;
- }
- }
- startMonitor(monitor, size << 1);
-
- // see if scope provider was passed in via option, otherwise create default one
- final IMatchScopeProvider scopeProvider = MatchScopeProviderUtil.getScopeProvider(optionMap,
- leftResource, rightResource, ancestorResource);
-
- final IMatchScope leftScope = scopeProvider.getLeftScope();
- final IMatchScope rightScope = scopeProvider.getRightScope();
- final IMatchScope ancestorScope = scopeProvider.getAncestorScope();
-
- if (leftScope.isInScope(leftResource) && rightScope.isInScope(rightResource)
- && ancestorScope.isInScope(ancestorResource)) {
- result = doMatch(leftResource, leftScope, rightResource, rightScope, ancestorResource,
- ancestorScope, monitor);
- }
- if (result != null) {
- Set<EObject> alreadyUnmatched = new LinkedHashSet<EObject>();
- for (UnmatchElement unmatched : new LinkedHashSet<UnmatchElement>(result.getUnmatchedElements())) {
- if (alreadyUnmatched.contains(unmatched.getElement())) {
- EcoreUtil.remove(unmatched);
- } else {
- alreadyUnmatched.add(unmatched.getElement());
- }
- }
- }
- return result;
- }
-
- /**
- * This will iterate through the given {@link List} and return its element which is most similar (as given
- * by {@link #absoluteMetric(EObject, EObject)}) to the given {@link EObject}.
- *
- * @param eObj
- * {@link EObject} we're searching a similar item for in the list.
- * @param list
- * {@link List} in which we are to find an object similar to <code>eObj</code>.
- * @return The element from <code>list</code> which is the most similar to <code>eObj</code>.
- * @throws FactoryException
- * Thrown if we cannot compute the {@link #absoluteMetric(EObject, EObject) absolute metric}
- * between <code>eObj</code> and one of the list's objects.
- */
- protected EObject findMostSimilar(EObject eObj, List<EObject> list) throws FactoryException {
- double max = 0d;
- EObject resultObject = null;
- final Iterator<EObject> it = list.iterator();
- while (it.hasNext() && max < 1.0d) {
- final EObject next = it.next();
- if (structuredOptions.shouldMatchDistinctMetamodels()
- || eClassMatch(eObj.eClass(), next.eClass())) {
- final double similarity = checker.absoluteMetric(eObj, next);
- if (similarity > max) {
- max = similarity;
- resultObject = next;
- }
- }
- }
- return resultObject;
- }
-
- /**
- * This will check whether the two given EClasses are the same. This has been created in order to avoid
- * EcoreUtil.equals (perfs).
- *
- * @param eClass1
- * First of the two EClasses to consider.
- * @param eClass2
- * Second of the two EClasses to consider.
- * @return <code>true</code> if the two EClasses match, <code>false</code> otherwise.
- */
- private boolean eClassMatch(EClass eClass1, EClass eClass2) {
- boolean match = false;
-
- EPackage eClass1Package = eClass1.getEPackage();
- EPackage eClass2Package = eClass2.getEPackage();
- if (eClass1Package == eClass2Package) {
- match = eClass1 == eClass2;
- } else if (eClass1Package.getNsURI() != null
- && eClass1Package.getNsURI().equals(eClass2Package.getNsURI())) {
- match = eClass1.getClassifierID() == eClass2.getClassifierID();
- } else if (eClass1Package.getNsURI() == null && eClass2Package.getNsURI() == null) {
- match = EcoreUtil.equals(eClass1, eClass2);
- }
-
- return match;
- }
-
- /**
- * Creates the progress monitor that will be displayed to the user while the comparison lasts.
- *
- * @return The progress monitor that will be displayed to the user while the comparison lasts.
- */
- private Monitor createProgressMonitor() {
- Monitor monitor = new BasicMonitor();
- final Object delegateMonitor = structuredOptions.getProgressMonitor();
- if (delegateMonitor != null && EMFPlugin.IS_ECLIPSE_RUNNING) {
- monitor = EclipseModelUtils.createProgressMonitor(delegateMonitor);
- }
- return monitor;
- }
-
- /**
- * This will recursively create three-way submatches and add them under the given {@link MatchModel}. The
- * two {@link Match2Elements} we consider as parameters are the result of the two-way comparisons between
- * :
- * <ul>
- * <li>The left and origin model.</li>
- * <li>The right and origin model.</li>
- * </ul>
- * <br/>
- * <br/>
- * We can then consider that a {@link match3elements} would be :
- *
- * <pre>
- * match.leftElement = left.getLeftElement();
- * match.originElement = left.getRightElement() = right.getRightElement();
- * match.rightElement = right.getLeftElement();
- * </pre>
- *
- * @param root
- * {@link MatchModel} under which to add our {@link match3elements}s.
- * @param matchElementRoot
- * Root of the {@link Match3Elements}s' hierarchy for the current element to be created.
- * @param left
- * Left {@link Match2Elements} to consider.
- * @param right
- * Right {@link Match2Elements} to consider.
- * @throws FactoryException
- * Thrown if we cannot compute the {@link #absoluteMetric(EObject, EObject, EObject) absolute
- * metric} between the three elements or if we cannot add a {@link match3elements} under the
- * given <code>matchElementRoot</code>.
- */
- private void createSub3Match(MatchModel root, Match3Elements matchElementRoot, Match2Elements left,
- Match2Elements right) throws FactoryException {
- final List<MatchElement> leftSubMatches = left.getSubMatchElements();
- final List<MatchElement> rightSubMatches = right.getSubMatchElements();
- final List<MatchElement> leftNotFound = new ArrayList<MatchElement>(leftSubMatches);
- final List<MatchElement> rightNotFound = new ArrayList<MatchElement>(rightSubMatches);
-
- for (final MatchElement nextLeft : leftSubMatches) {
- final Match2Elements nextLeftMatch = (Match2Elements)nextLeft;
- Match2Elements correspondingMatch = null;
-
- for (final MatchElement nextRight : rightNotFound) {
- final Match2Elements nextRightMatch = (Match2Elements)nextRight;
- if (nextRightMatch.getRightElement().equals(nextLeftMatch.getRightElement())) {
- correspondingMatch = nextRightMatch;
- break;
- }
- }
-
- if (correspondingMatch != null) {
- final Match3Elements match = MatchFactory.eINSTANCE.createMatch3Elements();
- match.setSimilarity(set3WaySimilarity(nextLeftMatch.getLeftElement(),
- correspondingMatch.getLeftElement(), correspondingMatch.getRightElement()));
- match.setLeftElement(nextLeftMatch.getLeftElement());
- match.setRightElement(correspondingMatch.getLeftElement());
- match.setOriginElement(correspondingMatch.getRightElement());
- redirectedAdd(matchElementRoot, SUBMATCH_ELEMENT_NAME, match);
- createSub3Match(root, matchElementRoot, nextLeftMatch, correspondingMatch);
- leftNotFound.remove(nextLeftMatch);
- rightNotFound.remove(correspondingMatch);
- }
- }
-
- for (final MatchElement nextLeftNotFound : leftNotFound) {
- stillToFindFromModel1.add(nextLeftNotFound);
- }
- for (final MatchElement nextRightNotFound : rightNotFound) {
- stillToFindFromModel2.add(nextRightNotFound);
- }
- }
-
- /**
- * Creates the {@link Match2Elements submatch elements} corresponding to the mapping of objects from the
- * two given {@link List}s.
- *
- * @param root
- * Root of the {@link MatchModel} where to insert all these mappings.
- * @param list1
- * First of the lists used to compute mapping.
- * @param list1Scope
- * The scope to restrict the matching of sub elements in list1.
- * @param list2
- * Second of the lists used to compute mapping.
- * @param list2Scope
- * The scope to restrict the matching of sub elements in list2.
- * @param monitor
- * {@link CompareProgressMonitor progress monitor} to display while the comparison lasts. Might
- * be <code>null</code>, in which case we won't monitor progress.
- * @throws FactoryException
- * Thrown if we cannot match the elements of the two lists or add submatch elements to
- * <code>root</code>.
- * @throws InterruptedException
- * Thrown if the operation is cancelled or fails somehow.
- */
- private void createSubMatchElements(EObject root, List<EObject> list1, IMatchScope list1Scope,
- List<EObject> list2, IMatchScope list2Scope, Monitor monitor) throws FactoryException,
- InterruptedException {
- stillToFindFromModel1.clear();
- stillToFindFromModel2.clear();
- final List<Match2Elements> mappings = mapLists(list1, list2, structuredOptions.getSearchWindow(),
- monitor);
-
- final Iterator<Match2Elements> it = mappings.iterator();
- while (it.hasNext()) {
- final Match2Elements map = it.next();
- final Match2Elements match = recursiveMappings(map.getLeftElement(), list1Scope,
- map.getRightElement(), list2Scope, monitor);
- redirectedAdd(root, SUBMATCH_ELEMENT_NAME, match);
- }
- }
-
- /**
- * Creates {@link UnmatchElement}s and {@link RemoteUnmatchElement}s wrapped around all the elements of
- * the given {@link List}.
- *
- * @param root
- * Root of the {@link MatchModel} under which to insert all these elements.
- * @param unmatchedElements
- * {@link List} containing all the elements we haven't been able to match.
- * @param leftSide
- * If set to <code>true</code>, the unmatched element will be set to be from the left side.
- * @throws FactoryException
- * Thrown if we cannot add elements under the given {@link MatchModel root}.
- */
- private void createThreeWayUnmatchElements(MatchModel root, Map<EObject, Boolean> unmatchedElements,
- boolean leftSide) throws FactoryException {
- for (final Map.Entry<EObject, Boolean> entry : unmatchedElements.entrySet()) {
- // We will only consider the highest level of an unmatched element
- // hierarchy
- if (!unmatchedElements.containsKey(entry.getKey().eContainer())) {
- final UnmatchElement unMap = MatchFactory.eINSTANCE.createUnmatchElement();
- unMap.setElement(entry.getKey());
- if (entry.getValue()) {
- unMap.setRemote(true);
- }
- if (leftSide) {
- unMap.setSide(Side.LEFT);
- } else {
- unMap.setSide(Side.RIGHT);
- }
- redirectedAdd(root, UNMATCH_ELEMENT_NAME, unMap);
- }
- }
- unmatchedElements.clear();
- }
-
- /**
- * Creates {@link UnmatchElement}s wrapped around all the elements of the given {@link List}.
- *
- * @param root
- * Root of the {@link MatchModel} under which to insert all these {@link UnmatchElement}s.
- * @param unmatchedElements
- * {@link Set} containing all the elements we haven't been able to match.
- * @param leftSide
- * If set to <code>true</code>, the unmatched elements will be set to be from the left side.
- * @param remote
- * If <code>true</code>, the unmatched elements will be set to reflect a remote change.
- * @throws FactoryException
- * Thrown if we cannot add elements under the given {@link MatchModel root}.
- */
- private void createUnmatchElements(MatchModel root, Set<EObject> unmatchedElements, boolean leftSide,
- boolean remote) throws FactoryException {
- for (final EObject element : unmatchedElements) {
- final UnmatchElement unMap = MatchFactory.eINSTANCE.createUnmatchElement();
- unMap.setElement(element);
- unMap.setRemote(remote);
- if (leftSide) {
- unMap.setSide(Side.LEFT);
- } else {
- unMap.setSide(Side.RIGHT);
- }
- redirectedAdd(root, UNMATCH_ELEMENT_NAME, unMap);
- }
- unmatchedElements.clear();
- }
-
- /**
- * This method handles the creation and returning of a two way model match.
- *
- * @param leftResource
- * Left model for the comparison.
- * @param leftScope
- * The {@link IMatchScope} restricting the left side of comparison.
- * @param rightResource
- * Right model for the comparison.
- * @param rightScope
- * The {@link IMatchScope} restricting the right side of comparison.
- * @param monitor
- * Progress monitor to display while the comparison lasts.
- * @return The corresponding {@link MatchModel}.
- * @throws InterruptedException
- * Thrown if the comparison is interrupted somehow.
- */
- private MatchModel doMatch(Resource leftResource, IMatchScope leftScope, Resource rightResource,
- IMatchScope rightScope, Monitor monitor) throws InterruptedException {
- externalRefMappings.clear();
- final MatchModel root = MatchFactory.eINSTANCE.createMatchModel();
- EObject leftRoot = null;
- EObject rightRoot = null;
-
- final List<EObject> leftContents = getScopeInternalContents(leftResource, leftScope);
- final List<EObject> rightContents = getScopeInternalContents(rightResource, rightScope);
-
- if (leftContents.size() > 0) {
- leftRoot = leftContents.get(0);
- }
-
- if (rightContents.size() > 0) {
- rightRoot = rightContents.get(0);
- }
-
- setModelRoots(root, leftRoot, leftScope, rightRoot, rightScope, null, null);
-
- // filters unused features
- filterUnused(leftResource);
- filterUnused(rightResource);
-
- // navigate through both models at the same time and realize mappings..
- try {
- checker.init(leftResource, rightResource);
-
- monitor.subTask(EMFCompareMatchMessages.getString("DifferencesServices.monitor.roots")); //$NON-NLS-1$
- final List<Match2Elements> matchedRoots = mapLists(leftContents, rightContents,
- structuredOptions.getSearchWindow(), monitor);
- stillToFindFromModel1.clear();
- stillToFindFromModel2.clear();
- final List<EObject> unmatchedLeftRoots = new ArrayList<EObject>(leftContents);
- final List<EObject> unmatchedRightRoots = new ArrayList<EObject>(rightContents);
- // These sets will help us in keeping track of the yet to be found
- // elements
- final Set<EObject> still1 = new LinkedHashSet<EObject>();
- final Set<EObject> still2 = new LinkedHashSet<EObject>();
-
- // If one of the resources has no roots, considers it as deleted
- if (leftContents.size() > 0 && rightContents.size() > 0) {
- Match2Elements matchModelRoot = MatchFactory.eINSTANCE.createMatch2Elements();
- // We haven't found any similar roots, we then consider the
- // firsts to be similar.
- if (matchedRoots.size() == 0) {
- final Match2Elements rootMapping = MatchFactory.eINSTANCE.createMatch2Elements();
- rootMapping.setLeftElement(leftContents.get(0));
- EObject rightElement = findMostSimilar(leftContents.get(0), unmatchedRightRoots);
- if (rightElement == null) {
- rightElement = unmatchedRightRoots.get(0);
- }
- rootMapping.setRightElement(rightElement);
- matchedRoots.add(rootMapping);
- }
- monitor.subTask(EMFCompareMatchMessages
- .getString("DifferencesServices.monitor.rootsContents")); //$NON-NLS-1$
- for (final Match2Elements matchedRoot : matchedRoots) {
- final Match2Elements rootMapping = recursiveMappings(matchedRoot.getLeftElement(),
- leftScope, matchedRoot.getRightElement(), rightScope, monitor);
- // this is the first time we're here
- if (matchModelRoot.getLeftElement() == null) {
- matchModelRoot = rootMapping;
- redirectedAdd(root, MATCH_ELEMENT_NAME, matchModelRoot);
- } else {
- redirectedAdd(matchModelRoot, SUBMATCH_ELEMENT_NAME, rootMapping);
- }
-
- // Synchronizes the two lists to avoid multiple elements
- still1.removeAll(stillToFindFromModel1);
- still2.removeAll(stillToFindFromModel2);
- // checks for matches within the yet to found elements lists
- createSubMatchElements(rootMapping, new ArrayList<EObject>(stillToFindFromModel1),
- leftScope, new ArrayList<EObject>(stillToFindFromModel2), rightScope, monitor);
- // Adds all unfound elements to the sets
- still1.addAll(stillToFindFromModel1);
- still2.addAll(stillToFindFromModel2);
-
- unmatchedLeftRoots.remove(matchedRoot.getLeftElement());
- unmatchedRightRoots.remove(matchedRoot.getRightElement());
- }
- // We'll iterate through the unmatchedRoots all contents
- monitor.subTask(EMFCompareMatchMessages
- .getString("DifferencesServices.monitor.unmatchedRoots")); //$NON-NLS-1$
- createSubMatchElements(matchModelRoot, unmatchedLeftRoots, leftScope, unmatchedRightRoots,
- rightScope, monitor);
- } else {
- // Roots are unmatched, this is either a file addition or
- // deletion
- still1.addAll(unmatchedLeftRoots);
- still2.addAll(unmatchedRightRoots);
- }
-
- // Now takes care of remaining unfound elements
- still1.addAll(stillToFindFromModel1);
- still2.addAll(stillToFindFromModel2);
- createUnmatchElements(root, still1, true, false);
- createUnmatchElements(root, still2, false, false);
- } catch (final FactoryException e) {
- EMFComparePlugin.log(e, false);
- }
-
- root.getMatchedElements().addAll(externalRefMappings);
- return root;
- }
-
- /**
- * This method handles the creation and returning of a three way model match.
- *
- * @param leftResource
- * Left model for the comparison.
- * @param leftScope
- * The {@link IMatchScope} restricting the left side of comparison.
- * @param rightResource
- * Right model for the comparison.
- * @param rightScope
- * The {@link IMatchScope} restricting the right side of comparison.
- * @param ancestorResource
- * Common ancestor of the right and left models.
- * @param ancestorScope
- * The {@link IMatchScope} restricting the ancestor side of comparison.
- * @param monitor
- * Progress monitor to display while the comparison lasts.
- * @return The corresponding {@link MatchModel}.
- * @throws InterruptedException
- * Thrown if the comparison is interrupted somehow.
- */
- private MatchModel doMatch(Resource leftResource, IMatchScope leftScope, Resource rightResource,
- IMatchScope rightScope, Resource ancestorResource, IMatchScope ancestorScope, Monitor monitor)
- throws InterruptedException {
- final MatchModel root = MatchFactory.eINSTANCE.createMatchModel();
- EObject leftRoot = null;
- EObject rightRoot = null;
- EObject ancestorRoot = null;
-
- final List<EObject> leftContents = getScopeInternalContents(leftResource, leftScope);
- final List<EObject> rightContents = getScopeInternalContents(rightResource, rightScope);
- final List<EObject> ancestorContents = getScopeInternalContents(ancestorResource, ancestorScope);
-
- if (leftContents.size() > 0) {
- leftRoot = leftContents.get(0);
- }
- if (rightContents.size() > 0) {
- rightRoot = rightContents.get(0);
- }
- if (ancestorContents.size() > 0) {
- ancestorRoot = ancestorContents.get(0);
- }
- setModelRoots(root, leftRoot, leftScope, rightRoot, rightScope, ancestorRoot, ancestorScope);
-
- final MatchModel root1AncestorMatch = doMatch(leftResource, leftScope, ancestorResource,
- ancestorScope, monitor);
- // remove those external mappings added by call to doMatch
- root1AncestorMatch.getMatchedElements().removeAll(externalRefMappings);
- final List<Match2Elements> leftExternal2WayMappings = new ArrayList<Match2Elements>(
- externalRefMappings);
-
- final MatchModel root2AncestorMatch = doMatch(rightResource, rightScope, ancestorResource,
- ancestorScope, monitor);
- // remove those external mappings added by call to doMatch
- root2AncestorMatch.getMatchedElements().removeAll(externalRefMappings);
- final List<Match2Elements> rightExternal2WayMappings = new ArrayList<Match2Elements>(
- externalRefMappings);
-
- final List<MatchElement> root1MatchedElements = new ArrayList<MatchElement>(
- root1AncestorMatch.getMatchedElements());
- final List<MatchElement> root2MatchedElements = new ArrayList<MatchElement>(
- root2AncestorMatch.getMatchedElements());
-
- // populates the unmatched elements list for later use
- // There cannot be any conflicts on those, as neither has an ancestor
- for (final UnmatchElement unmatch : root1AncestorMatch.getUnmatchedElements()) {
- remainingUnmatchedElements.add(unmatch);
- }
- for (final UnmatchElement unmatch : root2AncestorMatch.getUnmatchedElements()) {
- remainingUnmatchedElements.add(unmatch);
- }
-
- try {
- final Match3Elements subMatchRoot = MatchFactory.eINSTANCE.createMatch3Elements();
- if (root2MatchedElements.size() > 0) {
- final Match2Elements root1Match = (Match2Elements)root1MatchedElements.get(0);
- final Match2Elements root2Match = (Match2Elements)root2MatchedElements.get(0);
-
- subMatchRoot.setSimilarity(set3WaySimilarity(root1Match.getLeftElement(),
- root2Match.getLeftElement(), root2Match.getRightElement()));
- subMatchRoot.setLeftElement(root1Match.getLeftElement());
- subMatchRoot.setRightElement(root2Match.getLeftElement());
- subMatchRoot.setOriginElement(root2Match.getRightElement());
- redirectedAdd(root, MATCH_ELEMENT_NAME, subMatchRoot);
- createSub3Match(root, subMatchRoot, root1Match, root2Match);
- } else if (root1MatchedElements.size() > 0) {
- stillToFindFromModel1.add(root1MatchedElements.get(0));
- }
-
- // We will now check through the unmatched object for matches. This
- // will allow for a more accurate
- // difference detection when dealing with multiple roots models.
- processNotFoundElements(root, subMatchRoot);
-
- // #processNotFoundElements(MatchModel, Match3Element)
- // will have updated "remainingUnmatchedElements"
- /*
- * We'll have to make two passes : UnmatchElements are potential matches for one another (they
- * result in elements not having ancestors, yet we could still be able to match them through 2-way
- * handling). The second pass will try and match Match2Elements with one another. Note that these
- * can be matched simply through instance equality of their ancestor element.
- */
- processSingleUnmatchedElements(leftResource, rightResource, root, subMatchRoot, monitor);
- processUnmatchedMatch2Elements(leftResource, rightResource, root, subMatchRoot);
- } catch (final FactoryException e) {
- EMFComparePlugin.log(e, false);
- }
-
- // create three way mappings for external references
- root.getMatchedElements().addAll(
- create3WayMatches(leftExternal2WayMappings, rightExternal2WayMappings));
- return root;
- }
-
- /**
- * Creates {@link Match3Elements} by merging those {@link Match2Elements}, having the same ancestor.
- *
- * @param leftToAncestor
- * matches between a left elements and their ancestors.
- * @param rightToAncestor
- * matches between right elements and their ancestors.
- * @return A list of newly created {@link Match3Elements}, each created for a pair of
- * {@link Match2Elements} from the leftToAncestor and rightToAncestor lists, sharing the same
- * ancestor.
- */
- private List<Match3Elements> create3WayMatches(List<Match2Elements> leftToAncestor,
- List<Match2Elements> rightToAncestor) {
- // create three way mappings for external references
- final List<Match3Elements> threeWayMappings = new ArrayList<Match3Elements>();
- for (Match2Elements leftExternalMapping : leftToAncestor) {
- final Match2Elements rightExternalMapping = rightToAncestor.get(leftToAncestor
- .indexOf(leftExternalMapping));
-
- final Match3Elements mapping = MatchFactory.eINSTANCE.createMatch3Elements();
- mapping.setLeftElement(leftExternalMapping.getLeftElement());
- mapping.setRightElement(rightExternalMapping.getLeftElement());
- mapping.setOriginElement(rightExternalMapping.getRightElement());
- try {
- mapping.setSimilarity(set3WaySimilarity(mapping.getLeftElement(), mapping.getRightElement(),
- mapping.getOriginElement()));
- } catch (FactoryException e) {
- mapping.setSimilarity(1.0d);
- }
- threeWayMappings.add(mapping);
- }
- return threeWayMappings;
- }
-
- /**
- * Filters unused features of the resource.
- *
- * @param resource
- * Resource to be apply filter on.
- */
- private void filterUnused(Resource resource) {
- for (final EObject root : resource.getContents()) {
- filter.analyseModel(root);
- }
- }
-
- /**
- * This will return the value associated to the given key in the options map.
- * <p>
- * NOTE : Misuses of this method will easily throw {@link ClassCastException}s.
- * </p>
- *
- * @param <T>
- * Expected type of the value associated to <code>key</code>.
- * @param key
- * Key of the value to retrieve.
- * @return Value associated to the given key in the options map.
- * @throws ClassCastException
- * If the value isn't assignment compatible with the expected type.
- */
- @SuppressWarnings("unchecked")
- protected <T> T getOption(String key) throws ClassCastException {
- return (T)options.get(key);
- }
-
- /**
- * This will lookup in the {@link #matchedByID} map and check if the two given objects have indeed been
- * matched by their ID. This method is no more used by the generic match engine implementation itself as
- * this logic moved to the AbstractSimilarityChecker
- *
- * @param left
- * Left of the two objects to check.
- * @param right
- * Right of the two objects to check.
- * @return <code>True</code> these objects haven't been matched by their ID, <code>False</code> otherwise.
- * @throws FactoryException
- * Thrown if we cannot compute the key for the object to match.
- */
- @Deprecated
- protected boolean haveDistinctID(EObject left, EObject right) throws FactoryException {
- return checker.isSimilar(left, right);
- }
-
- /**
- * This will lookup in the {@link #matchedByXMIID} map and check if the two given objects have indeed been
- * matched by their XMI ID.
- *
- * @param left
- * Left of the two objects to check.
- * @param right
- * Right of the two objects to check.
- * @return <code>True</code> these objects haven't been matched by their XMI ID, <code>False</code>
- * otherwise.
- * @throws FactoryException
- * Thrown if we cannot compute the key for the object to match.
- */
- @Deprecated
- protected boolean haveDistinctXMIID(EObject left, EObject right) throws FactoryException {
- return checker.isSimilar(left, right);
- }
-
- /**
- * This will compute the similarity between two {@link EObject}s' names.
- *
- * @param obj1
- * First of the two {@link EObject}s.
- * @param obj2
- * Second of the two {@link EObject}s.
- * @return <code>double</code> representing the similarity between the two {@link EObject}s' names. 0 &lt;
- * value &lt; 1.
- * @see NameSimilarity#nameSimilarityMetric(String, String)
- */
- @Deprecated
- protected double nameSimilarity(EObject obj1, EObject obj2) {
- double similarity = 0d;
- try {
-
- similarity = NameSimilarity.nameSimilarityMetric(NameSimilarity.findName(obj1),
- NameSimilarity.findName(obj2));
- } catch (final FactoryException e) {
- // fails silently, will return a similarity of 0d
- }
- return similarity;
- }
-
- /**
- * This will compute the similarity between two {@link EObject}s' contents.
- *
- * @param obj1
- * First of the two {@link EObject}s.
- * @param obj2
- * Second of the two {@link EObject}s.
- * @return <code>double</code> representing the similarity between the two {@link EObject}s' contents. 0
- * &lt; value &lt; 1.
- * @throws FactoryException
- * Thrown if we cannot compute the {@link EObject}s' contents similarity metrics.
- * @see NameSimilarity#contentValue(EObject, MetamodelFilter)
- */
- @Deprecated
- protected double contentSimilarity(EObject obj1, EObject obj2) throws FactoryException {
- double similarity = 0d;
- similarity = NameSimilarity.nameSimilarityMetric(NameSimilarity.contentValue(obj1),
- NameSimilarity.contentValue(obj2));
- return similarity;
- }
-
- /**
- * Returns a list containing mappings of the nodes of both given {@link List}s.
- *
- * @param list1
- * First of the lists from which we need to map the elements
- * @param list2
- * Second list to map the elements from.
- * @param window
- * Number of siblings to consider for the matching.
- * @param monitor
- * {@link CompareProgressMonitor Progress monitor} to display while the comparison lasts. Might
- * be <code>null</code>, in which case we won't monitor progress.
- * @return A {@link List} containing mappings of the nodes of both given {@link List}s.
- * @throws FactoryException
- * Thrown if the metrics cannot be computed.
- * @throws InterruptedException
- * Thrown if the matching process is interrupted somehow.
- */
- private List<Match2Elements> mapLists(List<EObject> list1, List<EObject> list2, int window,
- Monitor monitor) throws FactoryException, InterruptedException {
- final List<Match2Elements> result = new ArrayList<Match2Elements>();
- int curIndex = 0 - window / 2;
- final List<EObject> notFoundList1 = new ArrayList<EObject>(list1);
- final List<EObject> notFoundList2 = new ArrayList<EObject>(list2);
-
- final Iterator<EObject> it1 = list1.iterator();
- // then iterate over the 2 lists and compare the elements
- while (it1.hasNext() && notFoundList2.size() > 0) {
- final EObject obj1 = it1.next();
- EObject obj2 = checker.fastLookup(obj1);
-
- if (obj2 == null) {
- // subtracts the difference between the notfound and the
- // original list to avoid ArrayOutOfBounds
- final int end = Math.min(curIndex + window - (list2.size() - notFoundList2.size()),
- notFoundList2.size());
- final int index = Math
- .min(Math.max(curIndex - (list2.size() - notFoundList2.size()), 0), end);
-
- obj2 = findMostSimilar(obj1, notFoundList2.subList(index, end));
- if (obj2 != null) {
- // checks if the most similar to obj2 is obj1
- final EObject obj1Check = findMostSimilar(obj2, notFoundList1);
- if (obj1Check != obj1 && obj1Check != null && isSimilar(obj1Check, obj2)) {
- continue;
- }
- }
- }
-
- if (notFoundList1.contains(obj1) && notFoundList2.contains(obj2) && isSimilar(obj1, obj2)) {
- final Match2Elements mapping = MatchFactory.eINSTANCE.createMatch2Elements();
- final double metric = checker.absoluteMetric(obj1, obj2);
-
- mapping.setLeftElement(obj1);
- mapping.setRightElement(obj2);
- mapping.setSimilarity(metric);
- result.add(mapping);
- notFoundList1.remove(obj1);
- notFoundList2.remove(obj2);
- }
- curIndex += 1;
- monitor.worked(1);
- if (monitor.isCanceled()) {
- throw new InterruptedException();
- }
- }
-
- // now putting the not found elements aside for later
- stillToFindFromModel1.addAll(notFoundList1);
- stillToFindFromModel2.addAll(notFoundList2);
- return result;
- }
-
- /**
- * Allows for a more accurate modifications detection for three way comparison with multiple roots models.
- *
- * @param root
- * Root of the {@link MatchModel}.
- * @param subMatchRoot
- * Root of the {@link match3elements}' hierarchy for the current element to be created.
- * @throws FactoryException
- * Thrown if we cannot compute {@link EObject}s similarity or if adding elements to either
- * <code>root</code> or <code>subMatchRoot</code> fails somehow.
- */
- private void processNotFoundElements(MatchModel root, Match3Elements subMatchRoot)
- throws FactoryException {
- for (final EObject obj1 : new ArrayList<EObject>(stillToFindFromModel1)) {
- if (obj1 instanceof Match2Elements) {
- final Match2Elements match1 = (Match2Elements)obj1;
- for (final EObject obj2 : new ArrayList<EObject>(stillToFindFromModel2)) {
- if (obj2 instanceof Match2Elements) {
- final Match2Elements match2 = (Match2Elements)obj2;
-
- if (match1.getRightElement() == match2.getRightElement()) {
- final Match3Elements match = MatchFactory.eINSTANCE.createMatch3Elements();
- match.setSimilarity(set3WaySimilarity(match1.getLeftElement(),
- match2.getLeftElement(), match2.getRightElement()));
- match.setLeftElement(match1.getLeftElement());
- match.setRightElement(match2.getLeftElement());
- match.setOriginElement(match2.getRightElement());
- // This will happen if we couldn't match previously
- if (subMatchRoot == null) {
- redirectedAdd(root, MATCH_ELEMENT_NAME, match);
- createSub3Match(root, match, match1, match2);
- } else {
- redirectedAdd(subMatchRoot, SUBMATCH_ELEMENT_NAME, match);
- createSub3Match(root, subMatchRoot, match1, match2);
- }
- stillToFindFromModel1.remove(match1);
- stillToFindFromModel2.remove(match2);
- }
- }
- }
- }
- }
-
- for (final EObject eObj : new ArrayList<EObject>(stillToFindFromModel1)) {
- if (eObj instanceof Match2Elements) {
- remainingUnmatchedElements.add(eObj);
- }
- }
- for (final EObject eObj : new ArrayList<EObject>(stillToFindFromModel2)) {
- if (eObj instanceof Match2Elements) {
- remainingUnmatchedElements.add(eObj);
- }
- }
- }
-
- /**
- * Compute a three way similarity combining results from the pairs.
- *
- * @param left
- * left element.
- * @param right
- * right element.
- * @param ancestor
- * common ancestor.
- * @return a value representing their distance.
- * @throws FactoryException
- */
- private double set3WaySimilarity(EObject left, EObject right, EObject ancestor) throws FactoryException {
- final double metric1 = checker.absoluteMetric(left, right);
- final double metric2 = checker.absoluteMetric(left, ancestor);
- final double metric3 = checker.absoluteMetric(right, ancestor);
- return (metric1 + metric2 + metric3) / 3;
- }
-
- /**
- * This will be used in three way matching to take care of all unmatched elements. Unmatched elements are
- * then comprised of two things :
- * <ul>
- * <li>Match2Elements between left and ancestor or right and ancestor that had no equivalent in
- * respectively the right or left model - elements that have been removed or remotely removed.</li>
- * <li>UnmatchElements in either the right or the left model - elements that have been added or remotely
- * added</li>
- * </ul>
- * <p>
- * We are here handling Match2Elements only. These particular elements cannot be conflicting.
- * UnmatchElements will be handled in
- * {@link #processSingleUnmatchedElements(Notifier, Notifier, MatchModel, Match3Elements, Monitor)} .
- * </p>
- *
- * @param leftModel
- * Left model for the comparison.
- * @param rightModel
- * Right model for the comparison.
- * @param root
- * Root of the {@link MatchModel}.
- * @param subMatchRoot
- * root under which new match elements are to be added.
- * @throws FactoryException
- * Thrown if we couldn't add the new UnmatchElements.
- */
- private void processUnmatchedMatch2Elements(Notifier leftModel, Notifier rightModel, MatchModel root,
- Match3Elements subMatchRoot) throws FactoryException {
- final Set<Match2Elements> remainingLeft = new LinkedHashSet<Match2Elements>();
- final Set<Match2Elements> remainingRight = new LinkedHashSet<Match2Elements>();
- for (final EObject unmatched : new ArrayList<EObject>(remainingUnmatchedElements)) {
- if (unmatched instanceof Match2Elements) {
- final EObject element = ((Match2Elements)unmatched).getLeftElement();
- final EObject rootContainer = EcoreUtil.getRootContainer(element);
-
- if (rootContainer == leftModel || element.eResource() == leftModel) {
- remainingLeft.add((Match2Elements)unmatched);
- } else if (rootContainer == rightModel || element.eResource() == rightModel) {
- remainingRight.add((Match2Elements)unmatched);
- }
-
- // unmatched in ancestor can be safely ignored.
- remainingUnmatchedElements.remove(unmatched);
- }
- }
-
- for (final Match2Elements left : new LinkedHashSet<Match2Elements>(remainingLeft)) {
- for (final Match2Elements right : new LinkedHashSet<Match2Elements>(remainingRight)) {
- if (left.getRightElement() == right.getRightElement()) {
- final Match3Elements subMatch = MatchFactory.eINSTANCE.createMatch3Elements();
- subMatch.setOriginElement(left.getRightElement());
- subMatch.setLeftElement(left.getLeftElement());
- subMatch.setRightElement(right.getLeftElement());
- redirectedAdd(subMatchRoot, SUBMATCH_ELEMENT_NAME, subMatch);
- remainingLeft.remove(left);
- remainingRight.remove(right);
- break;
- }
- }
- }
- for (final Match2Elements nextLeftUnmatch : remainingLeft) {
- final UnmatchElement unmatch = MatchFactory.eINSTANCE.createUnmatchElement();
- unmatch.setElement(nextLeftUnmatch.getLeftElement());
- unmatch.setSide(Side.LEFT);
- unmatch.setRemote(true);
- redirectedAdd(root, UNMATCH_ELEMENT_NAME, unmatch);
- }
- for (final Match2Elements nextRightUnmatch : remainingRight) {
- final UnmatchElement unmatch = MatchFactory.eINSTANCE.createUnmatchElement();
- unmatch.setElement(nextRightUnmatch.getLeftElement());
- unmatch.setSide(Side.RIGHT);
- redirectedAdd(root, UNMATCH_ELEMENT_NAME, unmatch);
- }
- }
-
- /**
- * This will be used in three way matching to take care of all unmatched elements. Unmatched elements are
- * then comprised of two things :
- * <ul>
- * <li>Match2Elements between left and ancestor or right and ancestor that had no equivalent in
- * respectively the right or left model - elements that have been removed or remotely removed.</li>
- * <li>UnmatchElements in either the right or the left model - elements that have been added or remotely
- * added</li>
- * </ul>
- * <p>
- * We are here handling UnmatchElements only. Note that these particular differences can be conflicting if
- * they are contained within elements that have themselves been removed from the model. Match2Elements
- * have been handled by
- * {@link #processUnmatchedMatch2Elements(Notifier, Notifier, MatchModel, Match3Elements)} .
- * </p>
- *
- * @param left
- * Left model for the comparison.
- * @param right
- * Right model for the comparison.
- * @param root
- * Root of the {@link MatchModel}.
- * @param subMatchRoot
- * root under which new match elements are to be added.
- * @param monitor
- * Progress monitor to display while the comparison lasts.
- * @throws InterruptedException
- * Thrown if the comparison is interrupted somehow.
- * @throws FactoryException
- * Thrown if we couldn't add the new UnmatchElements.
- */
- private void processSingleUnmatchedElements(Notifier left, Notifier right, MatchModel root,
- Match3Elements subMatchRoot, Monitor monitor) throws InterruptedException, FactoryException {
- final Set<EObject> remainingLeft = new LinkedHashSet<EObject>();
- final Set<EObject> remainingRight = new LinkedHashSet<EObject>();
- for (final EObject unmatched : new ArrayList<EObject>(remainingUnmatchedElements)) {
- if (unmatched instanceof UnmatchElement) {
- final EObject element = ((UnmatchElement)unmatched).getElement();
- final EObject rootContainer = EcoreUtil.getRootContainer(element);
-
- if (rootContainer == left || element.eResource() == left) {
- remainingLeft.add(element);
- } else if (rootContainer == right || element.eResource() == right) {
- remainingRight.add(element);
- }
-
- // unmatched in ancestor can be safely ignored.
- remainingUnmatchedElements.remove(unmatched);
- }
- }
-
- stillToFindFromModel1.clear();
- stillToFindFromModel2.clear();
-
- final List<Match2Elements> mappings = mapLists(new ArrayList<EObject>(remainingLeft),
- new ArrayList<EObject>(remainingRight), structuredOptions.getSearchWindow(), monitor);
- for (final Match2Elements map : mappings) {
- final Match3Elements subMatch = MatchFactory.eINSTANCE.createMatch3Elements();
- subMatch.setLeftElement(map.getLeftElement());
- subMatch.setRightElement(map.getRightElement());
- redirectedAdd(subMatchRoot, SUBMATCH_ELEMENT_NAME, subMatch);
- }
- for (final EObject unmatch : stillToFindFromModel1) {
- final UnmatchElement unMap = MatchFactory.eINSTANCE.createUnmatchElement();
- unMap.setElement(unmatch);
- unMap.setSide(Side.LEFT);
- unMap.setRemote(false);
- for (final EObject unmatched : remainingUnmatchedElements) {
- if (unmatched instanceof Match2Elements) {
- if (unmatch.eContainer() == ((Match2Elements)unmatched).getLeftElement()) {
- unMap.setConflicting(true);
- break;
- }
- }
- }
- redirectedAdd(root, UNMATCH_ELEMENT_NAME, unMap);
- }
- for (final EObject remoteUnmatch : stillToFindFromModel2) {
- final UnmatchElement unMap = MatchFactory.eINSTANCE.createUnmatchElement();
- unMap.setElement(remoteUnmatch);
- unMap.setSide(Side.RIGHT);
- unMap.setRemote(true);
- for (final EObject unmatched : remainingUnmatchedElements) {
- if (unmatched instanceof Match2Elements) {
- if (remoteUnmatch.eContainer() == ((Match2Elements)unmatched).getLeftElement()) {
- unMap.setConflicting(true);
- break;
- }
- }
- }
- redirectedAdd(root, UNMATCH_ELEMENT_NAME, unMap);
- }
- }
-
- /**
- * We consider here <code>current1</code> and <code>current2</code> are similar. This method creates the
- * mapping for the objects <code>current1</code> and <code>current2</code>, Then submappings for these two
- * elements' contents.
- *
- * @param current1
- * First element of the two elements mapping.
- * @param current1Scope
- * The {@link IMatchScope} to restrict the contents of current1.
- * @param current2
- * Second of the two elements mapping.
- * @param current2Scope
- * The {@link IMatchScope} to restrict the contents of current2.
- * @param monitor
- * {@link CompareProgressMonitor Progress monitor} to display while the comparison lasts. Might
- * be <code>null</code>, in which case we won't monitor progress.
- * @return The mapping for <code>current1</code> and <code>current2</code> and their content.
- * @throws FactoryException
- * Thrown when the metrics cannot be computed for <code>current1</code> and
- * <code>current2</code>.
- * @throws InterruptedException
- * Thrown if the matching process is interrupted somehow.
- */
- private Match2Elements recursiveMappings(EObject current1, IMatchScope current1Scope, EObject current2,
- IMatchScope current2Scope, Monitor monitor) throws FactoryException, InterruptedException {
- Match2Elements mapping = null;
- mapping = MatchFactory.eINSTANCE.createMatch2Elements();
- mapping.setLeftElement(current1);
- mapping.setRightElement(current2);
- mapping.setSimilarity(checker.absoluteMetric(current1, current2));
- final List<Match2Elements> mapList = mapLists(getScopeInternalContents(current1, current1Scope),
- getScopeInternalContents(current2, current2Scope), structuredOptions.getSearchWindow(),
- monitor);
- // We can map other elements with mapLists; we iterate through them.
- final Iterator<Match2Elements> it = mapList.iterator();
- while (it.hasNext()) {
- final Match2Elements subMapping = it.next();
- // As we know source and target are similars, we call recursive
- // mappings onto these objects
- EFactory.eAdd(
- mapping,
- SUBMATCH_ELEMENT_NAME,
- recursiveMappings(subMapping.getLeftElement(), current1Scope,
- subMapping.getRightElement(), current2Scope, monitor));
- }
-
- return mapping;
- }
-
- /**
- * This method is an indirection for adding Mappings in the current MappingGroup.
- *
- * @param object
- * {@link EObject} to add a feature value to.
- * @param name
- * Name of the feature to consider.
- * @param value
- * Value to add to the feature <code>name</code> of <code>object</code>.
- * @throws FactoryException
- * Thrown if the value's affectation fails.
- */
- private void redirectedAdd(EObject object, String name, Object value) throws FactoryException {
- final EStructuralFeature feature = object.eClass().getEStructuralFeature(name);
- if (feature.isMany()) {
- if (value != null) {
- if (value instanceof EObject) {
- ((BasicEList)object.eGet(feature)).addUnique(value);
- } else {
- ((List)object.eGet(feature)).add(value);
- }
- }
- } else {
- EFactory.eSet(object, name, value);
- }
- }
-
- /**
- * Sets the values of the {@link MatchModel}'s left and right models.
- *
- * @param modelRoot
- * Root of the {@link MatchModel}.
- * @param left
- * Element from which to resolve the left model URI.
- * @param right
- * Element from which to resolve the right model URI.
- * @since 1.1
- * @deprecated bug 346607 : roots can be out of the scope too. Use
- * {@link #setModelRoots(MatchModel, EObject, IMatchScope, EObject, IMatchScope, EObject, IMatchScope)}
- * instead.
- */
- @Deprecated
- protected void setModelRoots(MatchModel modelRoot, EObject left, EObject right) {
- setModelRoots(modelRoot, left, right, null);
- }
-
- /**
- * Sets the values of the {@link MatchModel}'s left, right and ancestor models.
- *
- * @param modelRoot
- * Root of the {@link MatchModel}.
- * @param left
- * Element from which to resolve the left model URI.
- * @param right
- * Element from which to resolve the right model URI.
- * @param ancestor
- * Element from which to resolve the ancestor model URI. Can be <code>null</code>.
- * @since 1.1
- * @deprecated bug 346607 : roots can be out of the scope too. Use
- * {@link #setModelRoots(MatchModel, EObject, IMatchScope, EObject, IMatchScope, EObject, IMatchScope)}
- * instead.
- */
- @Deprecated
- protected void setModelRoots(MatchModel modelRoot, EObject left, EObject right, EObject ancestor) {
- setModelRoots(modelRoot, left, null, right, null, ancestor, null);
- }
-
- /**
- * Sets the values of the {@link MatchModel}'s left, right and ancestor models.
- *
- * @param modelRoot
- * Root of the {@link MatchModel}.
- * @param left
- * Element from which to resolve the left model URI.
- * @param leftScope
- * Scope that should be used to filter out left roots. Can be <code>null</code>.
- * @param right
- * Element from which to resolve the right model URI.
- * @param rightScope
- * Scope that should be used to filter out right roots. Can be <code>null</code>.
- * @param ancestor
- * Element from which to resolve the ancestor model URI. Can be <code>null</code>.
- * @param ancestorScope
- * Scope that should be used to filter out ancestor roots. Can be <code>null</code>.
- * @since 1.3
- */
- protected void setModelRoots(MatchModel modelRoot, EObject left, IMatchScope leftScope, EObject right,
- IMatchScope rightScope, EObject ancestor, IMatchScope ancestorScope) {
- // Sets values of left, right and ancestor model roots
- if (left != null) {
- if (left.eResource() != null) {
- for (EObject leftRoot : left.eResource().getContents()) {
- if (leftScope == null || leftScope.isInScope(leftRoot)) {
- modelRoot.getLeftRoots().add(leftRoot);
- }
- }
- } else {
- EObject leftRoot = EcoreUtil.getRootContainer(left);
- if (leftScope.isInScope(leftRoot)) {
- modelRoot.getLeftRoots().add(leftRoot);
- }
- }
- }
- if (right != null) {
- if (right.eResource() != null) {
- for (EObject rightRoot : right.eResource().getContents()) {
- if (rightScope == null || rightScope.isInScope(rightRoot)) {
- modelRoot.getRightRoots().add(rightRoot);
- }
- }
- } else {
- EObject rightRoot = EcoreUtil.getRootContainer(right);
- if (rightScope.isInScope(rightRoot)) {
- modelRoot.getRightRoots().add(rightRoot);
- }
- }
- }
- if (ancestor != null) {
- if (ancestor.eResource() != null) {
- for (EObject ancestorRoot : ancestor.eResource().getContents()) {
- if (ancestorScope == null || ancestorScope.isInScope(ancestorRoot)) {
- modelRoot.getAncestorRoots().add(ancestorRoot);
- }
- }
- } else {
- EObject ancestorRoot = EcoreUtil.getRootContainer(ancestor);
- if (ancestorScope.isInScope(ancestorRoot)) {
- modelRoot.getAncestorRoots().add(ancestorRoot);
- }
- }
- }
- }
-
- /**
- * Starts the monitor for comparison progress. Externalized here to avoid multiple usage of the Strings.
- *
- * @param monitor
- * The monitor that need be started
- * @param size
- * Size of the monitor
- */
- private void startMonitor(Monitor monitor, int size) {
- monitor.beginTask(EMFCompareMatchMessages.getString("DifferencesServices.monitor.task"), size); //$NON-NLS-1$
- monitor.subTask(EMFCompareMatchMessages.getString("DifferencesServices.monitor.browsing")); //$NON-NLS-1$
- }
-
- /**
- * Returns <code>True</code> if the 2 given {@link EObject}s are considered similar.
- *
- * @param obj1
- * The first {@link EObject} to compare.
- * @param obj2
- * Second of the {@link EObject}s to compare.
- * @return <code>True</code> if both elements have the same serialization ID, <code>False</code>
- * otherwise.
- * @throws FactoryException
- * Thrown if we cannot compute one of the needed similarity.
- */
- protected boolean isSimilar(EObject obj1, EObject obj2) throws FactoryException {
- return checker.isSimilar(obj1, obj2);
- }
-
- /**
- * Workaround for bug #235606 : elements held by a reference with containment=true and derived=true are
- * not matched since not returned by {@link EObject#eContents()}. This allows us to return the list of all
- * contents from an EObject <u>including</u> those references.
- *
- * @param eObject
- * The EObject we seek the content of.
- * @param scope
- * The scope to restrict the contents.
- * @return The list of all the content of a given EObject, derived containmnent references included.
- * @since 1.1
- */
- protected List<EObject> getScopeInternalContents(EObject eObject, IMatchScope scope) {
- // filter out those contained objects belonging to a fragment resource
- final List<EObject> result = new ArrayList<EObject>();
- // add contents within scope
- for (EObject contents : eObject.eContents()) {
- // only add direct "non-fragment" contents
- if (!result.contains(contents) && scope.isInScope(contents)) {
- result.add(contents);
- }
- }
- // add derived containment references in scope (do not objects contained in fragments)
- for (final EReference reference : eObject.eClass().getEAllReferences()) {
- if (reference.isContainment() && reference.isDerived()) {
- final Object value = eObject.eGet(reference);
- if (value instanceof Collection) {
- for (Object contents : (Collection)value) {
- if (!result.contains(contents) && contents instanceof EObject) {
- final EObject object = (EObject)contents;
- if (scope.isInScope(object)) {
- result.add(object);
- }
- }
- }
- } else if (!result.contains(value) && value instanceof EObject) {
- final EObject object = (EObject)value;
- if (scope.isInScope(object)) {
- result.add(object);
- }
- }
- }
- }
- return result;
- }
-
- /**
- * Returns all objects contained in the given resource (via {@link Resource#getContents()}), covered by
- * the provided scope.
- *
- * @param resource
- * The resource, whose contents is to be regarded.
- * @param scope
- * The scope to restrict, which of the contents' objects is included in the returned list.
- * @return The list of conents' objects, covered within the given scope.
- */
- private List<EObject> getScopeInternalContents(Resource resource, IMatchScope scope) {
- final List<EObject> result = new ArrayList<EObject>();
- for (EObject contents : resource.getContents()) {
- if (!result.contains(contents) && scope.isInScope(contents)) {
- result.add(contents);
- }
- }
- return result;
- }
-}

Back to the top