1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
|
/*******************************************************************************
* Copyright (c) 2013, 2015 Obeo and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Obeo - initial API and implementation
* Alexandra Buzila - bug 469105
*******************************************************************************/
package org.eclipse.emf.compare.ide.ui.internal.logical;
import static org.eclipse.emf.compare.ide.ui.internal.util.PlatformElementUtil.adaptAs;
import static org.eclipse.emf.compare.ide.ui.internal.util.PlatformElementUtil.findFile;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
import org.eclipse.compare.ISharedDocumentAdapter;
import org.eclipse.compare.IStreamContentAccessor;
import org.eclipse.compare.ITypedElement;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.compare.ide.internal.utils.StoragePathAdapter;
import org.eclipse.emf.compare.ide.utils.IStoragePathAdapterProvider;
import org.eclipse.emf.compare.ide.utils.IStoragePathProvider;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.core.history.IFileRevision;
import org.eclipse.team.core.variants.CachedResourceVariant;
import org.eclipse.team.core.variants.IResourceVariant;
import org.eclipse.ui.IEditorInput;
/**
* This implementation of IStorage simply wraps a stream content accessor.
*
* @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
*/
public class StreamAccessorStorage implements IStorage, IStoragePathAdapterProvider {
/** The wrapped accessor. */
private final IStreamContentAccessor accessor;
/** Full path of the underlying content. */
private final String fullPath;
/**
* Wraps the given accessor.
*
* @param accessor
* The accessor to wrap as an IStorage.
* @param fullPath
* Full path to the underlying storage.
*/
public StreamAccessorStorage(IStreamContentAccessor accessor, String fullPath) {
this.accessor = accessor;
this.fullPath = fullPath;
}
/**
* This is a short-hand for {@link #fromTypedElement(String, ITypedElement)}. This second one should be
* preferred in case the given element is remote and we need a proper path for it.
*
* @param element
* The typed element for which we need to create a wrapper.
* @return The wrapped typed element.
* @throws IllegalArgumentException
* If the given element does not implement {@link IStreamContentAccessor}.
*/
public static StreamAccessorStorage fromTypedElement(ITypedElement element)
throws IllegalArgumentException {
return fromTypedElement(null, element);
}
/**
* Creates a StreamAccessorStorage given the input typed element. Note that the given typed element -must-
* implement {@link IStreamContentAccessor} as well.
*
* @param storagePath
* The full path to this storage, can be <code>null</code>.
* @param element
* The typed element for which we need to create a wrapper.
* @return The wrapped typed element.
* @throws IllegalArgumentException
* If the given element does not implement {@link IStreamContentAccessor}.
*/
public static StreamAccessorStorage fromTypedElement(String storagePath, ITypedElement element)
throws IllegalArgumentException {
if (!(element instanceof IStreamContentAccessor)) {
throw new IllegalArgumentException();
}
final String fullPath;
if (storagePath != null) {
fullPath = storagePath;
} else {
fullPath = findPath(element);
}
return new StreamAccessorStorage((IStreamContentAccessor)element, fullPath);
}
/**
* This will try to find a path for the given typed element. If that element can be adapted, it delegates
* to {@link #findPath(IAdaptable)}.
*
* @param element
* The element for which we need a path.
* @return A path for the given element.
*/
private static String findPath(ITypedElement element) {
final String fullPath;
final IFile file = findFile(element);
if (file != null) {
fullPath = file.getFullPath().toString();
} else {
final IFileRevision revision = findFileRevision(element);
String tmp = null;
if (revision != null) {
final URI uri = revision.getURI();
if (uri != null) {
tmp = org.eclipse.emf.common.util.URI.decode(uri.toString());
} else if (revision instanceof IAdaptable) {
tmp = findPath((IAdaptable)revision);
}
}
if (tmp != null) {
fullPath = tmp;
} else {
// We can't do much here...
fullPath = element.getName();
}
}
return fullPath;
}
/**
* Get the commit id for the given element
*
* @param element
* The element for which we want the commit id
* @return the commit id
*/
public static IFileRevision findCommitId(ITypedElement element) {
return findFileRevision(element);
}
/**
* {@inheritDoc}
*
* @see IStoragePathAdapterProvider#createStoragePathAdapter()
*/
public Adapter createStoragePathAdapter(String path, boolean isLocal) {
IFileRevision findFileRevision = findFileRevision((ITypedElement)accessor);
IFile file = findFile((ITypedElement)accessor);
// The parameter isLocal is overwritten because more informations are available here to determine
// whether the file is local or remote
boolean local = file != null;
if (!isLocal && findFileRevision != null) {
return new StoragePathAdapter(path, local, findFileRevision.getContentIdentifier(),
findFileRevision.getAuthor());
} else {
return new StoragePathAdapter(path, local);
}
}
/**
* If the {@code adaptable} can be adapted to an {@link IResourceVariant}, we'll try to retrieve the
* resource's path. It will use {@link IStoragePathProvider}s, if any are registered. May return null
*
* @param adaptable
* The {@link IAdaptable} for which we need a path
* @return A path for the given element.
*/
private static String findPath(IAdaptable adaptable) {
String result = null;
final IResourceVariant variant = (IResourceVariant)adaptable.getAdapter(IResourceVariant.class);
if (variant != null) {
try {
final IStorage storage = variant.getStorage(new NullProgressMonitor());
if (storage != null) {
final Object adapter = Platform.getAdapterManager().loadAdapter(storage,
IStoragePathProvider.class.getName());
if (adapter instanceof IStoragePathProvider) {
final IPath fixedPath = ((IStoragePathProvider)adapter).computeFixedPath(storage);
result = fixedPath.toString();
} else if (storage instanceof IFile) {
result = storage.getFullPath().toString();
}
} else if (variant instanceof CachedResourceVariant) {
result = ((CachedResourceVariant)variant).getDisplayPath().toString();
}
} catch (TeamException e) {
// Swallow, this was a best effort...
}
}
return result;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
*/
// suppressing since overriding.
@SuppressWarnings({"rawtypes", "unchecked" })
public Object getAdapter(Class adapter) {
Object adapted = null;
if (adapter.isInstance(this)) {
adapted = this;
} else if (adapter == IStreamContentAccessor.class) {
adapted = accessor;
} else if (accessor instanceof ITypedElement) {
if (adapter == ITypedElement.class) {
adapted = accessor;
} else if (adapter.isAssignableFrom(IFile.class)) {
adapted = findFile((ITypedElement)accessor);
}
}
return adapted;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.core.resources.IStorage#getContents()
*/
public InputStream getContents() throws CoreException {
return accessor.getContents();
}
/**
* {@inheritDoc}
*
* @see org.eclipse.core.resources.IStorage#getFullPath()
*/
public IPath getFullPath() {
return new Path(fullPath);
}
/**
* {@inheritDoc}
*
* @see org.eclipse.core.resources.IStorage#getName()
*/
public String getName() {
if (accessor instanceof ITypedElement) {
return ((ITypedElement)accessor).getName();
}
return getFullPath().lastSegment();
}
/**
* {@inheritDoc}
*
* @see org.eclipse.core.resources.IStorage#isReadOnly()
*/
public boolean isReadOnly() {
if (accessor instanceof ITypedElement) {
final IFile file = findFile((ITypedElement)accessor);
if (file != null) {
return file.isReadOnly();
}
}
final File file = getFullPath().toFile();
return !file.exists() || !file.canWrite();
}
/**
* Try and determine the file revision of the given element.
*
* @param element
* The element for which we need an {@link IFileRevision}.
* @return The file revision of the given element if we could find one, <code>null</code> otherwise.
*/
private static IFileRevision findFileRevision(ITypedElement element) {
if (element == null) {
return null;
}
// Can we adapt it directly?
IFileRevision revision = adaptAs(element, IFileRevision.class);
if (revision == null) {
// Quite the workaround... but CVS does not offer us any other way.
// These few lines of code is what make us depend on org.eclipse.ui... Can we find another way?
final ISharedDocumentAdapter documentAdapter = adaptAs(element, ISharedDocumentAdapter.class);
if (documentAdapter != null) {
final IEditorInput editorInput = documentAdapter.getDocumentKey(element);
if (editorInput != null) {
revision = adaptAs(editorInput, IFileRevision.class);
}
}
}
if (revision == null) {
// Couldn't do it the API way ...
// At the time of writing, this was the case with EGit
try {
final Method method = element.getClass().getMethod("getFileRevision"); //$NON-NLS-1$
final Object value = method.invoke(element);
if (value instanceof IFileRevision) {
revision = (IFileRevision)value;
}
} catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
// Ignore exceptions
}
}
return revision;
}
}
|