Comment, remove useless warnings, avoid API break
[EMFCompare2.git] / plugins / org.eclipse.emf.compare.ide / src / org / eclipse / emf / compare / ide / utils / ResourceUtil.java
blob5a80617d647e7723f5770a5ea1e73cb179282f95
1 /*******************************************************************************
2 * Copyright (c) 2012 Obeo.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * Obeo - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.emf.compare.ide.utils;
13 import com.google.common.io.Closeables;
15 import java.io.BufferedReader;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.io.InputStreamReader;
19 import java.io.Reader;
20 import java.util.Map;
22 import org.eclipse.core.resources.IFile;
23 import org.eclipse.core.resources.IStorage;
24 import org.eclipse.core.resources.IWorkspaceRoot;
25 import org.eclipse.core.resources.ResourcesPlugin;
26 import org.eclipse.core.runtime.CoreException;
27 import org.eclipse.core.runtime.IStatus;
28 import org.eclipse.core.runtime.Path;
29 import org.eclipse.core.runtime.Platform;
30 import org.eclipse.core.runtime.Status;
31 import org.eclipse.core.runtime.content.IContentType;
32 import org.eclipse.core.runtime.content.IContentTypeManager;
33 import org.eclipse.emf.common.util.EList;
34 import org.eclipse.emf.common.util.URI;
35 import org.eclipse.emf.common.util.WrappedException;
36 import org.eclipse.emf.compare.ide.EMFCompareIDEPlugin;
37 import org.eclipse.emf.ecore.resource.Resource;
38 import org.eclipse.emf.ecore.resource.ResourceSet;
40 /**
41 * This class will be used to provide various utilities aimed at IResource manipulation.
43 * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
45 public final class ResourceUtil {
46 /**
47 * This does not need to be instantiated.
49 private ResourceUtil() {
50 // hides default constructor
53 /**
54 * This will try and load the given file as an EMF model, and return the corresponding {@link Resource} if
55 * at all possible.
57 * @param storage
58 * The file we need to try and load as a model.
59 * @param resourceSet
60 * The resource set in which to load this Resource.
61 * @param options
62 * The options to pass to {@link Resource#load(java.util.Map)}.
63 * @return The loaded EMF Resource if {@code file} was a model, {@code null} otherwise.
65 public static Resource loadResource(IStorage storage, ResourceSet resourceSet, Map<?, ?> options) {
66 final String resourceName = storage.getName();
67 String path = storage.getFullPath().toString();
68 if (!path.endsWith(resourceName)) {
69 final int endIndex = path.indexOf(resourceName) + resourceName.length();
70 path = path.substring(0, endIndex);
73 final URI uri = createURIFor(storage);
75 InputStream stream = null;
76 Resource resource = null;
77 try {
78 resource = resourceSet.createResource(uri);
79 stream = storage.getContents();
80 resource.load(stream, options);
81 } catch (IOException e) {
82 // return null
83 } catch (CoreException e) {
84 // return null
85 } catch (WrappedException e) {
86 // return null
87 } finally {
88 if (stream != null) {
89 try {
90 stream.close();
91 } catch (IOException e) {
92 // Should have been caught by the outer try
97 return resource;
101 * Checks whether the two given storages point to binary identical data.
103 * @param left
104 * First of the two storages which content we are testing.
105 * @param right
106 * Second of the two storages which content we are testing.
107 * @return <code>true</code> if {@code left} and {@code right} are binary identical.
109 public static boolean binaryIdentical(IStorage left, IStorage right) {
110 Reader leftReader = null;
111 Reader rightReader = null;
112 try {
113 leftReader = new BufferedReader(new InputStreamReader(left.getContents()));
114 rightReader = new BufferedReader(new InputStreamReader(right.getContents()));
116 final int bufferSize = 16384;
117 final char[] leftBuff = new char[bufferSize];
118 final char[] rightBuff = new char[bufferSize];
119 int readLeft = leftReader.read(leftBuff);
120 int readRight = rightReader.read(rightBuff);
121 while (readLeft > 0 && readRight > 0 && equalArrays(readLeft, readRight, leftBuff, rightBuff)) {
122 readLeft = leftReader.read(leftBuff);
123 readRight = rightReader.read(rightBuff);
125 // One last check in case we've reached the end of one side but not of the other
126 return equalArrays(readLeft, readRight, leftBuff, rightBuff);
127 } catch (CoreException e) {
128 logError(e);
129 } catch (IOException e) {
130 logError(e);
131 } finally {
132 if (leftReader != null) {
133 Closeables.closeQuietly(leftReader);
135 if (rightReader != null) {
136 Closeables.closeQuietly(rightReader);
139 return false;
143 * Checks whether the three given storages point to binary identical data. This could be done by calling
144 * {@link #binaryIdentical(IStorage, IStorage)} twice, though this implementation allows us to shortcut
145 * whenever one byte differs... and will read one less file from its input stream.
147 * @param left
148 * First of the three storages which content we are testing.
149 * @param right
150 * Second of the three storages which content we are testing.
151 * @param origin
152 * Third of the three storages which content we are testing.
153 * @return <code>true</code> if {@code left}, {@code right} and {@code origin} are binary identical.
155 public static boolean binaryIdentical(IStorage left, IStorage right, IStorage origin) {
156 Reader leftReader = null;
157 Reader rightReader = null;
158 Reader originReader = null;
159 try {
160 leftReader = new BufferedReader(new InputStreamReader(left.getContents()));
161 rightReader = new BufferedReader(new InputStreamReader(right.getContents()));
162 originReader = new BufferedReader(new InputStreamReader(origin.getContents()));
164 final int bufferSize = 16384;
165 final char[] leftBuff = new char[bufferSize];
166 final char[] rightBuff = new char[bufferSize];
167 final char[] originBuff = new char[bufferSize];
168 int readLeft = leftReader.read(leftBuff);
169 int readRight = rightReader.read(rightBuff);
170 int readOrigin = originReader.read(originBuff);
171 while (readLeft > 0 && readRight > 0 && readOrigin > 0
172 && equalArrays(readLeft, readRight, readOrigin, leftBuff, rightBuff, originBuff)) {
173 readLeft = leftReader.read(leftBuff);
174 readRight = rightReader.read(rightBuff);
175 readOrigin = originReader.read(originBuff);
177 // One last check in case we've reached the end of one side but not of the other
178 return equalArrays(readLeft, readRight, readOrigin, leftBuff, rightBuff, originBuff);
179 } catch (CoreException e) {
180 logError(e);
181 } catch (IOException e) {
182 logError(e);
183 } finally {
184 if (leftReader != null) {
185 Closeables.closeQuietly(leftReader);
187 if (rightReader != null) {
188 Closeables.closeQuietly(rightReader);
190 if (originReader != null) {
191 Closeables.closeQuietly(originReader);
194 return false;
198 * Create the URI with which we'll load the given IFile as an EMF resource.
200 * @param file
201 * The file for which we need an EMF URI.
202 * @return The created URI.
204 public static URI createURIFor(IFile file) {
205 // whether it exists or not (no longer), use platform:/resource
206 return URI.createPlatformResourceURI(file.getFullPath().toString(), true);
210 * Create the URI with which we'll load the given IStorage as an EMF resource.
212 * @param storage
213 * The storage for which we need an EMF URI.
214 * @return The created URI.
216 public static URI createURIFor(IStorage storage) {
217 if (storage instanceof IFile) {
218 return createURIFor((IFile)storage);
221 final String resourceName = storage.getName();
222 String path = storage.getFullPath().toString();
223 if (!path.endsWith(resourceName)) {
224 final int endIndex = path.indexOf(resourceName) + resourceName.length();
225 path = path.substring(0, endIndex);
228 // Given the two paths
229 // "g:/ws/project/test.ecore"
230 // "/project/test.ecore"
231 // We have no way to determine which is absolute and which should be platform:/resource
232 // Furthermore, "ws" could be a git repository, in which case we would be here with
233 // ws/project/test.ecore
234 URI uri;
235 if (path.startsWith("file:/")) { //$NON-NLS-1$
236 uri = URI.createURI(path);
237 } else {
238 uri = URI.createFileURI(path);
241 final IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
242 if (root != null) {
243 if (root.getFile(new Path(path)).exists()) {
244 uri = URI.createPlatformResourceURI(path, true);
245 } else {
246 // is it a file coming from a Git repository?
247 final int indexOfSeparator = path.indexOf('/');
248 if (indexOfSeparator > 0 && root.getFile(new Path(path.substring(indexOfSeparator))).exists()) {
249 uri = URI.createPlatformResourceURI(path.substring(indexOfSeparator), true);
254 return uri;
258 * This can be called to save all resources contained by the resource set. This will not try and save
259 * resources that do not support output.
261 * @param resourceSet
262 * The resource set to save.
263 * @param options
264 * The options we are to pass on to {@link Resource#save(Map)}.
266 public static void saveAllResources(ResourceSet resourceSet, Map<?, ?> options) {
267 EList<Resource> resources = resourceSet.getResources();
268 for (Resource resource : resources) {
269 if (supportsOutput(resource)) {
270 try {
271 resource.save(options);
272 } catch (IOException e) {
273 logError(e);
280 * This will return <code>true</code> if and only if the given IFile has the given <em>contentTypeId</em>
281 * configured (as returned by {@link IContentTypeManager#findContentTypesFor(InputStream, String)
282 * Platform.getContentTypeManager().findContentTypesFor(InputStream, String)}.
284 * @param resource
285 * The resource from which to test the content types.
286 * @param contentTypeId
287 * Fully qualified identifier of the content type this <em>resource</em> has to feature.
288 * @return <code>true</code> if the given {@link IFile} has the given content type.
289 * @deprecated use {@link #hasContentType(String, IContentType[])} instead.
291 @Deprecated
292 public static boolean hasContentType(IFile resource, String contentTypeId) {
293 IContentTypeManager ctManager = Platform.getContentTypeManager();
294 IContentType expected = ctManager.getContentType(contentTypeId);
295 if (expected == null) {
296 return false;
299 final IContentType[] contentTypes = getContentTypes(resource);
301 boolean hasContentType = false;
302 for (int i = 0; i < contentTypes.length && !hasContentType; i++) {
303 if (contentTypes[i].isKindOf(expected)) {
304 hasContentType = true;
307 return hasContentType;
311 * This will return <code>true</code> if the given <em>contentTypeId</em> represents a content-type
312 * contained in the given array.
314 * @param contentTypeId
315 * Fully qualified identifier of the content type we seek.
316 * @param contentTypes
317 * The array of content-types to compare against.
318 * @return <code>true</code> if the given array contains a content-type with this id.
319 * @since 3.1
321 public static boolean hasContentType(String contentTypeId, IContentType[] contentTypes) {
322 IContentTypeManager ctManager = Platform.getContentTypeManager();
323 IContentType expected = ctManager.getContentType(contentTypeId);
324 if (expected == null) {
325 return false;
328 boolean hasContentType = false;
329 for (int i = 0; i < contentTypes.length && !hasContentType; i++) {
330 if (contentTypes[i].isKindOf(expected)) {
331 hasContentType = true;
334 return hasContentType;
338 * Returns the whole list of content types of the given IFile, or an empty array if none.
340 * @param file
341 * The file we need the content types of.
342 * @return All content types associated with the given file, an empty array if none.
343 * @since 3.1
345 public static IContentType[] getContentTypes(IFile file) {
346 IContentTypeManager ctManager = Platform.getContentTypeManager();
348 InputStream resourceContent = null;
349 IContentType[] contentTypes = new IContentType[0];
350 try {
351 resourceContent = file.getContents();
352 contentTypes = ctManager.findContentTypesFor(resourceContent, file.getName());
353 } catch (CoreException e) {
354 ctManager.findContentTypesFor(file.getName());
355 } catch (IOException e) {
356 ctManager.findContentTypesFor(file.getName());
357 } finally {
358 Closeables.closeQuietly(resourceContent);
360 return contentTypes;
364 * Disable saving for resources that cannot support it.
366 * @param resource
367 * The resource we are to check.
368 * @return <code>true</code> if we can save this <code>resource</code>, <code>false</code> otherwise.
370 private static boolean supportsOutput(Resource resource) {
371 final URI uri = resource.getURI();
372 if (uri.isPlatformResource() || uri.isRelative() || uri.isFile()) {
373 return true;
375 return false;
379 * Checks whether the two arrays contain identical data in the {@code [0:length]} range. Note that we
380 * won't even check the arrays' contents if {@code length1} is not equal to {@code length2}.
382 * @param length1
383 * Length of the data range to check within {@code array1}.
384 * @param length2
385 * Length of the data range to check within {@code array2}.
386 * @param array1
387 * First of the two arrays which content we need to check.
388 * @param array2
389 * Second of the two arrays which content we need to check.
390 * @return <code>true</code> if the two given arrays contain identical data in the {@code [0:length]}
391 * range.
393 private static boolean equalArrays(int length1, int length2, char[] array1, char[] array2) {
394 if (length1 == length2) {
395 boolean result = true;
396 if (array1 == array2) {
397 result = true;
398 } else if (array1 == null || array2 == null) {
399 result = false;
400 } else {
401 for (int i = 0; i < length1 && result; i++) {
402 result = array1[i] == array2[i];
405 return result;
407 return false;
411 * Checks whether the three arrays contain identical data in the {@code [0:length]} range. Note that we
412 * will only check the arrays' contents if {@code length1} is equal to {@code length2} and {@code length3}
415 * @param length1
416 * Length of the data range to check within {@code array1}.
417 * @param length2
418 * Length of the data range to check within {@code array2}.
419 * @param length3
420 * Length of the data range to check within {@code array3}.
421 * @param array1
422 * First of the three arrays which content we need to check.
423 * @param array2
424 * Second of the three arrays which content we need to check.
425 * @param array3
426 * Third of the three arrays which content we need to check.
427 * @return <code>true</code> if the three given arrays contain identical data in the {@code [0:length]}
428 * range.
430 private static boolean equalArrays(int length1, int length2, int length3, char[] array1, char[] array2,
431 char[] array3) {
432 if (length1 == length2 && length1 == length3) {
433 boolean result = true;
434 if (array1 == array2 && array1 == array3) {
435 result = true;
436 } else if (array1 == null || array2 == null || array3 == null) {
437 result = false;
438 } else {
439 for (int i = 0; i < length1 && result; i++) {
440 result = array1[i] == array2[i] && array1[1] == array3[i];
443 return result;
445 return false;
449 * Logs the given exception as an error.
451 * @param e
452 * The exception we need to log.
454 private static void logError(Exception e) {
455 final IStatus status = new Status(IStatus.ERROR, EMFCompareIDEPlugin.PLUGIN_ID, e.getMessage(), e);
456 EMFCompareIDEPlugin.getDefault().getLog().log(status);