Package com.postspectacular.doclet

Source Code of com.postspectacular.doclet.TextileDoclet

package com.postspectacular.doclet;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.Doclet;
import com.sun.javadoc.ExecutableMemberDoc;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.PackageDoc;
import com.sun.javadoc.ParamTag;
import com.sun.javadoc.Parameter;
import com.sun.javadoc.RootDoc;
import com.sun.javadoc.SeeTag;
import com.sun.javadoc.Tag;
import com.sun.javadoc.Type;

/**
* This custom doclet generates Javadocs in Textile markup. Textile is supported
* by popular wiki engines (e.g. Confluence) and as well is suitable for later
* translation into a number of other formats (e.g. Docbook, XHTML etc.). All
* generated files are stored as flat hierarchy in the specified target
* directory and are named as their corresponding qualified java types.
*
* @author Karsten Schmidt
*/
public class TextileDoclet extends Doclet {

    private static final String JAVA_API_URL = "http://download.oracle.com/javase/6/docs/api/";

    private static String getOption(RootDoc root, String option) {
        for (String[] o : root.options()) {
            if (o[0].equals(option)) {
                return o[1];
            }
        }
        return null;
    }

    public static int optionLength(String option) {
        if (option.equals("-d")) {
            return 2;
        }
        if (option.equals("-module")) {
            return 2;
        }
        return 0;
    }

    public static boolean start(RootDoc root) {
        String targetDir = getOption(root, "-d");
        String moduleName = getOption(root, "-module");
        TextileDoclet doclet = new TextileDoclet(root);
        doclet.setTargetDir(targetDir);
        doclet.setModuleName(moduleName);
        doclet.buildPackagePage();
        doclet.buildClassPages();
        doclet.buildMetadata();
        return true;
    }

    private final RootDoc root;

    private String targetDir;

    private String moduleName;

    public TextileDoclet(RootDoc root) {
        this.root = root;
    }

    private String buildClassMetaData(ClassDoc cd) {
        StringBuffer buf = new StringBuffer();
        buf.append("| *type* | ");
        if (cd.isOrdinaryClass()) {
            buf.append("class |\n");
            buf.append("| *abstract* | ");
            buf.append(cd.isAbstract() ? "yes" : "no");
            buf.append(" |\n");
        } else if (cd.isInterface()) {
            buf.append("interface |\n");
        } else if (cd.isAnnotationType()) {
            buf.append("annotation |\n");
        } else if (cd.isEnum()) {
            buf.append("enum |\n");
        }
        System.out.println(cd.enumConstants().length);
        buf.append("\n");
        return buf.toString();
    }

    private void buildClassPages() {
        for (ClassDoc cd : root.classes()) {
            StringBuffer buf = new StringBuffer();
            buf.append("h1. ").append(cd.qualifiedName()).append("\n\n");
            buf.append(buildClassMetaData(cd));
            buf.append(parseComment(cd.inlineTags())).append("\n\n");
            if (!cd.isInterface() && !cd.isEnum()) {
                buf.append("h2. Constructors\n\n");
                buf.append(parseMembers(cd.constructors())).append("\n\n");
            }
            buf.append("h2. Methods\n\n");
            buf.append(parseMembers(cd.methods())).append("\n\n");
            writeFile(cd.qualifiedName() + ".textile", buf.toString());
        }
    }

    private void buildMetadata() {
        StringBuffer buf = new StringBuffer();
        SimpleDateFormat fmt = new SimpleDateFormat(
                "yyyy-MM-dd (HH:mm:ss 'GMT')");
        fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
        buf.append("Generated by [TextileDoclet|http://hg.postspectacular.com/textile-doclet] on "
                + fmt.format(new Date()));
        writeFile("DocGenerator.textile", buf.toString());
    }

    private void buildPackageClassesPage(PackageDoc pdoc) {
        StringBuffer buf = new StringBuffer();
        buf.append("h1. ").append(pdoc.name()).append("\n\n");
        String comment = parseComment(pdoc.inlineTags());
        if (comment.length() > 0) {
            buf.append(comment).append("\n\n");
        }
        buf.append("h2. Package overview\n\n");
        List<ClassDoc> classes = Arrays.asList(pdoc.allClasses(true));
        Collections.sort(classes, new Comparator<ClassDoc>() {
            public int compare(ClassDoc a, ClassDoc b) {
                return a.name().compareTo(b.name());
            }
        });
        for (ClassDoc cd : classes) {
            buf.append("* [").append(cd.name()).append('|')
                    .append(cd.qualifiedName()).append("]\n");
        }
        writeFile(pdoc.name() + ".textile", buf.toString());
    }

    private void buildPackagePage() {
        StringBuffer buf = new StringBuffer();
        buf.append("h1. ").append(moduleName).append("\n\n");
        // TODO add module description from ???
        buf.append("h2. List of packages in this module\n\n");
        for (PackageDoc p : root.specifiedPackages()) {
            if (p.allClasses().length > 0) {
                buf.append("h3. [").append(p.name()).append("]\n\n");
                String comment = parseComment(p.inlineTags());
                if (comment.length() > 0) {
                    buf.append(comment).append("\n\n");
                }
                buildPackageClassesPage(p);
            }
        }
        writeFile(moduleName + ".textile", buf.toString());
    }

    private String buildTypeLink(Type type) {
        if (type.isPrimitive()) {
            return type.simpleTypeName();
        } else {
            if (type.qualifiedTypeName().startsWith("java")) {
                return "[" + type.simpleTypeName() + "|" + JAVA_API_URL
                        + type.qualifiedTypeName().replaceAll("\\.", "/")
                        + ".html]";
            } else {
                return "[" + type.simpleTypeName() + "|"
                        + type.qualifiedTypeName() + "]";
            }
        }
    }

    private String parseComment(Tag[] tags) {
        StringBuffer buf = new StringBuffer();
        for (Tag t : tags) {
            String type = t.name();
            if (type.equalsIgnoreCase("text")) {
                buf.append(t.text());
            } else if (type.equalsIgnoreCase("@link")) {
                SeeTag st = (SeeTag) t;
                buf.append('[');
                if (st.label() != null && st.label().length() > 0) {
                    buf.append(st.label()).append('|');
                }
                buf.append(st.referencedClassName());
                if (st.referencedMemberName() != null) {
                    buf.append('#').append(st.referencedMemberName());
                }
                buf.append("]");
            }
            // TODO support other tags like @see, etc.
        }
        String comment = buf.toString().replaceAll("\n", "");
        comment = comment.replaceAll("\\<.*?\\>", "");
        return comment;
    }

    private String parseMembers(ExecutableMemberDoc[] mems) {
        StringBuffer buf = new StringBuffer();
        for (ExecutableMemberDoc m : mems) {
            ParamTag[] params = m.paramTags();
            if (m instanceof MethodDoc) {
                MethodDoc md = (MethodDoc) m;
                buf.append("{anchor:").append(md.name())
                        .append(md.flatSignature()).append("}\n");
            }
            buf.append("h3. " + m.qualifiedName());
            buf.append('(');
            for (int i = 0, nump = m.parameters().length; i < nump; i++) {
                Parameter p = m.parameters()[i];
                buf.append(buildTypeLink(p.type())).append(" ")
                        .append(p.name());
                if (i < nump - 1) {
                    buf.append(", ");
                }
            }
            buf.append(")\n\n");
            String comment = parseComment(m.inlineTags());
            if (comment.length() > 0) {
                buf.append(comment).append("\n\n");
            }
            for (ParamTag p : params) {
                buf.append(
                        "* *" + p.parameterName() + "*: "
                                + p.parameterComment()).append("\n");
            }
            if (m instanceof MethodDoc) {
                MethodDoc md = (MethodDoc) m;
                buf.append("\n*Returns:* ")
                        .append(md.returnType().qualifiedTypeName())
                        .append("\n");
            }
            buf.append("\n");
        }
        return buf.toString();
    }

    public void setModuleName(String moduleName) {
        this.moduleName = moduleName;
    }

    public void setTargetDir(String targetDir) {
        this.targetDir = targetDir;
    }

    private void writeFile(String fileName, String buf) {
        try {
            File path = new File(targetDir + "/" + fileName);
            System.out.println("writing: " + path.getAbsolutePath());
            PrintWriter writer = FileUtils.createWriter(path);
            FileUtils.saveText(writer, buf);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
TOP

Related Classes of com.postspectacular.doclet.TextileDoclet

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.