package org.infinispan.tools.doclet.jmx;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.infinispan.jmx.annotations.MBean;
import org.infinispan.jmx.annotations.ManagedAttribute;
import org.infinispan.jmx.annotations.ManagedOperation;
import org.infinispan.tools.doclet.html.HtmlGenerator;
import com.sun.javadoc.AnnotationDesc;
import com.sun.javadoc.AnnotationTypeDoc;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.DocErrorReporter;
import com.sun.javadoc.FieldDoc;
import com.sun.javadoc.LanguageVersion;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.Parameter;
import com.sun.javadoc.RootDoc;
import com.sun.tools.doclets.standard.Standard;
import com.sun.tools.javadoc.Main;
/**
* A Doclet that generates a guide to all JMX components exposed by Infinispan
*
* @author Manik Surtani
* @since 4.0
*/
public class JmxDoclet {
private static String outputDirectory;
private static String encoding;
private static String bottom;
private static String footer;
private static String header;
private static String title;
public static void main(String[] args) {
String name = JmxDoclet.class.getName();
Main.execute(name, name, args);
}
public static boolean start(RootDoc root) throws IOException {
ClassDoc[] classes = root.classes();
List<MBeanComponent> mbeans = new LinkedList<MBeanComponent>();
for (ClassDoc cd : classes) {
MBeanComponent mbean = toJmxComponent(cd);
if (mbean != null)
mbeans.add(mbean);
}
// sort components alphabetically
Collections.sort(mbeans);
HtmlGenerator generator = new JmxHtmlGenerator(encoding, jmxTitle(), bottom, footer, header,
"JMX components exposed by Infinispan", Arrays.asList("JMX", "Infinispan", "Data Grids", "Documentation",
"Reference", "MBeans", "Management", "Console"), mbeans);
generator.generateHtml(new File(outputDirectory, "jmxComponents.html").getAbsolutePath());
return true;
}
public static LanguageVersion languageVersion() {
return LanguageVersion.JAVA_1_5;
}
public static int optionLength(String option) {
return Standard.optionLength(option);
}
public static boolean validOptions(String options[][], DocErrorReporter reporter) {
for (String[] option : options) {
if (option[0].equals("-d"))
outputDirectory = option[1];
else if (option[0].equals("-encoding"))
encoding = option[1];
else if (option[0].equals("-bottom"))
bottom = option[1];
else if (option[0].equals("-footer"))
footer = option[1];
else if (option[0].equals("-header"))
header = option[1];
else if (option[0].equals("-doctitle"))
title = option[1];
}
return Standard.validOptions(options, reporter);
}
private static String jmxTitle() {
String s = "JMX Components";
if (title.length() == 0)
return s;
else {
s += " (" + title + ")";
return s;
}
}
private static MBeanComponent toJmxComponent(ClassDoc cd) {
boolean isMBean = false;
MBeanComponent mbc = new MBeanComponent();
mbc.className = cd.qualifiedTypeName();
mbc.name = cd.typeName();
for (AnnotationDesc a : cd.annotations()) {
AnnotationTypeDoc atd = a.annotationType();
String annotationName = atd.qualifiedTypeName();
if (annotationName.equals(MBean.class.getName())) {
isMBean = true;
setNameDesc(a.elementValues(), mbc);
}
}
// now to test method level annotations
for (MethodDoc method : cd.methods()) {
for (AnnotationDesc a : method.annotations()) {
String annotationName = a.annotationType().qualifiedTypeName();
if (annotationName.equals(ManagedOperation.class.getName())) {
isMBean = true;
MBeanOperation o = new MBeanOperation();
o.name = method.name();
setNameDesc(a.elementValues(), o);
o.returnType = method.returnType().simpleTypeName();
for (Parameter p : method.parameters())
o.addParam(p.type().simpleTypeName());
mbc.operations.add(o);
} else if (annotationName.equals(ManagedAttribute.class.getName())) {
isMBean = true;
MBeanAttribute attr = new MBeanAttribute();
// if this is a getter, look at the return type
if (method.name().startsWith("get") || method.name().startsWith("is")) {
attr.type = method.returnType().simpleTypeName();
} else if (method.parameters().length > 0) {
attr.type = method.parameters()[0].type().simpleTypeName();
}
attr.name = fromBeanConvention(method.name());
setNameDesc(a.elementValues(), attr);
setWritable(a.elementValues(), attr);
mbc.attributes.add(attr);
}
}
}
// and field level annotations
for (FieldDoc field : cd.fields(false)) {
for (AnnotationDesc a : field.annotations()) {
String annotationName = a.annotationType().qualifiedTypeName();
if (annotationName.equals(ManagedAttribute.class.getName())) {
isMBean = true;
MBeanAttribute attr = new MBeanAttribute();
attr.name = field.name();
attr.type = field.type().simpleTypeName();
setNameDesc(a.elementValues(), attr);
setWritable(a.elementValues(), attr);
mbc.attributes.add(attr);
}
}
}
if (isMBean) {
Collections.sort(mbc.attributes);
Collections.sort(mbc.operations);
return mbc;
} else {
return null;
}
}
private static String fromBeanConvention(String getterOrSetter) {
if (getterOrSetter.startsWith("get") || getterOrSetter.startsWith("set")) {
String withoutGet = getterOrSetter.substring(4);
// not specifically BEAN convention, but this is what is bound in JMX.
return Character.toUpperCase(getterOrSetter.charAt(3)) + withoutGet;
} else if (getterOrSetter.startsWith("is")) {
String withoutIs = getterOrSetter.substring(3);
return Character.toUpperCase(getterOrSetter.charAt(2)) + withoutIs;
}
return getterOrSetter;
}
private static void setNameDesc(AnnotationDesc.ElementValuePair[] evps, JmxComponent mbc) {
for (AnnotationDesc.ElementValuePair evp : evps) {
if (evp.element().name().equals("objectName")) {
mbc.name = evp.value().value().toString();
} else if (evp.element().name().equals("name")) {
mbc.name = evp.value().value().toString();
} else if (evp.element().name().equals("description")) {
mbc.desc = evp.value().value().toString();
}
}
}
private static void setWritable(AnnotationDesc.ElementValuePair[] evps, MBeanAttribute attr) {
for (AnnotationDesc.ElementValuePair evp : evps) {
if (evp.element().name().equals("writable")) {
attr.writable = (Boolean) evp.value().value();
}
}
}
}