| <?xml version='1.0' encoding='utf-8' ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
| <html xmlns="http://www.w3.org/1999/xhtml"> |
| <head> |
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> |
| <title>Using The Compare APIs</title> |
| <link type="text/css" rel="stylesheet" href="/help/topic/org.eclipse.emf.compare.doc/doc/resources/bootstrap.css"/> |
| <link type="text/css" rel="stylesheet" href="/help/topic/org.eclipse.emf.compare.doc/doc/resources/custom.css"/> |
| </head> |
| <body> |
| <h1 id="Using_The_Compare_APIs">Using The Compare APIs</h1> |
| <p>The main entry point of EMF Compare is the |
| <i>org.eclipse.emf.compare.EMFCompare</i> class. It is what should be used in order to configure and launch a comparison. That is not all though. Once you have compared two models, you want to query the differences, maybe merge some of them, display the comparison result in the comparison editor... The following section will list the main entry points for each of these actions, along with a brief description of what can be done and what should be avoided. |
| </p> |
| <p>Most of these examples are set-up as "standalone" examples, and will include extra instructions for IDE use: pay attention to the environment in which you are using EMF Compare. Are you using it from an Eclipse plugin, in which case you'd like all of the extra features provided through extension points and contribution to be available to you? Or are you using it from a standalone environment, in which case you'd need to reduce the dependencies to the bare minimum and avoid OSGi-related code and extensions?</p> |
| <h2 id="Compare_two_models">Compare two models</h2> |
| <h3 id="Loading_your_models">Loading your models</h3> |
| <p>Whether you wish to compare two or three models, the first thing you need is to load them. We won't detail in-depth how to do that as this is standard EMF practice, you might want to look at EMF tutorial for detailled instructions on this point. Here, we'll use a simple method that loads an xmi file at a given URL into a resourceSet, expecting the given URL to be an absolute file URL:</p> |
| <pre class="source-java">public void load(String absolutePath, ResourceSet resourceSet) { |
| URI uri = URI.createFileURI(absolutePath); |
| |
| resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xmi", new XMIResourceFactoryImpl()); |
| |
| // Resource will be loaded within the resource set |
| resourceSet.getResource(uri, true); |
| } |
| |
| </pre> |
| <h3 id="Creating_the_comparison_scope">Creating the comparison scope</h3> |
| <p>EMF Compare uses a scoping mechanism to determine which elements should be compared, and which others should be ignored. Any element that is outside of the comparison scope will be ignored by the comparison engine and left alone (if it is a proxy, it won't even be loaded). As such, extra care should be taken to determine the proper scope of the comparison or customize the IEqualityHelper to handle the specific elements you remove from the scope. Refer to the |
| <a href="./Core%20Concepts.html#Comparison_Scope" title="./Core%20Concepts.html#Comparison Scope">appropriate section</a> above for more on the scoping mechanism. |
| </p> |
| <p>By default, the only thing that EMF Compare considers "out of scope" are Ecore's "EGenericType" elements. These are usually meaningless as far as comparison is concerned (as they are located in derived references and will be merged along with their "true" difference anyway). Other than that, Please note that EMF Compare will leave unresolved proxies alone: more on this can be found in the |
| <a href="./Core%20Concepts.html#Proxy_Resolution" title="./Core%20Concepts.html#Proxy Resolution">related section</a>. |
| </p> |
| <p>The default scope can be easily created through:</p> |
| <pre class="source-java">IComparisonScope scope = EMFCompare.createDefaultScope(resourceSet1, resourceSet2); |
| |
| </pre> |
| <h3 id="Configuring_the_comparison">Configuring the comparison</h3> |
| <p>EMF Compare can be customized in a number of ways, the most important of which were described |
| <a href="./Default%20Behavior%20and%20Extensibility.html" title="./Default%20Behavior%20and%20Extensibility.html">above</a>. Most of them re-use the same entry point, the |
| <i>org.eclipse.emf.compare.EMFCompare</i> class. We won't customize much here, please see the afore-mentionned section for extensibility means. |
| </p> |
| <p>All we will tell EMF Compare is not to use identifiers, and rely on its proximity algorithms instead (after all, we're comparing plain XMI files):</p> |
| <pre class="source-java">IEObjectMatcher matcher = DefaultMatchEngine.createDefaultEObjectMatcher(UseIdentifiers.NEVER); |
| IComparisonFactory comparisonFactory = new DefaultComparisonFactory(new DefaultEqualityHelperFactory()); |
| |
| IMatchEngine.Factory matchEngineFactory = new MatchEngineFactoryImpl(matcher, comparisonFactory); |
| matchEngineFactory.setRanking(20); |
| IMatchEngine.Factory.Registry matchEngineRegistry = new MatchEngineFactoryRegistryImpl(); |
| matchEngineRegistry.add(factory); |
| |
| EMFCompare comparator = EMFCompare.builder().setMatchEngineFactoryRegistry(matchEngineRegistry).build(); |
| |
| |
| </pre> |
| <h3 id="Putting_it_all_together">Putting it all together</h3> |
| <p>The following takes two input xmi files, loads them in their own resource sets, then calls the comparison without using identifiers:</p> |
| <pre class="source-java">public Comparison compare(File model1, File model2) { |
| // Load the two input models |
| ResourceSet resourceSet1 = new ResourceSetImpl(); |
| ResourceSet resourceSet2 = new ResourceSetImpl(); |
| String xmi1 = "path/to/first/model.xmi"; |
| String xmi2 = "path/to/second/model.xmi"; |
| load(xmi1, resourceSet1); |
| load(xmi2, resourceSet2); |
| |
| // Configure EMF Compare |
| IEObjectMatcher matcher = DefaultMatchEngine.createDefaultEObjectMatcher(UseIdentifiers.NEVER); |
| IComparisonFactory comparisonFactory = new DefaultComparisonFactory(new DefaultEqualityHelperFactory()); |
| IMatchEngine.Factory matchEngineFactory = new MatchEngineFactoryImpl(matcher, comparisonFactory); |
| matchEngineFactory.setRanking(20); |
| IMatchEngine.Factory.Registry matchEngineRegistry = new MatchEngineFactoryRegistryImpl(); |
| matchEngineRegistry.add(matchEngineFactory); |
| EMFCompare comparator = EMFCompare.builder().setMatchEngineFactoryRegistry(matchEngineRegistry).build(); |
| |
| // Compare the two models |
| IComparisonScope scope = EMFCompare.createDefaultScope(resourceSet1, resourceSet2); |
| return comparator.compare(scope); |
| } |
| |
| private void load(String absolutePath, ResourceSet resourceSet) { |
| URI uri = URI.createFileURI(absolutePath); |
| |
| resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xmi", new XMIResourceFactoryImpl()); |
| |
| // Resource will be loaded within the resource set |
| resourceSet.getResource(uri, true); |
| } |
| |
| </pre> |
| <h3 id="Comparing_from_an_Eclipse_plugin">Comparing from an Eclipse plugin</h3> |
| <p>The above example is for standalone usage, and as such will require extra work if you wish to compare UML models, benefit from EMF Compare extensions, provide your own mergers... The following represents the same example, but uses IDE-specific utilities (can you spot the two differences?):</p> |
| <pre class="source-java">public Comparison compare(File model1, File model2) { |
| // Load the two input models |
| ResourceSet resourceSet1 = new ResourceSetImpl(); |
| ResourceSet resourceSet2 = new ResourceSetImpl(); |
| String xmi1 = "path/to/first/model.xmi"; |
| String xmi2 = "path/to/second/model.xmi"; |
| load(xmi1, resourceSet1); |
| load(xmi2, resourceSet2); |
| |
| // Configure EMF Compare |
| IEObjectMatcher matcher = DefaultMatchEngine.createDefaultEObjectMatcher(UseIdentifiers.NEVER); |
| IComparisonFactory comparisonFactory = new DefaultComparisonFactory(new DefaultEqualityHelperFactory()); |
| IMatchEngine matchEngine = new DefaultMatchEngine(matcher, comparisonFactory); |
| IMatchEngine.Factory.Registry matchEngineRegistry = EMFCompareRCPPlugin.getDefault().getMatchEngineFactoryRegistry(); |
| IPostProcessor.Descriptor.Registry<String> postProcessorRegistry = EMFCompareRCPPlugin.getDefault().getPostProcessorRegistry(); |
| EMFCompare comparator = EMFCompare.builder() |
| .setMatchEngineFactoryRegistry(matchEngineRegistry) |
| .setPostProcessorRegistry(postProcessorRegistry) |
| .build(); |
| |
| // Compare the two models |
| IComparisonScope scope = EMFCompare.createDefaultScope(resourceSet1, resourceSet2); |
| return comparator.compare(scope); |
| } |
| |
| private void load(String absolutePath, ResourceSet resourceSet) { |
| URI uri = URI.createFileURI(absolutePath); |
| |
| // Resource will be loaded within the resource set |
| resourceSet.getResource(uri, true); |
| } |
| |
| </pre> |
| <h2 id="Query_the_differences">Query the differences</h2> |
| <p>Once you have the result of a comparison (in the form of a |
| <i>Comparison</i> object), what you are interested in are most likely the differences between your models. We will detail the merging process later on it its own section, but before anything we need to retrieve the list of differences of interest. Within the Comparison model, differences are spread under the elements on which they've been detected, more precisely, under the |
| <i>Match</i> of the element on which they were detected. |
| </p> |
| <p>Let's use a complex example as reference. Consider the three following models:</p> |
| <table border="1" cellpadding="5" cellspacing="0"> |
| <tr> |
| <th align="center" colspan="2">Origin</th> |
| </tr> |
| <tr> |
| <td align="center" colspan="2"> |
| <img align="middle" border="0" src="./../images/EMF_Compare_Origin_Model.png"/> |
| </td> |
| </tr> |
| <tr> |
| <th align="center">Left</th> |
| <th align="center">Right</th> |
| </tr> |
| <tr> |
| <td> |
| <img align="middle" border="0" src="./../images/EMF_Compare_Use_Compare_Master.png"/> |
| </td> |
| <td> |
| <img align="middle" border="0" src="./../images/EMF_Compare_Use_Compare_5.png"/> |
| </td> |
| </tr> |
| </table> |
| <h3 id="All_differences">All differences</h3> |
| <p>What we need is usually to retrieve the list of |
| <i>all</i> differences, wherever they were detected, or whatever their source (the left model, or the right model). Instead of iterating all over the Comparison model to collect them, you can use: |
| </p> |
| <pre class="source-java">List<Diff> differences = comparison.getDifferences(); |
| |
| </pre> |
| <h3 id="Differences_related_to_element_X">Differences related to element X</h3> |
| <p>Sometimes, we need to retrieve all of the differences that were detected on (or that are related to) a given model element. For example, with the above example, we might want to retrieve the list of all differences that relate to |
| <i>Borrowable</i>. Well, there are a number of them, which can all be collected through: |
| </p> |
| <pre class="source-java">// borrowable is a reference on the like-named EObject |
| List<Diff> differencesOnBorrowable = comparison.getDifferences(borrowable); |
| |
| </pre> |
| <p>This will return a list containing a number of differences:</p> |
| <ul> |
| <li> |
| <i>Borrowable</i> has been added in the right model |
| </li> |
| <li> |
| <i>copies</i> has been added to reference |
| <i>ownedProperties</i> of Borrowable |
| </li> |
| <li> |
| <i>Borrowable</i> has been added to the generalization reference of |
| <i>Book</i> |
| </li> |
| <li> |
| <i>Borrowable</i> has been added as the |
| <i>borrowed</i> target of an association with |
| <i>Person</i> |
| </li> |
| </ul> |
| <p>In other words, this method will return differences |
| <b>under</b> the target (here, |
| <i>copies</i> has been added), as well as differences which |
| <b>changed value</b> is the target. |
| </p> |
| <h3 id="Filtering_differences">Filtering differences</h3> |
| <p>EMF Compare depends on guava for many of its internals. A number of "common" difference filtering predicates have been extracted to the |
| <i>org.eclipse.emf.compare.utils.EMFComparePredicates</i> utility class. Using this class, it is trivial to filter the list of differences so as to keep only those we are interested in. For example, what if we wish to retrieve the list of all |
| <b>non-conflictual</b> differences that originate from the |
| <b>left</b> side? (This is the case when you use the "copy all non-conflicting from left to right" action from the comparison editor for example.) |
| </p> |
| <pre class="source-java">// Construct the predicate |
| Predicate<? super Diff> predicate = and(fromSide(DifferenceSource.LEFT), not(hasConflict(ConflictKind.REAL, ConflictKind.PSEUDO)); |
| // Filter out the diff that do not satisfy the predicate |
| Iterable<Diff> nonConflictualDifferencesFromLeft = filter(comparison.getDifferences(), predicate); |
| |
| </pre> |
| <p>Note that for clarity, we've made static references to a number of methods here. This particular snippet requires the following imports:</p> |
| <pre class="source-java">import static com.google.common.base.Predicates.and; |
| import static com.google.common.base.Predicates.not; |
| import static com.google.common.collect.Iterables.filter; |
| import static org.eclipse.emf.compare.utils.EMFComparePredicates.fromSide; |
| import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasConflict; |
| |
| </pre> |
| <p>We strongly encourage you to look around more in these classes: |
| <i>Predicates</i> provides a number of basic, general-purpose predicates while |
| <i>EMFComparePredicates</i> provides EMF Compare specific predicates used throughout both core and user-interface of EMF Compare. |
| </p> |
| <h2 id="Merge_differences">Merge differences</h2> |
| <p>PENDING how to re-implement |
| <i>copyDiff</i> and |
| <i>copyAllNonConflicting</i> |
| </p> |
| <p>entry points: org.eclipse.emf.compare.merge.IMerger and org.eclipse.emf.compare.merge.IBatchMerger</p> |
| <h2 id="Open_a_compare_editor">Open a compare editor</h2> |
| <p>PENDING description of the need (dialog and editor), link to |
| <a href="./How%20To%20Open%20Compare%20Dialog%20With%20Comparison" title="./How%20To%20Open%20Compare%20Dialog%20With%20Comparison">appropriate page</a> |
| </p> |
| </body> |
| </html> |