[477767] Introduce new MatchingStrategy for models shared with git

When a comparison invloves models shared with git, the
NameMatchingStrategy is not effective. The strategy should use the
entire location for matching instead of name. This strategy must be
active only when comparison invloves models shared with git.

Change-Id: I27a4b03871845ed1f1e54de4659ebad844dc8e72
Signed-off-by: Axel Richard <axel.richard@obeo.fr>
diff --git a/plugins/org.eclipse.emf.compare.egit/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.compare.egit/META-INF/MANIFEST.MF
index edf18e0..5b1d498 100644
--- a/plugins/org.eclipse.emf.compare.egit/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.emf.compare.egit/META-INF/MANIFEST.MF
@@ -11,7 +11,8 @@
  org.eclipse.emf.compare.ide;bundle-version="3.2.0",
  org.eclipse.emf.compare.rcp,
  org.eclipse.emf.compare
-Import-Package: org.apache.log4j;version="1.2.0"
+Import-Package: com.google.common.collect;version="[11.0.0,16.0.0)",
+ org.apache.log4j;version="1.2.0"
 Bundle-RequiredExecutionEnvironment: J2SE-1.5
 Bundle-ActivationPolicy: lazy
 Bundle-Vendor: %providerName
diff --git a/plugins/org.eclipse.emf.compare.egit/plugin.xml b/plugins/org.eclipse.emf.compare.egit/plugin.xml
index 097f89d..6b0279b 100644
--- a/plugins/org.eclipse.emf.compare.egit/plugin.xml
+++ b/plugins/org.eclipse.emf.compare.egit/plugin.xml
@@ -29,5 +29,14 @@
                value=".*">

          </nsURI>

       </processor>

+   </extension>

+   <extension

+         point="org.eclipse.emf.compare.rcp.matchEngine">

+      <engineFactory

+            class="org.eclipse.emf.compare.egit.internal.match.EGitMatchEngineFactory"

+            description="EGit implementation of the Matching engine provided by EMF Compare"

+            label="EGit Match Engine"

+            ranking="10">

+      </engineFactory>

    </extension>
 </plugin>

diff --git a/plugins/org.eclipse.emf.compare.egit/src/org/eclipse/emf/compare/egit/internal/match/EGitMatchEngineFactory.java b/plugins/org.eclipse.emf.compare.egit/src/org/eclipse/emf/compare/egit/internal/match/EGitMatchEngineFactory.java
new file mode 100644
index 0000000..35d2b57
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.egit/src/org/eclipse/emf/compare/egit/internal/match/EGitMatchEngineFactory.java
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * Copyright (c) 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.egit.internal.match;
+
+import com.google.common.collect.Sets;
+
+import java.util.Collection;
+
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.compare.ide.internal.utils.StoragePathAdapter;
+import org.eclipse.emf.compare.match.DefaultMatchEngine;
+import org.eclipse.emf.compare.match.IMatchEngine;
+import org.eclipse.emf.compare.match.resource.IResourceMatchingStrategy;
+import org.eclipse.emf.compare.match.resource.LocationMatchingStrategy;
+import org.eclipse.emf.compare.rcp.EMFCompareRCPPlugin;
+import org.eclipse.emf.compare.rcp.internal.match.DefaultRCPMatchEngineFactory;
+import org.eclipse.emf.compare.scope.IComparisonScope;
+import org.eclipse.emf.compare.utils.UseIdentifiers;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+/**
+ * Specialization of {@link DefaultRCPMatchEngineFactory} for EGit. When a comparison involves models shared
+ * with EGit, the {@link org.eclipse.emf.compare.match.resource.StrategyResourceMatcher} must use the
+ * {@link org.eclipse.emf.compare.match.resource.LocationMatchingStrategy} instead of the
+ * {@link org.eclipse.emf.compare.match.resource.NameMatchingStrategy}.
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ */
+@SuppressWarnings("restriction")
+public class EGitMatchEngineFactory extends DefaultRCPMatchEngineFactory {
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean isMatchEngineFactoryFor(IComparisonScope scope) {
+
+		final Notifier right = scope.getRight();
+		boolean activateEGitMatchEngine = isNotifierContainsSharedResource(right);
+
+		if (!activateEGitMatchEngine) {
+			final Notifier left = scope.getLeft();
+			activateEGitMatchEngine = isNotifierContainsSharedResource(left);
+			if (!activateEGitMatchEngine) {
+				final Notifier origin = scope.getOrigin();
+				activateEGitMatchEngine = isNotifierContainsSharedResource(origin);
+			}
+		}
+
+		return activateEGitMatchEngine;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public IMatchEngine getMatchEngine() {
+		final UseIdentifiers useUdentifier = getUseIdentifierValue(getConfiguration());
+		final Collection<IResourceMatchingStrategy> strategies = Sets.newLinkedHashSet();
+		strategies.add(new LocationMatchingStrategy());
+		return DefaultMatchEngine.create(useUdentifier, EMFCompareRCPPlugin.getDefault()
+				.getWeightProviderRegistry(), strategies);
+	}
+
+	/**
+	 * Check if the given {@link Notifier} contains at least on resource shared with git.
+	 * 
+	 * @param notifier
+	 *            the given {@link Notifier}.
+	 * @return true if the given {@link Notifier} contains at least on resource shared with git, false
+	 *         otherwise.
+	 */
+	private boolean isNotifierContainsSharedResource(final Notifier notifier) {
+		if (notifier instanceof ResourceSet) {
+			for (Resource resource : ((ResourceSet)notifier).getResources()) {
+				if (isResourceSharedWithGit(resource)) {
+					return true;
+				}
+			}
+		} else if (notifier instanceof Resource && isResourceSharedWithGit((Resource)notifier)) {
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * Check if the given {@link Resource} is shared with git.
+	 * 
+	 * @param resource
+	 *            the given {@link Resource}.
+	 * @return true if the given {@link Resource} is shared with git, false otherwise.
+	 */
+	private boolean isResourceSharedWithGit(Resource resource) {
+		Adapter leftAdapter = EcoreUtil.getAdapter(resource.eAdapters(), StoragePathAdapter.class);
+		// If the resource is a storage path adapter and this storage path adapter contains a file URI, this
+		// means that this is a resource from the Local History, not from a Git repository.
+		if (leftAdapter instanceof StoragePathAdapter && !((StoragePathAdapter)leftAdapter).isLocal()
+				&& !isFileURI(((StoragePathAdapter)leftAdapter).getStoragePath())) {
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Check if the given path is has a file scheme (file:).
+	 * 
+	 * @param path
+	 *            the given path.
+	 * @return true if the given path is has a file scheme (file:), false otherwise.
+	 */
+	private boolean isFileURI(String path) {
+		final boolean isFileURI;
+		if (path == null) {
+			isFileURI = false;
+		} else {
+			isFileURI = path.startsWith("file:"); //$NON-NLS-1$
+		}
+		return isFileURI;
+	}
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui.tests/src/org/eclipse/emf/compare/ide/ui/tests/suite/AllTests.java b/plugins/org.eclipse.emf.compare.ide.ui.tests/src/org/eclipse/emf/compare/ide/ui/tests/suite/AllTests.java
index 9384299..68cb930 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui.tests/src/org/eclipse/emf/compare/ide/ui/tests/suite/AllTests.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui.tests/src/org/eclipse/emf/compare/ide/ui/tests/suite/AllTests.java
@@ -36,6 +36,7 @@
 import org.eclipse.emf.compare.ide.ui.tests.structuremergeviewer.actions.MergeActionTest;
 import org.eclipse.emf.compare.ide.ui.tests.structuremergeviewer.actions.MergeNonConflictingRunnableTest;
 import org.eclipse.emf.compare.ide.ui.tests.structuremergeviewer.actions.PseudoConflictsMergeActionTest;
+import org.eclipse.emf.compare.ide.ui.tests.structuremergeviewer.notloadedfragment.NotLoadedFragmentNodeTest;
 import org.eclipse.emf.compare.ide.ui.tests.unit.DependenciesTest;
 import org.eclipse.emf.compare.tests.nodes.NodesPackage;
 import org.eclipse.emf.compare.tests.nodes.util.NodesResourceFactoryImpl;
@@ -49,15 +50,13 @@
 @RunWith(Suite.class)
 @SuiteClasses({EMFCompareConfigurationTest.class, DependenciesTest.class, MergeActionTest.class,
 		PseudoConflictsMergeActionTest.class, BugsTestSuite.class, NavigatableTest.class,
-		/*
-		 * FIXME Reintegrate this test when local comparisons work again NotLoadedFragmentNodeTest.class,
-		 */
-		NotLoadedFragmentItemTest.class, ResolutionEventsTest.class, ResourceComputationSchedulerTest.class,
-		ResourceComputationSchedulerWithEventBusTest.class, ThreadedModelResolverGraphTest.class,
-		ThreadedModelResolverWithCustomDependencyProviderTest.class, DependencyGraphUpdaterTest.class,
-		GraphResolutionTest.class, EMFModelProviderTest.class, MergeAllCommandTests.class,
-		LocalMonitoredProxyCreationListenerTest.class, RemoteMonitoredProxyCreationListenerTest.class,
-		MergeNonConflictingRunnableTest.class, RenameDetectorTest.class, SimilarityComputerTest.class })
+		NotLoadedFragmentNodeTest.class, NotLoadedFragmentItemTest.class, ResolutionEventsTest.class,
+		ResourceComputationSchedulerTest.class, ResourceComputationSchedulerWithEventBusTest.class,
+		ThreadedModelResolverGraphTest.class, ThreadedModelResolverWithCustomDependencyProviderTest.class,
+		DependencyGraphUpdaterTest.class, GraphResolutionTest.class, EMFModelProviderTest.class,
+		MergeAllCommandTests.class, LocalMonitoredProxyCreationListenerTest.class,
+		RemoteMonitoredProxyCreationListenerTest.class, MergeNonConflictingRunnableTest.class,
+		RenameDetectorTest.class, SimilarityComputerTest.class })
 public class AllTests {
 	/**
 	 * Launches the test with the given arguments.
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/fragmentation/FragmentationTest.java b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/fragmentation/FragmentationTest.java
index 1ce88a8..e852f4f 100644
--- a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/fragmentation/FragmentationTest.java
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/fragmentation/FragmentationTest.java
@@ -643,7 +643,6 @@
 	}
 
 	// This only tests the merge. Will fail if testControledObjectFolderResourceSet does.
-	@Ignore("To ignore while an Egit merge strategy hasn't be provided.")
 	@Test
 	public void testMergeControledObjectFolderResourceSetLtR() throws IOException {
 		final Resource left = input.getControlLeftFolder();
@@ -956,7 +955,6 @@
 	}
 
 	// This only tests the merge. Will fail if testDeletedRootResourceSet does.
-	@Ignore("To ignore while an Egit merge strategy hasn't be provided.")
 	@Test
 	public void testMergeDeletedRootResourceSetRtL() throws IOException {
 		final Resource left = input.getDeletedRootLeft();
@@ -1101,7 +1099,6 @@
 	}
 
 	// This only tests the merge. Will fail if testNewRootResourceSet does.
-	@Ignore("To ignore while an Egit merge strategy hasn't be provided.")
 	@Test
 	public void testMergeNewRootResourceSetLtR() throws IOException {
 		final Resource left = input.getNewRootLeft();
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/DefaultMatchEngine.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/DefaultMatchEngine.java
index 2acbf5b..7408e05 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/DefaultMatchEngine.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/DefaultMatchEngine.java
@@ -16,6 +16,7 @@
 import com.google.common.collect.Iterators;
 import com.google.common.collect.Lists;
 
+import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
 
@@ -35,6 +36,7 @@
 import org.eclipse.emf.compare.match.eobject.WeightProvider;
 import org.eclipse.emf.compare.match.eobject.WeightProviderDescriptorRegistryImpl;
 import org.eclipse.emf.compare.match.resource.IResourceMatcher;
+import org.eclipse.emf.compare.match.resource.IResourceMatchingStrategy;
 import org.eclipse.emf.compare.match.resource.StrategyResourceMatcher;
 import org.eclipse.emf.compare.scope.IComparisonScope;
 import org.eclipse.emf.compare.utils.UseIdentifiers;
@@ -60,6 +62,9 @@
 	/** The delegate {@link IEObjectMatcher matcher} that will actually pair EObjects together. */
 	private final IEObjectMatcher eObjectMatcher;
 
+	/** The strategy that will actually pair Resources together. */
+	private final IResourceMatcher resourceMatcher;
+
 	/** The factory that will be use to instantiate Comparison as return by match() methods. */
 	private final IComparisonFactory comparisonFactory;
 
@@ -73,7 +78,24 @@
 	 * @since 3.0
 	 */
 	public DefaultMatchEngine(IEObjectMatcher matcher, IComparisonFactory comparisonFactory) {
-		this.eObjectMatcher = checkNotNull(matcher);
+		this(matcher, new StrategyResourceMatcher(), comparisonFactory);
+	}
+
+	/**
+	 * This default engine delegates the pairing of EObjects to an {@link IEObjectMatcher}.
+	 * 
+	 * @param eObjectMatcher
+	 *            The matcher that will be in charge of pairing EObjects together for this comparison process.
+	 * @param resourceMatcher
+	 *            The matcher that will be in charge of pairing EObjects together for this comparison process.
+	 * @param comparisonFactory
+	 *            factory that will be use to instantiate Comparison as return by match() methods.
+	 * @since 3.2
+	 */
+	public DefaultMatchEngine(IEObjectMatcher eObjectMatcher, IResourceMatcher resourceMatcher,
+			IComparisonFactory comparisonFactory) {
+		this.eObjectMatcher = checkNotNull(eObjectMatcher);
+		this.resourceMatcher = checkNotNull(resourceMatcher);
 		this.comparisonFactory = checkNotNull(comparisonFactory);
 	}
 
@@ -158,11 +180,9 @@
 			originChildren = Iterators.emptyIterator();
 		}
 
-		final IResourceMatcher resourceMatcher = createResourceMatcher();
-
 		// TODO Change API to pass the monitor to createMappings()
-		final Iterable<MatchResource> mappings = resourceMatcher.createMappings(leftChildren, rightChildren,
-				originChildren);
+		final Iterable<MatchResource> mappings = this.resourceMatcher.createMappings(leftChildren,
+				rightChildren, originChildren);
 
 		final List<Iterator<? extends EObject>> leftIterators = Lists.newLinkedList();
 		final List<Iterator<? extends EObject>> rightIterators = Lists.newLinkedList();
@@ -329,12 +349,24 @@
 	 * 
 	 * @return An {@link IResourceMatcher} that can be used to retrieve the {@link MatchResource}s for this
 	 *         comparison.
+	 * @deprecated use {@link DefaultMatchEngine} constructor with {@link StrategyResourceMatcher} parameter
+	 *             instead.
 	 */
+	@Deprecated
 	protected IResourceMatcher createResourceMatcher() {
 		return new StrategyResourceMatcher();
 	}
 
 	/**
+	 * Returns the Resource matcher associated with this match engine.
+	 * 
+	 * @return The Resource matcher associated with this match engine.
+	 */
+	protected final IResourceMatcher getResourceMatcher() {
+		return this.resourceMatcher;
+	}
+
+	/**
 	 * Returns the EObject matcher associated with this match engine.
 	 * 
 	 * @return The EObject matcher associated with this match engine.
@@ -385,11 +417,37 @@
 	 */
 	public static IMatchEngine create(UseIdentifiers useIDs,
 			WeightProvider.Descriptor.Registry weightProviderRegistry) {
+		return create(useIDs, weightProviderRegistry, null);
+	}
+
+	/**
+	 * Helper creator method that instantiate a {@link DefaultMatchEngine} that will use identifiers as
+	 * specified by the given {@code useIDs} enumeration.
+	 * 
+	 * @param useIDs
+	 *            the kinds of matcher to use.
+	 * @param weightProviderRegistry
+	 *            the match engine needs a WeightProvider in case of this match engine do not use identifiers.
+	 * @param strategies
+	 *            the matching strategies you want to use for the match step.
+	 * @return a new {@link DefaultMatchEngine} instance.
+	 */
+	public static IMatchEngine create(UseIdentifiers useIDs,
+			WeightProvider.Descriptor.Registry weightProviderRegistry,
+			Collection<IResourceMatchingStrategy> strategies) {
 		final IComparisonFactory comparisonFactory = new DefaultComparisonFactory(
 				new DefaultEqualityHelperFactory());
-		final IEObjectMatcher matcher = createDefaultEObjectMatcher(useIDs, weightProviderRegistry);
+		final IEObjectMatcher eObjectMatcher = createDefaultEObjectMatcher(useIDs, weightProviderRegistry);
 
-		final IMatchEngine matchEngine = new DefaultMatchEngine(matcher, comparisonFactory);
+		final IResourceMatcher resourceMatcher;
+		if (strategies == null || strategies.isEmpty()) {
+			resourceMatcher = new StrategyResourceMatcher();
+		} else {
+			resourceMatcher = new StrategyResourceMatcher(strategies);
+		}
+
+		final IMatchEngine matchEngine = new DefaultMatchEngine(eObjectMatcher, resourceMatcher,
+				comparisonFactory);
 		return matchEngine;
 	}
 
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/LocationMatchingStrategy.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/LocationMatchingStrategy.java
index 09f5090..7a30401 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/LocationMatchingStrategy.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/LocationMatchingStrategy.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012 Obeo.
+ * Copyright (c) 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
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/StrategyResourceMatcher.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/StrategyResourceMatcher.java
index 853820f..68feb31 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/StrategyResourceMatcher.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/resource/StrategyResourceMatcher.java
@@ -11,8 +11,10 @@
  *******************************************************************************/
 package org.eclipse.emf.compare.match.resource;
 
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
@@ -53,6 +55,30 @@
 	};
 
 	/**
+	 * The known strategies.
+	 */
+	private final ImmutableSet<IResourceMatchingStrategy> knownStrategies;
+
+	/**
+	 * Default constructor with two strategies: {@link NameMatchingStrategy} & {@link RootIDMatchingStrategy}.
+	 */
+	public StrategyResourceMatcher() {
+		this.knownStrategies = ImmutableSet.of(new NameMatchingStrategy(), new RootIDMatchingStrategy());
+
+	}
+
+	/**
+	 * Constructor that allows to give your own {@link IResourceMatchingStrategy}.
+	 * 
+	 * @param strategies
+	 *            the strategies you want to use for the match step. A defensive copy of the provided
+	 *            strategies will be done.
+	 */
+	public StrategyResourceMatcher(Collection<IResourceMatchingStrategy> strategies) {
+		this.knownStrategies = ImmutableSet.copyOf(strategies);
+	}
+
+	/**
 	 * {@inheritDoc}
 	 * 
 	 * @see org.eclipse.emf.compare.match.resource.IResourceMatcher#createMappings(java.util.Iterator,
@@ -148,8 +174,7 @@
 	 * @return The resource matching strategies that should be used by this matcher.
 	 */
 	protected IResourceMatchingStrategy[] getResourceMatchingStrategies() {
-		final IResourceMatchingStrategy locationStrategy = new LocationMatchingStrategy();
-		return new IResourceMatchingStrategy[] {locationStrategy, };
+		return knownStrategies.toArray(new IResourceMatchingStrategy[] {});
 	}
 
 	/**