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 021package org.granite.builder.util; 022 023import static org.granite.builder.GraniteBuilder.FLEX_BUILDER_ID; 024import static org.granite.builder.GraniteBuilder.GRANITE_BUILDER_ID; 025 026import java.io.File; 027import java.io.IOException; 028import java.net.URI; 029import java.net.URL; 030import java.util.ArrayList; 031import java.util.Arrays; 032import java.util.Comparator; 033import java.util.List; 034 035import org.eclipse.core.resources.ICommand; 036import org.eclipse.core.resources.IFile; 037import org.eclipse.core.resources.IProject; 038import org.eclipse.core.resources.IResource; 039import org.eclipse.core.resources.IWorkspace; 040import org.eclipse.core.resources.IWorkspaceRoot; 041import org.eclipse.core.runtime.CoreException; 042import org.eclipse.core.runtime.IPath; 043import org.eclipse.core.runtime.IStatus; 044import org.eclipse.core.runtime.Path; 045import org.eclipse.core.runtime.Status; 046import org.eclipse.jdt.core.IClasspathContainer; 047import org.eclipse.jdt.core.IClasspathEntry; 048import org.eclipse.jdt.core.IJavaElement; 049import org.eclipse.jdt.core.IJavaProject; 050import org.eclipse.jdt.core.JavaCore; 051import org.granite.builder.GraniteActivator; 052import org.granite.util.ClassUtil; 053 054/** 055 * @author Franck WOLFF 056 */ 057public 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}