Model merger not found [message #1752581] |
Wed, 25 January 2017 05:13  |
Eclipse User |
|
|
|
Hi!
I am using EMF Compare to handle model merging in my own EMF-based application and I have encountered a problem when merging.
The use case I've been looking at is the following:
1. A model has one local, non-conflicting change and the user tries to merge another non-conflicting change from the remote. The models we use are split into multiple files and the changes in this use case represent new files added to the model. (both the local and the remote add new files)
2. Before starting the merge we commit all local changes and start the merge process (using the JGit MergeCommand for each commit coming from the remote)
The problem appears during the merge process. In the mergeTreeWalk(...) method of the RecursiveModelMerger class, the modelMerger returned by the method LogicalModels.findAdapter(...) is null for all iterations of resources belonging to the model. This happens because of the following condition in the findAdapter method:
if (matchingResources.length == modelArray.length)
It seems like the new file created on the remote is not found by the IModelProviderDescriptor, therefore, the size of the matchingResources array will always be smaller than the size of the modelArray.
I was wondering why is this condition required and how can this case be handled?
|
|
|
|
Re: Model merger not found [message #1752723 is a reply to message #1752709] |
Thu, 26 January 2017 09:25  |
Eclipse User |
|
|
|
Hi Laurent,
Thanks for the reply.
To answer your questions first:
1) No, we do not refresh the workspace files at any moment, should we? What I've noticed, however, is that in the mergeTreeWalk(...) method of the RecursiveModelMerger, the refreshRoots(...) method is called both before the creation of the logicalModel and before the creation of the modelMerger.
2) As for reproducing the behavior, I am not sure the exact same workflow can be achieved outside of our application so, unfortunately, I cannot give you any other details than what I've already mentioned in the use case above.
What I don't understand is why is it a must that the files found in the modelArray will also be found in the matchingResources.
As far as I could see from debugging through the code yesterday, the modelArray contains all the resources found by the logicalModel which is built from the knownResources of the variantTreeProvider (TreeWalkResourceVariantTreeProvider).
The variantTreeProvider will, of course, also consider the resources that are on the remote because the remote (THEIRS) tree contains them and they are all added to the knownResources set, therefore they will all be added to the modelArray as well:
knownResources = new LinkedHashSet<IResource>();
knownResources.addAll(baseCache.getKnownResources());
knownResources.addAll(oursCache.getKnownResources());
knownResources.addAll(theirsCache.getKnownResources());
On the other hand, matchingResources only contains files that exist in the local workspace, therefore the remote ones will never be found since they are only copied locally after the merge process has finished successfully.
Another thing that confuses me is the comment of the build(...) method in LogicalModels:
/**
* Iterate over the resources in the given set to discover and cache the logical model of each.
* <p>
* Resources that do not exist locally will be excluded from the lookup to avoid NPEs from the expression
* framework (model providers look for the resource's content type, which fails for remote resources). If
* these resources _are_ part of a larger model, it will be detected through the "other parts" of said
* model.
* </p>
* <p>
* Models provided by the {@link #ignoredModelDescriptors} will be ignored from this lookup.
* </p>
*
* @param resources
* @param remoteMappingContext
*/
If resources that do not exist locally will be excluded from the lookup, how come my new file from the remote is not excluded? Or perhaps "locally" in this context means something different?
Could you please clarify some of these concepts and tell me if there is something I misunderstood?
What I did as a solution, for now, is to remove the remote resources from the knownResources list before building the logical models:
Set<IResource> knownResources = variantTreeProvider.getKnownResources();
ArrayList<IResource> toBeRemoved = new ArrayList<>();
for (IResource iResource : knownResources) {
if (!iResource.isLocal(IResource.DEPTH_INFINITE)) {
toBeRemoved.add(iResource);
}
}
knownResources.removeAll(toBeRemoved);
logicalModels.build(knownResources, remoteMappingContext);
|
|
|
Powered by
FUDForum. Page generated in 0.05051 seconds