[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Newsgroup Home]
[news.eclipse.technology.emft] Re: [EMF Compare] 3 way match

Hi Laurent,

Unfortunately I can't give you the code, because it has plugin dependencies to over 50 other plugins. I think we will refactor it somehow to get it independent and I will give it to you as soon as possible. Thanks for your support.

Daniel


laurent Goubet wrote:

Hi Daniel,

For the discussion you linked to ... No bug has ever been raised and I simply forgot about it. This is most likely not the same bug though.

I cannot make heads or tails about any of the two stack traces :( Could you provide us with your sample code and models so that I can try and reproduce in order to see what's hapenning there (preferably through a bug report on bugzilla)?

Laurent Goubet
Obeo

Daniel a écrit :
Hi Laurent,
With your help I successfully could solve my previous problems and got the program running for some Models.
However I still get Nullpointer Exceptions for some Models I try to compare.
Depending on the model at the diffing or at the merging:



java.lang.NullPointerException
at


org.eclipse.emf.compare.diff.engine.GenericDiffEngine.checkMoves(GenericDiffEngine.java:413)

at


org.eclipse.emf.compare.diff.engine.GenericDiffEngine.checkForDiffs(GenericDiffEngine.java:357)

at


org.eclipse.emf.compare.diff.engine.GenericDiffEngine.doDiffDelegate(GenericDiffEngine.java:970)

at


org.eclipse.emf.compare.diff.engine.GenericDiffEngine.doDiffDelegate(GenericDiffEngine.java:994)

at


org.eclipse.emf.compare.diff.engine.GenericDiffEngine.doDiffThreeWay(GenericDiffEngine.java:526)

at


org.eclipse.emf.compare.diff.engine.GenericDiffEngine.doDiff(GenericDiffEngine.java:111)

at


org.eclipse.emf.compare.diff.service.DiffService.doDiff(DiffService.java:101)

java.lang.NullPointerException
at


org.eclipse.emf.compare.diff.internal.merge.impl.ModelElementChangeLeftTargetMerger.undoInTarget(ModelElementChangeLeftTargetMerger.java:84)

at


org.eclipse.emf.compare.diff.merge.service.MergeService.doMerge(MergeService.java:172)

at


org.eclipse.emf.compare.diff.merge.service.MergeService.merge(MergeService.java:136)

at


org.eclipse.emf.compare.diff.internal.merge.impl.DiffGroupMerger.undoInTarget(DiffGroupMerger.java:48)

at


org.eclipse.emf.compare.diff.merge.service.MergeService.doMerge(MergeService.java:172)

at


org.eclipse.emf.compare.diff.merge.service.MergeService.merge(MergeService.java:136)

at


org.eclipse.emf.compare.diff.internal.merge.impl.DiffGroupMerger.undoInTarget(DiffGroupMerger.java:48)

at


org.eclipse.emf.compare.diff.merge.service.MergeService.doMerge(MergeService.java:172)

at


org.eclipse.emf.compare.diff.merge.service.MergeService.merge(MergeService.java:136)

at


org.eclipse.emf.compare.diff.internal.merge.impl.DiffGroupMerger.undoInTarget(DiffGroupMerger.java:48)

at


org.eclipse.emf.compare.diff.merge.service.MergeService.doMerge(MergeService.java:172)

at


org.eclipse.emf.compare.diff.merge.service.MergeService.merge(MergeService.java:136)

at


org.eclipse.emf.compare.diff.internal.merge.impl.DiffGroupMerger.undoInTarget(DiffGroupMerger.java:48)

at


org.eclipse.emf.compare.diff.merge.service.MergeService.doMerge(MergeService.java:172)

at


org.eclipse.emf.compare.diff.merge.service.MergeService.merge(MergeService.java:136)

at


org.eclipse.emf.compare.diff.internal.merge.impl.DiffGroupMerger.undoInTarget(DiffGroupMerger.java:48)

at


org.eclipse.emf.compare.diff.merge.service.MergeService.doMerge(MergeService.java:172)

at


org.eclipse.emf.compare.diff.merge.service.MergeService.merge(MergeService.java:136)

at


org.eclipse.emf.compare.diff.internal.merge.impl.DiffGroupMerger.undoInTarget(DiffGroupMerger.java:48)

at


org.eclipse.emf.compare.diff.merge.service.MergeService.doMerge(MergeService.java:172)

at


org.eclipse.emf.compare.diff.merge.service.MergeService.merge(MergeService.java:136)


Do you have any suggestions?

Thank you very much

Daniel

Ps: Could the second npe be the same problem as in: http://dev.eclipse.org/newslists/news.eclipse.technology.emft/msg06623.html ?
I'm using 1.0.0



laurent Goubet wrote:

Hi Daniel,

isConflicting() will always return false except for actually conflicting changes. If your "origin" file has an element named "Element1", your first file has this same element renamed in "Element2" and the third file has the very same element renamed as "Element3"; EMF Compare will detect a change : both models have been changed since the origin, and they have changed to different values. This is the only way changes will be seen as "conflicting".

Other than that, EMF Compare may not detect conflicts if it doesn't manage to match your elements together before checking for differences. Have you got XMI IDs in your files? eIdAttributes? If yes, and your IDs are not the same between each versions; take a look at MatchOption.OPTION_IGNORE_XMI_ID and MatchOption.OPTION_IGNORE_ID.

As for your merging issues, this comes from me not copying the list before merging. Taken from the javadoc of MergeService.doMerge :

----------8<----------
@throws ConcurrentModificationException
* Could be thrown if the list you give is directly a reference from the meta model such as
* {@link DiffModel#getOwnedElements()} or {@link DiffElement#getSubDiffElements()}. Copy the
* list before merging it.
---------->8----------

Please raise a bug with the stack trace, you're not the first I copy the doc to; I'll copy the list from the MergeService manually before merging so that this cannot be triggered anymore :).

Laurent Goubet
Obeo

Daniel a écrit :
Hi Laurent,

I've decided to do the normal 3-way comparison and validate the resulting model (don't know how, yet) afterwards.

However I got some problems. The isConflicting() method always returns false.
I've changed the same property to different values in File2&3, or changed it to a value in one File and deleted it in the other File. Always false.


My other problem is, that I can't get the merge to work.

if I use :    MergeService.merge( differences, true ); i get:

java.util.ConcurrentModificationException
at

org.eclipse.emf.common.util.BasicEList$EIterator.checkModCount(BasicEList.java:1378)


at

org.eclipse.emf.common.util.BasicEList$EIterator.doNext(BasicEList.java:1332)


at


org.eclipse.emf.common.util.BasicEList$EIterator.next(BasicEList.java:1312)

at

org.eclipse.emf.compare.diff.merge.service.MergeService.merge(MergeService.java:132)




and if i change it to: MergeService.merge( differences, false ); i get:

java.lang.NullPointerException
at


org.eclipse.emf.compare.util.EFactory.eStructuralFeature(EFactory.java:216)

at org.eclipse.emf.compare.util.EFactory.eAdd(EFactory.java:58) at

org.eclipse.emf.compare.diff.internal.merge.impl.MoveModelElementMerger.applyInOrigin(MoveModelElementMerger.java:44)


at

org.eclipse.emf.compare.diff.merge.service.MergeService.doMerge(MergeService.java:174)


at

org.eclipse.emf.compare.diff.merge.service.MergeService.merge(MergeService.java:136)


at

org.eclipse.emf.compare.diff.internal.merge.impl.DiffGroupMerger.applyInOrigin(DiffGroupMerger.java:35)


at

org.eclipse.emf.compare.diff.merge.service.MergeService.doMerge(MergeService.java:174)


at

org.eclipse.emf.compare.diff.merge.service.MergeService.merge(MergeService.java:136)


at

org.eclipse.emf.compare.diff.internal.merge.impl.DiffGroupMerger.applyInOrigin(DiffGroupMerger.java:35)


at

org.eclipse.emf.compare.diff.merge.service.MergeService.doMerge(MergeService.java:174)


at

org.eclipse.emf.compare.diff.merge.service.MergeService.merge(MergeService.java:136)


at

org.eclipse.emf.compare.diff.internal.merge.impl.DiffGroupMerger.applyInOrigin(DiffGroupMerger.java:35)


at

org.eclipse.emf.compare.diff.merge.service.MergeService.doMerge(MergeService.java:174)


at

org.eclipse.emf.compare.diff.merge.service.MergeService.merge(MergeService.java:136)


at

org.eclipse.emf.compare.diff.internal.merge.impl.DiffGroupMerger.applyInOrigin(DiffGroupMerger.java:35)


at

org.eclipse.emf.compare.diff.merge.service.MergeService.doMerge(MergeService.java:174)


at

org.eclipse.emf.compare.diff.merge.service.MergeService.merge(MergeService.java:136)


at

org.eclipse.emf.compare.diff.internal.merge.impl.DiffGroupMerger.applyInOrigin(DiffGroupMerger.java:35)


at

org.eclipse.emf.compare.diff.merge.service.MergeService.doMerge(MergeService.java:174)


at

org.eclipse.emf.compare.diff.merge.service.MergeService.merge(MergeService.java:136)


at

org.eclipse.emf.compare.diff.internal.merge.impl.DiffGroupMerger.applyInOrigin(DiffGroupMerger.java:35)


at

org.eclipse.emf.compare.diff.merge.service.MergeService.doMerge(MergeService.java:174)


at

org.eclipse.emf.compare.diff.merge.service.MergeService.merge(MergeService.java:136)




Do you have any advice or suggestions?

Thanks a lot.

Daniel


laurent Goubet wrote:

Hi Daniel,

3-way matching doesn't seem to be what you seek. As you mentionned, you want to compare File1 with File2, File1 with File3 _and_ File2 with File3... and execute some logic with the results of these comparisons, ignoring part of the changes, resolving conflicts, and merging part of the others. Well the logic here clearly is more important than a standard 3-way diff.

You might be able to create a mix of changes with 2-way diffing 1 and 2, then 1 and 3 and a 3-way differencing to detect conflicts ... but I think you should clearly determine the needed logic beforehand :p.

Laurent Goubet
Obeo

Daniel a écrit :
Hi Laurent,

Thanks for your fast answer. I upgraded to 1.0 and finally saw the methods and classes you were talking about. ;-)

The thing with the many movings also dissapeared, seems like a fixed bug. So I also don't have to do the instance of "ReferenceOrderChange" check.

Still my problem is, that I need to know the origin File of a change, even if it is not conflicting. This is because the resulting file has to be conform to the new base, only enhanced with the customizings but there is logic, which has to be checked before i can add it (even if nonconflicting)otherwise the model could be unusable.

If I check on isRemote() in the 3wayDiff I get a false for every (nonconflicting) DiffElement in the Diff.
So I assume that a 3 way Diff has only the informations of the ancestor on one side and a nonconflicting mixture of the changes from the 2 customized childfiles on the other side, however without reference from which file the changes came from.


If it is not possible to get the origin file of a change I have to use another approach and do two 2way diffs, than somehow compare the diffs and delete the ones I don't like. Is there some unique id with which i can compare the DiffElements of two Diffs? (Maybe i'll do a Diff of File 2 and 3 and then subtract the Diff of File 1 and 3 from it.)

Cheers

Daniel


laurent Goubet wrote:

Hi Daniel,

Comments inlined below.

Daniel a écrit :
Hi,
Thank you for your work and effort.

My situation is the following: I have 3 Model instances,
File 1: a base, File 2: a base file with some customisations
File 3: and another customized (further developed) base file, say new base.



I want to get the customisations of File 2 into file 3. Therefore i have to solve some conflicts between those files.


Firstly I want to make sure that this is the right approach for the 3way match.
I use the ressourceMatch() Method with the 3 Files, than created a Diff out of it.



conflict detection/resolution can only be made when comparing two files along with their common ancestor. Thus you can indeed use three-way differencing and hope to have interesting results if both your "file3" and "file2" are derived from the same base "file1".

MatchService.doResourceMatch() followed by DiffService.doDiff(match) is indeed the way to get the differences.


1 Question: How do I ignore changes which only affect the order of the elements? (...has been moved from ... to)

We've never implemented a way to ignore differences when comparing, but you can do it programmatically when merging by not merging all DiffElements instance of "ReferenceOrderChange".


2 Question: I get an Diff out of the 3way Matchmodel, but how do i get the origin file of a DiffElement? So how do I know if the change was between file 1 and 2 or 1 and 3?

MatchService.doResourceMatch takes 3 resources as parameter : left, right and ancestor (in this order). Talking in terms of version control system, "left" is your "local" resource (File3), "right" is the remote file (on repository) (File2) and "ancestor" is, well, the common ancestor of both files (File1).

With 3-way changes, we'll see "remote" changes and "normal" changes. Namely, if you have a Class "Class1" in File1, File2 has renamed this class "Class2" and File3 sports a change in which the class is renamed "Class3", we'll detect a conflicting change. In the DiffModel, this means we'll have a "ConflictingDiffElement" containing an "AttributeChange" for the change to "Class3" and a remote "AttributeChange" (which method "isRemote() returns true) for the change to "Class2".

In opposition, if your File2 had changed the name of your class to "Class" and File3 has done the same, no difference would have even been detected even though File1 had this class named "Class1".

You can know whether the change had been made in File2 if it is marked as a "remote" change.


3 Question: I've found a graphic with a "diff extensions" api marked. But where and how do I use this api, and can I use it to manually solve the conflicts with it?

The diff extension API can be used to change the DiffModel itself by regrouping differencesin order to "hide" them between a higher difference. This doesn't seem to be what you seek.

If you want to merge differences, use the MergeService API (similar to MatchService and DiffService, this allows you to merge differences easily given the DiffModel). Conflict resolution is only a matter of merging the conflicting difference from left to right or right to left (in my exemple above, File3 to File2 or File2 to File3 respectively).

We might need to implement a "smarter" conflict resolution API, but for now that's what you can access :).


Thank you in advance, greetings

Daniel



Cheers,

Laurent Goubet
Obeo