/*
* Copyright 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.util.compat;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.VariableTree;
import com.sun.source.util.JavacTask;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Member;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import javax.lang.model.element.Modifier;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
public class CoreExtractorAST {
private static int counter = 0;
private static String tempdir = "japicv";
public static List<ClassNode> extract(File sourceRoot) throws IOException {
return extract(sourceRoot, new ArrayList<ClassNode>(),
new ArrayList<String>());
}
public static List<ClassNode> extract(File sourceRoot, List<ClassNode>
exclusions, List<String> exclusionPkgs) throws IOException {
List<ClassNode> retValue = new ArrayList<ClassNode>();
if (sourceRoot.getCanonicalPath().endsWith(".jar"))
sourceRoot = constructTemp(sourceRoot);
List<File> files = new ArrayList<File>();
constructFileTree(sourceRoot, files);
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
JavacTask task = (JavacTask)compiler.getTask(null, null, null, null, null,
compiler.getStandardFileManager(null, null, null)
.getJavaFileObjectsFromFiles(files));
for (CompilationUnitTree c : task.parse()) {
boolean pkgConsider = true;
String currentPkg = c.getPackageName().toString();
for (String pkgname : exclusionPkgs)
if (currentPkg.startsWith(pkgname)) {
pkgConsider = false;
break;
}
if (pkgConsider)
for (Tree rt : c.getTypeDecls())
retValue.addAll(parseClass((ClassTree)rt, currentPkg, "", exclusions));
}
Collections.sort(retValue);
return retValue;
}
private static List<ClassNode> parseClass(ClassTree root, String pkgname,
String parent, List<ClassNode> exclusions) {
List<ClassNode> retValue = new ArrayList<ClassNode>();
Set<Modifier> flags = root.getModifiers().getFlags();
if (!(flags.contains(Modifier.PUBLIC) || flags.contains(Modifier.PROTECTED)))
return retValue;
ClassNode current = new ClassNode(pkgname,
parent + root.getSimpleName().toString(), flags);
for (Tree iface : root.getImplementsClause())
current.addInterface(iface.toString());
if (root.getExtendsClause() != null)
current.setParent(root.getExtendsClause().toString());
for (Tree member : root.getMembers())
if (member.getKind() == Tree.Kind.VARIABLE) {
VariableTree vtree = (VariableTree)member;
Set<Modifier> mods = vtree.getModifiers().getFlags();
FieldNode fn = getField(vtree);
int index = exclusions.indexOf(current);
if (index >= 0 && exclusions.get(index).fields.contains(fn))
continue;
if (mods.contains(Modifier.PUBLIC) || mods.contains(Modifier.PROTECTED))
current.addField(fn);
}
else if (member.getKind() == Tree.Kind.METHOD) {
MethodTree mtree = (MethodTree)member;
Set<Modifier> mods = mtree.getModifiers().getFlags();
if (mods.contains(Modifier.PUBLIC) || mods.contains(Modifier.PROTECTED)) {
List<FieldNode> params = new ArrayList<FieldNode>();
for (VariableTree vt : mtree.getParameters())
params.add(getField(vt));
String mname = mtree.getName().toString();
if (mname.equals("<init>"))
mname = root.getSimpleName().toString();
MethodNode mn = new MethodNode(mname, mtree.getReturnType(), mods,
params);
MethodNode mExcluded = null;
try {
List<MethodNode> temp = exclusions.get(exclusions.indexOf(current)).methods;
mExcluded = temp.get(temp.indexOf(mn));
} catch(IndexOutOfBoundsException e) {}
if (mExcluded != null && mExcluded.exceptions.isEmpty())
continue;
for (ExpressionTree et : mtree.getThrows())
if (!(mExcluded != null && mExcluded.exceptions.contains(et.toString())))
mn.addException(et.toString());
current.addMethod(mn);
}
}
else if (member.getKind() == Tree.Kind.CLASS)
retValue.addAll(parseClass((ClassTree)member, pkgname,
current.name + ".", exclusions));
if (exclusions.contains(current)) {
ClassNode temp = exclusions.get(exclusions.indexOf(current));
if (temp.fields.isEmpty() && temp.methods.isEmpty())
return retValue;
}
current.done();
retValue.add(current);
return retValue;
}
private static FieldNode getField(VariableTree vt) {
return new FieldNode(vt.getName().toString(), vt.getType().toString(),
vt.getModifiers().getFlags());
}
private static void constructFileTree(File current, List<File> list) {
if (current.isFile() && current.getName().endsWith(".java"))
list.add(current);
else if (current.isDirectory())
for (File f : current.listFiles())
constructFileTree(f, list);
}
private static File constructTemp(File sourceRoot) throws IOException {
String tempRootPath = System.getProperty("java.io.tmpdir") + File.separator +
tempdir + (++counter) + File.separator;
File tempRoot = new File(tempRootPath);
tempRoot.mkdir();
tempRoot.deleteOnExit();
JarFile jar = new JarFile(sourceRoot);
Enumeration<JarEntry> en = jar.entries();
JarEntry je;
while (en.hasMoreElements()) {
je = en.nextElement();
File current = new File(tempRootPath + je.getName());
current.deleteOnExit();
if (je.isDirectory())
current.mkdirs();
if (je.getName().endsWith(".java")) {
current.createNewFile();
BufferedReader in = new BufferedReader(new InputStreamReader(jar.getInputStream(je)));
BufferedWriter out = new BufferedWriter(new FileWriter(current));
while (in.ready()) {
out.write(in.readLine());
out.newLine();
}
out.close();
in.close();
}
}
return tempRoot;
}
}