1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.tools;
24  
25  import com.liferay.portal.kernel.util.GetterUtil;
26  import com.liferay.portal.kernel.util.StringPool;
27  import com.liferay.portal.kernel.util.StringUtil;
28  import com.liferay.portal.kernel.util.Validator;
29  import com.liferay.portal.kernel.xml.Document;
30  import com.liferay.portal.kernel.xml.Element;
31  import com.liferay.portal.tools.servicebuilder.ServiceBuilder;
32  import com.liferay.portal.util.FileImpl;
33  import com.liferay.portal.xml.SAXReaderImpl;
34  import com.liferay.util.xml.DocUtil;
35  
36  import com.thoughtworks.qdox.JavaDocBuilder;
37  import com.thoughtworks.qdox.model.AbstractJavaEntity;
38  import com.thoughtworks.qdox.model.DocletTag;
39  import com.thoughtworks.qdox.model.JavaClass;
40  import com.thoughtworks.qdox.model.JavaField;
41  import com.thoughtworks.qdox.model.JavaMethod;
42  import com.thoughtworks.qdox.model.JavaParameter;
43  import com.thoughtworks.qdox.model.Type;
44  
45  import jargs.gnu.CmdLineParser;
46  
47  import java.io.File;
48  import java.io.FileInputStream;
49  import java.io.Reader;
50  import java.io.StringReader;
51  
52  import java.util.ArrayList;
53  import java.util.HashMap;
54  import java.util.HashSet;
55  import java.util.List;
56  import java.util.Map;
57  import java.util.Set;
58  import java.util.TreeMap;
59  
60  import org.apache.tools.ant.DirectoryScanner;
61  
62  /**
63   * <a href="JavadocFormatter.java.html"><b><i>View Source</i></b></a>
64   *
65   * @author Brian Wing Shun Chan
66   */
67  public class JavadocFormatter {
68  
69      public static void main(String[] args) {
70          try {
71              new JavadocFormatter(args);
72          }
73          catch (Exception e) {
74              e.printStackTrace();
75          }
76      }
77  
78      public JavadocFormatter(String[] args) throws Exception {
79          CmdLineParser cmdLineParser = new CmdLineParser();
80  
81          CmdLineParser.Option limitOption = cmdLineParser.addStringOption(
82              "limit");
83          CmdLineParser.Option initOption = cmdLineParser.addStringOption(
84              "init");
85  
86          cmdLineParser.parse(args);
87  
88          String limit = (String)cmdLineParser.getOptionValue(limitOption);
89          String init = (String)cmdLineParser.getOptionValue(initOption);
90  
91          if (!init.startsWith("$")) {
92              _initializeMissingJavadocs = GetterUtil.getBoolean(init);
93          }
94  
95          DirectoryScanner ds = new DirectoryScanner();
96  
97          ds.setBasedir(_basedir);
98          ds.setExcludes(
99              new String[] {
100                 "**\\classes\\**", "**\\portal-client\\**"
101             });
102 
103         List<String> includes = new ArrayList<String>();
104 
105         if (Validator.isNotNull(limit) && !limit.startsWith("$")) {
106             String[] limitArray = StringUtil.split(limit, "/");
107 
108             for (String curLimit : limitArray) {
109                 includes.add(
110                     "**\\" + StringUtil.replace(curLimit, ".", "\\") +
111                         "\\**\\*.java");
112                 includes.add("**\\" + curLimit + ".java");
113             }
114         }
115         else {
116             includes.add("**\\*.java");
117         }
118 
119         ds.setIncludes(includes.toArray(new String[includes.size()]));
120 
121         ds.scan();
122 
123         String[] fileNames = ds.getIncludedFiles();
124 
125         for (String fileName : fileNames) {
126             fileName = StringUtil.replace(fileName, "\\", "/");
127 
128             _format(fileName);
129         }
130     }
131 
132     private void _addClassCommentElement(
133         Element rootElement, JavaClass javaClass) {
134 
135         Element commentElement = rootElement.addElement("comment");
136 
137         String comment = _getCDATA(javaClass);
138 
139         if (comment.startsWith("Copyright (c) 2000-2009 Liferay, Inc.")) {
140             comment = StringPool.BLANK;
141         }
142 
143         if (comment.startsWith(
144                 "<a href=\"" + javaClass.getName() + ".java.html\">")) {
145 
146             int pos = comment.indexOf("</a>");
147 
148             comment = comment.substring(pos + 4).trim();
149         }
150 
151         commentElement.addCDATA(comment);
152     }
153 
154     private void _addDocletElements(
155             Element parentElement, AbstractJavaEntity abstractJavaEntity,
156             String name)
157         throws Exception {
158 
159         DocletTag[] docletTags = abstractJavaEntity.getTagsByName(name);
160 
161         for (DocletTag docletTag : docletTags) {
162             String value = docletTag.getValue();
163 
164             value = StringUtil.replace(value, "\n", " ");
165 
166             if (name.equals("author") || name.equals("see") ||
167                 name.equals("since") || name.equals("version")) {
168 
169                 if (value.startsWith("Raymond Aug")) {
170                     value = new String(
171                         "Raymond Aug\u00c3\u00a9".getBytes(), StringPool.UTF8);
172                 }
173             }
174 
175             Element element = parentElement.addElement(name);
176 
177             element.addCDATA(value);
178         }
179 
180         if ((docletTags.length == 0) && name.equals("author")) {
181             Element element = parentElement.addElement(name);
182 
183             element.addCDATA(ServiceBuilder.AUTHOR);
184         }
185     }
186 
187     private String _addDocletTags(
188         Element parentElement, String[] names, String indent) {
189 
190         StringBuilder sb = new StringBuilder();
191 
192         int maxNameLength = 0;
193 
194         for (String name : names) {
195             if (name.length() < maxNameLength) {
196                 continue;
197             }
198 
199             List<Element> elements = parentElement.elements(name);
200 
201             for (Element element : elements) {
202                 Element commentElement = element.element("comment");
203 
204                 String comment = null;
205 
206                 if (commentElement != null) {
207                     comment = commentElement.getText();
208                 }
209                 else {
210                     comment = element.getText();
211                 }
212 
213                 if (!name.equals("deprecated") && !_initializeMissingJavadocs &&
214                     Validator.isNull(comment)) {
215 
216                     continue;
217                 }
218 
219                 maxNameLength = name.length();
220 
221                 break;
222             }
223         }
224 
225         int indentLength =_getIndentLength(indent) + maxNameLength;
226 
227         String maxNameIndent = "\t ";
228 
229         for (int i = 0; i < maxNameLength; i++) {
230             maxNameIndent += " ";
231         }
232 
233         maxNameIndent = StringUtil.replace(
234             maxNameIndent, StringPool.FOUR_SPACES, "\t");
235 
236         for (String name : names) {
237             String curNameIndent = " ";
238 
239             if (name.length() < maxNameLength) {
240                 int firstTab = 4 - (name.length() % 4);
241 
242                 int delta = (maxNameLength + 1) - (name.length() + firstTab);
243 
244                 if (delta == 0) {
245                     curNameIndent = "\t";
246                 }
247                 else if (delta < 0) {
248                     for (int i = 0; i < (maxNameLength - name.length()); i++) {
249                         curNameIndent += " ";
250                     }
251                 }
252                 else if (delta > 0) {
253                     curNameIndent = "\t";
254 
255                     int numberOfTabs = delta / 4;
256 
257                     if (numberOfTabs > 0) {
258                         for (int i = 0; i < numberOfTabs; i++) {
259                             curNameIndent += "\t";
260                         }
261                     }
262 
263                     int numberOfSpaces = delta % 4;
264 
265                     if (numberOfSpaces > 0) {
266                         for (int i = 0; i < numberOfSpaces; i++) {
267                             curNameIndent += " ";
268                         }
269                     }
270                 }
271             }
272 
273             List<Element> elements = parentElement.elements(name);
274 
275             for (Element element : elements) {
276                 Element commentElement = element.element("comment");
277 
278                 String comment = null;
279 
280                 if (commentElement != null) {
281                     comment = commentElement.getText();
282                 }
283                 else {
284                     comment = element.getText();
285                 }
286 
287                 if (!name.equals("deprecated") && !_initializeMissingJavadocs &&
288                     Validator.isNull(comment)) {
289 
290                     continue;
291                 }
292 
293                 sb.append(indent);
294                 sb.append(" * @");
295                 sb.append(name);
296 
297                 if (Validator.isNotNull(comment) || (commentElement != null)) {
298                     sb.append(curNameIndent);
299                 }
300 
301                 if (commentElement != null) {
302                     comment = element.elementText("name") + " " + comment;
303                 }
304 
305                 comment = StringUtil.wrap(comment, 80 - indentLength - 5, "\n");
306 
307                 comment = comment.trim();
308 
309                 comment = StringUtil.replace(
310                     comment, "\n", "\n" + indent + " *" + maxNameIndent);
311 
312                 while (comment.contains(" \n")) {
313                     comment = StringUtil.replace(comment, " \n", "\n");
314                 }
315 
316                 while (comment.startsWith("\n")) {
317                     comment = comment.substring(1, comment.length());
318                 }
319 
320                 sb.append(comment);
321                 sb.append("\n");
322             }
323         }
324 
325         return sb.toString();
326     }
327 
328     private void _addFieldElement(Element rootElement, JavaField javaField)
329         throws Exception {
330 
331         Element fieldElement = rootElement.addElement("field");
332 
333         DocUtil.add(fieldElement, "name", javaField.getName());
334 
335         Element commentElement = fieldElement.addElement("comment");
336 
337         commentElement.addCDATA(_getCDATA(javaField));
338 
339         _addDocletElements(fieldElement, javaField, "version");
340         _addDocletElements(fieldElement, javaField, "see");
341         _addDocletElements(fieldElement, javaField, "since");
342         _addDocletElements(fieldElement, javaField, "deprecated");
343     }
344 
345     private void _addMethodElement(Element rootElement, JavaMethod javaMethod)
346         throws Exception {
347 
348         Element methodElement = rootElement.addElement("method");
349 
350         DocUtil.add(methodElement, "name", javaMethod.getName());
351 
352         Element commentElement = methodElement.addElement("comment");
353 
354         commentElement.addCDATA(_getCDATA(javaMethod));
355 
356         _addDocletElements(methodElement, javaMethod, "version");
357         _addParamElements(methodElement, javaMethod);
358         _addReturnElement(methodElement, javaMethod);
359         _addThrowsElements(methodElement, javaMethod);
360         _addDocletElements(methodElement, javaMethod, "see");
361         _addDocletElements(methodElement, javaMethod, "since");
362         _addDocletElements(methodElement, javaMethod, "deprecated");
363     }
364 
365     private void _addParamElement(
366         Element methodElement, JavaParameter javaParameter,
367         DocletTag[] paramDocletTags) {
368 
369         String name = javaParameter.getName();
370         String type = javaParameter.getType().getValue();
371         String value = null;
372 
373         for (DocletTag paramDocletTag : paramDocletTags) {
374             String curValue = paramDocletTag.getValue();
375 
376             if (!curValue.startsWith(name)) {
377                 continue;
378             }
379             else {
380                 value = curValue;
381 
382                 break;
383             }
384         }
385 
386         Element paramElement = methodElement.addElement("param");
387 
388         DocUtil.add(paramElement, "name", name);
389         DocUtil.add(paramElement, "type", type);
390 
391         if (value != null) {
392             value = value.substring(name.length());
393         }
394 
395         Element commentElement = paramElement.addElement("comment");
396 
397         commentElement.addCDATA(_getCDATA(value));
398     }
399 
400     private void _addParamElements(
401         Element methodElement, JavaMethod javaMethod) {
402 
403         JavaParameter[] javaParameters = javaMethod.getParameters();
404 
405         DocletTag[] paramDocletTags = javaMethod.getTagsByName("param");
406 
407         for (JavaParameter javaParameter : javaParameters) {
408             _addParamElement(methodElement, javaParameter, paramDocletTags);
409         }
410     }
411 
412     private void _addReturnElement(
413             Element methodElement, JavaMethod javaMethod)
414         throws Exception {
415 
416         Type returns = javaMethod.getReturns();
417 
418         if ((returns == null) || returns.getValue().equals("void")) {
419             return;
420         }
421 
422         _addDocletElements(methodElement, javaMethod, "return");
423     }
424 
425     private void _addThrowsElement(
426         Element methodElement, Type exception, DocletTag[] throwsDocletTags) {
427 
428         String name = exception.getJavaClass().getName();
429         String value = null;
430 
431         for (DocletTag throwsDocletTag : throwsDocletTags) {
432             String curValue = throwsDocletTag.getValue();
433 
434             if (!curValue.startsWith(name)) {
435                 continue;
436             }
437             else {
438                 value = curValue;
439 
440                 break;
441             }
442         }
443 
444         Element throwsElement = methodElement.addElement("throws");
445 
446         DocUtil.add(throwsElement, "name", name);
447         DocUtil.add(throwsElement, "type", exception.getValue());
448 
449         if (value != null) {
450             value = value.substring(name.length());
451         }
452 
453         Element commentElement = throwsElement.addElement("comment");
454 
455         commentElement.addCDATA(_getCDATA(value));
456 
457     }
458 
459     private void _addThrowsElements(
460         Element methodElement, JavaMethod javaMethod) {
461 
462         Type[] exceptions = javaMethod.getExceptions();
463 
464         DocletTag[] throwsDocletTags = javaMethod.getTagsByName("throws");
465 
466         for (Type exception : exceptions) {
467             _addThrowsElement(methodElement, exception, throwsDocletTags);
468         }
469     }
470 
471     private String _getCDATA(AbstractJavaEntity abstractJavaEntity) {
472         return _getCDATA(abstractJavaEntity.getComment());
473     }
474 
475     private String _getCDATA(String cdata) {
476         if (cdata == null) {
477             return StringPool.BLANK;
478         }
479 
480         cdata = StringUtil.replace(
481             cdata,
482             new String[] {
483                 "\n", "<p>", "</p>", "<li>", "</li>"
484             },
485             new String[] {
486                 " ", " \n<p>\n", "\n</p>\n", " \n<li>\n", "\n</li>\n"
487             });
488 
489         while (cdata.contains("\n ")) {
490             cdata = StringUtil.replace(cdata, "\n ", "\n");
491         }
492 
493         while (cdata.contains("  ")) {
494             cdata = StringUtil.replace(cdata, "  ", " ");
495         }
496 
497         cdata = StringUtil.replace(cdata, "</p>\n<p>", "</p>\n\n<p>");
498         cdata = StringUtil.replace(cdata, "</li>\n<li>", "</li>\n\n<li>");
499 
500         return cdata.trim();
501     }
502 
503     private String _getFieldKey(Element fieldElement) {
504         return fieldElement.elementText("name");
505     }
506 
507     private String _getFieldKey(JavaField javaField) {
508         return javaField.getName();
509     }
510 
511     private int _getIndentLength(String indent) {
512         int indentLength = 0;
513 
514         for (char c : indent.toCharArray()) {
515             if (c == '\t') {
516                 indentLength = indentLength + 4;
517             }
518             else {
519                 indentLength++;
520             }
521         }
522 
523         return indentLength;
524     }
525 
526     private JavaClass _getJavaClass(String fileName, Reader reader)
527         throws Exception {
528 
529         int pos = fileName.indexOf("src/");
530 
531         if (pos == -1) {
532             pos = fileName.indexOf("test/");
533         }
534 
535         if (pos == -1) {
536             throw new RuntimeException(fileName);
537         }
538 
539         pos = fileName.indexOf("/", pos);
540 
541         String srcFile = fileName.substring(pos + 1, fileName.length());
542         String className = StringUtil.replace(
543             srcFile.substring(0, srcFile.length() - 5), "/", ".");
544 
545         JavaDocBuilder builder = new JavaDocBuilder();
546 
547         if (reader == null) {
548             File file = new File(fileName);
549 
550             if (!file.exists()) {
551                 return null;
552             }
553 
554             builder.addSource(file);
555         }
556         else {
557             builder.addSource(reader);
558         }
559 
560         return builder.getClassByName(className);
561     }
562 
563     private String _getJavaClassComment(
564         Element rootElement, JavaClass javaClass) {
565 
566         StringBuilder sb = new StringBuilder();
567 
568         String indent = StringPool.BLANK;
569 
570         sb.append("/**\n");
571 
572         String viewSourceHREF =
573             " * <a href=\"" + javaClass.getName() +
574                 ".java.html\"><b><i>View Source</i></b></a>";
575 
576         if (viewSourceHREF.length() > 80) {
577             int x = viewSourceHREF.lastIndexOf("<", 80);
578             int y = viewSourceHREF.lastIndexOf(" ", 80);
579 
580             int start = x;
581             int end = x;
582 
583             if (x < y) {
584                 start = y;
585                 end = y + 1;
586             }
587 
588             viewSourceHREF =
589                 viewSourceHREF.substring(0, start) + "\n * " +
590                     viewSourceHREF.substring(end);
591         }
592 
593         sb.append(viewSourceHREF);
594         sb.append("\n");
595 
596         String comment = rootElement.elementText("comment");
597 
598         if (_initializeMissingJavadocs || Validator.isNotNull(comment)) {
599             sb.append(" *\n");
600             sb.append(_wrapText(comment, indent));
601             sb.append("\n");
602         }
603 
604         String docletTags = _addDocletTags(
605             rootElement,
606             new String[] {
607                 "author", "version", "see", "since", "serial", "deprecated"
608             },
609             indent);
610 
611         if (docletTags.length() > 0) {
612             //if (_initializeMissingJavadocs || Validator.isNotNull(comment)) {
613                 sb.append(" *\n");
614             //}
615 
616             sb.append(docletTags);
617         }
618 
619         sb.append(" */\n");
620 
621         return sb.toString();
622     }
623 
624     private Document _getJavadocDocument(JavaClass javaClass) throws Exception {
625         Element rootElement = _saxReaderUtil.createElement("javadoc");
626 
627         Document document = _saxReaderUtil.createDocument(rootElement);
628 
629         DocUtil.add(rootElement, "name", javaClass.getName());
630         DocUtil.add(rootElement, "type", javaClass.getFullyQualifiedName());
631 
632         _addClassCommentElement(rootElement, javaClass);
633         _addDocletElements(rootElement, javaClass, "author");
634         _addDocletElements(rootElement, javaClass, "version");
635         _addDocletElements(rootElement, javaClass, "see");
636         _addDocletElements(rootElement, javaClass, "since");
637         _addDocletElements(rootElement, javaClass, "serial");
638         _addDocletElements(rootElement, javaClass, "deprecated");
639 
640         JavaMethod[] javaMethods = javaClass.getMethods();
641 
642         for (JavaMethod javaMethod : javaMethods) {
643             _addMethodElement(rootElement, javaMethod);
644         }
645 
646         JavaField[] javaFields = javaClass.getFields();
647 
648         for (JavaField javaField : javaFields) {
649             _addFieldElement(rootElement, javaField);
650         }
651 
652         return document;
653     }
654 
655     private String _getJavaFieldComment(
656         String[] lines, Map<String, Element> fieldElementsMap,
657         JavaField javaField) {
658 
659         String fieldKey = _getFieldKey(javaField);
660 
661         Element fieldElement = fieldElementsMap.get(fieldKey);
662 
663         if (fieldElement == null) {
664             return null;
665         }
666 
667         String line = lines[javaField.getLineNumber() - 1];
668 
669         String indent = StringPool.BLANK;
670 
671         for (char c : line.toCharArray()) {
672             if (Character.isWhitespace(c)) {
673                 indent += c;
674             }
675             else {
676                 break;
677             }
678         }
679 
680         StringBuilder sb = new StringBuilder();
681 
682         sb.append(indent);
683         sb.append("/**\n");
684 
685         String comment = fieldElement.elementText("comment");
686 
687         if (_initializeMissingJavadocs || Validator.isNotNull(comment)) {
688             sb.append(_wrapText(comment, indent));
689             sb.append("\n");
690         }
691 
692         String docletTags = _addDocletTags(
693             fieldElement,
694             new String[] {"version", "see", "since", "deprecated"}, indent);
695 
696         if (docletTags.length() > 0) {
697             if (_initializeMissingJavadocs || Validator.isNotNull(comment)) {
698                 sb.append(indent);
699                 sb.append(" *\n");
700             }
701 
702             sb.append(docletTags);
703         }
704 
705         sb.append(indent);
706         sb.append(" */\n");
707 
708         if (!_initializeMissingJavadocs && Validator.isNull(comment) &&
709             Validator.isNull(docletTags)) {
710 
711             return null;
712         }
713 
714         return sb.toString();
715     }
716 
717     private String _getJavaMethodComment(
718         String[] lines, Map<String, Element> methodElementsMap,
719         JavaMethod javaMethod) {
720 
721         String methodKey = _getMethodKey(javaMethod);
722 
723         Element methodElement = methodElementsMap.get(methodKey);
724 
725         if (methodElement == null) {
726             return null;
727         }
728 
729         String line = lines[javaMethod.getLineNumber() - 1];
730 
731         String indent = StringPool.BLANK;
732 
733         for (char c : line.toCharArray()) {
734             if (Character.isWhitespace(c)) {
735                 indent += c;
736             }
737             else {
738                 break;
739             }
740         }
741 
742         StringBuilder sb = new StringBuilder();
743 
744         sb.append(indent);
745         sb.append("/**\n");
746 
747         String comment = methodElement.elementText("comment");
748 
749         if (_initializeMissingJavadocs || Validator.isNotNull(comment)) {
750             sb.append(_wrapText(comment, indent));
751             sb.append("\n");
752         }
753 
754         String docletTags = _addDocletTags(
755             methodElement,
756             new String[] {
757                 "version", "param", "return", "throws", "see", "since",
758                 "deprecated"
759             },
760             indent);
761 
762         if (docletTags.length() > 0) {
763             if (_initializeMissingJavadocs || Validator.isNotNull(comment)) {
764                 sb.append(indent);
765                 sb.append(" *\n");
766             }
767 
768             sb.append(docletTags);
769         }
770 
771         sb.append(indent);
772         sb.append(" */\n");
773 
774         if (!_initializeMissingJavadocs && Validator.isNull(comment) &&
775             Validator.isNull(docletTags)) {
776 
777             return null;
778         }
779 
780         return sb.toString();
781     }
782 
783     private String _getMethodKey(Element methodElement) {
784         StringBuilder sb = new StringBuilder();
785 
786         sb.append(methodElement.elementText("name"));
787         sb.append("(");
788 
789         List<Element> paramElements = methodElement.elements("param");
790 
791         for (Element paramElement : paramElements) {
792             sb.append(paramElement.elementText("name"));
793             sb.append("|");
794             sb.append(paramElement.elementText("type"));
795             sb.append(",");
796         }
797 
798         sb.append(")");
799 
800         return sb.toString();
801     }
802 
803     private String _getMethodKey(JavaMethod javaMethod) {
804         StringBuilder sb = new StringBuilder();
805 
806         sb.append(javaMethod.getName());
807         sb.append("(");
808 
809         JavaParameter[] javaParameters = javaMethod.getParameters();
810 
811         for (JavaParameter javaParameter : javaParameters) {
812             sb.append(javaParameter.getName());
813             sb.append("|");
814             sb.append(javaParameter.getType().getValue());
815             sb.append(",");
816         }
817 
818         sb.append(")");
819 
820         return sb.toString();
821     }
822 
823     private boolean _isGenerated(String content) {
824         if (content.contains("* @generated")) {
825             return true;
826         }
827         else {
828             return false;
829         }
830     }
831 
832     private String _removeJavadocFromJava(
833         JavaClass javaClass, String content) {
834 
835         Set<Integer> lineNumbers = new HashSet<Integer>();
836 
837         lineNumbers.add(javaClass.getLineNumber());
838 
839         JavaMethod[] javaMethods = javaClass.getMethods();
840 
841         for (JavaMethod javaMethod : javaMethods) {
842             lineNumbers.add(javaMethod.getLineNumber());
843         }
844 
845         JavaField[] javaFields = javaClass.getFields();
846 
847         for (JavaField javaField : javaFields) {
848             lineNumbers.add(javaField.getLineNumber());
849         }
850 
851         String[] lines = StringUtil.split(content, "\n");
852 
853         for (int lineNumber : lineNumbers) {
854             int pos = lineNumber - 2;
855 
856             String line = lines[pos].trim();
857 
858             if (line.endsWith("*/")) {
859                 while (true) {
860                     lines[pos] = null;
861 
862                     if (line.startsWith("/**")) {
863                         break;
864                     }
865 
866                     line = lines[--pos].trim();
867                 }
868             }
869         }
870 
871         StringBuilder sb = new StringBuilder(content.length());
872 
873         for (String line : lines) {
874             if (line != null) {
875                 sb.append(line);
876                 sb.append("\n");
877             }
878         }
879 
880         return sb.toString().trim();
881     }
882 
883     private void _format(String fileName) throws Exception {
884         FileInputStream fis = new FileInputStream(
885             new File(_basedir + fileName));
886 
887         byte[] bytes = new byte[fis.available()];
888 
889         fis.read(bytes);
890 
891         fis.close();
892 
893         String originalContent = new String(bytes);
894 
895         if (!fileName.endsWith("JavadocFormatter.java") &&
896             _isGenerated(originalContent)) {
897 
898             return;
899         }
900 
901         JavaClass javaClass = _getJavaClass(
902             fileName, new StringReader(originalContent));
903 
904         String javadocLessContent = _removeJavadocFromJava(
905             javaClass, originalContent);
906 
907         Document document = _getJavadocDocument(javaClass);
908 
909         _updateJavaFromDocument(
910             fileName, originalContent, javadocLessContent, document);
911     }
912 
913     private void _updateJavaFromDocument(
914             String fileName, String originalContent, String javadocLessContent,
915             Document document)
916         throws Exception {
917 
918         String[] lines = StringUtil.split(javadocLessContent, "\n");
919 
920         JavaClass javaClass = _getJavaClass(
921             fileName, new StringReader(javadocLessContent));
922 
923         Element rootElement = document.getRootElement();
924 
925         Map<Integer, String> commentsMap = new TreeMap<Integer, String>();
926 
927         commentsMap.put(
928             javaClass.getLineNumber(),
929             _getJavaClassComment(rootElement, javaClass));
930 
931         Map<String, Element> methodElementsMap = new HashMap<String, Element>();
932 
933         List<Element> methodElements = rootElement.elements("method");
934 
935         for (Element methodElement : methodElements) {
936             String methodKey = _getMethodKey(methodElement);
937 
938             methodElementsMap.put(methodKey, methodElement);
939         }
940 
941         JavaMethod[] javaMethods = javaClass.getMethods();
942 
943         for (JavaMethod javaMethod : javaMethods) {
944             if (commentsMap.containsKey(javaMethod.getLineNumber())) {
945                 continue;
946             }
947 
948             commentsMap.put(
949                 javaMethod.getLineNumber(),
950                 _getJavaMethodComment(lines, methodElementsMap, javaMethod));
951         }
952 
953         Map<String, Element> fieldElementsMap = new HashMap<String, Element>();
954 
955         List<Element> fieldElements = rootElement.elements("field");
956 
957         for (Element fieldElement : fieldElements) {
958             String fieldKey = _getFieldKey(fieldElement);
959 
960             fieldElementsMap.put(fieldKey, fieldElement);
961         }
962 
963         JavaField[] javaFields = javaClass.getFields();
964 
965         for (JavaField javaField : javaFields) {
966             if (commentsMap.containsKey(javaField.getLineNumber())) {
967                 continue;
968             }
969 
970             commentsMap.put(
971                 javaField.getLineNumber(),
972                 _getJavaFieldComment(lines, fieldElementsMap, javaField));
973         }
974 
975         StringBuilder sb = new StringBuilder(javadocLessContent.length());
976 
977         for (int lineNumber = 1; lineNumber <= lines.length; lineNumber++) {
978             String line = lines[lineNumber - 1];
979 
980             String comments = commentsMap.get(lineNumber);
981 
982             if (comments != null) {
983                 sb.append(comments);
984             }
985 
986             sb.append(line);
987             sb.append("\n");
988         }
989 
990         String formattedContent = sb.toString().trim();
991 
992         if (!originalContent.equals(formattedContent)) {
993             File file = new File(_basedir + fileName);
994 
995             _fileUtil.write(file, formattedContent.getBytes());
996 
997             System.out.println("Writing " + file);
998         }
999     }
1000
1001    private String _wrapText(String text, String indent) {
1002        int indentLength = _getIndentLength(indent);
1003
1004        text = StringUtil.wrap(text, 80 - indentLength - 3, "\n");
1005
1006        text = "\n" + text.trim();
1007
1008        text = StringUtil.replace(text, "\n", "\n" + indent + " * ");
1009
1010        while (text.contains(" \n")) {
1011            text = StringUtil.replace(text, " \n", "\n");
1012        }
1013
1014        while (text.startsWith("\n")) {
1015            text = text.substring(1, text.length());
1016        }
1017
1018        return text;
1019    }
1020
1021    private static FileImpl _fileUtil = FileImpl.getInstance();
1022    private static SAXReaderImpl _saxReaderUtil = SAXReaderImpl.getInstance();
1023
1024    private String _basedir = "./";
1025    private boolean _initializeMissingJavadocs;
1026
1027}