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
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
;
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
;
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
{
47 * This does not need to be instantiated.
49 private ResourceUtil() {
50 // hides default constructor
54 * This will try and load the given file as an EMF model, and return the corresponding {@link Resource} if
58 * The file we need to try and load as a model.
60 * The resource set in which to load this Resource.
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;
78 resource
= resourceSet
.createResource(uri
);
79 stream
= storage
.getContents();
80 resource
.load(stream
, options
);
81 } catch (IOException e
) {
83 } catch (CoreException e
) {
85 } catch (WrappedException e
) {
91 } catch (IOException e
) {
92 // Should have been caught by the outer try
101 * Checks whether the two given storages point to binary identical data.
104 * First of the two storages which content we are testing.
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;
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
) {
129 } catch (IOException e
) {
132 if (leftReader
!= null) {
133 Closeables
.closeQuietly(leftReader
);
135 if (rightReader
!= null) {
136 Closeables
.closeQuietly(rightReader
);
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.
148 * First of the three storages which content we are testing.
150 * Second of the three storages which content we are testing.
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;
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
) {
181 } catch (IOException e
) {
184 if (leftReader
!= null) {
185 Closeables
.closeQuietly(leftReader
);
187 if (rightReader
!= null) {
188 Closeables
.closeQuietly(rightReader
);
190 if (originReader
!= null) {
191 Closeables
.closeQuietly(originReader
);
198 * Create the URI with which we'll load the given IFile as an EMF resource.
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.
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
235 if (path
.startsWith("file:/")) { //$NON-NLS-1$
236 uri
= URI
.createURI(path
);
238 uri
= URI
.createFileURI(path
);
241 final IWorkspaceRoot root
= ResourcesPlugin
.getWorkspace().getRoot();
243 if (root
.getFile(new Path(path
)).exists()) {
244 uri
= URI
.createPlatformResourceURI(path
, true);
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);
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.
262 * The resource set to save.
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
)) {
271 resource
.save(options
);
272 } catch (IOException 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)}.
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.
292 public static boolean hasContentType(IFile resource
, String contentTypeId
) {
293 IContentTypeManager ctManager
= Platform
.getContentTypeManager();
294 IContentType expected
= ctManager
.getContentType(contentTypeId
);
295 if (expected
== null) {
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.
321 public static boolean hasContentType(String contentTypeId
, IContentType
[] contentTypes
) {
322 IContentTypeManager ctManager
= Platform
.getContentTypeManager();
323 IContentType expected
= ctManager
.getContentType(contentTypeId
);
324 if (expected
== null) {
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.
341 * The file we need the content types of.
342 * @return All content types associated with the given file, an empty array if none.
345 public static IContentType
[] getContentTypes(IFile file
) {
346 IContentTypeManager ctManager
= Platform
.getContentTypeManager();
348 InputStream resourceContent
= null;
349 IContentType
[] contentTypes
= new IContentType
[0];
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());
358 Closeables
.closeQuietly(resourceContent
);
364 * Disable saving for resources that cannot support it.
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()) {
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}.
383 * Length of the data range to check within {@code array1}.
385 * Length of the data range to check within {@code array2}.
387 * First of the two arrays which content we need to check.
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]}
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
) {
398 } else if (array1
== null || array2
== null) {
401 for (int i
= 0; i
< length1
&& result
; i
++) {
402 result
= array1
[i
] == array2
[i
];
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}
416 * Length of the data range to check within {@code array1}.
418 * Length of the data range to check within {@code array2}.
420 * Length of the data range to check within {@code array3}.
422 * First of the three arrays which content we need to check.
424 * Second of the three arrays which content we need to check.
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]}
430 private static boolean equalArrays(int length1
, int length2
, int length3
, char[] array1
, char[] array2
,
432 if (length1
== length2
&& length1
== length3
) {
433 boolean result
= true;
434 if (array1
== array2
&& array1
== array3
) {
436 } else if (array1
== null || array2
== null || array3
== null) {
439 for (int i
= 0; i
< length1
&& result
; i
++) {
440 result
= array1
[i
] == array2
[i
] && array1
[1] == array3
[i
];
449 * Logs the given exception as an error.
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
);