Home » Modeling » Compare » [EMF COMPARE] Apply diffs between two objects in a third one(EMF COMPARE)
[EMF COMPARE] Apply diffs between two objects in a third one [message #1775240] |
Thu, 26 October 2017 15:53 |
Loic Wasquel Messages: 4 Registered: October 2017 |
Junior Member |
|
|
Hello everyone,
My issue is a little similar to the topic: "[EMF Compare] 3 way match" of this forum.
I have 3 files:
File1: the base file (a resource containing an EMF object)
File2: File1 + some changes
File3: a quite different file / or File1 + some other changes
I want to create an EMF comparison from File1 to File2, and select some of the "top diffs" (or all) from this comparison and try to apply them to the File3 , if they can be applied to File3 (if they cannot, I just want to ignore them).
First approach: I first thought I could change the references to objects in File1 in the comparison to new references to objects in File3. I expect that the EMF Compare process can still apply with a EMF BatchMerger. Let's assume that I replace the objects in File 1 with objects from the same Class File3.
Second approach: get back to a 3 way comparison, with origin=File1, left = File2, right= File3.
Problems:
- the matching strategy from File1 to File2 would not be the same strategy as the one between File1 to File3 (from File1 to File2 I can rely on a strategy upon ids, although from File1 to File3 I have to determine my own matching strategy).
-I would have to apply only the selected diffs from File1 to File2 when applying the merge from origin (File1) to left (File2)
-It is cumbersome to go back to a 3 way comparison, especially because, according to me, there is no real conflict: we try to apply all the changes from File1 to File2, if we cannot apply them, just log that the change that could not be performed.
I doubt that my approachs are right.
Do you have some advice?
Which process should I perform?
Thank you for your help!
Greetings,
Loïc
|
|
|
Re: [EMF COMPARE] Apply diffs between two objects in a third one [message #1775442 is a reply to message #1775240] |
Mon, 30 October 2017 09:10 |
|
Hi Loïc,
If I didn't misunderstand your question, your main question is whether you can apply the diffs between file1 and file2 to an unrelated file, in your example file3. Unfortunately, this is not supported by EMF Compare. A diff is always directly linked to the model element from which the diff was computed. This is manifested through the references to the original and the changed model in the match and the diff objects of the comparison model. Otherwise, how should EMF Compare know which model elements in file3 correspond to the ones in file1 and file2?
A few years ago, there was a project called "EMF Patch" which allowed to detach a diff from specific model elements and replace those references with generic queries of this model element (e.g., instead of a direct reference to model element "A", it used a query of any model element with a name "A") so that it could be applied to other versions. However, I think this project is discontinued (I'm not sure if it is still available -- I wasn't involved in that).
Of course, you could write your own code that "rewires" a comparison model from one file (e.g. file2) to another (e.g. file3 in your example) and then apply the diffs using the merges of EMF Compare. That should work, but you have to make sure all the references from the comparison model to file2 are correctly rewritten to the corresponding ones in file3.
I don't know your scenario in detail, but I think you'd be better of trying to run a three-way merge instead (your second approach), with a custom matcher that tries to match by ID and then tries to re-match those model elements that it couldn't match based on other criteria so that file3 can also be matched with file2 and file1.
Hope that helps!
Best wishes,
Philip
--
Philip Langer
Get professional Eclipse developer support:
http://eclipsesource.com/en/services/developer-support/
|
|
|
Re: [EMF COMPARE] Apply diffs between two objects in a third one [message #1775454 is a reply to message #1775442] |
Mon, 30 October 2017 10:53 |
Loic Wasquel Messages: 4 Registered: October 2017 |
Junior Member |
|
|
Hello Philip and many thanks!
You well summed up my issue.
Quote:Of course, you could write your own code that "rewires" a comparison model from one file (e.g. file2) to another (e.g. file3 in your example) and then apply the diffs using the merges of EMF Compare. That should work, but you have to make sure all the references from the comparison model to file2 are correctly rewritten to the corresponding ones in file3.
This corresponds to my first approach, I will try this one first.
Quote:I don't know your scenario in detail, but I think you'd be better of trying to run a three-way merge instead (your second approach), with a custom matcher that tries to match by ID and then tries to re-match those model elements that it couldn't match based on other criteria so that file3 can also be matched with file2 and file1.
And I assume that after having compared the 3 files with the three -way merge with origin=File1, left = File2, right= File3, you would accept all left and right diffs to create File3 + changes from File2. I like your idea about this custom matcher. I am glad you validate this approach too, unfortunately in my case it is complicated to perform: we would like to perform first comparison between File1 and File2, and later apply it on file 3, and other issues due to my context. But eventually, it could be the solution we would choose.
The third approach I thought about, and that I have not yet mentionned, would be to browse the EMF comparison and treat the Diffs myself in my own code, It would work, but it would be redoing the EMF merge process, and it needs us to be cautious, and it seems to be painful: a lot of cases, be careful about the diffs dependencies order...
Thanks a lot for your help Philip!
Greetings,
Loïc
|
|
|
Solved: [EMF COMPARE] Apply diffs between two objects in a third one [message #1776190 is a reply to message #1775240] |
Mon, 13 November 2017 15:05 |
Loic Wasquel Messages: 4 Registered: October 2017 |
Junior Member |
|
|
Hello everyone,
I used the first approach, and managed to get the third object with the diffs between the others.
Here is the process:
Collect all references creations (ReferenceChange which is an ADD as DifferenceKind, and whose ReferenceChange.getReference() is a containment) and put it in a list "createdObjects".
Browse comparison.getMatches() from the comparison from File1 to File2: (so LEFT=File2 and RIGHT=File1) : Do not change left match, but for right match, find a matching object.
If no matching object has been found, discard the match, its AllSubMatchs and its AllDifferences (actually stock them into a Set containing all the objects which will be deleted later: "outDatedDiffs" and "outDatedMatchs".
If a matching object has been found, replace the right from the match with this matching object, and then browse the match Differences, and then browse the match SubMatches (same as we just did for the comparison matches).
Browse the Differences means: we need to change the ReferenceDiffs, Attribute Diffs will be merged naturally. For all ReferenceDiffs we browse, get the ReferenceChange.getValue() called "value".
If value==null or if the current diff is a creation (ADD + isContainment), do nothing.
Else get the matching object for value.
If the matchingObject!= null and if matchingObject==value, it references a created object, belonging to "createdObjects" list, do nothing.
Else If matchingObject!= null, ReferenceChange.setValue(matchingObject).
Else If the diff is a change required by a deletion on the right value (and we didn't find matching object as we are in the else block), we cannot discard this diff because the previous state will be corrupted by the deletion, so transform this diff as a deletion, so that the reference will be unset, prevents having an unresolved proxy).
Else we didn't find a matching object, so we discard the diff, actually add it to "outDatedDiffs" set.
After that, we call EcoreUtil.delete on all elements in "outDatedDiffs" and "outDatedMatchs".
Finally, we create a BatchMerger from EMFCompare, and we copyAllLeftToRight the Diffs we want to.
End of the process.
What does find a matching object means:
if the source object is contained in "createdObjects" list, returns the source object itself.
else returns the matching object in the File3 resource, or null if there is no matching object.
How to determine if a Diff is a Change required by a deletion on its old value:
if diff is not a DifferenceKing.CHANGE return false;
else if diff.getReference.isMany() returns false
else :
if(diff.getMatch().getRight()==null) return false;
oldValue=diff.getMatch().getRight().eGet(diff.getReference())
if oldValue != null : we return true if any of the required Diff is
DifferenceKind.DELETE
and is a ReferenceChange instance
and ( [oldValue is equal to requiredDiff.getValue()] or [matchingObject of value is equal to requiredDiff.getValue()])
finally return false either in all other cases.
Cheers,
Loïc
[Updated on: Mon, 13 November 2017 15:07] Report message to a moderator
|
|
|
Re: Solved: [EMF COMPARE] Apply diffs between two objects in a third one [message #1776460 is a reply to message #1776190] |
Thu, 16 November 2017 15:09 |
Loic Wasquel Messages: 4 Registered: October 2017 |
Junior Member |
|
|
Hello,
Note that this can produce doubloons.
If you don't want to get doubloons, instead of adding the creation value directly in a list "createdObjects", check if there is already an existing matching object in File3 for the creation value.
If there indeed is a matching object for creation.getValue(), do not add the value in "createdObjects" list and discard this creation (what I call a creation is a ReferenceChange with DifferenceKind.ADD as DifferenceKind, and whose ReferenceChange.getReference() is a containment).
If there is no matching object, add the value creation.getValue() in "createdObjects" list.
Cheers,
Loïc
[Updated on: Thu, 16 November 2017 15:11] Report message to a moderator
|
|
|
Goto Forum:
Current Time: Mon Dec 09 04:23:58 GMT 2024
Powered by FUDForum. Page generated in 0.25207 seconds
|