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