package com.subhajit.eclipse.util;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IJavaModelMarker;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.progress.IProgressService;
import org.jdom.JDOMException;
import com.subhajit.common.classloaders.URLClassLoaderX;
import com.subhajit.common.javacompiler.Compiler.CodeLevel;
import com.subhajit.common.util.CommonUtils;
import com.subhajit.common.util.IConstants;
import com.subhajit.common.util.IProgress;
import com.subhajit.eclipse.entities.CompiledJar;
import com.subhajit.eclipse.entities.EclipseClasspath;
import com.subhajit.eclipse.entities.EclipseMetafile;
import com.subhajit.eclipse.entities.EclipseProject;
import com.subhajit.eclipse.swt.SwtDialog;
import com.subhajit.eclipse.swt.SwtProgressImpl;
import com.sun.idm.svc.common.xmlutil.XmlUtils;
public class ProjectUtils {
private static final URL[] ZERO_LENGTH_URL_ARRAY = new URL[0];
private ProjectUtils() {
super();
}
/**
* Convenient organization of build related methods.
*
* @author sdasgupta
*
*/
public static class BuildUtils {
/**
* Builds the given java project and all its dependencies in the correct
* order using the {@link IncrementalProjectBuilder}.
*
* @param javaProject
* @throws Exception
*/
public static Map<IJavaProject, IMarker[]> buildProjectInteractively0(
final IJavaProject javaProject, final int buildKind)
throws Exception {
final Map<IJavaProject, IMarker[]> problems = new HashMap<IJavaProject, IMarker[]>();
final List<Exception> exceptionHolder = new ArrayList<Exception>();
IWorkbench wb = PlatformUI.getWorkbench();
IProgressService ps = wb.getProgressService();
ps.busyCursorWhile(new IRunnableWithProgress() {
public void run(IProgressMonitor progressMonitor) {
try {
IProgress progress = new SwtProgressImpl(
progressMonitor);
ProjectUtils.updateProjectLocations(progress);
List<IJavaProject> dependentProjects = BuildUtils
.getDependentProjects(javaProject, progress);
progress.setRange(0, dependentProjects.size());
int index = 0;
for (IJavaProject project : dependentProjects) {
progress.increment(1, "Building "
+ project.getProject().getName());
BuildUtils.buildJavaProjectInteractively0(project,
progress, buildKind, problems);
progress.setRange(0, dependentProjects.size());
for (int i = 0; i < index; i++) {
progress.increment(1, "");
}
index++;
}
BuildUtils.buildJavaProjectInteractively0(javaProject,
progress, buildKind, problems);
} catch (Exception exc) {
exceptionHolder.add(exc);
}
}
});
if (!exceptionHolder.isEmpty()) {
SwtDialog.show(exceptionHolder.get(0));
}
return problems;
}
private static void buildJavaProjectInteractively0(
final IJavaProject javaProject, IProgress progress,
int buildKind, Map<IJavaProject, IMarker[]> markers)
throws InvocationTargetException, InterruptedException {
try {
IProgressMonitor progressMonitor = ((SwtProgressImpl) progress)
.getProgressMonitor();
javaProject.getProject().clearHistory(progressMonitor);
javaProject.getProject().refreshLocal(IResource.DEPTH_INFINITE,
null);
if (progressMonitor != null) {
progressMonitor.subTask("Building "
+ javaProject.getProject().getName());
}
javaProject.getProject().build(buildKind, progressMonitor);
IMarker[] problemMarkers = javaProject.getUnderlyingResource()
.findMarkers(
IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER,
true, IResource.DEPTH_INFINITE);
if (problemMarkers.length != 0) {
markers.put(javaProject, problemMarkers);
}
} catch (CoreException exc) {
exc.printStackTrace();
}
}
private static List<IJavaProject> getDependentProjects(
final IJavaProject javaProject, IProgress progress)
throws IOException, JDOMException, InterruptedException {
int[] initialProgressRange = null;
if (progress != null) {
initialProgressRange = progress.getRange();
}
try {
if (progress != null) {
progress.setRange(0, 2);
progress.increment(1, "Computing project dependencies");
}
final File projectFile = ProjectUtils
.getProjectFile(javaProject);
EclipseProject eclipseProject = new EclipseProject(projectFile);
EclipseMetafile[] metafiles = eclipseProject.getAllDependants();
List<IJavaProject> projects = new ArrayList<IJavaProject>();
if (progress != null) {
progress.setRange(0, metafiles.length);
}
for (EclipseMetafile metafile : metafiles) {
if (progress != null) {
progress.increment(1, "Inspecting "
+ metafile.getFile().getAbsolutePath());
}
if (metafile instanceof EclipseProject) {
projects.add(ProjectUtils
.getJavaProject(((EclipseProject) metafile)
.getFile()));
}
}
return projects;
} finally {
if (progress != null) {
progress.setRange(initialProgressRange[0],
initialProgressRange[1]);
}
}
}
}
public static File getProjectFile(final IJavaProject javaProject) {
return new File(javaProject.getProject().getLocation().toFile(),
".project");
}
public static IJavaProject getJavaProject(final File projectFile)
throws IOException {
try {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceRoot root = workspace.getRoot();
final String projectName = XmlUtils.loadElement(projectFile)
.getChild("name").getText().trim();
IProject project = root.getProject(projectName);
IJavaProject ret = JavaCore.create(project);
try {
project.create(null);
} catch (CoreException exc) {
}
try {
project.open(null);
} catch (CoreException exc) {
}
return ret;
} catch (JDOMException exc) {
throw new RuntimeException(exc);
}
}
/**
* Returns a Set containing the project locations of all projects loaded in
* this workspace.
*
* @param javaProject
* @return
* @throws IOException
*/
// protected static Set<String> getProjectLocations() throws IOException {
// // Get the base directories of all projects in the workspace.
// IWorkspace workspace = ResourcesPlugin.getWorkspace();
// IProject[] projects = workspace.getRoot().getProjects();
// Set<String> projectLocations = new HashSet<String>();
// for (IProject project : projects) {
// File projectLocation = project.getProject().getLocation().toFile();
// projectLocations.add(projectLocation.getParentFile()
// .getCanonicalPath());
// }
// return projectLocations;
// }
protected static Set<File> getDirectoriesContainingProjects()
throws IOException {
// Get the base directories of all projects in the workspace.
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IProject[] projects = workspace.getRoot().getProjects();
Set<File> projectLocations = new HashSet<File>();
for (IProject project : projects) {
File projectLocation = project.getProject().getLocation().toFile();
projectLocations.add(projectLocation.getParentFile()
.getCanonicalFile());
}
return projectLocations;
}
public static Set<File> getProjectLocations() throws IOException {
// Get the base directories of all projects in the workspace.
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IProject[] projects = workspace.getRoot().getProjects();
Set<File> projectLocations = new HashSet<File>();
for (IProject project : projects) {
File projectLocation = project.getProject().getLocation().toFile();
projectLocations.add(projectLocation.getCanonicalFile());
}
return projectLocations;
}
public static void updateProjectLocations(IProgress... progresses)
throws IOException {
Set<File> projectLocations = getDirectoriesContainingProjects();
for (IProgress progress : progresses) {
progress.setRange(0, projectLocations.size());
}
StringBuilder str = new StringBuilder();
int index = 0;
for (File projectLocation : projectLocations) {
for (IProgress progress : progresses) {
progress.increment(1, "Updating project info - "
+ projectLocation.getAbsolutePath());
}
str.append(projectLocation.getCanonicalPath());
index++;
if (index < projectLocations.size()) {
str.append(IConstants.COMMA);
}
}
for (IProgress progress : progresses) {
progress.increment(1, "Updated project info.");
}
System.setProperty(EclipseProject.PROJECT_LOCATIONS_SYSTEM_PROPERTIES,
str.toString());
}
public static final URLClassLoader getClassLoader(
final IJavaProject javaProject, boolean rebuildProject)
throws Exception {
final File projectFile = getProjectFile(javaProject);
if (rebuildProject) {
BuildUtils.buildProjectInteractively0(javaProject,
IncrementalProjectBuilder.FULL_BUILD);
} else {
BuildUtils.buildProjectInteractively0(javaProject,
IncrementalProjectBuilder.INCREMENTAL_BUILD);
}
// return new URLClassLoaderX(EclipseProjectBuilder
// .computeProjectOutputURLs(projectFile).toArray(
// ZERO_LENGTH_URL_ARRAY), ProjectUtils.class
// .getClassLoader());
List<URL> urls = new ArrayList<URL>();
EclipseProject project = new EclipseProject(projectFile);
urls.add(project.getOutputDirectory().toURI().toURL());
for (EclipseMetafile dependent : project.getAllDependants()) {
if (dependent instanceof CompiledJar) {
urls.add(((CompiledJar) dependent).getFile().toURI().toURL());
} else if (dependent instanceof EclipseProject) {
EclipseProject dependentProject = (EclipseProject) dependent;
urls.add(dependentProject.getOutputDirectory().toURI().toURL());
} else if (dependent instanceof EclipseClasspath) {
// EclipseClasspath classpath = ( EclipseClasspath )dependent;
}
}
return new URLClassLoaderX(urls.toArray(ZERO_LENGTH_URL_ARRAY));
}
// public static URLClassLoader getClassLoader(final File projectFile,
// boolean rebuildProject) throws Exception, IOException,
// JDOMException, InterruptedException {
// if (rebuildProject) {
// buildProjectInteractively(projectFile);
// }
// return new URLClassLoader(EclipseProjectBuilder
// .computeProjectOutputURLs(projectFile).toArray(
// ZERO_LENGTH_URL_ARRAY), ProjectUtils.class
// .getClassLoader());
// }
public static CodeLevel getTargetCompilerVersion(IJavaProject javaProject) {
String value = (String) javaProject.getOptions(true).get(
"org.eclipse.jdt.core.compiler.codegen.targetPlatform");
if (value == null) {
value = "1.6";
}
if (value.equals("1.5")) {
return CodeLevel.ONE_FIVE;
} else if (value.equals("1.6")) {
return CodeLevel.ONE_SIX;
} else {
throw new UnsupportedOperationException(
"Class version not supported - " + value);
}
}
public static Set<EclipseProject> getAllEclipseProjectsInWorkspace()
throws IOException, JDOMException, InterruptedException {
Set<File> projectLocations = getProjectLocations();
Set<EclipseProject> allEclipseProjects = new HashSet<EclipseProject>();
for (File projectLocation : projectLocations) {
try {
allEclipseProjects.add(new EclipseProject(new File(
projectLocation.getAbsolutePath(), ".project")));
} catch (Exception exc) {
// This project could not be loaded correctly.
System.out
.println("While trying to create EclipseProject from project location "
+ projectLocation.getAbsolutePath() + ":");
exc.printStackTrace(System.out);
}
}
return allEclipseProjects;
}
/**
* Returns all elements of <tt>problems</tt> that have a severity of
* {@link IMarker#SEVERITY_ERROR}.
*
* @param problems
* @return
* @throws CoreException
*/
public static Map<IJavaProject, List<IMarker>> getProblemMarkers(
Map<IJavaProject, IMarker[]> problems) throws CoreException {
Map<IJavaProject, List<IMarker>> ret = new HashMap<IJavaProject, List<IMarker>>();
for (Map.Entry<IJavaProject, IMarker[]> entry : problems.entrySet()) {
List<IMarker> problemMarkers = new ArrayList<IMarker>();
for (IMarker marker : entry.getValue()) {
@SuppressWarnings("unchecked")
Map<String, Object> attributes = marker.getAttributes();
if (attributes.containsKey(IMarker.SEVERITY)
&& attributes.get(IMarker.SEVERITY).equals(
IMarker.SEVERITY_ERROR)) {
problemMarkers.add(marker);
}
}
if (!problemMarkers.isEmpty()) {
ret.put(entry.getKey(), problemMarkers);
}
}
return ret;
}
/**
* Locates the {@link Method} corresponding to the given
* <tt>sourceMethod</tt>.
*
* @param classLoader
* @param className
* @param sourceMethod
* @return
* @throws ClassNotFoundException
*/
public static Method locateMethod(URLClassLoader classLoader,
String className, IMethod sourceMethod)
throws ClassNotFoundException {
Class<?> klass = Class.forName(className, true, classLoader);
Method[] declaredMethods = klass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
if (declaredMethod.getName().equals(sourceMethod.getElementName())
&& declaredMethod.getParameterTypes().length == sourceMethod
.getParameterTypes().length) {
int index = 0;
boolean parameterTypesMatch = true;
for (String sourceMethodParameterType : sourceMethod
.getParameterTypes()) {
String simpleTypeName = Signature
.toString(sourceMethodParameterType);
boolean typesAreEqual = false;
String simpleArgumentType = null;
if (declaredMethod.getParameterTypes()[index].isArray()) {
int dim = 0;
Class<?> klass0 = declaredMethod.getParameterTypes()[index];
while (klass0.isArray()) {
klass0 = klass0.getComponentType();
dim++;
}
simpleArgumentType = klass0.getName();
for (int i = 0; i < dim; i++) {
simpleArgumentType += "[]";
}
} else {
simpleArgumentType = declaredMethod.getParameterTypes()[index]
.getName();
}
if (simpleTypeName.indexOf(".") != -1) {
if (simpleArgumentType.equals(simpleTypeName)) {
typesAreEqual = true;
}
} else {
if (CommonUtils.getClassNameSansPackage(
simpleArgumentType).equals(simpleTypeName)) {
typesAreEqual = true;
}
}
index++;
if (!typesAreEqual) {
parameterTypesMatch = false;
break;
}
}
if (parameterTypesMatch) {
return declaredMethod;
}
}
}
return null;
}
}