org.areasy.common.doclet.Doclet.java Source code

Java tutorial

Introduction

Here is the source code for org.areasy.common.doclet.Doclet.java

Source

package org.areasy.common.doclet;

/*
 * Copyright (c) 2007-2016 AREasy Runtime
 *
 * This library, AREasy Runtime and API for BMC Remedy AR System, is free software ("Licensed Software");
 * you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either version 2.1 of the License,
 * or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * including but not limited to, the implied warranty of MERCHANTABILITY, NONINFRINGEMENT,
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
 */

import com.lowagie.text.Chunk;
import com.lowagie.text.Element;
import com.lowagie.text.Paragraph;
import org.areasy.common.logger.Logger;
import org.areasy.common.logger.LoggerFactory;
import org.areasy.common.doclet.document.*;
import org.areasy.common.doclet.document.filters.Filter;
import org.areasy.common.doclet.document.filters.FilteredRootDoc;
import org.areasy.common.doclet.document.tags.HtmlParserWrapper;
import org.areasy.common.doclet.utilities.DocletUtility;
import org.areasy.common.doclet.utilities.PDFUtility;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.PackageDoc;
import com.sun.javadoc.RootDoc;

import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * This javadoc doclet creates PDF output
 * for an API documentation.
 * <p/>
 * Please note that this doclet is a very old-fashioned,
 * straightforward batch-process application. It holds the
 * current state of the process in static variables which
 * also means that it is definitely NOT thread-safe.
 * 
 * @version $Id: Doclet.java,v 1.5 2008/05/14 09:36:48 swd\stefan.damian Exp $
 */
public class Doclet implements AbstractConfiguration {
    /**
     * Logger reference
     */
    private static Logger log = LoggerFactory.getLog(Doclet.class);

    /**
     * Index generation class reference.
     */
    private static Index index = null;

    /**
     * Reference to the PDF file.
     */
    private static File file = null;

    // Stores list of inner classes
    private static Hashtable innerClassesList = new Hashtable();

    /**
     * Constructor for PDFDoclet.
     */
    public Doclet() {
        //nothing to do.
    }

    /**
     * Constructs a PDFDoclet object.
     *
     * @param filename The filename of the target otuput PDF file.
     */
    public Doclet(String filename) {
        String workDir = DefaultConfiguration.getWorkDir();
        boolean relative = false;

        if ((filename.startsWith(".") || filename.startsWith("..")) && (workDir != null))
            relative = true;

        if (filename.indexOf(File.separator) != -1) {
            String dirname = filename.substring(0, filename.lastIndexOf(File.separator));
            File dir = (!relative ? new File(dirname) : new File(workDir, dirname));

            dir.mkdirs();
        }

        file = (!relative ? new File(filename) : new File(workDir, filename));
    }

    /**
     * Processes all packages of a given javadoc root.
     *
     * @param root The javadoc root.
     * @throws Exception
     */
    private void listClasses(RootDoc root) throws Exception {
        try {
            Document.initialize();

            Document.open();

            Bookmarks.init();
        } catch (IOException e) {
            log.error("Failed to open PDF file for writing", e);
            return;
        }

        // Prepare index
        index = new Index(Document.getWriter(), Document.instance());

        // Print title page
        CustomTitle title = new CustomTitle(Document.instance());
        State.setCurrentHeaderType(HEADER_DETAILS);
        title.print();

        // Print description page
        CustomDescription description = new CustomDescription(Document.instance());
        State.setCurrentHeaderType(HEADER_DETAILS);
        description.print();

        // Print javadoc overview
        State.setCurrentHeaderType(HEADER_OVERVIEW);
        Overview.print(root);

        State.setCurrentHeaderType(HEADER_API);

        ClassDoc[] classes = root.classes();

        Map pkgMap = null;
        if (DefaultConfiguration.getPackageOrder() != null) {
            // Use a custom comparator to sort the list of packages in a custom way
            Comparator cmp = new Comparator() {

                public int compare(Object packageName1, Object packageName2) {
                    String packageOrder = DefaultConfiguration.getPackageOrder();
                    PackageDoc package1 = (PackageDoc) packageName1;
                    PackageDoc package2 = (PackageDoc) packageName2;
                    int retval1 = packageOrder.indexOf(package1.name());
                    int retval2 = packageOrder.indexOf(package2.name());

                    if (retval1 < retval2)
                        return -1;
                    if (retval1 > retval2)
                        return 1;

                    return 0;
                }
            };

            pkgMap = new TreeMap(cmp);
        } else {
            // Use a treemap to create an alphabetically sorted list of all packages
            pkgMap = new TreeMap();
        }

        // Iterate through all single, separately specified classes
        for (int i = 0; i < classes.length; i++) {
            // Fetch the classes list for the package of this class
            List classList = (List) pkgMap.get(classes[i].containingPackage());
            if (classList == null) {
                // If there's no list for this package yet, create one
                classList = new ArrayList();
                pkgMap.put(classes[i].containingPackage(), classList);
            }

            // Store class in the list for this package
            classList.add(classes[i]);
        }

        // Prepare alphabetically sorted list of all classes for bookmarks
        Bookmarks.prepareBookmarkEntries(pkgMap);

        // Now process all packages and classes
        for (Iterator i = pkgMap.entrySet().iterator(); i.hasNext();) {
            // Get package..
            Map.Entry entry = (Map.Entry) i.next();
            PackageDoc pkgDoc = (PackageDoc) entry.getKey();
            List pkgList = (List) entry.getValue();

            // Get list of classes in package...
            ClassDoc[] pkgClasses = (ClassDoc[]) pkgList.toArray(new ClassDoc[pkgList.size()]);
            State.increasePackageChapter();

            // Print package info (includes printing classes info)
            printPackage(pkgDoc, pkgClasses);
        }

        Appendices.print();

        index.create();

        Bookmarks.createBookmarkOutline();

        String endMessage = "PDF completed: " + file.getPath();
        String line = DocletUtility.getLine(endMessage.length());
        log.debug(line);
        log.debug(endMessage);
        log.debug(line);

        // step 5: we close the document
        Document.close();
    }

    /**
     * Processes one Java package of the whole API.
     *
     * @param packageDoc The javadoc information for the package.
     * @throws Exception
     */
    private void printPackage(PackageDoc packageDoc, ClassDoc[] packageClasses) throws Exception {
        State.setCurrentPackage(packageDoc.name());
        State.setCurrentDoc(packageDoc);

        Document.newPage();

        String packageName = State.getCurrentPackage();

        // Text "package"
        State.setCurrentClass("");

        Paragraph label = new Paragraph((float) 22.0, LB_PACKAGE, Fonts.getFont(TEXT_FONT, BOLD, 18));
        Document.add(label);

        Paragraph titlePara = new Paragraph((float) 30.0, "");
        // Name of the package (large font)
        Chunk titleChunk = new Chunk(packageName, Fonts.getFont(TEXT_FONT, BOLD, 30));
        titleChunk.setLocalDestination(packageName);
        if (State.getCurrentFile() != null) {
            String packageAnchor = Destinations.createAnchorDestination(State.getCurrentFile(), null);
            titlePara.add(PDFUtility.createAnchor(packageAnchor, titleChunk.font()));
        }

        titlePara.add(titleChunk);
        Document.add(titlePara);

        // Some empty space
        Document.add(new Paragraph((float) 20.0, " "));

        State.setContinued(true);

        String packageText = DocletUtility.getComment(packageDoc);
        Element[] objs = HtmlParserWrapper.createPdfObjects(packageText);

        if (objs.length == 0) {
            String packageDesc = DocletUtility.stripLineFeeds(packageText);
            Document.add(new Paragraph((float) 11.0, packageDesc, Fonts.getFont(TEXT_FONT, 10)));
        } else
            PDFUtility.printPdfElements(objs);

        State.setContinued(false);

        State.increasePackageSection();

        printClasses(DocletUtility.sort(packageClasses), packageDoc);
    }

    /**
     * Processes all classes of one Java package..
     *
     * @param classDocs  The javadoc information list for the classes.
     * @param packageDoc The javadoc information for the package
     *                   which the classes belong to.
     * @throws Exception
     */
    private void printClasses(ClassDoc[] classDocs, PackageDoc packageDoc) throws Exception {
        for (int i = 0; i < classDocs.length; i++) {

            // Avoid processing a class which has already been processed as an inner class
            if (innerClassesList.get(classDocs[i]) == null) {
                ClassDoc doc = (ClassDoc) classDocs[i];
                printClassWithInnerClasses(doc, packageDoc);
            }
        }
    }

    /**
     * This method prints the doc of a class and of all
     * its inner classes. It calls itself recursively
     * to make sure that also nested inner classes are
     * printed correctly.
     *
     * @param doc        The doc of the class to print.
     * @param packageDoc The packagedoc of the containing package.
     * @throws Exception If something failed.
     */
    private void printClassWithInnerClasses(ClassDoc doc, PackageDoc packageDoc) throws Exception {
        Classes.printClass(doc, packageDoc);

        ClassDoc[] innerClasses = doc.innerClasses();
        if (innerClasses != null && innerClasses.length > 0) {
            for (int u = 0; u < innerClasses.length; u++) {
                // Check if this inner class has not yet been handled
                if (innerClassesList.get(innerClasses[u]) == null) {
                    innerClassesList.put(innerClasses[u], "x");

                    State.setInnerClass(true);
                    ClassDoc innerDoc = (ClassDoc) innerClasses[u];
                    printClassWithInnerClasses(innerDoc, packageDoc);

                    State.setInnerClass(false);
                }
            }
        }
    }

    /**
     * Main doclet method.
     *
     * @param rootDoc The root of the javadoc information.
     * @return True if the javadoc generation was successful,
     *         false if it failed.
     */
    public static boolean start(RootDoc rootDoc) {
        try {
            FilteredRootDoc root = new FilteredRootDoc(rootDoc);

            DefaultConfiguration.start(root);

            Filter.initialize();
            TagList.initialize();
            Appendices.initialize();

            String outputFilename = DefaultConfiguration.getString(ARG_PDF, ARG_VAL_PDF);

            // Prepare list of classes and packages
            DocletUtility.buildPackageList(root);

            // Do some pre-processing first (building class derivation trees)
            ImplementorsInformation.initialize(root);
            ImplementorsInformation.collectInformation();

            Doclet doclet = new Doclet(outputFilename);

            if (root.classes() != null)
                doclet.listClasses(root);
            else
                DocletUtility.error("No classes available");

            return true;

        } catch (Throwable e) {
            DocletUtility.error("Exception", e);

            return false;
        }
    }

    /**
     * Doclet method called by Javadoc to recognize
     * custom parameters.
     *
     * @param option The parameter found in the command line
     * @return Zero (0) if the parameter is unknown, or the number
     *         of parts that make up the whole parameter.
     */
    public static int optionLength(String option) {
        if (option.equals("-" + ARG_WORKDIR))
            return 2;

        if (option.equals("-" + ARG_SOURCEPATH))
            return 2;

        if (option.equals("-" + ARG_PDF))
            return 2;

        if (option.equals("-" + ARG_CONFIG))
            return 2;

        if (option.equals("-" + ARG_DEBUG))
            return 1;

        if (option.equals("-" + ARG_AUTHOR))
            return 1;

        if (option.equals("-" + ARG_VERSION))
            return 1;

        if (option.equals("-" + ARG_GROUP))
            return 3;

        if (option.equals("-" + ARG_DONTSPEC))
            return 2;

        if (option.equals("-" + ARG_SORT))
            return 2;

        if (option.equals("-" + ARG_SINCE))
            return 1;

        if (option.equals("-" + ARG_SUMMARY_TABLE))
            return 1;

        if (option.equals("-" + ARG_CREATE_LINKS))
            return 1;

        if (option.equals("-" + ARG_ALLOW_ENCRYPTION))
            return 1;

        if (option.equals("-" + ARG_ALLOW_PRINTING))
            return 1;

        if (option.equals("-" + ARG_HEADER_LEFT))
            return 2;

        if (option.equals("-" + ARG_HEADER_CENTER))
            return 2;

        if (option.equals("-" + ARG_HEADER_RIGHT))
            return 2;

        if (option.equals("-" + ARG_PGN_TYPE))
            return 2;

        if (option.equals("-" + ARG_PGN_ALIGNMENT))
            return 2;

        if (option.equals("-" + ARG_CREATE_FRAME))
            return 1;

        if (option.equals("-" + ARG_DOC_TITLE_PAGE))
            return 1;

        if (option.equals("-" + ARG_DOC_TITLE_FILE))
            return 2;

        if (option.equals("-" + ARG_DOC_TITLE))
            return 2;

        if (option.equals("-" + ARG_DOC_AUTHOR))
            return 2;

        if (option.equals("-" + ARG_DOC_COPYRIGHT))
            return 2;

        if (option.equals("-" + ARG_FONT_TEXT_NAME))
            return 2;

        if (option.equals("-" + ARG_FONT_TEXT_ENC))
            return 2;

        if (option.equals("-" + ARG_FONT_CODE_NAME))
            return 2;

        if (option.equals("-" + ARG_FONT_CODE_ENC))
            return 2;

        if (option.startsWith("-" + ARG_APPENDIX_PREFIX))
            return 2;

        return 0;
    }

    /**
     * Returns a reference to the Index object.
     *
     * @return The index object.
     */
    public static Index getIndex() {
        return index;
    }

    /**
     * Returns a reference to the PDF file object.
     *
     * @return The PDF file object.
     */
    public static File getPdfFile() {
        return file;
    }

    /**
     * Set a reference to the PDF file object.
     *
     * @param f The PDF file object.
     */
    public static void setPdfFile(File f) {
        file = f;
    }
}