Skip to content

Commit fe92de7

Browse files
committed
Fix OML model compare in Git staging view
In the Git staging view, opening a comparison for a changed file would fail with a NullPointerException from trying to read the contents of an IStorage for the "origin" side of the comparison, which doesn't exist. To handle this, instead of using a given IStorage directly, make sure a file for it actually exists by re-loading it from the IStorageProviderAccessor by name.
1 parent 8f62da7 commit fe92de7

File tree

1 file changed

+61
-14
lines changed

1 file changed

+61
-14
lines changed

io.opencaesar.rosetta.oml.ui/src/io/opencaesar/rosetta/oml/ui/compare/OmlModelResolver.java

Lines changed: 61 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,15 @@
2222

2323
import org.eclipse.core.resources.IResource;
2424
import org.eclipse.core.resources.IStorage;
25+
import org.eclipse.core.resources.ResourcesPlugin;
26+
import org.eclipse.core.runtime.CoreException;
2527
import org.eclipse.core.runtime.IProgressMonitor;
28+
import org.eclipse.core.runtime.SubMonitor;
2629
import org.eclipse.emf.compare.ide.ui.logical.AbstractModelResolver;
2730
import org.eclipse.emf.compare.ide.ui.logical.IStorageProviderAccessor;
31+
import org.eclipse.emf.compare.ide.ui.logical.IStorageProviderAccessor.DiffSide;
2832
import org.eclipse.emf.compare.ide.ui.logical.SynchronizationModel;
33+
import org.eclipse.emf.compare.ide.utils.ResourceUtil;
2934
import org.eclipse.emf.compare.ide.utils.StorageTraversal;
3035

3136
/**
@@ -36,33 +41,75 @@
3641
public class OmlModelResolver extends AbstractModelResolver {
3742

3843
@Override
39-
public SynchronizationModel resolveLocalModels(IResource left, IResource right, IResource origin,
40-
IProgressMonitor monitor) throws InterruptedException {
41-
return new SynchronizationModel(getTraversal(left), getTraversal(right), getTraversal(origin));
42-
}
43-
44-
@Override
45-
public SynchronizationModel resolveModels(IStorageProviderAccessor storageAccessor, IStorage left, IStorage right,
46-
IStorage origin, IProgressMonitor monitor) throws InterruptedException {
47-
return new SynchronizationModel(getTraversal(left), getTraversal(right), getTraversal(origin));
44+
public boolean canResolve(IStorage sourceStorage) {
45+
return true;
4846
}
49-
47+
48+
// Local
49+
5050
@Override
5151
public StorageTraversal resolveLocalModel(IResource resource, IProgressMonitor monitor)
5252
throws InterruptedException {
53-
return getTraversal(resource);
53+
return getLocalTraversal(resource);
5454
}
5555

5656
@Override
57-
public boolean canResolve(IStorage sourceStorage) {
58-
return true;
57+
public SynchronizationModel resolveLocalModels(IResource left, IResource right, IResource origin,
58+
IProgressMonitor monitor) throws InterruptedException {
59+
return new SynchronizationModel(getLocalTraversal(left), getLocalTraversal(right), getLocalTraversal(origin));
5960
}
6061

61-
private static StorageTraversal getTraversal(Object resource) {
62+
/**
63+
* For local resources, include the given resource directly in the StorageTraversal.
64+
*/
65+
private static StorageTraversal getLocalTraversal(IResource resource) {
6266
if (resource instanceof IStorage) {
6367
return new StorageTraversal(Collections.singleton((IStorage)resource));
6468
} else {
6569
return new StorageTraversal(Collections.emptySet());
6670
}
6771
}
72+
73+
// Remote
74+
75+
@Override
76+
public SynchronizationModel resolveModels(IStorageProviderAccessor storageAccessor, IStorage left, IStorage right,
77+
IStorage origin, IProgressMonitor monitor) throws InterruptedException {
78+
var subMonitor = SubMonitor.convert(monitor, 3);
79+
return new SynchronizationModel(
80+
getRemoteTraversal(storageAccessor, left, DiffSide.SOURCE, subMonitor.split(1)),
81+
getRemoteTraversal(storageAccessor, right, DiffSide.REMOTE, subMonitor.split(1)),
82+
getRemoteTraversal(storageAccessor, origin, DiffSide.ORIGIN, subMonitor.split(1))
83+
);
84+
}
85+
86+
/**
87+
* For remote traversals, the IStorage given to us may be a wrapper for an underlying IStorage object that
88+
* doesn't actually exist and is null; trying to load the contents of this IStorage results in an error.
89+
*
90+
* To prevent this, try to locate the storage object ourselves from the
91+
* storageAccessor using the given storage object's name to ensure it exists.
92+
*/
93+
private static StorageTraversal getRemoteTraversal(IStorageProviderAccessor storageAccessor, IStorage givenStorage, DiffSide side, IProgressMonitor monitor) {
94+
try {
95+
if (givenStorage != null) {
96+
var path = ResourceUtil.getAbsolutePath(givenStorage);
97+
var file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
98+
var storageProvider = storageAccessor.getStorageProvider(file, side);
99+
if (storageProvider != null) {
100+
var foundStorage = storageProvider.getStorage(monitor);
101+
if (foundStorage != null) {
102+
return new StorageTraversal(Collections.singleton(foundStorage));
103+
}
104+
}
105+
}
106+
} catch (CoreException e) {
107+
// returns an empty traversal in the event of a CoreException
108+
e.printStackTrace();
109+
} finally {
110+
monitor.done();
111+
}
112+
return new StorageTraversal(Collections.emptySet());
113+
}
114+
68115
}

0 commit comments

Comments
 (0)