// Tags - make a tags table by reflection
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or (at your option)
// any later version.
// So here’s how to generate the home directory’s tags file:
// javac -d ~/ Tags.java
// java -cp ~/:$JAVA_HOME/jre/lib/rt.jar Tags "java.*"
// or java Tags
// then it will generate a file ~/.java_base.tag in your home
// This program 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 General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; see the file COPYING. If not, write to the
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
//Sometimes you may see some exceptions like:
//
//java.lang.ClassNotFoundException: org.apache.log4j.pattern.BridgePatternParser
//
//that means this class is not in your classpath or some imported class in
//org.apache.log4j.pattern.BridgePatternParser is not in your classpath,
//you must find out all jars it depends on ,and put it in your classpath.
//or if you think this class is not very important ,you can just ignore this
//exception, it will not be indexed.
//maybe this link may do help to you :http://www.findjar.com
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
import java.util.regex.*;
import java.util.jar.*;
import java.util.zip.*;
/** Make a tags table from the class files in a classpath.
* The classpath is obtained from the property java.class.path
*
* The class names that get output must match the packageFilter
* if it is specified.
*
* @author joseph
*/
public class Tags {
BufferedWriter tagFile=null;
PrintWriter logError=null;
PrintWriter logInfo=null;
List clss= new LinkedList();
List pkgs=new LinkedList();
List classes=new LinkedList();
List members=new LinkedList();
String fileSeparator=System.getProperty("file.separator");
int shift=6;
public Tags(){
try {
tagFile = new BufferedWriter(new FileWriter (new File(System.getProperty("user.home"),".java_base.tag"))) ;
logError= new PrintWriter(new File(System.getProperty("java.io.tmpdir"), "ajc_error.log")) ;
logInfo= new PrintWriter(new File(System.getProperty("java.io.tmpdir"), "ajc_info.log")) ;
}catch (Exception e){
System.err.print(e.getMessage());
}
}
private void log(Throwable e){
System.err.println("cause:"+e.getCause()+" "+ e.getClass().getName()+":"+ e.getMessage());
e.printStackTrace(logError);
}
private void logInfo(String info){
logInfo.println(info);
}
/** If this is not null it's used as a filter for acceptable classes.
* Only packages that matches(packageFilter)
will be tagged.
*/
protected String packageFilter;
File randomTmpPath = new File(System.getProperty("java.io.tmpdir")+File.separatorChar+UUID.randomUUID().toString()+File.separatorChar);
ClassLoader cl = new CL(randomTmpPath);
//copy $CLASSPATH/**.class to randomTmpPath
//unzip $CLASSPATH/**.jar to randomTmpPath
//CLASSLOADER CL will load class from this directory.
private void prepare(){
String classpath=System.getProperty("java.class.path");
String [] cls=classpath.split( System.getProperty("path.separator"));
for (int i=0;i clazzFiles =IOUtils.getAllFilesUnderDir
(randomTmpPath, new FileFilter(){public boolean accept(File f){
if (f.getName().endsWith(".class")) return true;
return false;
}});
for(File clazz:clazzFiles){
String classAbsolutePath=clazz.getAbsolutePath();
String classFullName = classAbsolutePath
.substring(dirFullPath.length()+1 , classAbsolutePath.indexOf(".class") )
.replace(fileSeparator,".");
processClass(classFullName);
}
tagAll();
write();
}
clear();
}
private void processJarFile (File f) {
Unzip.unzip(f ,randomTmpPath);
System.out.println("adding "+f.getAbsolutePath() +" to classpath...");
// JarFile jar=null;
// try { jar = new JarFile(f); } catch (IOException e) {log(e);}
// Enumeration en = jar.entries();
// int i = 0;
// while (en.hasMoreElements()){
// ZipEntry z = (ZipEntry) en.nextElement();
// String name = z.getName();
// if (name.indexOf(".class") < 0) continue;
// name= name.substring(0, name.lastIndexOf(".class"));
// String className= name.replace("/", ".");
// processClass(className);
// }
}
/**
@param className full className
*/
private void processClass(String className){
if (packageFilter != null && !(className.matches(packageFilter))) return;
if (className.startsWith("sun")) return;
if (className.startsWith("com.sun")) return;
if (className.startsWith("com.thaiopensource")) return;
if (className .contains("org.iso_relax.ant")) return;
if (className .contains("$")) return;
try{
// Class c = Class.forName(className,false,ClassLoader.getSystemClassLoader()) ;
Class c = Class.forName(className ,false,cl);
clss.add(c);
} catch(Throwable t){
log(t);
}
}
/** Find class file and jar in the directory.
* and process the found class file and jar file with processJar,and processClass
*/
private void processDirectory (File dir){
if (dir!=null &&dir.isDirectory()){
String dirFullPath=dir.getAbsolutePath();
List clazzFiles =IOUtils.getAllFilesUnderDir
(dir, new FileFilter(){public boolean accept(File f){
if (f.getName().endsWith(".class")) return true;
return false;
}});
for(File clazz:clazzFiles){
String classAbsolutePath=clazz.getAbsolutePath();
IOUtils.copy(clazz,new File(randomTmpPath ,classAbsolutePath.substring(dirFullPath.length()+1) ));
// String classFullName = classAbsolutePath
// .substring(dirFullPath.length()+1 , classAbsolutePath.indexOf(".class") )
// .replace(fileSeparator,".");
// processClass(classFullName);
}
List jarz =IOUtils.getAllFilesUnderDir( dir,
new FileFilter(){
public boolean accept(File f){
if (f.getName().endsWith(".jar")) return true;
return false;
}
});
// File [] jarz=dir.listFiles(
// new FileFilter(){
// public boolean accept(File f){
// if (f.getName().endsWith(".jar")) return true;
// return false;
// }
// }
// );
if(jarz!=null){
for(File jarFile:jarz){
processJarFile(jarFile);
}
}
}
}
private void tagAll(){
System.out.println("found "+clss.size() +" classes.");
try {
for (Class c :clss){
try {
ClassItem cItem=tagClass(c);
classes.add(cItem);
}catch(ApplicationException e){
logInfo(e.getMessage());
}catch (Throwable ex) {log(ex);}
}
Collections.sort(pkgs);
Collections.sort(classes);
System.out.println("tagged "+classes.size() +" classes.");
for (ClassItem cItem:classes){
try {
List localMems=tagConstructors(cItem);
localMems.addAll(tagMethods(cItem));
localMems.addAll(tagFields(cItem));
cItem.members=localMems;
}catch(ApplicationException e){
logInfo(e.getMessage());
}catch (Throwable ex) {log(ex);}
}
int pkg_size=pkgs.size();
int classes_size=classes.size();
PackageItem pkgItem=null;
ClassItem cItem=null;
for(int i=0;i tagFields(ClassItem cItem)throws Throwable {
Field[] fields =cItem.cls.getDeclaredFields();
List localMems=new ArrayList();
for (int i = 0; i < fields.length; i++){
if (!Modifier.isPublic(fields[i].getModifiers())){
continue;
}
Class fieldType=(Class) fields[i].getType();
ClassItemWrapper returnType=getClassItemWrapper(fieldType);
MemberItem memItem= new MemberItem();
memItem.cItem=cItem;
memItem.name=fields[i].getName();
memItem.returnType =returnType;
memItem.field=fields[i];
localMems.add(memItem);
}
return localMems;
}
private List tagConstructors(ClassItem cItem)throws Throwable {
Constructor[] methods = cItem.cls.getDeclaredConstructors();
List localMems=new ArrayList();
for (int i = 0; i < methods.length; i++){
if (! Modifier.isPublic(methods[i].getModifiers())) continue;
MemberItem memItem = new MemberItem();
memItem.constructor=methods[i];
String name=methods[i ].getName() ;
if(name.contains(".")){
memItem.name=name.substring(name.lastIndexOf(".")+1);
}else{
memItem.name=name;
}
memItem.cItem=cItem;
Class[] params = methods[i].getParameterTypes();
List paramsKV=new ArrayList();
for(Class param:params) paramsKV.add(getClassItemWrapper(param));
memItem.params=paramsKV;
Class[] exceptions= methods[i].getExceptionTypes();
List exceptionsKV=new ArrayList();
for(Class e:exceptions) exceptionsKV.add(getClassItemWrapper(e));
memItem.exceptions=exceptionsKV;
localMems.add(memItem);
}
return localMems;
}
private List tagMethods(ClassItem cItem) throws Throwable{
// Method[] methods = cItem.cls.getDeclaredMethods();
Method[] methods = cItem.cls.getMethods();
List localMems=new ArrayList();
for (int i = 0; i < methods.length; i++){
if (! Modifier.isPublic(methods[i].getModifiers())) continue;
MemberItem memItem = new MemberItem();
memItem.method=methods[i];
memItem.name=methods[i].getName();
memItem.cItem=cItem;
memItem.returnType=getClassItemWrapper(methods[i].getReturnType());
Class[] params = methods[i].getParameterTypes();
List paramsKV=new ArrayList();
for(Class param:params) paramsKV.add(getClassItemWrapper(param));
memItem.params=paramsKV;
Class[] exceptions= methods[i].getExceptionTypes();
List exceptionsKV=new ArrayList();
for(Class e:exceptions) exceptionsKV.add(getClassItemWrapper(e));
memItem.exceptions=exceptionsKV;
localMems.add(memItem);
}
return localMems;
}
private void write(){
try{
tagFile.append("don't try to edit this file ,even this line!!!!") ;tagFile.newLine();
tagFile.append("package count="+pkgs.size() +" ,Class count="+classes.size() +" , member count(constructor, field, method)= "+members.size() );tagFile.newLine();
tagFile.append(""+ (shift+1));tagFile.newLine();
tagFile.append(""+(shift+pkgs.size()+1));tagFile.newLine();
tagFile.append(""+ (shift+pkgs.size()+classes.size()+1)); tagFile.newLine();
tagFile.append(""+ (shift+pkgs.size() +classes.size()+members.size()+1 ));tagFile.newLine();
int i=0;
for(PackageItem pkgItem:pkgs){
tagFile.append(pkgItem.toString());
tagFile.newLine();
if (i%300==0 ) tagFile.flush();
i++;
}
tagFile.flush();
i=0;
for(ClassItem cItem:classes){
tagFile.append(cItem.toString());
tagFile.newLine();
if (i%300==0 ) tagFile.flush();
i++;
}
tagFile.flush();
i=0;
for(MemberItem mi:members){
tagFile.append(mi.toString());
tagFile.newLine();
if (i%300==0 ) tagFile.flush();
i++;
}
tagFile.flush();
}catch(Exception e){
System.err.println(e.getMessage());
}finally{
try{tagFile.close(); tagFile=null;}catch(Exception e){e.printStackTrace();}
try{logError.close(); logError=null;}catch(Exception e){e.printStackTrace();}
try{logInfo.close(); logInfo=null;}catch(Exception e){e.printStackTrace();}
}
}
public static void main (String[] argv) throws Exception {
System.out.println(
"*****************************************************************\n"+
"** this program will need about 3 to 5 min , **\n"+
"** maybe half an hour ,(just kidding),but you must be patient.**\n" +
"** before it exit,you may see a few exceptions **\n" +
"** If it don't kill the program ,just ignore it . **\n" +
"** and when you add a jar to classpath, you'd better make sure**\n" +
"** all jars it depends on are in classpath. **\n" +
"******************************************************************\n"
);
System.out.println("log file is located at: " +System.getProperty("java.io.tmpdir")+ "/ajc_error.log");
System.out.println("log file is located at: " +System.getProperty("java.io.tmpdir")+ "/ajc_info.log\n\n");
System.out.println(
"******************************************************************************\n"+
"*** you can use this Class like this: ***\n"+
"*** java Tags com.company.* ***\n"+
"*** java -cp yourclasspath Tags ***\n"+
"*** only those package name starts with com.company will be tagged. ***\n"+
"*** or all jar file in $CLASSPATH will be tagged . ***\n"+
"*** before that you'd better backup the file ~/.java_base.tag,if exists***\n"+
"******************************************************************************\n"
);
System.out.println("if you see java.lang.OutOfMemoryError: PermGen space ,you can increment permsize:");
System.out.println(" java -XX:MaxPermSize=512m Tags");
// System.out.println("sleep 20 seconds...");
// try {
// Thread.sleep(20000);
// } catch (Exception ex) {}
Tags tags = new Tags();
if (argv.length > 0) tags.packageFilter = argv[0];
tags.process() ;
System.out.println(
"\n*********************************************************************\n"+
"*** exit successful!!! ***\n"+
"***you will see a file named '.java_base.tag' in your home directory***\n"+
"***********************************************************************\n"
);
System.out.println(new File (System.getProperty("user.home"), ".java_base.tag").getAbsolutePath());
System.exit(0);
}
}
class PackageItem implements Comparable{
String name;
int lineNum;
int classStartLineNum;
int classEndLineNum;
Package pkg;
public int compareTo(PackageItem pkgItem){
return this.name.compareTo(pkgItem.name);
}
public String toString(){
return this.name+"`"+this.classStartLineNum+"`"+this.classEndLineNum;
}
}
class ClassItem implements Comparable {
String name ;
int lineNum;
int memStartLineNum;
int memEndLineNum;
Class cls;
PackageItem pkgItem;
List members;
public int compareTo(ClassItem cItem){
int pkgCmp=this.pkgItem.name.compareTo(cItem.pkgItem.name);
if( pkgCmp!=0) return pkgCmp;
return (this.name.compareTo(cItem.name));
}
public int hashCode(){
if (this.pkgItem==null||this.pkgItem.name==null) return this.name.hashCode();
return (this.name+"."+this.pkgItem.name).hashCode();
}
public boolean equals(Object obj){
if (obj==null) return false;
if(!(obj instanceof ClassItem)) return false;
ClassItem other=(ClassItem) obj;
if(this.pkgItem==null &&other.pkgItem==null &&this.name!=null) return this.name.equals(other.name);
if(this.pkgItem!=null&&other.pkgItem!=null&&this.name!=null&&this.name.equals(other.name) &&this.pkgItem.name!=null&&this.pkgItem.name.equals(other.pkgItem.name)){
return true;
}
return false;
}
public String toString(){
return this.name+"`"+this.pkgItem.lineNum+"`"+this.memStartLineNum+"`"+this.memEndLineNum;
}
}
class MemberItem implements Comparable{
String name;
ClassItem cItem;
int lineNum;
List params;
List exceptions ;
ClassItemWrapper returnType;
Field field;
Method method;
Constructor constructor;
public String toString(){
StringBuffer returnStr=new StringBuffer();
if (constructor!=null){
returnStr.append(" "+name+"`");
//append params
if (params!=null){
for(ClassItemWrapper param:params){
if(param.alternativeString!=null) returnStr.append("~"+param.alternativeString+",");
else returnStr.append(param.cItem.lineNum+",");
}
if(params.size()>0) returnStr.deleteCharAt(returnStr.length()-1);
}
returnStr.append("`");
//append exceptions
if (exceptions!=null){
for(ClassItemWrapper exp:exceptions){
if(exp.alternativeString!=null) returnStr.append("~"+exp.alternativeString+",");
else returnStr.append(exp.cItem.lineNum+",");
}
if( exceptions.size()>0) returnStr.deleteCharAt(returnStr.length()-1);
}
}else if(field!=null){
returnStr.append(" "+name+"`");
// returnStr.append(cItem.lineNum+"`");
//apend the field type
if(returnType.alternativeString!=null) returnStr.append("~"+returnType.alternativeString);
else returnStr.append(returnType.cItem.lineNum);
}else if (method!=null){
returnStr.append(name+"`");
//append returnType
if(returnType.alternativeString!=null) {
returnStr.append("~"+returnType.alternativeString);
} else {
if(returnType.cItem==null){
System.out.println("mem.name="+name);
System.out.println(method.getDeclaringClass().getName());
}
returnStr.append(returnType.cItem.lineNum);
}
returnStr.append("`");
//append params
if (params!=null){
for(ClassItemWrapper param:params){
if(param.alternativeString!=null) returnStr.append("~"+param.alternativeString+",");
else returnStr.append(param.cItem.lineNum+",");
}
if(params.size()>0) returnStr.deleteCharAt(returnStr.length()-1);
}
returnStr.append("`");
//append exceptions
if (exceptions!=null){
for(ClassItemWrapper exp:exceptions){
if(exp.alternativeString!=null) returnStr.append("~"+exp.alternativeString+",");
else returnStr.append(exp.cItem.lineNum+",");
}
if( exceptions.size()>0) returnStr.deleteCharAt(returnStr.length()-1);
}
}
return returnStr.toString();
}
public int compareTo(MemberItem memItem){
int classCompareResult=cItem.compareTo(memItem.cItem);
if (classCompareResult!=0){
return classCompareResult;
}
if (this.field!=null){
if (memItem.field==null) return -1;
return this.name.compareTo(memItem.name);
}else {
if(memItem.method==null) return 1;
return this.name.compareTo(memItem.name);
}
}
}
class ClassItemWrapper{
ClassItem cItem;
String alternativeString;
}
class ApplicationException extends Exception{
public ApplicationException(String msg){
super(msg);
}
}
class Unzip {
/** unzip zip file to sDestPath
* @param sZipPathFile :path of zip file
* @param sDestPath :path ,where to put the ectracted files
*
*/
public static void unzip(File sZipPathFile, File sDestPath){
try{
FileInputStream fins = new FileInputStream(sZipPathFile);
ZipInputStream zins = new ZipInputStream(fins);
ZipEntry ze = null;
byte ch[] = new byte[256];
while((ze = zins.getNextEntry()) != null){
File zfile = new File(sDestPath , ze.getName());
File fpath = new File(zfile.getParentFile().getPath());
if(ze.isDirectory()){
if(!zfile.exists())
zfile.mkdirs();
zins.closeEntry();
}else{
if(!fpath.exists())
fpath.mkdirs();
FileOutputStream fouts = new FileOutputStream(zfile);
int i;
while((i = zins.read(ch)) != -1)
fouts.write(ch,0,i);
zins.closeEntry();
fouts.close();
}
}
fins.close();
zins.close();
}catch(Exception e){
System.err.println("Extract error(maybe bad zip(jar) file.):" + e.getMessage());
}
}
// public static void main(String[] args) {
// // TODO Auto-generated method stub
// Unzip z = new Unzip();
// z.unzip("/tmp/a.zip", "/tmp/d/");
// }
}
class CL extends ClassLoader{
private File classBasePath=null;
public CL(File classBasePath ){
this.classBasePath=classBasePath;
if(!classBasePath.exists()){
classBasePath.mkdirs();
}
}
public Class> findClass(String name)throws ClassNotFoundException{
File classFile=new File(classBasePath, name.replace(".",File.separator)+".class");
if(!classFile.exists()) throw new ClassNotFoundException("Can't find class:"+name);
// Add the package information
final int packageIndex = name.lastIndexOf('.') ;
if (packageIndex != -1) {
final String packageName = name.substring(0, packageIndex) ;
final Package classPackage = getPackage(packageName) ;
if (classPackage == null) { definePackage(packageName, null, null, null, null, null, null, null) ; }
}
byte[] classByte= new byte[(int)classFile.length()];
FileInputStream fis=null;
try {
fis = new FileInputStream(classFile);
fis.read(classByte);
return defineClass(name, classByte, 0, classByte.length);
} catch (IOException ex) {
throw new ClassNotFoundException("Can't find class:"+name);
} finally {
IOUtils.close(fis);
}
}
}
class IOUtils{
/**
* find out all readable files under dir recursively
*/
public static List getAllFilesUnderDir(File dir, final FileFilter fileFilter) {
FileFilter acceptDirFileFilterWrapper = new FileFilter(){
public boolean accept(File f) {
if (f.isDirectory()) return true;
return fileFilter.accept(f);
}
};
ArrayList files = new ArrayList();
Stack s = new Stack();
s.push(dir);
File tmp = null;
while (!s.isEmpty()) {
tmp = s.pop();
if (tmp.isDirectory() && tmp.canRead() && tmp.canExecute()) {
File[] cs = tmp.listFiles(acceptDirFileFilterWrapper);
for (File c : cs) {
s.push(c);
}
} else if (tmp.isFile() && tmp.canRead()) {
files.add(tmp);
}
}
return files;
}
/**
* delete file or directory recursively.
*/
public static void del(File f) {
if(f.exists() && f.isDirectory()){
if(f.listFiles().length==0){
f.delete();
}else{
File delFile[]=f.listFiles();
int i =f.listFiles().length;
for(int j=0;j