001    /*
002     * Copyright 1997-2008 Sun Microsystems, Inc.  All Rights Reserved.
003     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004     *
005     * This code is free software; you can redistribute it and/or modify it
006     * under the terms of the GNU General Public License version 2 only, as
007     * published by the Free Software Foundation.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun in the LICENSE file that accompanied this code.
010     *
011     * This code is distributed in the hope that it will be useful, but WITHOUT
012     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014     * version 2 for more details (a copy is included in the LICENSE file that
015     * accompanied this code).
016     *
017     * You should have received a copy of the GNU General Public License version
018     * 2 along with this work; if not, write to the Free Software Foundation,
019     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020     *
021     * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    package com.sun.tools.doclets.formats.html;
026    
027    import com.sun.tools.doclets.internal.toolkit.*;
028    import com.sun.tools.doclets.internal.toolkit.builders.*;
029    import com.sun.tools.doclets.internal.toolkit.util.*;
030    
031    import com.sun.javadoc.*;
032    import java.util.*;
033    import java.io.*;
034    
035    /**
036     * The class with "start" method, calls individual Writers.
037     *
038     * @author Atul M Dambalkar
039     * @author Robert Field
040     * @author Jamie Ho
041     *
042     */
043    public class HtmlDoclet extends AbstractDoclet {
044        public HtmlDoclet() {
045            configuration = (ConfigurationImpl) configuration();
046        }
047    
048        /**
049         * The global configuration information for this run.
050         */
051        public ConfigurationImpl configuration;
052    
053        /**
054         * The "start" method as required by Javadoc.
055         *
056         * @param root the root of the documentation tree.
057         * @see com.sun.javadoc.RootDoc
058         * @return true if the doclet ran without encountering any errors.
059         */
060        public static boolean start(RootDoc root) {
061            try {
062                HtmlDoclet doclet = new HtmlDoclet();
063                return doclet.start(doclet, root);
064            } finally {
065                ConfigurationImpl.reset();
066            }
067        }
068    
069        /**
070         * Create the configuration instance.
071         * Override this method to use a different
072         * configuration.
073         */
074        public Configuration configuration() {
075            return ConfigurationImpl.getInstance();
076        }
077    
078        /**
079         * Start the generation of files. Call generate methods in the individual
080         * writers, which will in turn genrate the documentation files. Call the
081         * TreeWriter generation first to ensure the Class Hierarchy is built
082         * first and then can be used in the later generation.
083         *
084         * For new format.
085         *
086         * @see com.sun.javadoc.RootDoc
087         */
088        protected void generateOtherFiles(RootDoc root, ClassTree classtree)
089                throws Exception {
090            super.generateOtherFiles(root, classtree);
091            if (configuration.linksource) {
092                if (configuration.destDirName.length() > 0) {
093                    SourceToHTMLConverter.convertRoot(configuration,
094                        root, configuration.destDirName + File.separator
095                        + DocletConstants.SOURCE_OUTPUT_DIR_NAME);
096                } else {
097                    SourceToHTMLConverter.convertRoot(configuration,
098                        root, DocletConstants.SOURCE_OUTPUT_DIR_NAME);
099                }
100            }
101    
102            if (configuration.topFile.length() == 0) {
103                configuration.standardmessage.
104                    error("doclet.No_Non_Deprecated_Classes_To_Document");
105                return;
106            }
107            boolean nodeprecated = configuration.nodeprecated;
108            String configdestdir = configuration.destDirName;
109            String confighelpfile = configuration.helpfile;
110            String configstylefile = configuration.stylesheetfile;
111            performCopy(configdestdir, confighelpfile);
112            performCopy(configdestdir, configstylefile);
113            Util.copyResourceFile(configuration, "inherit.gif", false);
114            // do early to reduce memory footprint
115            if (configuration.classuse) {
116                ClassUseWriter.generate(configuration, classtree);
117            }
118            IndexBuilder indexbuilder = new IndexBuilder(configuration, nodeprecated);
119    
120            if (configuration.createtree) {
121                TreeWriter.generate(configuration, classtree);
122            }
123            if (configuration.createindex) {
124                if (configuration.splitindex) {
125                    SplitIndexWriter.generate(configuration, indexbuilder);
126                } else {
127                    SingleIndexWriter.generate(configuration, indexbuilder);
128                }
129            }
130    
131            if (!(configuration.nodeprecatedlist || nodeprecated)) {
132                DeprecatedListWriter.generate(configuration);
133            }
134    
135            AllClassesFrameWriter.generate(configuration,
136                new IndexBuilder(configuration, nodeprecated, true));
137    
138            FrameOutputWriter.generate(configuration);
139    
140            if (configuration.createoverview) {
141                PackageIndexWriter.generate(configuration);
142            }
143            if (configuration.helpfile.length() == 0 &&
144                !configuration.nohelp) {
145                HelpWriter.generate(configuration);
146            }
147            if (configuration.stylesheetfile.length() == 0) {
148                StylesheetWriter.generate(configuration);
149            }
150        }
151    
152        /**
153         * {@inheritDoc}
154         */
155        protected void generateClassFiles(ClassDoc[] arr, ClassTree classtree) {
156            Arrays.sort(arr);
157            for(int i = 0; i < arr.length; i++) {
158                if (!(configuration.isGeneratedDoc(arr[i]) && arr[i].isIncluded())) {
159                    continue;
160                }
161                ClassDoc prev = (i == 0)?
162                    null:
163                    arr[i-1];
164                ClassDoc curr = arr[i];
165                ClassDoc next = (i+1 == arr.length)?
166                    null:
167                    arr[i+1];
168                try {
169                    if (curr.isAnnotationType()) {
170                        AbstractBuilder annotationTypeBuilder =
171                            configuration.getBuilderFactory()
172                                .getAnnotationTypeBuilder((AnnotationTypeDoc) curr,
173                                    prev, next);
174                        annotationTypeBuilder.build();
175                    } else {
176                        AbstractBuilder classBuilder =
177                            configuration.getBuilderFactory()
178                                .getClassBuilder(curr, prev, next, classtree);
179                        classBuilder.build();
180                    }
181                } catch (Exception e) {
182                    e.printStackTrace();
183                    throw new DocletAbortException();
184                }
185            }
186        }
187    
188        /**
189         * {@inheritDoc}
190         */
191        protected void generatePackageFiles(ClassTree classtree) throws Exception {
192            PackageDoc[] packages = configuration.packages;
193            if (packages.length > 1) {
194                PackageIndexFrameWriter.generate(configuration);
195            }
196            PackageDoc prev = null, next;
197            for(int i = 0; i < packages.length; i++) {
198                PackageFrameWriter.generate(configuration, packages[i]);
199                next = (i + 1 < packages.length && packages[i+1].name().length() > 0) ?
200                    packages[i+1] : null;
201                //If the next package is unnamed package, skip 2 ahead if possible
202                next = (i + 2 < packages.length && next == null) ?
203                    packages[i+2]: next;
204                AbstractBuilder packageSummaryBuilder = configuration.
205                    getBuilderFactory().getPackageSummaryBuilder(
206                    packages[i], prev, next);
207                packageSummaryBuilder.build();
208                if (configuration.createtree) {
209                    PackageTreeWriter.generate(configuration,
210                            packages[i], prev, next,
211                            configuration.nodeprecated);
212                }
213                prev = packages[i];
214            }
215        }
216    
217        /**
218         * Check for doclet added options here.
219         *
220         * @return number of arguments to option. Zero return means
221         * option not known.  Negative value means error occurred.
222         */
223        public static int optionLength(String option) {
224            // Construct temporary configuration for check
225            return (ConfigurationImpl.getInstance()).optionLength(option);
226        }
227    
228        /**
229         * Check that options have the correct arguments here.
230         * <P>
231         * This method is not required and will default gracefully
232         * (to true) if absent.
233         * <P>
234         * Printing option related error messages (using the provided
235         * DocErrorReporter) is the responsibility of this method.
236         *
237         * @return true if the options are valid.
238         */
239        public static boolean validOptions(String options[][],
240                DocErrorReporter reporter) {
241            // Construct temporary configuration for check
242            return (ConfigurationImpl.getInstance()).validOptions(options, reporter);
243        }
244    
245        private void performCopy(String configdestdir, String filename) {
246            try {
247                String destdir = (configdestdir.length() > 0) ?
248                    configdestdir + File.separatorChar: "";
249                if (filename.length() > 0) {
250                    File helpstylefile = new File(filename);
251                    String parent = helpstylefile.getParent();
252                    String helpstylefilename = (parent == null)?
253                        filename:
254                        filename.substring(parent.length() + 1);
255                    File desthelpfile = new File(destdir + helpstylefilename);
256                    if (!desthelpfile.getCanonicalPath().equals(
257                            helpstylefile.getCanonicalPath())) {
258                        configuration.message.
259                            notice((SourcePosition) null,
260                                "doclet.Copying_File_0_To_File_1",
261                                helpstylefile.toString(), desthelpfile.toString());
262                        Util.copyFile(desthelpfile, helpstylefile);
263                    }
264                }
265            } catch (IOException exc) {
266                configuration.message.
267                    error((SourcePosition) null,
268                        "doclet.perform_copy_exception_encountered",
269                        exc.toString());
270                throw new DocletAbortException();
271            }
272        }
273    }