001    /*
002     * Copyright 2003-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    
026    package com.sun.tools.doclets.internal.toolkit.builders;
027    
028    import com.sun.tools.doclets.internal.toolkit.util.*;
029    import com.sun.tools.doclets.internal.toolkit.*;
030    import com.sun.javadoc.*;
031    import java.io.*;
032    import java.util.*;
033    import java.lang.reflect.*;
034    
035    /**
036     * Builds the summary for a given class.
037     *
038     * This code is not part of an API.
039     * It is implementation that is subject to change.
040     * Do not use it as an API
041     *
042     * @author Jamie Ho
043     * @since 1.5
044     */
045    public class ClassBuilder extends AbstractBuilder {
046    
047        /**
048         * The root element of the class XML is {@value}.
049         */
050        public static final String ROOT = "ClassDoc";
051    
052        /**
053         * The class being documented.
054         */
055        private ClassDoc classDoc;
056    
057        /**
058         * The doclet specific writer.
059         */
060        private ClassWriter writer;
061    
062        /**
063         * Keep track of whether or not this classdoc is an interface.
064         */
065        private boolean isInterface = false;
066    
067        /**
068         * Keep track of whether or not this classdoc is an enum.
069         */
070        private boolean isEnum = false;
071    
072        /**
073         * Construct a new ClassBuilder.
074         *
075         * @param configuration the current configuration of the
076         *                      doclet.
077         */
078        private ClassBuilder(Configuration configuration) {
079            super(configuration);
080        }
081    
082        /**
083         * Construct a new ClassBuilder.
084         *
085         * @param configuration the current configuration of the doclet.
086         * @param classDoc the class being documented.
087         * @param writer the doclet specific writer.
088         */
089        public static ClassBuilder getInstance(Configuration configuration,
090            ClassDoc classDoc, ClassWriter writer)
091        throws Exception {
092            ClassBuilder builder = new ClassBuilder(configuration);
093            builder.configuration = configuration;
094            builder.classDoc = classDoc;
095            builder.writer = writer;
096            if (classDoc.isInterface()) {
097                builder.isInterface = true;
098            } else if (classDoc.isEnum()) {
099                builder.isEnum = true;
100                Util.setEnumDocumentation(configuration, classDoc);
101            }
102            if(containingPackagesSeen == null) {
103                containingPackagesSeen = new HashSet<String>();
104            }
105            return builder;
106        }
107    
108        /**
109         * {@inheritDoc}
110         */
111        public void invokeMethod(String methodName, Class<?>[] paramClasses,
112                Object[] params)
113        throws Exception {
114            if (DEBUG) {
115                configuration.root.printError("DEBUG: " + this.getClass().getName()
116                    + "." + methodName);
117            }
118            Method method = this.getClass().getMethod(methodName, paramClasses);
119            method.invoke(this, params);
120        }
121    
122        /**
123         * {@inheritDoc}
124         */
125        public void build() throws IOException {
126            build(LayoutParser.getInstance(configuration).parseXML(ROOT));
127        }
128    
129        /**
130         * {@inheritDoc}
131         */
132        public String getName() {
133            return ROOT;
134        }
135    
136         /**
137          * Handles the &lt;ClassDoc> tag.
138          *
139          * @param elements the XML elements that specify how to document a class.
140          */
141         public void buildClassDoc(List<?> elements) throws Exception {
142            build(elements);
143            writer.close();
144            copyDocFiles();
145         }
146    
147    
148         /**
149          * Copy the doc files for the current ClassDoc if necessary.
150          */
151         private void copyDocFiles() {
152            PackageDoc containingPackage = classDoc.containingPackage();
153            if((configuration.packages == null ||
154                    Arrays.binarySearch(configuration.packages,
155                                        containingPackage) < 0) &&
156               ! containingPackagesSeen.contains(containingPackage.name())){
157                //Only copy doc files dir if the containing package is not
158                //documented AND if we have not documented a class from the same
159                //package already. Otherwise, we are making duplicate copies.
160                Util.copyDocFiles(configuration,
161                    Util.getPackageSourcePath(configuration,
162                        classDoc.containingPackage()) +
163                    DirectoryManager.getDirectoryPath(classDoc.containingPackage())
164                        + File.separator, DocletConstants.DOC_FILES_DIR_NAME, true);
165                containingPackagesSeen.add(containingPackage.name());
166            }
167         }
168    
169        /**
170         * Build the header of the page.
171         */
172        public void buildClassHeader() {
173            String key;
174            if (isInterface) {
175                key =  "doclet.Interface";
176            } else if (isEnum) {
177                key = "doclet.Enum";
178            } else {
179                key =  "doclet.Class";
180            }
181    
182            writer.writeHeader(configuration.getText(key) + " " + classDoc.name());
183        }
184    
185        /**
186         * Build the class tree documentation.
187         */
188        public void buildClassTree() {
189            writer.writeClassTree();
190        }
191    
192        /**
193         * If this is a class, list all interfaces
194         * implemented by this class.
195         */
196        public void buildImplementedInterfacesInfo() {
197            writer.writeImplementedInterfacesInfo();
198        }
199    
200        /**
201         * If this is an interface, list all super interfaces.
202         */
203        public void buildSuperInterfacesInfo() {
204            writer.writeSuperInterfacesInfo();
205        }
206    
207        /**
208         * List the parameters of this class.
209         */
210        public void buildTypeParamInfo() {
211            writer.writeTypeParamInfo();
212        }
213    
214        /**
215         * List all the classes extend this one.
216         */
217        public void buildSubClassInfo() {
218            writer.writeSubClassInfo();
219        }
220    
221        /**
222         * List all the interfaces that extend this one.
223         */
224        public void buildSubInterfacesInfo() {
225            writer.writeSubInterfacesInfo();
226        }
227    
228        /**
229         * If this is an interface, list all classes that implement this interface.
230         */
231        public void buildInterfaceUsageInfo () {
232            writer.writeInterfaceUsageInfo();
233        }
234    
235        /**
236         * If this is an inner class or interface, list the enclosing class or
237         * interface.
238         */
239        public void buildNestedClassInfo () {
240            writer.writeNestedClassInfo();
241        }
242    
243        /**
244         * If this class is deprecated, print the appropriate information.
245         */
246        public void buildDeprecationInfo () {
247            writer.writeClassDeprecationInfo();
248        }
249    
250        /**
251         * Build the signature of the current class.
252         */
253        public void buildClassSignature() {
254            StringBuffer modifiers = new StringBuffer(classDoc.modifiers() + " ");
255            if (isEnum) {
256                modifiers.append("enum ");
257                int index;
258                if ((index = modifiers.indexOf("abstract")) >= 0) {
259                    modifiers.delete(index, index + (new String("abstract")).length());
260                    modifiers = new StringBuffer(
261                        Util.replaceText(modifiers.toString(), "  ", " "));
262                }
263                if ((index = modifiers.indexOf("final")) >= 0) {
264                    modifiers.delete(index, index + (new String("final")).length());
265                    modifiers = new StringBuffer(
266                        Util.replaceText(modifiers.toString(), "  ", " "));
267                }
268            //} else if (classDoc.isAnnotationType()) {
269                //modifiers.append("@interface ");
270            } else if (! isInterface) {
271                modifiers.append("class ");
272            }
273            writer.writeClassSignature(modifiers.toString());
274        }
275    
276        /**
277         * Build the class description.
278         */
279        public void buildClassDescription() {
280           writer.writeClassDescription();
281        }
282    
283        /**
284         * Build the tag information for the current class.
285         */
286        public void buildClassTagInfo() {
287           writer.writeClassTagInfo();
288        }
289    
290        /**
291         * Build the contents of the page.
292         *
293         * @param elements the XML elements that specify how a member summary is
294         *                 documented.
295         */
296        public void buildMemberSummary(List<?> elements) throws Exception {
297            configuration.getBuilderFactory().
298                getMemberSummaryBuilder(writer).build(elements);
299            writer.completeMemberSummaryBuild();
300        }
301    
302        /**
303         * Build the enum constants documentation.
304         *
305         * @param elements the XML elements that specify how a enum constants are
306         *                 documented.
307         */
308        public void buildEnumConstantsDetails(List<?> elements) throws Exception {
309            configuration.getBuilderFactory().
310                getEnumConstantsBuilder(writer).build(elements);
311        }
312    
313        /**
314         * Build the field documentation.
315         *
316         * @param elements the XML elements that specify how a field is documented.
317         */
318        public void buildFieldDetails(List<?> elements) throws Exception {
319            configuration.getBuilderFactory().
320                getFieldBuilder(writer).build(elements);
321        }
322    
323        /**
324         * Build the constructor documentation.
325         *
326         * @param elements the XML elements that specify how to document a
327         * constructor.
328         */
329        public void buildConstructorDetails(List<?> elements) throws Exception {
330            configuration.getBuilderFactory().
331                getConstructorBuilder(writer).build(elements);
332        }
333    
334        /**
335         * Build the method documentation.
336         *
337         * @param elements the XML elements that specify how a method is documented.
338         */
339        public void buildMethodDetails(List<?> elements) throws Exception {
340            configuration.getBuilderFactory().
341                    getMethodBuilder(writer).build(elements);
342        }
343    
344        /**
345         * Build the footer of the page.
346         */
347        public void buildClassFooter() {
348            writer.writeFooter();
349        }
350    }