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    }