Fix some of the warnings
[EMFCompare2.git] / plugins / org.eclipse.emf.compare.edit / src / org / eclipse / emf / compare / domain / impl / EMFCompareEditingDomain.java
blobc55392d46e07d19f3bdf8c84c29622010849bab7
1 /*******************************************************************************
2 * Copyright (c) 2012, 2014 Obeo.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * Obeo - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.emf.compare.domain.impl;
13 import com.google.common.collect.ImmutableCollection;
14 import com.google.common.collect.ImmutableList;
15 import com.google.common.collect.ImmutableSet;
17 import java.util.ArrayList;
18 import java.util.List;
20 import org.eclipse.core.runtime.IStatus;
21 import org.eclipse.core.runtime.Status;
22 import org.eclipse.emf.common.command.BasicCommandStack;
23 import org.eclipse.emf.common.command.Command;
24 import org.eclipse.emf.common.command.CommandStack;
25 import org.eclipse.emf.common.notify.Notifier;
26 import org.eclipse.emf.common.util.BasicMonitor;
27 import org.eclipse.emf.compare.Comparison;
28 import org.eclipse.emf.compare.Diff;
29 import org.eclipse.emf.compare.command.ICompareCommandStack;
30 import org.eclipse.emf.compare.command.ICompareCopyCommand;
31 import org.eclipse.emf.compare.command.impl.CompareCommandStack;
32 import org.eclipse.emf.compare.command.impl.DualCompareCommandStack;
33 import org.eclipse.emf.compare.command.impl.MergeAllNonConflictingCommand;
34 import org.eclipse.emf.compare.command.impl.MergeCommand;
35 import org.eclipse.emf.compare.command.impl.TransactionalDualCompareCommandStack;
36 import org.eclipse.emf.compare.domain.ICompareEditingDomain;
37 import org.eclipse.emf.compare.domain.IMergeRunnable;
38 import org.eclipse.emf.compare.internal.domain.IMergeAllNonConflictingRunnable;
39 import org.eclipse.emf.compare.merge.BatchMerger;
40 import org.eclipse.emf.compare.merge.IBatchMerger;
41 import org.eclipse.emf.compare.merge.IMerger;
42 import org.eclipse.emf.compare.merge.IMerger.Registry;
43 import org.eclipse.emf.compare.provider.EMFCompareEditPlugin;
44 import org.eclipse.emf.ecore.EObject;
45 import org.eclipse.emf.ecore.change.util.ChangeRecorder;
46 import org.eclipse.emf.ecore.resource.Resource;
47 import org.eclipse.emf.ecore.resource.ResourceSet;
48 import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
49 import org.eclipse.emf.edit.domain.EditingDomain;
50 import org.eclipse.emf.edit.provider.IDisposable;
51 import org.eclipse.emf.transaction.TransactionalEditingDomain;
52 import org.eclipse.emf.transaction.impl.AbstractTransactionalCommandStack;
53 import org.eclipse.emf.transaction.util.TransactionUtil;
55 /**
56 * Default implementation that use a change recorder in the background to record the changes made by executed
57 * commands.
59 * @author <a href="mailto:mikael.barbero@obeo.fr">Mikael Barbero</a>
61 public class EMFCompareEditingDomain implements ICompareEditingDomain, IDisposable {
63 /** The change recorder instance. */
64 private final ChangeRecorder fChangeRecorder;
66 /** The notifiers on which the change recorder will be installed. */
67 private final ImmutableCollection<Notifier> fNotifiers;
69 /** The command stack on which the merge commands will be executed. */
70 private final ICompareCommandStack fCommandStack;
72 /** List of domains we've created ourselves and should thus cleanup ourselves. */
73 private final List<TransactionalEditingDomain> disposableDomains;
75 /**
76 * Creates a new instance with the given notifiers to be listen to when something will be changed.
78 * @param left
79 * the left root notifier of the comparison (i.e. the
80 * {@link org.eclipse.emf.compare.scope.IComparisonScope#getLeft()}
81 * @param right
82 * the right root notifier of the comparison (i.e. the
83 * {@link org.eclipse.emf.compare.scope.IComparisonScope#getRight()}
84 * @param ancestor
85 * the ancestor root notifier of the comparison (i.e. the
86 * {@link org.eclipse.emf.compare.scope.IComparisonScope#getOrigin()}
87 * @param commandStack
88 * the command stack to be used to track execution of commands.
90 public EMFCompareEditingDomain(Notifier left, Notifier right, Notifier ancestor,
91 ICompareCommandStack commandStack) {
92 if (ancestor == null) {
93 fNotifiers = ImmutableList.of(left, right);
94 } else {
95 fNotifiers = ImmutableList.of(left, right, ancestor);
98 fCommandStack = commandStack;
100 fChangeRecorder = new ChangeRecorder();
101 fChangeRecorder.setResolveProxies(false);
102 disposableDomains = new ArrayList<TransactionalEditingDomain>();
106 * Returns the resource set containing the given notifier, the given {@code notifier} if it is a
107 * {@link ResourceSet}, <code>null</code> otherwise.
109 * @param notifier
110 * the notifier from which we have to look for a {@link ResourceSet}.
111 * @return the resource set containing the given notifier, the given {@code notifier} if it is a
112 * {@link ResourceSet}, <code>null</code> otherwise
114 private static ResourceSet getResourceSet(Notifier notifier) {
115 ResourceSet resourceSet = null;
116 if (notifier instanceof ResourceSet) {
117 resourceSet = (ResourceSet)notifier;
118 } else if (notifier instanceof Resource) {
119 resourceSet = ((Resource)notifier).getResourceSet();
120 } else if (notifier instanceof EObject) {
121 Resource eResource = ((EObject)notifier).eResource();
122 if (eResource != null) {
123 resourceSet = eResource.getResourceSet();
125 } else {
126 // impossible as of today
128 return resourceSet;
132 * Creates a new compare editing domain on the given notifier with an appropriate
133 * {@link ICompareCommandStack} set up on it.
135 * @param left
136 * the left notifier. Should not be <code>null</code>.
137 * @param right
138 * the right notifier. Should not be <code>null</code>.
139 * @param ancestor
140 * the ancestor notifier. May be <code>null</code>.
141 * @return a new compare editing domain on the given notifier.
143 public static ICompareEditingDomain create(Notifier left, Notifier right, Notifier ancestor) {
144 boolean hadLeftED = getExistingEditingDomain(left) != null;
145 boolean hadRightED = getExistingEditingDomain(right) != null;
147 EditingDomain leftED = getOrCreateEditingDomain(left);
148 EditingDomain rightED = getOrCreateEditingDomain(right);
150 final ICompareEditingDomain domain;
151 if (leftED != null && rightED != null) {
152 CommandStack leftCommandStack = leftED.getCommandStack();
153 CommandStack rightCommandStack = rightED.getCommandStack();
154 ICompareCommandStack commandStack;
155 if (leftCommandStack instanceof AbstractTransactionalCommandStack
156 && rightCommandStack instanceof AbstractTransactionalCommandStack) {
157 commandStack = new TransactionalDualCompareCommandStack(
158 (AbstractTransactionalCommandStack)leftCommandStack,
159 (AbstractTransactionalCommandStack)rightCommandStack);
160 } else if (leftCommandStack instanceof BasicCommandStack
161 && rightCommandStack instanceof BasicCommandStack) {
162 commandStack = new DualCompareCommandStack((BasicCommandStack)leftCommandStack,
163 (BasicCommandStack)rightCommandStack);
164 } else {
165 EMFCompareEditPlugin
166 .getPlugin()
167 .getLog()
168 .log(new Status(
169 IStatus.WARNING,
170 EMFCompareEditPlugin.PLUGIN_ID,
171 "Command stacks of the editing domain of " //$NON-NLS-1$
172 + left
173 + " and " //$NON-NLS-1$
174 + right
175 + " are not instances of BasicCommandStack, nor AbstractTransactionalCommandStack, therefore, they will not be used as backing command stacks for the current merge session.")); //$NON-NLS-1$
176 commandStack = new CompareCommandStack(new BasicCommandStack());
178 domain = new EMFCompareEditingDomain(left, right, ancestor, commandStack);
179 } else {
180 domain = create(left, right, ancestor, new BasicCommandStack());
183 if (!hadLeftED && leftED instanceof TransactionalEditingDomain) {
184 ((EMFCompareEditingDomain)domain).addDomainToDispose((TransactionalEditingDomain)leftED);
186 if (!hadRightED && rightED instanceof TransactionalEditingDomain) {
187 ((EMFCompareEditingDomain)domain).addDomainToDispose((TransactionalEditingDomain)rightED);
190 return domain;
194 * Return an existing editing domain associated with the given {@link Notifier}.
196 * @param notifier
197 * the notifier from which the editing domain has to be linked.
198 * @return an editing domain associated with the given {@link Notifier} if any.
200 private static EditingDomain getExistingEditingDomain(Notifier notifier) {
201 EditingDomain editingDomain = TransactionUtil.getEditingDomain(notifier);
202 if (editingDomain == null) {
203 editingDomain = AdapterFactoryEditingDomain.getEditingDomainFor(notifier);
205 return editingDomain;
209 * Returns an editing domain associated with the given {@link Notifier}. It will first look for a
210 * {@link TransactionalEditingDomain} then for an {@link AdapterFactoryEditingDomain}. It neither is found
211 * a new {@link TransactionalEditingDomain} is created.
213 * @param notifier
214 * the notifier from which the editing domain has to be linked.
215 * @return an editing domain associated with the given {@link Notifier}
217 private static EditingDomain getOrCreateEditingDomain(Notifier notifier) {
218 EditingDomain editingDomain = getExistingEditingDomain(notifier);
219 if (editingDomain == null) {
220 ResourceSet resourceSet = getResourceSet(notifier);
221 if (resourceSet != null) {
222 editingDomain = TransactionalEditingDomain.Factory.INSTANCE.createEditingDomain(resourceSet);
226 return editingDomain;
230 * Equivalent to {@code create(left, right, ancestor, commandStack, null)}.
232 * @param left
233 * the left notifier. Should not be <code>null</code>.
234 * @param right
235 * the right notifier. Should not be <code>null</code>.
236 * @param ancestor
237 * the ancestor notifier. May be <code>null</code>.
238 * @param commandStack
239 * a command stack to which merge command will be delegated to.
240 * @return a newly created compare editing domain.
242 public static ICompareEditingDomain create(Notifier left, Notifier right, Notifier ancestor,
243 CommandStack commandStack) {
244 return create(left, right, ancestor, commandStack, null);
248 * Creates a new compare editing domain on the given notifier with an appropriate
249 * {@link ICompareCommandStack} set up on it.
251 * @param left
252 * the left notifier. Should not be <code>null</code>.
253 * @param right
254 * the right notifier. Should not be <code>null</code>.
255 * @param ancestor
256 * the ancestor notifier. May be <code>null</code>.
257 * @param leftCommandStack
258 * a command stack to which merge to left command will be delegated to.
259 * @param rightCommandStack
260 * a command stack to which merge to irght command will be delegated to.
261 * @return a newly created compare editing domain.
263 public static ICompareEditingDomain create(Notifier left, Notifier right, Notifier ancestor,
264 CommandStack leftCommandStack, CommandStack rightCommandStack) {
266 final ICompareCommandStack commandStack;
268 if (leftCommandStack == null && rightCommandStack != null) {
269 if (rightCommandStack instanceof ICompareCommandStack) {
270 commandStack = (ICompareCommandStack)rightCommandStack;
271 } else {
272 commandStack = new CompareCommandStack(rightCommandStack);
274 } else if (leftCommandStack != null && rightCommandStack == null) {
275 if (leftCommandStack instanceof ICompareCommandStack) {
276 commandStack = (ICompareCommandStack)leftCommandStack;
277 } else {
278 commandStack = new CompareCommandStack(leftCommandStack);
280 } else if (leftCommandStack instanceof BasicCommandStack
281 && rightCommandStack instanceof BasicCommandStack) {
282 commandStack = new DualCompareCommandStack((BasicCommandStack)leftCommandStack,
283 (BasicCommandStack)rightCommandStack);
284 } else {
285 commandStack = new CompareCommandStack(new BasicCommandStack());
288 return new EMFCompareEditingDomain(left, right, ancestor, commandStack);
292 * {@inheritDoc}
294 * @see org.eclipse.emf.compare.domain.ICompareEditingDomain#dispose()
296 public void dispose() {
297 fChangeRecorder.dispose();
298 if (fCommandStack instanceof IDisposable) {
299 ((IDisposable)fCommandStack).dispose();
301 for (TransactionalEditingDomain domain : disposableDomains) {
302 domain.dispose();
307 * {@inheritDoc}
309 * @see org.eclipse.emf.compare.domain.ICompareEditingDomain#getCommandStack()
311 public ICompareCommandStack getCommandStack() {
312 return fCommandStack;
316 * {@inheritDoc}
318 * @see org.eclipse.emf.compare.domain.ICompareEditingDomain#createCopyCommand(org.eclipse.emf.compare.Diff,
319 * boolean, org.eclipse.emf.compare.merge.IMerger.Registry)
320 * @since 3.0
322 public Command createCopyCommand(List<? extends Diff> differences, boolean leftToRight,
323 IMerger.Registry mergerRegistry) {
324 ImmutableSet.Builder<Notifier> notifiersBuilder = ImmutableSet.builder();
325 for (Diff diff : differences) {
326 notifiersBuilder.add(diff.getMatch().getComparison());
328 ImmutableSet<Notifier> notifiers = notifiersBuilder.addAll(fNotifiers).build();
330 IMergeRunnable runnable = new IMergeRunnable() {
331 public void merge(List<? extends Diff> diffs, boolean lTR, Registry registry) {
332 final IBatchMerger merger = new BatchMerger(registry);
333 if (lTR) {
334 merger.copyAllLeftToRight(diffs, new BasicMonitor());
335 } else {
336 merger.copyAllRightToLeft(diffs, new BasicMonitor());
340 return new MergeCommand(fChangeRecorder, notifiers, differences, leftToRight, mergerRegistry,
341 runnable);
345 * {@inheritDoc}
347 * @see org.eclipse.emf.compare.domain.ICompareEditingDomain#createCopyCommand(java.util.List, boolean,
348 * org.eclipse.emf.compare.merge.IMerger.Registry,
349 * org.eclipse.emf.compare.command.ICompareCopyCommand.IMergeRunnable)
351 public ICompareCopyCommand createCopyCommand(List<? extends Diff> differences, boolean leftToRight,
352 Registry mergerRegistry, IMergeRunnable runnable) {
353 ImmutableSet.Builder<Notifier> notifiersBuilder = ImmutableSet.builder();
354 for (Diff diff : differences) {
355 notifiersBuilder.add(diff.getMatch().getComparison());
357 ImmutableSet<Notifier> notifiers = notifiersBuilder.addAll(fNotifiers).build();
359 return new MergeCommand(fChangeRecorder, notifiers, differences, leftToRight, mergerRegistry,
360 runnable);
364 * Creates a command that will merge all non-conflicting differences in the given direction.
365 * <p>
366 * A "non-conflicting" difference is any difference that is not in a real conflict with another <u>and</u>
367 * that does not, directly or indirectly, depend on the merge of a difference that is in conflict itself.
368 * </p>
369 * <p>
370 * Note that only the differences originating from the "source" side of the chosen merge direction will be
371 * considered.
372 * </p>
374 * @param comparison
375 * The comparison which differences to merge.
376 * @param leftToRight
377 * The direction in which we should merge the differences.
378 * @param mergerRegistry
379 * The registry to query for specific mergers for each difference.
380 * @param runnable
381 * the runnable to execute for the actual merge operation.
382 * @return The copy command, ready for use.
383 * @since 4.1
385 public ICompareCopyCommand createCopyAllNonConflictingCommand(Comparison comparison, boolean leftToRight,
386 IMerger.Registry mergerRegistry, IMergeAllNonConflictingRunnable runnable) {
387 ImmutableSet.Builder<Notifier> notifiersBuilder = ImmutableSet.builder();
388 notifiersBuilder.add(comparison);
389 ImmutableSet<Notifier> notifiers = notifiersBuilder.addAll(fNotifiers).build();
390 return new MergeAllNonConflictingCommand(fChangeRecorder, notifiers, comparison, leftToRight,
391 mergerRegistry, runnable);
395 * {@inheritDoc}
397 * @see org.eclipse.emf.compare.domain.ICompareEditingDomain#getChangeRecorder()
399 public ChangeRecorder getChangeRecorder() {
400 return fChangeRecorder;
404 * Sets up a {@link TransactionalEditingDomain} for disposal along with {@code this}.
406 * @param domain
407 * The domain that should be disposed when we are.
409 private void addDomainToDispose(TransactionalEditingDomain domain) {
410 disposableDomains.add(domain);