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 public int compare(IPath path1, IPath path2) {
061 return path1.toString().compareTo(path2.toString());
062 }
063 };
064
065 public static IProject[] getAllProjects(IProject project) {
066 if (project == null)
067 return new IProject[0];
068 return project.getWorkspace().getRoot().getProjects();
069 }
070
071 public static IProject[] getAllOtherGraniteProjects(IProject project) throws CoreException {
072 if (project == null)
073 return new IProject[0];
074 List<IProject> projects = new ArrayList<IProject>();
075 for (IProject p : getAllProjects(project)) {
076 if (!p.equals(project) && isGraniteProject(p))
077 projects.add(p);
078 }
079 return projects.toArray(new IProject[projects.size()]);
080 }
081
082 public static IProject getProject(IProject project, String name) {
083 if (project == null || name == null)
084 return null;
085 return project.getWorkspace().getRoot().getProject(name);
086 }
087
088 public static boolean isGraniteProject(IProject project) throws CoreException {
089 if (project != null && project.exists() && project.isOpen()) {
090 for (ICommand command : project.getDescription().getBuildSpec()) {
091 if (GRANITE_BUILDER_ID.equals(command.getBuilderName()))
092 return true;
093 }
094 }
095 return false;
096 }
097
098 public static boolean isFlexBuilderProject(IProject project) throws CoreException {
099 if (project != null && project.exists() && project.isOpen()) {
100 for (ICommand command : project.getDescription().getBuildSpec()) {
101 if (FLEX_BUILDER_ID.equals(command.getBuilderName()))
102 return true;
103 }
104 }
105 return false;
106 }
107
108 public static List<IPath> makeRelative(List<IPath> paths) {
109 if (paths == null)
110 return null;
111 return Arrays.asList(makeRelative(paths.toArray(new IPath[paths.size()])));
112 }
113
114 public static IPath[] makeRelative(IPath[] paths) {
115 if (paths != null) {
116 for (int i = 0; i < paths.length; i++)
117 paths[i] = paths[i].makeRelative();
118 }
119 return paths;
120 }
121
122 public static File getWorkspaceFile(IProject project) {
123 IWorkspace workspace = project.getWorkspace();
124 return workspace.getRoot().getLocation().toFile().getAbsoluteFile();
125 }
126
127 public static URI getWorkspaceURI(IProject project) {
128 return getWorkspaceFile(project).toURI();
129 }
130
131 public static File getProjectFile(IProject project) {
132 return new File(project.getLocationURI()).getAbsoluteFile();
133 }
134
135 public static URI getProjectURI(IProject project) {
136 return project.getLocationURI();
137 }
138
139 public static List<CpEntry> getFullClasspath(IJavaProject project) throws CoreException {
140 List<CpEntry> classpath = new ArrayList<CpEntry>();
141
142 IWorkspaceRoot workspace = project.getProject().getWorkspace().getRoot();
143 IPath path = null;
144 try {
145
146 // Output locations.
147 if (project.getOutputLocation() != null) {
148 path = project.getOutputLocation();
149 File file = workspace.findMember(path).getLocation().toFile();
150 classpath.add(new CpEntry(path.makeRelative().toString(), path, file, CpEntry.CpeKind.PROJECT_OUTPUT_DIR));
151 }
152 for (IClasspathEntry cpe : project.getRawClasspath()) {
153 if (cpe.getEntryKind() == IClasspathEntry.CPE_SOURCE && cpe.getOutputLocation() != null) {
154 path = cpe.getOutputLocation();
155 File file = workspace.findMember(path).getLocation().toFile();
156 classpath.add(new CpEntry(path.makeRelative().toString(), path, file, CpEntry.CpeKind.SOURCE_OUTPUT_DIR));
157 }
158 }
159
160 // Project jars.
161 for (IClasspathEntry cpe : project.getRawClasspath()) {
162 if (cpe.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
163 path = cpe.getPath();
164 if (path != null) {
165 IResource member = workspace.findMember(path);
166 String description = path.lastSegment();
167 if (path.segmentCount() > 1)
168 description += " - " + path.removeLastSegments(1).makeRelative();
169 if (member != null)
170 classpath.add(new CpEntry(description, path, member.getLocation().toFile(), CpEntry.CpeKind.LIB_JAR));
171 else
172 classpath.add(new CpEntry(description, path, path.toFile(), CpEntry.CpeKind.LIB_JAR));
173 }
174 }
175 }
176
177 // Containers jars/directories.
178 for (IClasspathEntry cpe : project.getRawClasspath()) {
179 if (cpe.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
180 path = cpe.getPath();
181 IClasspathContainer container = JavaCore.getClasspathContainer(path, project);
182 String description = container.getDescription();
183 CpEntry entry = new CpEntry(description, path, (path != null ? path.toFile() : null), CpEntry.CpeKind.CONTAINER_JAR);
184
185 for (IClasspathEntry ccpe : container.getClasspathEntries()) {
186 path = ccpe.getPath();
187 String label = path.lastSegment();
188 if (path.segmentCount() > 1)
189 label += " - " + path.removeLastSegments(1).makeRelative();
190
191 File file = path.toFile();
192 IResource resource = workspace.findMember(path);
193 if (resource != null)
194 file = resource.getLocation().toFile();
195
196 entry.getChildren().add(new CpEntry(label, path, file, CpEntry.CpeKind.LIB_JAR));
197 }
198
199 classpath.add(entry);
200 }
201 }
202
203 } catch (Exception e) {
204 String msg = "Problem with classpath location: " + path;
205 throw new CoreException(createErrorStatus(msg, e));
206 }
207
208 return classpath;
209 }
210
211 public static List<IPath> getSourceFolders(IJavaProject project) throws CoreException {
212 List<IPath> paths = new ArrayList<IPath>();
213
214 for (IClasspathEntry cpe : project.getRawClasspath()) {
215 if (cpe.getEntryKind() == IClasspathEntry.CPE_SOURCE)
216 paths.add(cpe.getPath());
217 }
218
219 return paths;
220 }
221
222 public static IPath getOutputFolder(IJavaProject project, IClasspathEntry cpe) throws CoreException {
223 if (cpe.getOutputLocation() != null)
224 return cpe.getOutputLocation();
225 return project.getOutputLocation();
226 }
227
228 public static List<IPath> getOutputFolders(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 IPath output = cpe.getOutputLocation();
234 if (output != null)
235 paths.add(output);
236 }
237 }
238 IPath output = project.getOutputLocation();
239 if (output != null)
240 paths.add(output);
241
242 return paths;
243 }
244
245 public static IPath getJavaPath(IJavaProject project, IFile classFile, boolean keepInner) throws CoreException {
246 IPath classPath = classFile.getFullPath();
247
248 List<IPath> outputFolders = getOutputFolders(project);
249 IPath classOutputFolder = null;
250 for (IPath outputFolder : outputFolders) {
251 if (outputFolder.isPrefixOf(classPath)) {
252 classOutputFolder = outputFolder;
253 break;
254 }
255 }
256 if (classOutputFolder == null)
257 return null;
258
259 classPath = classPath.removeFirstSegments(classOutputFolder.segmentCount());
260
261 String sPath = classPath.toString();
262 sPath = sPath.substring(0, sPath.length() - classPath.getFileExtension().length() - 1);
263 if (!keepInner) {
264 int iDollar = sPath.indexOf('$');
265 if (iDollar != -1)
266 sPath = sPath.substring(iDollar);
267 }
268 sPath += ".java";
269
270 return new Path(sPath);
271 }
272
273 public static JavaClassInfo getJavaClassInfo(IJavaProject project, Class<?> clazz) {
274 try {
275 URI clazzUri = ClassUtil.findResource(clazz).toURI();
276 URI projectUri = getProjectURI(project.getProject());
277 URI relativeURI = projectUri.relativize(clazzUri);
278 return getJavaClassInfo(project, project.getProject().getFile(relativeURI.toString()));
279 } catch (Exception e) {
280 return null;
281 }
282 }
283
284 public static JavaClassInfo getJavaClassInfo(IJavaProject project, IFile resource) throws CoreException {
285 // classPath = "<project name>/<output folder>/<package>/<file>.class"
286 IPath classPath = resource.getFullPath().makeRelative();
287
288 // Find output folder: "<project name>/<output folder>".
289 IPath outputFolder = null;
290 if (project.getOutputLocation() != null && project.getOutputLocation().isPrefixOf(classPath))
291 outputFolder = project.getOutputLocation();
292 else {
293 for (IClasspathEntry cpe : project.getRawClasspath()) {
294 if (cpe.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
295 IPath output = cpe.getOutputLocation();
296 if (output != null && output.isPrefixOf(classPath)) {
297 outputFolder = output;
298 break;
299 }
300 }
301 }
302 }
303
304 if (outputFolder == null)
305 return null;
306
307 // Compute class name.
308 IPath relativeClassPath = classPath.removeFirstSegments(outputFolder.segmentCount());
309 IPath relativeClassName = relativeClassPath.removeFileExtension();
310 String className = relativeClassName.toPortableString().replace('/', '.');
311
312 // Compute java source path: "<package>/<class name>[$<inner class>].java".
313 String javaFullPath = relativeClassName.addFileExtension("java").toPortableString();
314 String javaFilePath = javaFullPath;
315 int iDollar = javaFilePath.indexOf('$');
316 if (iDollar != -1)
317 javaFilePath = javaFilePath.substring(0, iDollar) + ".java";
318
319 IJavaElement javaElement = project.findElement(new Path(javaFilePath));
320 if (javaElement == null)
321 return null;
322
323 IJavaElement sourceFolder = javaElement.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
324 if (sourceFolder == null)
325 return null;
326
327 IPath folderPath = sourceFolder.getPath().makeRelative();
328 if (folderPath.segmentCount() > 0)
329 folderPath = folderPath.removeFirstSegments(1);
330
331 // Fix issues with project not in the workspace directory.
332 outputFolder = project.getProject().getWorkspace().getRoot().findMember(outputFolder).getLocation();
333
334 return new JavaClassInfo(
335 folderPath.toPortableString(),
336 javaFullPath,
337 className,
338 new File(outputFolder.toPortableString(), relativeClassPath.toPortableString())
339 );
340 }
341
342 public static IStatus createErrorStatus(String message) {
343 return new Status(IStatus.ERROR, GraniteActivator.PLUGIN_ID, message);
344 }
345
346 public static IStatus createErrorStatus(String message, Throwable t) {
347 return new Status(IStatus.ERROR, GraniteActivator.PLUGIN_ID, IStatus.OK, message, t);
348 }
349
350 public static class CpEntry {
351
352 public enum CpeKind {
353 PROJECT_OUTPUT_DIR,
354 SOURCE_OUTPUT_DIR,
355 CONTAINER_JAR,
356 LIB_JAR
357 }
358
359 private final String description;
360 private final IPath path;
361 private final File file;
362 private final CpeKind kind;
363 private final List<CpEntry> children = new ArrayList<CpEntry>();
364
365 public CpEntry(String description, IPath path, File file, CpeKind kind) {
366 this.description = description;
367 this.path = path;
368 this.file = file;
369 this.kind = kind;
370 }
371
372 public String getDescription() {
373 return description;
374 }
375
376 public IPath getPath() {
377 return path;
378 }
379
380 public File getFile() {
381 return file;
382 }
383
384 public CpeKind getKind() {
385 return kind;
386 }
387
388 public List<CpEntry> getChildren() {
389 return children;
390 }
391
392 public boolean exists() {
393 return (file != null && file.exists());
394 }
395
396 public URL toURL() throws IOException {
397 if (file == null)
398 return null;
399 return file.getCanonicalFile().toURI().toURL();
400 }
401
402 @Override
403 public String toString() {
404 return "[" + kind + "] " + path + " -> " + file;
405 }
406 }
407 }