import java.io.*;
import java.lang.*;
import java.lang.reflect.*;
import java.util.*;
import java.util.jar.*;
import java.util.zip.ZipEntry;
import java.text.Collator;
/**
* Builds Api file for use with SciTe.
* Note: Classes to be processed must be in your CLASSPATH
*
* @author Alex Nazimok
* @version 1.1
*/
public class ApiBuilder
{
private static ArrayList fileList = new ArrayList();
private static boolean appendToFile = false;
private static boolean isJar = false;
private static final int MAX_OPTIONS = 2;
/**
* main method
*/
public static void main(String args[])
throws Exception
{
ApiBuilder apiB = new ApiBuilder();
if (args.length < 2)
printUsage();
int argNum = 0;
for(int i = 0; i < MAX_OPTIONS; i++)
{
if(args[i].equals("-a"))
{
appendToFile = true;
argNum++;
}
if(args[i].equals("-j"))
{
isJar = true;
argNum++;
}
if(args[i].equals("-s"))
{
apiB.sortApiFile(args[1]);
return;
}
}
System.out.println("\n-----------------------------------------------");
System.out.println("Starting processing...");
if(!isJar)
apiB.buildFileList(new File(args[argNum]));
else
apiB.processJar(args[argNum]);
apiB.writeToFile(args[argNum], args[++argNum]);
System.out.println("Done...");
System.out.println("-----------------------------------------------\n");
}
/**
* Creates a list of all of the methods for basedir .class files.
* TODO: I am not sure at this point what the best way to handle inner
* classes is so I am just replacing '$' with '.'
*/
private List buildMethodList(String baseDir)
throws Exception
{
List methodList = new ArrayList();
for (int i = 0; i < fileList.size(); i++)
{
String className = formatClassName(fileList.get(i).toString(), baseDir);
Class clazz = getClass().getClassLoader().loadClass(className);
if (clazz != null)
{
Method methods[] = clazz.getMethods();
for (int j = 0; j < methods.length; j++)
{
String sig = (methods[j].getName()).replace('$', '.') + "(";
Class[] params = methods[j].getParameterTypes();
for (int k = 0; k < params.length; k++)
sig += formatParams(params[k].getName());
if (sig.lastIndexOf(",") == sig.length() - 1)
sig = sig.substring(0, sig.length() - 1);
sig += ")";
if (!methodList.contains(sig))
methodList.add(sig);
}
}
}
return methodList;
}
/**
* Creates a list of all of the constructors for basedir .class files.
*/
private List buildConstructorList(String baseDir)
throws Exception
{
List methodList = new ArrayList();
for (int i = 0; i < fileList.size(); i++)
{
String className = formatClassName(fileList.get(i).toString(), baseDir);
Class clazz = getClass().getClassLoader().loadClass(className);
if (clazz != null)
{
String packName = null;
try{packName = clazz.getPackage().getName();}
catch(Exception e){}
Constructor methods[] = clazz.getConstructors();
for (int j = 0; j < methods.length; j++)
{
String constName = (methods[j].getName()).replace('$', '.');
if (packName != null && packName.length() > 0)
constName = constName.substring(constName.indexOf(packName) + packName.length() + 1);
String sig = constName + "(";
Class[] params = methods[j].getParameterTypes();
for (int k = 0; k < params.length; k++)
sig += formatParams(params[k].getName());
if (sig.lastIndexOf(",") == sig.length() - 1)
sig = sig.substring(0, sig.length() - 1);
sig += ")";
if (!methodList.contains(sig))
methodList.add(sig);
}
}
}
return methodList;
}
/**
* Replaces arrays classloader representation with real values
*/
private String formatParams(String paramName)
{
String name = "";
if (paramName.startsWith("[B"))
name = "byte[],";
else if (paramName.startsWith("[C"))
name = "char[],";
else if (paramName.startsWith("[D"))
name = "double[],";
else if (paramName.startsWith("[F"))
name = "float[],";
else if (paramName.startsWith("[I"))
name = "int[],";
else if (paramName.startsWith("[J"))
name = "long[],";
else if (paramName.startsWith("[S"))
name = "short[],";
else if (paramName.startsWith("[Z"))
name = "boolean[],";
else if (paramName.startsWith("[L"))
name = paramName.substring(2, paramName.indexOf(";")) + "[],";
else
name = paramName + ",";
return name.replace('$', '.');
}
/**
* Sorts methods and constructors lists and writes them to file.
*/
private void writeToFile(String baseDir, String outputFile)
throws Exception
{
RandomAccessFile output = new RandomAccessFile(outputFile, "rw");
if (appendToFile)
output.seek(output.length());
PrintWriter bw = new PrintWriter(new FileWriter(output.getFD()));
List methodList = buildMethodList(baseDir);
List constructorList = buildConstructorList(baseDir);
List all = new ArrayList();
all.addAll(methodList);
all.addAll(constructorList);
Collections.sort(all, new CaseCompareator());
for (int j = 0; j < all.size(); j++)
{
bw.println((String) all.get(j));
bw.flush();
}
bw.close();
}
/**
* Builds list of .class files to be processed (recursively)
*/
private void buildFileList(File baseDir)
{
String files[] = baseDir.list();
if(files == null || files.length == 0)
{
System.out.println("\nUnable to find .class files in " + baseDir);
printUsage();
}
for (int i = 0; i < files.length; i++)
{
File f = new File(baseDir, files[i]);
if (f.isDirectory())
buildFileList(f);
if (f.getName().endsWith(".class"))
if (!fileList.contains(f))
fileList.add(f);
}
}
/**
* Builds a className from filename passed in.
* @param f File to be processed
* @param baseDir based directory for the file being processed.
* It is stripped out from class name.
* @return className
*
*/
private String formatClassName(String fileName, String baseDir)
{
fileName = fileName.replace('\\', '/');
if(!isJar)
fileName = fileName.substring(fileName.indexOf(baseDir) + baseDir.length(), fileName.indexOf(".class"));
else
fileName = fileName.substring(0, fileName.indexOf(".class"));
fileName = fileName.replace('/', '.');
return (fileName.startsWith(".") ? fileName.substring(1) : fileName);
}
/**
* Builds list of files from Jar File.
* Jar File must be in your CLASSPATH
*/
private void processJar(String jarFile)
throws Exception
{
JarFile jar = new JarFile(jarFile);
for(Enumeration e = jar.entries(); e.hasMoreElements();)
{
String fileName = ((ZipEntry)e.nextElement()).getName();
if(fileName.endsWith(".class"))
if(!fileList.contains(fileName))
fileList.add(fileName);
}
}
private static void printUsage()
{
System.out.println("\nUsage: ApiBuilder [option]