001 /*
002 GRANITE DATA SERVICES
003 Copyright (C) 2011 GRANITE DATA SERVICES S.A.S.
004
005 This file is part of Granite Data Services.
006
007 Granite Data Services is free software; you can redistribute it and/or modify
008 it under the terms of the GNU Library General Public License as published by
009 the Free Software Foundation; either version 2 of the License, or (at your
010 option) any later version.
011
012 Granite Data Services is distributed in the hope that it will be useful, but
013 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015 for more details.
016
017 You should have received a copy of the GNU Library General Public License
018 along with this library; if not, see <http://www.gnu.org/licenses/>.
019 */
020
021 package org.granite.builder.util;
022
023 import static org.granite.builder.GraniteBuilder.FLEX_BUILDER_ID;
024 import static org.granite.builder.GraniteBuilder.GRANITE_BUILDER_ID;
025
026 import java.io.File;
027 import java.io.IOException;
028 import java.net.URI;
029 import java.net.URL;
030 import java.util.ArrayList;
031 import java.util.Arrays;
032 import java.util.Comparator;
033 import java.util.List;
034
035 import org.eclipse.core.resources.ICommand;
036 import org.eclipse.core.resources.IFile;
037 import org.eclipse.core.resources.IProject;
038 import org.eclipse.core.resources.IResource;
039 import org.eclipse.core.resources.IWorkspace;
040 import org.eclipse.core.resources.IWorkspaceRoot;
041 import org.eclipse.core.runtime.CoreException;
042 import org.eclipse.core.runtime.IPath;
043 import org.eclipse.core.runtime.IStatus;
044 import org.eclipse.core.runtime.Path;
045 import org.eclipse.core.runtime.Status;
046 import org.eclipse.jdt.core.IClasspathContainer;
047 import org.eclipse.jdt.core.IClasspathEntry;
048 import org.eclipse.jdt.core.IJavaElement;
049 import org.eclipse.jdt.core.IJavaProject;
050 import org.eclipse.jdt.core.JavaCore;
051 import org.granite.builder.GraniteActivator;
052 import org.granite.util.ClassUtil;
053
054 /**
055 * @author Franck WOLFF
056 */
057 public class ProjectUtil {
058
059 public static final Comparator<IPath> IPATH_COMPARATOR = new Comparator<IPath>() {
060 @Override
061 public int compare(IPath path1, IPath path2) {
062 return path1.toString().compareTo(path2.toString());
063 }
064 };
065
066 public static IProject[] getAllProjects(IProject project) {
067 if (project == null)
068 return new IProject[0];
069 return project.getWorkspace().getRoot().getProjects();
070 }
071
072 public static IProject[] getAllOtherGraniteProjects(IProject project) throws CoreException {
073 if (project == null)
074 return new IProject[0];
075 List<IProject> projects = new ArrayList<IProject>();
076 for (IProject p : getAllProjects(project)) {
077 if (!p.equals(project) && isGraniteProject(p))
078 projects.add(p);
079 }
080 return projects.toArray(new IProject[projects.size()]);
081 }
082
083 public static IProject getProject(IProject project, String name) {
084 if (project == null || name == null)
085 return null;
086 return project.getWorkspace().getRoot().getProject(name);
087 }
088
089 public static boolean isGraniteProject(IProject project) throws CoreException {
090 if (project != null && project.exists() && project.isOpen()) {
091 for (ICommand command : project.getDescription().getBuildSpec()) {
092 if (GRANITE_BUILDER_ID.equals(command.getBuilderName()))
093 return true;
094 }
095 }
096 return false;
097 }
098
099 public static boolean isFlexBuilderProject(IProject project) throws CoreException {
100 if (project != null && project.exists() && project.isOpen()) {
101 for (ICommand command : project.getDescription().getBuildSpec()) {
102 if (FLEX_BUILDER_ID.equals(command.getBuilderName()))
103 return true;
104 }
105 }
106 return false;
107 }
108
109 public static List<IPath> makeRelative(List<IPath> paths) {
110 if (paths == null)
111 return null;
112 return Arrays.asList(makeRelative(paths.toArray(new IPath[paths.size()])));
113 }
114
115 public static IPath[] makeRelative(IPath[] paths) {
116 if (paths != null) {
117 for (int i = 0; i < paths.length; i++)
118 paths[i] = paths[i].makeRelative();
119 }
120 return paths;
121 }
122
123 public static File getWorkspaceFile(IProject project) {
124 IWorkspace workspace = project.getWorkspace();
125 return workspace.getRoot().getLocation().toFile().getAbsoluteFile();
126 }
127
128 public static URI getWorkspaceURI(IProject project) {
129 return getWorkspaceFile(project).toURI();
130 }
131
132 public static File getProjectFile(IProject project) {
133 try {
134 return FileUtil.getLocationFile(project).getAbsoluteFile();
135 } catch (CoreException e) {
136 throw new RuntimeException("Could not get " + project + " location file", e);
137 }
138 }
139
140 public static URI getProjectURI(IProject project) {
141 try {
142 return FileUtil.getLocationURI(project);
143 } catch (CoreException e) {
144 throw new RuntimeException("Could not get " + project + " location URI", e);
145 }
146 }
147
148 public static List<CpEntry> getFullResolvedClasspath(IJavaProject project) throws CoreException {
149 return getFullClasspath(project, project.getResolvedClasspath(true));
150 }
151
152 public static List<CpEntry> getFullClasspath(IJavaProject project) throws CoreException {
153 return getFullClasspath(project, project.getRawClasspath());
154 }
155
156 public static List<CpEntry> getFullClasspath(IJavaProject project, IClasspathEntry[] classpathEntries) throws CoreException {
157 List<CpEntry> classpath = new ArrayList<CpEntry>();
158
159 IWorkspaceRoot workspace = project.getProject().getWorkspace().getRoot();
160 IPath path = null;
161 try {
162
163 // Output locations.
164 if (project.getOutputLocation() != null) {
165 path = project.getOutputLocation();
166 File file = workspace.findMember(path).getLocation().toFile();
167 classpath.add(new CpEntry(path.makeRelative().toString(), path, file, CpEntry.CpeKind.PROJECT_OUTPUT_DIR));
168 }
169 for (IClasspathEntry cpe : classpathEntries) {
170 if (cpe.getEntryKind() == IClasspathEntry.CPE_SOURCE && cpe.getOutputLocation() != null) {
171 path = cpe.getOutputLocation();
172 File file = workspace.findMember(path).getLocation().toFile();
173 classpath.add(new CpEntry(path.makeRelative().toString(), path, file, CpEntry.CpeKind.SOURCE_OUTPUT_DIR));
174 }
175 }
176
177 // Project jars.
178 for (IClasspathEntry cpe : classpathEntries) {
179 if (cpe.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
180 path = cpe.getPath();
181 if (path != null) {
182 IResource member = workspace.findMember(path);
183 String description = path.lastSegment();
184 if (path.segmentCount() > 1)
185 description += " - " + path.removeLastSegments(1).makeRelative();
186 if (member != null)
187 classpath.add(new CpEntry(description, path, member.getLocation().toFile(), CpEntry.CpeKind.LIB_JAR));
188 else
189 classpath.add(new CpEntry(description, path, path.toFile(), CpEntry.CpeKind.LIB_JAR));
190 }
191 }
192 }
193
194 // Containers jars/directories.
195 for (IClasspathEntry cpe : classpathEntries) {
196 if (cpe.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
197 path = cpe.getPath();
198 IClasspathContainer container = JavaCore.getClasspathContainer(path, project);
199 String description = container.getDescription();
200 CpEntry entry = new CpEntry(description, path, (path != null ? path.toFile() : null), CpEntry.CpeKind.CONTAINER_JAR);
201
202 for (IClasspathEntry ccpe : container.getClasspathEntries()) {
203 path = ccpe.getPath();
204 String label = path.lastSegment();
205 if (path.segmentCount() > 1)
206 label += " - " + path.removeLastSegments(1).makeRelative();
207
208 File file = path.toFile();
209 IResource resource = workspace.findMember(path);
210 if (resource != null)
211 file = resource.getLocation().toFile();
212
213 entry.getChildren().add(new CpEntry(label, path, file, CpEntry.CpeKind.LIB_JAR));
214 }
215
216 classpath.add(entry);
217 }
218 }
219
220 } catch (Exception e) {
221 String msg = "Problem with classpath location: " + path;
222 throw new CoreException(createErrorStatus(msg, e));
223 }
224
225 return classpath;
226 }
227
228 public static List<IPath> getSourceFolders(IJavaProject project) throws CoreException {
229 List<IPath> paths = new ArrayList<IPath>();
230
231 for (IClasspathEntry cpe : project.getRawClasspath()) {
232 if (cpe.getEntryKind() == IClasspathEntry.CPE_SOURCE)
233 paths.add(cpe.getPath());
234 }
235
236 return paths;
237 }
238
239 public static IPath getOutputFolder(IJavaProject project, IClasspathEntry cpe) throws CoreException {
240 if (cpe.getOutputLocation() != null)
241 return cpe.getOutputLocation();
242 return project.getOutputLocation();
243 }
244
245 public static List<IPath> getOutputFolders(IJavaProject project) throws CoreException {
246 List<IPath> paths = new ArrayList<IPath>();
247
248 for (IClasspathEntry cpe : project.getRawClasspath()) {
249 if (cpe.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
250 IPath output = cpe.getOutputLocation();
251 if (output != null)
252 paths.add(output);
253 }
254 }
255 IPath output = project.getOutputLocation();
256 if (output != null)
257 paths.add(output);
258
259 return paths;
260 }
261
262 public static IPath getJavaPath(IJavaProject project, IFile classFile, boolean keepInner) throws CoreException {
263 IPath classPath = classFile.getFullPath();
264
265 List<IPath> outputFolders = getOutputFolders(project);
266 IPath classOutputFolder = null;
267 for (IPath outputFolder : outputFolders) {
268 if (outputFolder.isPrefixOf(classPath)) {
269 classOutputFolder = outputFolder;
270 break;
271 }
272 }
273 if (classOutputFolder == null)
274 return null;
275
276 classPath = classPath.removeFirstSegments(classOutputFolder.segmentCount());
277
278 String sPath = classPath.toString();
279 sPath = sPath.substring(0, sPath.length() - classPath.getFileExtension().length() - 1);
280 if (!keepInner) {
281 int iDollar = sPath.indexOf('$');
282 if (iDollar != -1)
283 sPath = sPath.substring(iDollar);
284 }
285 sPath += ".java";
286
287 return new Path(sPath);
288 }
289
290 public static JavaClassInfo getJavaClassInfo(IJavaProject project, Class<?> clazz) {
291 try {
292 URI clazzUri = ClassUtil.findResource(clazz).toURI();
293 URI projectUri = getProjectURI(project.getProject());
294 URI relativeURI = projectUri.relativize(clazzUri);
295 return getJavaClassInfo(project, project.getProject().getFile(relativeURI.toString()));
296 } catch (Exception e) {
297 return null;
298 }
299 }
300
301 public static JavaClassInfo getJavaClassInfo(IJavaProject project, IFile resource) throws CoreException {
302 // classPath = "<project name>/<output folder>/<package>/<file>.class"
303 IPath classPath = resource.getFullPath().makeRelative();
304
305 // Find output folder: "<project name>/<output folder>".
306 IPath outputFolder = null;
307 if (project.getOutputLocation() != null && project.getOutputLocation().isPrefixOf(classPath))
308 outputFolder = project.getOutputLocation();
309 else {
310 for (IClasspathEntry cpe : project.getRawClasspath()) {
311 if (cpe.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
312 IPath output = cpe.getOutputLocation();
313 if (output != null && output.isPrefixOf(classPath)) {
314 outputFolder = output;
315 break;
316 }
317 }
318 }
319 }
320
321 if (outputFolder == null)
322 return null;
323
324 // Compute class name.
325 IPath relativeClassPath = classPath.removeFirstSegments(outputFolder.segmentCount());
326 IPath relativeClassName = relativeClassPath.removeFileExtension();
327 String className = relativeClassName.toPortableString().replace('/', '.');
328
329 // Compute java source path: "<package>/<class name>[$<inner class>].java".
330 String javaFullPath = relativeClassName.addFileExtension("java").toPortableString();
331 String javaFilePath = javaFullPath;
332 int iDollar = javaFilePath.indexOf('$');
333 if (iDollar != -1)
334 javaFilePath = javaFilePath.substring(0, iDollar) + ".java";
335
336 IJavaElement javaElement = project.findElement(new Path(javaFilePath));
337 if (javaElement == null)
338 return null;
339
340 IJavaElement sourceFolder = javaElement.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
341 if (sourceFolder == null)
342 return null;
343
344 IPath folderPath = sourceFolder.getPath().makeRelative();
345 if (folderPath.segmentCount() > 0)
346 folderPath = folderPath.removeFirstSegments(1);
347
348 // Fix issues with project not in the workspace directory.
349 outputFolder = project.getProject().getWorkspace().getRoot().findMember(outputFolder).getLocation();
350
351 return new JavaClassInfo(
352 folderPath.toPortableString(),
353 javaFullPath,
354 className,
355 new File(outputFolder.toPortableString(), relativeClassPath.toPortableString())
356 );
357 }
358
359 public static IStatus createErrorStatus(String message) {
360 return new Status(IStatus.ERROR, GraniteActivator.PLUGIN_ID, message);
361 }
362
363 public static IStatus createErrorStatus(String message, Throwable t) {
364 return new Status(IStatus.ERROR, GraniteActivator.PLUGIN_ID, IStatus.OK, message, t);
365 }
366
367 public static class CpEntry {
368
369 public enum CpeKind {
370 PROJECT_OUTPUT_DIR,
371 SOURCE_OUTPUT_DIR,
372 CONTAINER_JAR,
373 LIB_JAR
374 }
375
376 private final String description;
377 private final IPath path;
378 private final File file;
379 private final CpeKind kind;
380 private final List<CpEntry> children = new ArrayList<CpEntry>();
381
382 public CpEntry(String description, IPath path, File file, CpeKind kind) {
383 this.description = description;
384 this.path = path;
385 this.file = file;
386 this.kind = kind;
387 }
388
389 public String getDescription() {
390 return description;
391 }
392
393 public IPath getPath() {
394 return path;
395 }
396
397 public File getFile() {
398 return file;
399 }
400
401 public CpeKind getKind() {
402 return kind;
403 }
404
405 public List<CpEntry> getChildren() {
406 return children;
407 }
408
409 public boolean exists() {
410 return (file != null && file.exists());
411 }
412
413 public URL toURL() throws IOException {
414 if (file == null)
415 return null;
416 return file.getCanonicalFile().toURI().toURL();
417 }
418
419 @Override
420 public String toString() {
421 return "[" + kind + "] " + path + " -> " + file;
422 }
423 }
424 }