Skip to main content
summaryrefslogtreecommitdiffstats
blob: 165b9bacc43bd04ead13fd9eb6da5ec3f61a107d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/*******************************************************************************
 * Copyright (c) 2013 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.ide.ui.internal.logical;

import static org.eclipse.emf.compare.ide.utils.ResourceUtil.binaryIdentical;

import com.google.common.collect.Sets;

import java.util.Iterator;
import java.util.Set;

import org.eclipse.core.resources.IStorage;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.emf.compare.ide.ui.internal.EMFCompareIDEUIMessages;
import org.eclipse.emf.compare.ide.ui.logical.IModelMinimizer;
import org.eclipse.emf.compare.ide.ui.logical.SynchronizationModel;
import org.eclipse.emf.compare.ide.utils.StorageTraversal;

/**
 * Instances of this class will be used by EMF Compare to minimize the scope to parts of a logical model that
 * can be considered valid candidates for a difference.
 * <p>
 * This default implementation will consider that all files that are binary identical between the two (or
 * three) sides of the comparison can be safely removed from the scope. Likewise, unmatched read-only files
 * will be removed from the scope.
 * </p>
 * 
 * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
 */
public class IdenticalResourceMinimizer implements IModelMinimizer {
	/**
	 * {@inheritDoc} Specifically, we'll remove all resources that can be seen as binary identical (we match
	 * resources through exact equality of their names) or unmatched and read-only.
	 * 
	 * @see org.eclipse.emf.compare.ide.ui.logical.IModelMinimizer#minimize(org.eclipse.emf.compare.ide.ui.logical.SynchronizationModel,
	 *      org.eclipse.core.runtime.IProgressMonitor)
	 */
	public void minimize(SynchronizationModel syncModel, IProgressMonitor monitor) {
		SubMonitor progess = SubMonitor.convert(monitor, EMFCompareIDEUIMessages
				.getString("EMFSynchronizationModel.minimizing"), 100); //$NON-NLS-1$

		final StorageTraversal leftTraversal = syncModel.getLeftTraversal();
		final StorageTraversal rightTraversal = syncModel.getRightTraversal();
		final StorageTraversal originTraversal = syncModel.getOriginTraversal();

		final boolean threeWay = !originTraversal.getStorages().isEmpty();
		// Copy the sets to update them as we go.
		final Set<IStorage> leftCopy = Sets.newLinkedHashSet(leftTraversal.getStorages());
		final Set<IStorage> rightCopy = Sets.newLinkedHashSet(rightTraversal.getStorages());
		final Set<IStorage> originCopy = Sets.newLinkedHashSet(originTraversal.getStorages());

		SubMonitor subMonitor = progess.newChild(98).setWorkRemaining(leftCopy.size());
		for (IStorage left : leftCopy) {
			final IStorage right = removeLikeNamedStorageFrom(left, rightCopy);
			if (right != null && threeWay) {
				final IStorage origin = removeLikeNamedStorageFrom(left, originCopy);

				if (origin != null && equals(left, right, origin)) {
					leftTraversal.removeStorage(left);
					rightTraversal.removeStorage(right);
					originTraversal.removeStorage(origin);
				}
			} else if (right != null && equals(left, right)) {
				leftTraversal.removeStorage(left);
				rightTraversal.removeStorage(right);
			} else if (right == null) {
				// This file has no match. remove it if read only
				if (left.isReadOnly()) {
					leftTraversal.getStorages().remove(left);
				}
			}
			subMonitor.worked(1);
		}

		subMonitor = progess.newChild(1).setWorkRemaining(rightCopy.size());
		for (IStorage right : rightCopy) {
			// These have no match on left. Remove if read only
			if (right.isReadOnly()) {
				rightTraversal.removeStorage(right);
			}
			subMonitor.worked(1);
		}

		subMonitor = progess.newChild(1).setWorkRemaining(rightCopy.size());
		for (IStorage origin : originCopy) {
			// These have no match on left and right. Remove if read only
			if (origin.isReadOnly()) {
				originTraversal.removeStorage(origin);
			}
			subMonitor.worked(1);
		}
	}

	/**
	 * Checks whether the three given (non-<code>null</code>) resources are identical. This default
	 * implementation only checks that the three are identical binary-wise.
	 * <p>
	 * Identical resources will be filtered out of the comparison scope.
	 * </p>
	 * 
	 * @param left
	 *            Left of the resources to consider.
	 * @param right
	 *            Right of the resources to consider.
	 * @param origin
	 *            Common ancestor of the left and right resources.
	 * @return <code>true</code> if the given resources are to be considered identical, <code>false</code>
	 *         otherwise.
	 */
	protected boolean equals(IStorage left, IStorage right, IStorage origin) {
		return binaryIdentical(left, right, origin);
	}

	/**
	 * Checks whether the two given (non-<code>null</code>) resources are identical. This default
	 * implementation only checks that the two are identical binary-wise.
	 * <p>
	 * Identical resources will be filtered out of the comparison scope.
	 * </p>
	 * 
	 * @param left
	 *            Left of the resources to consider.
	 * @param rightRight
	 *            of the resources to consider.
	 * @return <code>true</code> if the given resources are to be considered identical, <code>false</code>
	 *         otherwise.
	 */
	protected boolean equals(IStorage left, IStorage right) {
		return binaryIdentical(left, right);
	}

	/**
	 * Looks up into the {@code candidates} set for a storage which name matches that of the {@code reference}
	 * storage, removing it if there is one.
	 * 
	 * @param reference
	 *            The storage for which we'll seek a match into {@code candidates}.
	 * @param candidates
	 *            The set of candidates into which to look up for a match to {@code reference}.
	 * @return The first storage from the set of candidates that matches the {@code reference}, if any.
	 *         <code>null</code> if none match.
	 */
	protected IStorage removeLikeNamedStorageFrom(IStorage reference, Set<IStorage> candidates) {
		final String referenceName = reference.getName();
		final Iterator<IStorage> candidatesIterator = candidates.iterator();
		while (candidatesIterator.hasNext()) {
			final IStorage candidate = candidatesIterator.next();
			final String candidateName = candidate.getName();

			if (referenceName.equals(candidateName)) {
				candidatesIterator.remove();
				return candidate;
			}
		}
		return null;
	}
}

Back to the top