blob: 636442f73e4ba46340fbf60823c1fa820c858df4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.vysper.compliance.reporting;
import static java.util.Collections.emptySet;
import static java.util.Collections.unmodifiableCollection;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.apache.vysper.compliance.SpecCompliance;
import org.apache.vysper.compliance.SpecCompliant;
import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.apt.AnnotationProcessorFactory;
import com.sun.mirror.apt.Filer;
import com.sun.mirror.declaration.AnnotationTypeDeclaration;
import com.sun.mirror.declaration.ClassDeclaration;
import com.sun.mirror.declaration.Declaration;
import com.sun.mirror.declaration.FieldDeclaration;
import com.sun.mirror.declaration.MemberDeclaration;
import com.sun.mirror.declaration.MethodDeclaration;
import com.sun.mirror.declaration.TypeDeclaration;
/**
* this generates from all SpecCompliant annotations a HTML doc to show what parts of the spec are covered.
* The table is sorted by implemented spec section and links out to the spec and the apidocs.
*
* apt can be invoked like this (tools.jar must be on the classpath)
* apt -cp build/ant/classes;lib/* -s src/main/java -factory org.apache.vysper.compliance.reporting.DocumentSpecCompliantAnnotationFactory
* it generates a file spec_compliance.html in src/main/java
*
* @author The Apache MINA Project (dev@mina.apache.org)
*/
public class DocumentSpecCompliantAnnotationFactory implements AnnotationProcessorFactory {
// Process any set of annotations
private static final Collection<String> supportedAnnotations = unmodifiableCollection(Arrays
.asList("org.apache.vysper.compliance.*"));
// No supported options
private static final Collection<String> supportedOptions = emptySet();
public Collection<String> supportedAnnotationTypes() {
return supportedAnnotations;
}
public Collection<String> supportedOptions() {
return supportedOptions;
}
public AnnotationProcessor getProcessorFor(Set<AnnotationTypeDeclaration> atds, AnnotationProcessorEnvironment env) {
return new SpecCompliantClassAP(env);
}
private static class SpecCompliantClassAP implements AnnotationProcessor {
protected final AnnotationProcessorEnvironment env;
protected AnnotationTypeDeclaration specCompliantAnnotation;
protected AnnotationTypeDeclaration specCompliantCollectionAnnotation;
protected Map<String, SpecDoc> map = new TreeMap<String, SpecDoc>();
protected PrintWriter fileWriter;
SpecCompliantClassAP(AnnotationProcessorEnvironment env) {
this.env = env;
specCompliantAnnotation = (AnnotationTypeDeclaration) env
.getTypeDeclaration("org.apache.vysper.compliance.SpecCompliant");
specCompliantCollectionAnnotation = (AnnotationTypeDeclaration) env
.getTypeDeclaration("org.apache.vysper.compliance.SpecCompliance");
try {
fileWriter = env.getFiler().createTextFile(Filer.Location.SOURCE_TREE, "",
new File("spec_compliance.html"), null);
} catch (IOException e) {
throw new RuntimeException("could not write to output file", e);
}
}
public void process() {
// Retrieve all declarations with SpecCompliant annotations
Collection<Declaration> declarations = env.getDeclarationsAnnotatedWith(specCompliantAnnotation);
System.out.println("number of solitairy @SpecCompliant: " + declarations.size());
for (Declaration declaration : declarations) {
final SpecDoc doc = new SpecDoc(declaration, declaration.getAnnotation(SpecCompliant.class));
map.put(doc.getKey(), doc);
}
// Retrieve all SpecCompliance-typed declarations and extract SpecCompliant annotations
Collection<Declaration> moreDeclarations = env
.getDeclarationsAnnotatedWith(specCompliantCollectionAnnotation);
System.out.println("number of @SpecCompliance: " + moreDeclarations.size());
for (Declaration declaration : moreDeclarations) {
final SpecCompliance compliance = declaration.getAnnotation(SpecCompliance.class);
final SpecCompliant[] specCompliants = compliance.compliant();
for (SpecCompliant specCompliant : specCompliants) {
if (specCompliant == null)
continue;
final SpecDoc doc = new SpecDoc(declaration, specCompliant);
map.put(doc.getKey(), doc);
}
}
// visit every annotation fromt the now sorted map
// write the HTML file
fileWriter
.println("<html><head>"
+ "<link rel='stylesheet' type='text/css' href='http://yui.yahooapis.com/2.7.0/build/reset-fonts-grids/reset-fonts-grids.css'>\n"
+ "<link rel='stylesheet' type='text/css' href='http://yui.yahooapis.com/2.7.0/build/base/base-min.css'>\n"
+ "</head><body><table><thead><th>spec</th><th>section</th><th>package</th><th>class</th><th>field/method/etc.</th><th>coverage</th><th>implementation</th><th>comment</th></thead>");
for (String key : map.keySet()) {
fileWriter.print("<tr>");
System.out.println(key);
final SpecDoc doc = map.get(key);
// spec
fileWriter.print("<td>");
final String specURL = doc.getSpecDocURL();
if (specURL != null)
fileWriter.print("<a href='" + specURL + "'>");
final String specDoc = doc.getSpecDoc();
if (specDoc != null)
fileWriter.print(specDoc);
if (specURL != null)
fileWriter.print("</a>");
fileWriter.print("</td>");
// spec section
fileWriter.print("<td>");
String specSection = doc.getSpecSection();
if (specSection != null && specSection.length() > 0) {
if (specSection.endsWith("."))
specSection = specSection.substring(0, specSection.length() - 1);
String anchorLink = Character.isDigit(specSection.charAt(0)) ? "#section-" : "#appendix-";
if (specURL != null)
fileWriter.print("<a href='" + specURL + anchorLink + specSection + "'>");
fileWriter.print(specSection);
if (specURL != null)
fileWriter.print("</a>");
}
fileWriter.print("</td>");
// package
fileWriter.print("<td>");
final String packageName = doc.getPackage();
if (packageName != null) {
fileWriter.print(o_a_v_shortened(packageName));
}
fileWriter.print("</td>");
// class
fileWriter.print("<td>");
final String className = doc.getClassName();
if (className != null) {
fileWriter.print("<a href='" + doc.getFQClassName().replace(".", "/") + ".html'>");
fileWriter.print(o_a_v_cut(packageName, className));
fileWriter.print("</a>");
}
fileWriter.print("</td>");
// class element
fileWriter.print("<td>");
final String member = doc.getMember();
if (member != null) {
if (className != null) {
fileWriter.print("<a href='" + className.replace(".", "/") + ".html#"
+ doc.getMemberAnchor().replace(",", ",%20") + "'>");
}
fileWriter.print(o_a_v_cut(packageName, member));
if (className != null) {
fileWriter.print("</a>");
}
}
fileWriter.print("</td>");
// coverage
fileWriter.print("<td>");
final SpecCompliant.ComplianceCoverage coverage = doc.getCoverageLevel();
if (coverage != null)
fileWriter.print(coverage.toString().toLowerCase());
fileWriter.print("</td>");
// status
fileWriter.print("<td>");
final SpecCompliant.ComplianceStatus complianceStatus = doc.getComplianceStatus();
if (complianceStatus != null)
fileWriter.print(complianceStatus.toString().toLowerCase());
fileWriter.print("</td>");
// comment
fileWriter.print("<td>");
final String comment = doc.getComment();
if (comment != null)
fileWriter.print(comment);
fileWriter.print("</td>");
fileWriter.println("</tr>");
}
fileWriter.println("</table></body>");
}
private String o_a_v_shortened(String packageString) {
if (packageString != null && packageString.contains("org.apache.vysper."))
return packageString.replace("org.apache.vysper.", "o.a.v.");
return packageString;
}
private String o_a_v_cut(String packageString, String memberString) {
if (memberString != null && memberString.contains(packageString + "."))
return memberString.replace(packageString + ".", "");
return memberString;
}
}
static class SpecDoc {
Declaration declaration;
SpecCompliant specCompliant;
SpecDoc(Declaration declaration, SpecCompliant specCompliant) {
this.declaration = declaration;
this.specCompliant = specCompliant;
}
public String getClassName() {
if (declaration instanceof FieldDeclaration || declaration instanceof MethodDeclaration) {
MemberDeclaration memberDeclaration = (MemberDeclaration) declaration;
return memberDeclaration.getDeclaringType().getQualifiedName();
} else {
return declaration.getSimpleName();
}
}
public String getFQClassName() {
if (declaration instanceof FieldDeclaration || declaration instanceof MethodDeclaration) {
MemberDeclaration memberDeclaration = (MemberDeclaration) declaration;
return memberDeclaration.getDeclaringType().getQualifiedName();
} else if (declaration instanceof ClassDeclaration) {
ClassDeclaration classDeclaration = (ClassDeclaration) declaration;
return classDeclaration.getPackage() + "." + classDeclaration.getSimpleName();
} else {
return declaration.getSimpleName();
}
}
public String getPackage() {
if (declaration instanceof TypeDeclaration) {
TypeDeclaration typeDeclaration = (TypeDeclaration) declaration;
return typeDeclaration.getPackage().getQualifiedName();
} else if (declaration instanceof FieldDeclaration || declaration instanceof MethodDeclaration) {
MemberDeclaration memberDeclaration = (MemberDeclaration) declaration;
return memberDeclaration.getDeclaringType().getPackage().getQualifiedName();
} else {
return null;
}
}
public String getMember() {
if (declaration instanceof FieldDeclaration || declaration instanceof MethodDeclaration) {
MemberDeclaration memberDeclaration = (MemberDeclaration) declaration;
return declaration.getSimpleName();
} else {
return null;
}
}
public String getMemberAnchor() {
if (declaration instanceof FieldDeclaration || declaration instanceof MethodDeclaration) {
MemberDeclaration memberDeclaration = (MemberDeclaration) declaration;
return declaration.toString();
} else {
return null;
}
}
public String getKey() {
return getSpecDoc() + " " + getSpecSection() + " " + getClassName() + " " + getMember() + " "
+ getCoverageLevel() + " " + getComplianceStatus();
}
public String getSpecSection() {
return specCompliant.section();
}
public String getSpecDoc() {
final String specRaw = specCompliant.spec();
if (specRaw == null)
return null;
return specRaw.toLowerCase();
}
public String getSpecDocURL() {
final String spec = getSpecDoc();
if (spec == null)
return null;
if (spec.startsWith("xep"))
return "http://xmpp.org/extensions/" + spec + ".html";
if (spec.startsWith("rfc")) {
if (!spec.contains("bis")) {
return "http://tools.ietf.org/html/" + spec;
} else {
return "http://tools.ietf.org/html/draft-saintandre-" + spec;
}
}
return null;
}
public SpecCompliant.ComplianceCoverage getCoverageLevel() {
return specCompliant.coverage();
}
public SpecCompliant.ComplianceStatus getComplianceStatus() {
return specCompliant.status();
}
public String getComment() {
return specCompliant.comment();
}
}
}