001/**
002 * Copyright 2013-2015 John Ericksen
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *    http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.asciidoctor.asciidoclet;
017
018import com.google.common.base.Optional;
019import com.google.common.io.Files;
020import com.sun.javadoc.*;
021
022import java.io.File;
023import java.io.IOException;
024import java.util.HashSet;
025import java.util.Set;
026import java.util.regex.Pattern;
027
028/**
029 * Iterates over the various elements of a RootDoc, handing off to the
030 * DocletRenderer to perform the rendering work.
031 *
032 * @author John Ericksen
033 */
034public class DocletIterator {
035
036        private static final Pattern ASCIIDOC_FILE_PATTERN = Pattern.compile("(.*\\.(ad|adoc|txt|asciidoc))");
037
038        private final DocletOptions docletOptions;
039
040        public DocletIterator(DocletOptions docletOptions) {
041                this.docletOptions = docletOptions;
042        }
043
044        /**
045         * Renders a RootDoc's contents.
046         *
047         * @param rootDoc
048         * @param renderer
049         */
050        public boolean render(RootDoc rootDoc, DocletRenderer renderer) {
051                if (!processOverview(rootDoc, renderer)) {
052                        return false;
053                }
054                ClassDoc[] specifiedClasses = rootDoc.specifiedClasses();
055                PackageDoc[] specifiedPackages = rootDoc.specifiedPackages();
056                Set<PackageDoc> packages = new HashSet<>();
057                if (specifiedClasses != null && specifiedClasses.length > 0) {
058                        for (ClassDoc doc : specifiedClasses) {
059                                packages.add(doc.containingPackage());
060                                renderClass(doc, renderer);
061                        }
062                } else {
063                        for (ClassDoc doc : rootDoc.classes()) {
064                                packages.add(doc.containingPackage());
065                                renderClass(doc, renderer);
066                        }
067                }
068                if (specifiedPackages != null && specifiedPackages.length > 0) {
069                        for (PackageDoc doc : specifiedPackages) {
070                                renderer.renderDoc(doc);
071                        }
072                } else {
073                        for (PackageDoc doc : packages) {
074                                renderer.renderDoc(doc);
075                        }
076                }
077
078                return true;
079        }
080
081        /**
082         * Renders an individual class.
083         *
084         * @param doc input
085         */
086        private void renderClass(ClassDoc doc, DocletRenderer renderer) {
087                // handle the various parts of the Class doc
088                renderer.renderDoc(doc);
089                for (MemberDoc member : doc.fields()) {
090                        renderer.renderDoc(member);
091                }
092                for (MemberDoc member : doc.constructors()) {
093                        renderer.renderDoc(member);
094                }
095                for (MemberDoc member : doc.methods()) {
096                        renderer.renderDoc(member);
097                }
098                for (MemberDoc member : doc.enumConstants()) {
099                        renderer.renderDoc(member);
100                }
101                if (doc instanceof AnnotationTypeDoc) {
102                        for (MemberDoc member : ((AnnotationTypeDoc) doc).elements()) {
103                                renderer.renderDoc(member);
104                        }
105                }
106        }
107
108        private boolean processOverview(RootDoc rootDoc, DocletRenderer renderer) {
109                Optional<File> overview = docletOptions.overview();
110                if (overview.isPresent()) {
111                        File overviewFile = overview.get();
112                        if (isAsciidocFile(overviewFile.getName())) {
113                                try {
114                                        String overviewContent = Files.asCharSource(overviewFile, docletOptions.encoding()).read();
115                                        rootDoc.setRawCommentText(overviewContent);
116                                        renderer.renderDoc(rootDoc);
117                                } catch (IOException e) {
118                                        rootDoc.printError("Error reading overview file: " + e.getLocalizedMessage());
119                                        return false;
120                                }
121                        } else {
122                                rootDoc.printNotice(
123                                                "Skipping non-AsciiDoc overview " + overviewFile + ", will be processed by standard Doclet.");
124                        }
125                }
126                return true;
127        }
128
129        private static boolean isAsciidocFile(String name) {
130                return ASCIIDOC_FILE_PATTERN.matcher(name).matches();
131        }
132}