aQute.bnd.make.calltree.CalltreeResource Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bndlib Show documentation
Show all versions of bndlib Show documentation
A Swiss Army Knife for OSGi
package aQute.bnd.make.calltree;
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
import aQute.lib.osgi.*;
/**
* Create an XML call tree of a set of classes. The structure of the XML is:
*
*
* calltree ::= <using> <usedby>
* using ::= <method> *
* usedby ::= <method> *
* method ::= <ref>
*
*
* The using
element contains methods in the set of classes and
* their references. The usedby
element contains the used methods
* and their references to the set of classes. The ref
element
* contains the class, the method name, the descriptor, and a pretty print
* version of the method.
*
* The XML does not contain an XML processor instruction to make it easier to
* include in other XML. The encoding is always UTF-8.
*
* This class can be used as a resource, just add it to a JAR and the data is
* generated when the resource is written (saving time when the JAR is up to
* date and does not have to be generated). However, the actual write method is
* a static method and can be called as well:
* {@link #writeCalltree(PrintWriter, Collection)}.
*/
public class CalltreeResource extends WriteResource {
Collection classes;
/**
* Create a resource for inclusion that will print a call tree.
*
* @param values the classes for which the call tree is generated.
*/
public CalltreeResource(Collection values) {
this.classes = values;
System.out.println(values);
}
/**
* We set the last modified to 0 so this resource does not force
* a new JAR if all other resources are up to date.
*/
public long lastModified() {
return 0;
}
/**
* The write method is called to write the resource. We just call the static
* method.
*/
public void write(OutputStream out) throws Exception {
OutputStreamWriter osw = new OutputStreamWriter(out, Constants.DEFAULT_CHARSET);
PrintWriter pw = new PrintWriter(osw);
try {
writeCalltree(pw, classes);
} finally {
pw.flush();
}
}
/**
* Print the call tree in XML.
*
* @param out The output writer
* @param classes The set of classes
* @throws IOException Any errors
*/
public static void writeCalltree(PrintWriter out, Collection classes)
throws Exception {
final Map> using = new TreeMap>();
final Map> usedby = new TreeMap>();
ClassDataCollector cd = new ClassDataCollector() {
Clazz.MethodDef source;
// Before a method is parsed
public void method(Clazz.MethodDef source) {
this.source = source;
xref(using, source, null);
xref(usedby, source, null);
}
// For any reference in the previous method.
public void reference(Clazz.MethodDef reference) {
xref(using, source, reference);
xref(usedby, reference, source);
}
};
for (Clazz clazz : classes) {
clazz.parseClassFileWithCollector(cd);
}
out.println("");
xref(out, "using", using);
xref(out, "usedby", usedby);
out.println(" ");
}
/*
* Add a new reference
*/
private static void xref(
Map> references,
Clazz.MethodDef source, Clazz.MethodDef reference) {
Set set = references.get(source);
if (set == null)
references.put(source, set=new TreeSet());
if ( reference != null)
set.add(reference);
}
/*
* Print out either using or usedby sets
*/
private static void xref(PrintWriter out, String group,
Map> references) {
out.println(" <" + group + ">");
for (Map.Entry> entry : references
.entrySet()) {
Clazz.MethodDef source = entry.getKey();
Set refs = entry.getValue();
method(out, "method", source, ">");
for (Clazz.MethodDef ref : refs) {
method(out, "ref", ref, "/>");
}
out.println(" ");
}
out.println(" " + group + ">");
}
/*
* Print out a method.
*/
private static void method(PrintWriter out, String element,
Clazz.MethodDef source, String closeElement) {
out.println(" <" + element + " class='" + source.clazz + "'"
+ getAccess(source.access) +
( source.isConstructor() ? "" : " name='" + source.name + "'") + " descriptor='" + source.descriptor + "' pretty='"
+ source.getPretty() + "'" + closeElement);
}
private static String getAccess(int access) {
StringBuilder sb = new StringBuilder();
if ( Modifier.isPublic(access) )
sb.append(" public='true'");
if ( Modifier.isStatic(access) )
sb.append(" static='true'");
if ( Modifier.isProtected(access) )
sb.append(" protected='true'");
if ( Modifier.isInterface(access) )
sb.append(" interface='true'");
return sb.toString();
}
}