/**
* Copyright 2004-2016 Riccardo Solmi. All rights reserved.
* This file is part of the Whole Platform.
*
* The Whole Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Whole Platform is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whole.gen.util;
import java.io.File;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.ISourceReference;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.ToolFactory;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.formatter.CodeFormatter;
import org.eclipse.jface.text.Document;
import org.eclipse.text.edits.TextEdit;
import org.whole.lang.bindings.IBindingManager;
import org.whole.lang.iterators.IEntityIterator;
import org.whole.lang.iterators.IteratorFactory;
import org.whole.lang.java.factories.JavaEntityFactory;
import org.whole.lang.java.model.JavaSystemSoftware;
import org.whole.lang.java.util.JDTTransformerVisitor;
import org.whole.lang.model.IEntity;
import org.whole.lang.operations.JavaCompilerOperation;
import org.whole.lang.reflect.ReflectionFactory;
import org.whole.lang.util.IRunnable;
/**
* @author Riccardo Solmi, Enrico Persiani
*/
public class JDTUtils {
public static enum JAVA_FRAGMENT {
COMPILATION_UNIT(ASTParser.K_COMPILATION_UNIT, CompilationUnit.class),
CLASS_BODY_DECLARATIONS(ASTParser.K_CLASS_BODY_DECLARATIONS, TypeDeclaration.class),
STATEMENTS(ASTParser.K_STATEMENTS, Block.class),
EXPRESSION(ASTParser.K_EXPRESSION, Expression.class);
public final int kind;
public final Class<?> type;
JAVA_FRAGMENT(int kind, Class<?> type) {
this.kind = kind;
this.type = type;
}
}
public static ASTNode parse(String source) {
for (JAVA_FRAGMENT f : JAVA_FRAGMENT.values()) {
try {
return parseAs(source, f);
} catch (IllegalArgumentException e) {}
}
throw new IllegalArgumentException();
}
public static CompilationUnit parseAsCompilationUnit(String source) {
return (CompilationUnit) parseAs(source, JAVA_FRAGMENT.COMPILATION_UNIT);
}
public static ASTNode parseAs(String source, JAVA_FRAGMENT f) {
ASTParser parser = ASTParser.newParser(AST.JLS8);
parser.setKind(f.kind);
parser.setSource(source.toCharArray());
ASTNode astNode = parser.createAST(null);
if (f.type.isInstance(astNode) && isValid(astNode))
return astNode;
else
throw new IllegalArgumentException();
}
private static boolean isValid(ASTNode astNode) {
return !(astNode instanceof CompilationUnit && ((CompilationUnit) astNode).types().isEmpty()) &&
!(astNode instanceof Block && ((Block) astNode).statements().isEmpty());
}
public static String asString(ASTNode astNode) {
return astNode.toString();
}
public static Document asDocument(ASTNode astNode) {
return new Document(asString(astNode));
}
public static String asFormattedString(ASTNode astNode) {
return asFormattedDocument(astNode, CodeFormatter.K_UNKNOWN).get();
}
public static String asFormattedString(CompilationUnit cu) {
return asFormattedDocument(cu).get();
}
public static Document asFormattedDocument(CompilationUnit cu) {
return asFormattedDocument(cu, CodeFormatter.K_COMPILATION_UNIT);
}
public static Document asFormattedDocument(Statement stm) {
return asFormattedDocument(stm, CodeFormatter.K_STATEMENTS);
}
public static Document asFormattedDocument(Expression exp) {
return asFormattedDocument(exp, CodeFormatter.K_EXPRESSION);
}
@SuppressWarnings("unchecked")
public static Document asFormattedDocument(ASTNode astNode, int kind) {
String source = asString(astNode);
Document document = new Document(source);
Map<String, String> options = JavaCore.getOptions();
options.put(JavaCore.COMPILER_SOURCE, "1.5");
options.put(JavaCore.COMPILER_COMPLIANCE, "1.5");
options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, "1.5");
CodeFormatter formatter = ToolFactory.createCodeFormatter(options);
TextEdit textEdit = formatter.format(kind, source, 0, source.length(), 0, null);
try {
textEdit.apply(document);
} catch (Exception e) {
throw new IllegalArgumentException();
}
return document;
}
public static String getTypeName(CompilationUnit cu) {
if (cu.types().isEmpty())
return "";
String packageName = cu.getPackage().getName().toString();
String typeName = ((TypeDeclaration)cu.types().get(0)).getName().getIdentifier();
return packageName+"."+typeName;
}
public static void save(CompilationUnit cu, IPackageFragmentRoot packageFragmentRoot, IProgressMonitor monitor) throws JavaModelException {
if (cu.types().isEmpty())
return;
String packageName = cu.getPackage().getName().toString();
String typeName = ((TypeDeclaration)cu.types().get(0)).getName().getIdentifier();
IPackageFragment packageFragment = packageFragmentRoot.createPackageFragment(packageName, true, monitor);
packageFragment.createCompilationUnit(typeName+".java", asFormattedString(cu), true, monitor);
}
public static IEntityIterator<IEntity> generateJavaSystemSoftware() {
return IteratorFactory.singleValuedRunnableIterator(new IRunnable() {
public void run(IEntity selfEntity, IBindingManager bm, IEntity... arguments) {
final List<CompilationUnit> cuList = JavaCompilerOperation.compile(selfEntity, bm);
final JavaSystemSoftware javaSystemSoftware = JavaEntityFactory.instance.createJavaSystemSoftware(0);
for (CompilationUnit cu : cuList)
javaSystemSoftware.add((org.whole.lang.java.model.CompilationUnit) JDTTransformerVisitor.transform(cu));
bm.setResult(javaSystemSoftware);
}
});
}
public static IWorkspaceRoot getWorkspaceRoot() {
return ResourcesPlugin.getWorkspace().getRoot();
}
public static IPackageFragmentRoot getPackageFragmentRoot(String locationPath) {
return getPackageFragmentRoot(new Path(locationPath));
}
public static IPackageFragmentRoot getPackageFragmentRoot(IPath location) {
IContainer container = getWorkspaceRoot().getContainerForLocation(location);
if (container == null)
throw new IllegalArgumentException();
return getPackageFragmentRoot(container);
}
public static IPackageFragmentRoot getPackageFragmentRoot(IContainer container) {
IProject proj = container.getProject();
try {
if (!proj.hasNature(JavaCore.NATURE_ID))
throw new IllegalArgumentException();
IJavaProject jProject = JavaCore.create(proj);
if (jProject == null || !jProject.exists())
throw new IllegalArgumentException();
return jProject.getPackageFragmentRoot(container);
} catch (CoreException e) {
throw new IllegalArgumentException();
}
}
public static String findSourceAttachment(ISourceReference sourceReference) {
try {
return sourceReference.getSource();
} catch (JavaModelException e) {
return null;
}
}
public static ISourceReference findSourceReference(String className, IJavaProject javaProject) {
try {
return javaProject.findType(className).getCompilationUnit();
} catch (JavaModelException e) {
return null;
}
}
public static String getCompilationUnitName(IFile compilationUnitFile) {
IProject prj = compilationUnitFile.getProject();
try {
if (!prj.hasNature(JavaCore.NATURE_ID))
return null;
IJavaProject jProject = JavaCore.create(prj);
IClasspathEntry cpes[] = jProject.getResolvedClasspath(true);
for (IClasspathEntry cpe : cpes) {
IPath filePath = compilationUnitFile.getFullPath();
IPath cpePath = cpe.getPath();
if (cpe.getEntryKind() == IClasspathEntry.CPE_SOURCE && cpePath.isPrefixOf(filePath)) {
IPath path = filePath.removeFirstSegments(cpePath.segmentCount()).removeFileExtension();
StringBuilder sb = new StringBuilder();
String[] segments = path.segments();
for (int i=0; i<segments.length; i++) {
if (i>0)
sb.append('.');
sb.append(segments[i]);
}
return sb.toString();
}
}
} catch (CoreException e) {
throw new IllegalArgumentException("Cannot retrieve "+compilationUnitFile+" fully qualified class name", e);
}
throw new IllegalArgumentException("Missing top-level type declaration in "+compilationUnitFile);
}
public static Class<?> loadCompilationUnit(IBindingManager bm) {
IFile compilationUnitFile = (IFile) bm.wGetValue("file");
ClassLoader ideClassLoader = ReflectionFactory.getClassLoader(bm);
return loadCompilationUnit(compilationUnitFile, ideClassLoader);
}
public static Class<?> loadCompilationUnit(IFile compilationUnitFile, ClassLoader classLoader) {
IProject project = compilationUnitFile.getProject();
try {
if (!project.hasNature(JavaCore.NATURE_ID))
return null;
IJavaElement javaElement = JavaCore.create(compilationUnitFile);
if(javaElement instanceof ICompilationUnit) {
ICompilationUnit compilationUnit = ((ICompilationUnit)javaElement);
IType[] types = compilationUnit.getTypes();
for(IType type : types) {
Class<?> clazz = classLoader.loadClass(type.getFullyQualifiedName());
if(clazz != null && !clazz.isAnonymousClass() && !clazz.isMemberClass())
return clazz;
}
}
} catch (Exception e) {
}
return null;
}
public static ClassLoader createClassLoader(IJavaProject javaProject, boolean override) {
ClassLoader platformClassLoader = ReflectionFactory.getPlatformClassLoader();
String outputLocation = null;
String[] projectClassPath;
try {
IPath outputPath = javaProject.getOutputLocation();
if (override && outputPath != null)
outputLocation = ResourcesPlugin.getWorkspace().getRoot().getFolder(outputPath).getLocation().toPortableString();
projectClassPath = computeDefaultRuntimeClassPath(javaProject);
} catch (CoreException e) {
return platformClassLoader;
}
List<URL> projectCPEntries = new ArrayList<URL>(projectClassPath.length);
for(int i=0; i<projectClassPath.length; i++) {
try {
projectCPEntries.add(new File(projectClassPath[i]).toURI().toURL());
} catch (MalformedURLException e) {
}
}
return new URLClassLoader(projectCPEntries.toArray(new URL[0]),
outputLocation != null ?
new FilteringClassLoader(new FolderClassFilter(outputLocation), platformClassLoader) :
platformClassLoader);
}
public static IJavaProject getJavaProject(IProject project) {
try {
return JavaCore.create(project);
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
}
public static IJavaProject getJavaProject(String projectName) {
return getJavaProject(ResourcesPlugin.getWorkspace().getRoot().getProject(projectName));
}
public static String[] computeDefaultRuntimeClassPath(IJavaProject javaProject) throws JavaModelException {
// try {
// IClasspathEntry[] rawClasspath = javaProject.getRawClasspath();
// for (IClasspathEntry entry : rawClasspath) {
// JavaCore.getClasspathContainer(entry.getPath(), javaProject);
// }
// String[] locations = new String[resolvedClasspath.length];
// for (int i = 0; i < resolvedClasspath.length; i++) {
// IClasspathEntry entry = resolvedClasspath[i];
// IPath path = entry.getPath();
// locations[i] = path.toString();
// }
// return locations;
// } catch (Exception e) {
try {
Class<?> javaRuntimeClass = Class.forName("org.eclipse.jdt.launching.JavaRuntime", true, ReflectionFactory.getPlatformClassLoader());
Method method = javaRuntimeClass.getMethod("computeDefaultRuntimeClassPath", IJavaProject.class);
String[] originals = (String[]) method.invoke(null, javaProject);
return originals;
} catch (Exception e2) {
}
// }
return new String[] { javaProject.getCorrespondingResource().getLocation().toString()+"/bin"};
}
}