Jump to: navigation, search

EMF Compare/Specifications/MergeExtension

Evolution Specification: Provide a merge extension mechanism

Current status is DRAFT

Preamble

It enables to provide his own merger implementation for a set of differences concerned by a given predicate.

  • Bug 398863 - Provide a merge extension mechanism


Introduction

The merge operation is implemented on a per difference type. It has three implementations in the core engine (ReferenceChange, AttributeChange and ResourceAttachmentChange). Each extension (UML, GMF Notation) has to provide its own type of difference to override the merge semantic. This is not very flexible and the required number of difference types it requires to implement does not add any value.


Detailed Specification

We propose to provide a merge extension mechanism.

Any extension will be able to contribute a merger on a subclass of Diff. The mergers registry will be queried each time a merge about to be performed. A merger contribution will provide its own predicate that will need to be verified before it is considered to be a valid candidate for a difference. It will also have a ranking in order to choose over multiple possible merger for a given difference.

Standard merge operations will be rewritten with the lowest ranking in order to be overrideable.

MergeExtensionClassDiagram.png

MergeExtensionSeq.png

Backward Compatibility and Migration Paths

Metamodel Changes

Diff.copyLeftToRight() and Diff.copyRightToLeft() are now deprecated.

Merging a single diff sometimes requires EMF Compare to merge other differences. Requirements and equivalences come to mind, but there are also refining and extension that will trigger the merge of multiple differences at once. We need to be able to ask the merger registry for the correct merger for every single diff, which cannot be done from the differences themselves.

These two methods have been deprecated, though we expect no breakage as they delegate to a "standalone" implementation of the merger registry. However, all uses of these APIs should be migrated to the new one, namely :

diff.copyRightToLeft();

becomes

  • In standalone mode :
IMerger.Registry registry = IMerger.RegistryImpl.createStandaloneInstance();
registry.getHighestRankingMerger(diff).copyRightToLeft(diff, new BasicMonitor());
  • From a plug-in :
IMerger.Registry registry = EMFCompareIdePugin.getDefault().getMergerRegistry();
registry.getHighestRankingMerger(diff).copyRightToLeft(diff, new BasicMonitor());

Likewise, merging differences in a batch operation previously required a for loop such as

for (Diff diff : comparison.getDifferences()) {
  diff.copyRightToLeft();
}

This should now be changed to (the same as above applies for standalone/plug-in use) :

IMerger.Registry registry = IMerger.RegistryImpl.createStandaloneInstance();
IBatchMerger merger = new BatchMerger(registry);
merger.copyAllRightToLeft(comparison.getDifferences(), new BasicMonitor());

API Changes

  • Add interfaces:

This change will mainly add two public interfaces : IMerger represents the merge for individual differences and will hold the merging code currently implemented within the Diffs themselved, while IBatchMerger represents a batch operation and will allow the customization of how multiple differences are merged concurrently.

public interface IMerger {
 
	boolean isMergerFor(Diff target);
 
	int getRanking();
 
	void setRanking(int parseInt);
 
	void copyRightToLeft(Diff target, Monitor monitor);
 
	void copyLeftToRight(Diff target, Monitor monitor);
 
	void setRegistry(Registry registry);
 
	Registry getRegistry();
 
	interface Registry {
 
		IMerger getHighestRankingMerger(Diff target);
 
		Collection<IMerger> getMergers(Diff target);
 
		IMerger add(IMerger merger);
 
		IMerger remove(String className);
 
		void clear();
	}
 
}
public interface IBatchMerger {
	void copyAllLeftToRight(Iterable<? extends Diff> differences, Monitor monitor);
 
	void copyAllRightToLeft(Iterable<? extends Diff> differences, Monitor monitor);
}
  • Add extension point:
<extension-point id="mergerExtension" name="Merger Extension" schema="schema/MergerExtension.exsd"/>

Example of use:

<extension point="org.eclipse.emf.compare.ide.mergerExtension">
  <merger
      class="org.eclipse.emf.compare.merge.ResourceAttachmentChangeMerger"
      ranking="10">
  </merger>
  <merger
      class="org.eclipse.emf.compare.merge.ReferenceChangeMerger"
      ranking="10">
  </merger>
  <merger
      class="org.eclipse.emf.compare.merge.AttributeChangeMerger"
      ranking="10">
  </merger>
</extension>
  • Change of createCopyCommand() and createCopyAllNonConflictingCommand() methods in ICompareEditingDomain:
Command createCopyCommand(Diff diff, boolean leftToRight, IMerger.Registry mergerRegistry);	
Command createCopyAllNonConflictingCommand(List<? extends Diff> differences, boolean leftToRight, IMerger.Registry mergerRegistry);

User Interface Changes

This evolution does not change any user interface.

Documentation Changes

This documentation will have to be updated:

  • New and Noteworthy
  • Developer Guide


Tests and Non-regression strategy

JUnit tests: ExtensionMergeTest.java in o.e.e.c.tests, o.e.e.c.diagram.ecoretools.tests, o.e.e.c.uml2.tests.

Manual tests: Detection of the extension launching a merge action.


Implementation choices and tradeoffs

N/A