001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.tools;
016    
017    import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
018    import com.liferay.portal.kernel.util.GetterUtil;
019    import com.liferay.portal.kernel.util.StringBundler;
020    import com.liferay.portal.kernel.util.StringPool;
021    import com.liferay.portal.kernel.util.StringUtil;
022    import com.liferay.portal.kernel.util.Tuple;
023    import com.liferay.portal.kernel.util.Validator;
024    import com.liferay.portal.kernel.xml.Document;
025    import com.liferay.portal.kernel.xml.Element;
026    import com.liferay.portal.tools.servicebuilder.ServiceBuilder;
027    import com.liferay.portal.util.FileImpl;
028    import com.liferay.portal.xml.SAXReaderImpl;
029    import com.liferay.util.xml.DocUtil;
030    
031    import com.thoughtworks.qdox.JavaDocBuilder;
032    import com.thoughtworks.qdox.model.AbstractBaseJavaEntity;
033    import com.thoughtworks.qdox.model.AbstractJavaEntity;
034    import com.thoughtworks.qdox.model.Annotation;
035    import com.thoughtworks.qdox.model.DocletTag;
036    import com.thoughtworks.qdox.model.JavaClass;
037    import com.thoughtworks.qdox.model.JavaField;
038    import com.thoughtworks.qdox.model.JavaMethod;
039    import com.thoughtworks.qdox.model.JavaPackage;
040    import com.thoughtworks.qdox.model.JavaParameter;
041    import com.thoughtworks.qdox.model.Type;
042    
043    import java.io.File;
044    import java.io.FileInputStream;
045    import java.io.InputStream;
046    import java.io.Reader;
047    
048    import java.util.ArrayList;
049    import java.util.Collection;
050    import java.util.HashMap;
051    import java.util.HashSet;
052    import java.util.List;
053    import java.util.Map;
054    import java.util.Set;
055    import java.util.TreeMap;
056    import java.util.regex.Matcher;
057    import java.util.regex.Pattern;
058    
059    import org.apache.tools.ant.DirectoryScanner;
060    
061    /**
062     * @author Brian Wing Shun Chan
063     * @author Connor McKay
064     * @author James Hinkey
065     */
066    public class JavadocFormatter {
067    
068            public static void main(String[] args) {
069                    try {
070                            new JavadocFormatter(args);
071                    }
072                    catch (Exception e) {
073                            e.printStackTrace();
074                    }
075            }
076    
077            public JavadocFormatter(String[] args) throws Exception {
078                    Map<String, String> arguments = ArgumentsUtil.parseArguments(args);
079    
080                    String init = arguments.get("javadoc.init");
081    
082                    if (Validator.isNotNull(init) && !init.startsWith("$")) {
083                            _initializeMissingJavadocs = GetterUtil.getBoolean(init);
084                    }
085    
086                    _inputDir = GetterUtil.getString(arguments.get("javadoc.input.dir"));
087    
088                    if (_inputDir.startsWith("$")) {
089                            _inputDir = "./";
090                    }
091    
092                    if (!_inputDir.endsWith("/")) {
093                            _inputDir += "/";
094                    }
095    
096                    System.out.println("Input directory is " + _inputDir);
097    
098                    String limit = arguments.get("javadoc.limit");
099    
100                    _outputFilePrefix = GetterUtil.getString(
101                            arguments.get("javadoc.output.file.prefix"));
102    
103                    if (_outputFilePrefix.startsWith("$")) {
104                            _outputFilePrefix = "javadocs";
105                    }
106    
107                    String update = arguments.get("javadoc.update");
108    
109                    if (Validator.isNotNull(update) && !update.startsWith("$")) {
110                            _updateJavadocs = GetterUtil.getBoolean(update);
111                    }
112    
113                    DirectoryScanner directoryScanner = new DirectoryScanner();
114    
115                    directoryScanner.setBasedir(_inputDir);
116                    directoryScanner.setExcludes(
117                            new String[] {"**\\classes\\**", "**\\portal-client\\**"});
118    
119                    List<String> includes = new ArrayList<String>();
120    
121                    if (Validator.isNotNull(limit) && !limit.startsWith("$")) {
122                            System.out.println("Limit on " + limit);
123    
124                            String[] limitArray = StringUtil.split(limit, '/');
125    
126                            for (String curLimit : limitArray) {
127                                    includes.add(
128                                            "**\\" + StringUtil.replace(curLimit, ".", "\\") +
129                                                    "\\**\\*.java");
130                                    includes.add("**\\" + curLimit + ".java");
131                            }
132                    }
133                    else {
134                            includes.add("**\\*.java");
135                    }
136    
137                    directoryScanner.setIncludes(
138                            includes.toArray(new String[includes.size()]));
139    
140                    directoryScanner.scan();
141    
142                    String[] fileNames = directoryScanner.getIncludedFiles();
143    
144                    if ((fileNames.length == 0) && Validator.isNotNull(limit) &&
145                            !limit.startsWith("$")) {
146    
147                            StringBundler sb = new StringBundler("Limit file not found: ");
148    
149                            sb.append(limit);
150    
151                            if (limit.contains(".")) {
152                                    sb.append(" Specify limit filename without package path or ");
153                                    sb.append("file type suffix.");
154                            }
155    
156                            System.out.println(sb.toString());
157                    }
158    
159                    for (String fileName : fileNames) {
160                            fileName = StringUtil.replace(fileName, "\\", "/");
161    
162                            _format(fileName);
163                    }
164    
165                    for (Map.Entry<String, Tuple> entry : _javadocxXmlTuples.entrySet()) {
166                            Tuple tuple = entry.getValue();
167    
168                            File javadocsXmlFile = (File)tuple.getObject(1);
169                            String oldJavadocsXmlContent = (String)tuple.getObject(2);
170                            Document javadocsXmlDocument = (Document)tuple.getObject(3);
171    
172                            Element javadocsXmlRootElement =
173                                    javadocsXmlDocument.getRootElement();
174    
175                            javadocsXmlRootElement.sortElementsByChildElement(
176                                    "javadoc", "type");
177    
178                            String newJavadocsXmlContent =
179                                    javadocsXmlDocument.formattedString();
180    
181                            if (!oldJavadocsXmlContent.equals(newJavadocsXmlContent)) {
182                                    _fileUtil.write(javadocsXmlFile, newJavadocsXmlContent);
183                            }
184    
185                            _detachUnnecessaryTypes(javadocsXmlRootElement);
186    
187                            File javadocsRuntimeXmlFile = new File(
188                                    StringUtil.replaceLast(
189                                            javadocsXmlFile.toString(), "-all.xml", "-rt.xml"));
190    
191                            String oldJavadocsRuntimeXmlContent = StringPool.BLANK;
192    
193                            if (javadocsRuntimeXmlFile.exists()) {
194                                    oldJavadocsRuntimeXmlContent = _fileUtil.read(
195                                            javadocsRuntimeXmlFile);
196                            }
197    
198                            String newJavadocsRuntimeXmlContent =
199                                    javadocsXmlDocument.compactString();
200    
201                            if (!oldJavadocsRuntimeXmlContent.equals(
202                                            newJavadocsRuntimeXmlContent)) {
203    
204                                    _fileUtil.write(
205                                            javadocsRuntimeXmlFile, newJavadocsRuntimeXmlContent);
206                            }
207                    }
208            }
209    
210            private void _addClassCommentElement(
211                    Element rootElement, JavaClass javaClass) {
212    
213                    String comment = _getCDATA(javaClass);
214    
215                    if (comment.startsWith("Copyright (c)")) {
216                            comment = StringPool.BLANK;
217                    }
218    
219                    if (Validator.isNull(comment)) {
220                            return;
221                    }
222    
223                    Element commentElement = rootElement.addElement("comment");
224    
225                    commentElement.addCDATA(comment);
226            }
227    
228            private void _addDocletElements(
229                            Element parentElement, AbstractJavaEntity abstractJavaEntity,
230                            String name)
231                    throws Exception {
232    
233                    DocletTag[] docletTags = abstractJavaEntity.getTagsByName(name);
234    
235                    for (DocletTag docletTag : docletTags) {
236                            String value = docletTag.getValue();
237    
238                            value = _trimMultilineText(value);
239    
240                            value = StringUtil.replace(value, " </", "</");
241    
242                            Element element = parentElement.addElement(name);
243    
244                            element.addCDATA(value);
245                    }
246    
247                    if ((docletTags.length == 0) && name.equals("author")) {
248                            Element element = parentElement.addElement(name);
249    
250                            element.addCDATA(ServiceBuilder.AUTHOR);
251                    }
252            }
253    
254            private String _addDocletTags(
255                    Element parentElement, String[] tagNames, String indent,
256                    boolean publicAccess) {
257    
258                    List<String> allTagNames = new ArrayList<String>();
259                    List<String> commonTagNamesWithComments = new ArrayList<String>();
260                    List<String> customTagNames = new ArrayList<String>();
261    
262                    for (String tagName : tagNames) {
263                            List<Element> elements = parentElement.elements(tagName);
264    
265                            for (Element element : elements) {
266                                    Element commentElement = element.element("comment");
267    
268                                    String comment = null;
269    
270                                    // Get comment by comment element's text or the element's text
271    
272                                    if (commentElement != null) {
273                                            comment = commentElement.getText();
274                                    }
275                                    else {
276                                            comment = element.getText();
277                                    }
278    
279                                    if (tagName.equals("param") || tagName.equals("return") ||
280                                            tagName.equals("throws")) {
281    
282                                            if (Validator.isNotNull(comment)) {
283                                                    commonTagNamesWithComments.add(tagName);
284                                            }
285                                    }
286                                    else {
287                                            customTagNames.add(tagName);
288                                    }
289    
290                                    allTagNames.add(tagName);
291                            }
292                    }
293    
294                    int maxTagNameLength = 0;
295    
296                    List<String> maxTagNameLengthTags = new ArrayList<String>();
297    
298                    if (_initializeMissingJavadocs) {
299                            maxTagNameLengthTags.addAll(allTagNames);
300                    }
301                    else if (_updateJavadocs) {
302                            if (!commonTagNamesWithComments.isEmpty()) {
303                                    maxTagNameLengthTags.addAll(allTagNames);
304                            }
305                            else {
306                                    maxTagNameLengthTags.addAll(commonTagNamesWithComments);
307                                    maxTagNameLengthTags.addAll(customTagNames);
308                            }
309                    }
310                    else {
311                            maxTagNameLengthTags.addAll(commonTagNamesWithComments);
312                            maxTagNameLengthTags.addAll(customTagNames);
313                    }
314    
315                    for (String name : maxTagNameLengthTags) {
316                            if (name.length() > maxTagNameLength) {
317                                    maxTagNameLength = name.length();
318                            }
319                    }
320    
321                    // There should be an @ sign before the tag name and a space after it
322    
323                    maxTagNameLength += 2;
324    
325                    String tagNameIndent = _getSpacesIndent(maxTagNameLength);
326    
327                    StringBundler sb = new StringBundler();
328    
329                    for (String tagName : tagNames) {
330                            List<Element> elements = parentElement.elements(tagName);
331    
332                            for (Element element : elements) {
333                                    Element commentElement = element.element("comment");
334    
335                                    String comment = null;
336    
337                                    if (commentElement != null) {
338                                            comment = commentElement.getText();
339                                    }
340                                    else {
341                                            comment = element.getText();
342                                    }
343    
344                                    String elementName = null;
345    
346                                    if (commentElement != null) {
347                                            elementName = element.elementText("name");
348                                    }
349    
350                                    if (Validator.isNotNull(comment)) {
351                                            comment = _assembleTagComment(
352                                                    tagName, elementName, comment, indent, tagNameIndent);
353    
354                                            sb.append(comment);
355                                    }
356                                    else {
357                                            if (_initializeMissingJavadocs && publicAccess) {
358    
359                                                    // Write out all tags
360    
361                                                    comment = _assembleTagComment(
362                                                            tagName, elementName, comment, indent,
363                                                            tagNameIndent);
364    
365                                                    sb.append(comment);
366                                            }
367                                            else if (_updateJavadocs && publicAccess) {
368                                                    if (!tagName.equals("param") &&
369                                                            !tagName.equals("return") &&
370                                                            !tagName.equals("throws")) {
371    
372                                                            // Write out custom tag name
373    
374                                                            comment = _assembleTagComment(
375                                                                    tagName, elementName, comment, indent,
376                                                                    tagNameIndent);
377    
378                                                            sb.append(comment);
379                                                    }
380                                                    else if (!commonTagNamesWithComments.isEmpty()) {
381    
382                                                            // Write out all tags
383    
384                                                            comment = _assembleTagComment(
385                                                                    tagName, elementName, comment, indent,
386                                                                    tagNameIndent);
387    
388                                                            sb.append(comment);
389                                                    }
390                                                    else {
391    
392                                                            // Skip empty common tag name
393    
394                                                    }
395                                            }
396                                            else {
397                                                    if (!tagName.equals("param") &&
398                                                            !tagName.equals("return") &&
399                                                            !tagName.equals("throws")) {
400    
401                                                            // Write out custom tag name
402    
403                                                            comment = _assembleTagComment(
404                                                                    tagName, elementName, comment, indent,
405                                                                    tagNameIndent);
406    
407                                                            sb.append(comment);
408                                                    }
409                                                    else {
410    
411                                                            // Skip empty common tag name
412    
413                                                    }
414                                            }
415                                    }
416                            }
417                    }
418    
419                    return sb.toString();
420            }
421    
422            private void _addFieldElement(Element rootElement, JavaField javaField)
423                    throws Exception {
424    
425                    Element fieldElement = rootElement.addElement("field");
426    
427                    DocUtil.add(fieldElement, "name", javaField.getName());
428    
429                    String comment = _getCDATA(javaField);
430    
431                    if (Validator.isNotNull(comment)) {
432                            Element commentElement = fieldElement.addElement("comment");
433    
434                            commentElement.addCDATA(comment);
435                    }
436    
437                    _addDocletElements(fieldElement, javaField, "version");
438                    _addDocletElements(fieldElement, javaField, "see");
439                    _addDocletElements(fieldElement, javaField, "since");
440                    _addDocletElements(fieldElement, javaField, "deprecated");
441            }
442    
443            private void _addMethodElement(Element rootElement, JavaMethod javaMethod)
444                    throws Exception {
445    
446                    Element methodElement = rootElement.addElement("method");
447    
448                    DocUtil.add(methodElement, "name", javaMethod.getName());
449    
450                    String comment = _getCDATA(javaMethod);
451    
452                    if (Validator.isNotNull(comment)) {
453                            Element commentElement = methodElement.addElement("comment");
454    
455                            commentElement.addCDATA(_getCDATA(javaMethod));
456                    }
457    
458                    _addDocletElements(methodElement, javaMethod, "version");
459                    _addParamElements(methodElement, javaMethod);
460                    _addReturnElement(methodElement, javaMethod);
461                    _addThrowsElements(methodElement, javaMethod);
462                    _addDocletElements(methodElement, javaMethod, "see");
463                    _addDocletElements(methodElement, javaMethod, "since");
464                    _addDocletElements(methodElement, javaMethod, "deprecated");
465            }
466    
467            private void _addParamElement(
468                    Element methodElement, JavaParameter javaParameter,
469                    DocletTag[] paramDocletTags) {
470    
471                    String name = javaParameter.getName();
472    
473                    String value = null;
474    
475                    for (DocletTag paramDocletTag : paramDocletTags) {
476                            String curValue = paramDocletTag.getValue();
477    
478                            if (!curValue.startsWith(name)) {
479                                    continue;
480                            }
481                            else {
482                                    value = curValue;
483    
484                                    break;
485                            }
486                    }
487    
488                    Element paramElement = methodElement.addElement("param");
489    
490                    DocUtil.add(paramElement, "name", name);
491                    DocUtil.add(paramElement, "type", _getTypeValue(javaParameter));
492    
493                    if (value != null) {
494                            value = value.substring(name.length());
495                    }
496    
497                    value = _trimMultilineText(value);
498    
499                    if (Validator.isNotNull(value)) {
500                            Element commentElement = paramElement.addElement("comment");
501    
502                            commentElement.addCDATA(value);
503                    }
504            }
505    
506            private void _addParamElements(
507                    Element methodElement, JavaMethod javaMethod) {
508    
509                    JavaParameter[] javaParameters = javaMethod.getParameters();
510    
511                    DocletTag[] paramDocletTags = javaMethod.getTagsByName("param");
512    
513                    for (JavaParameter javaParameter : javaParameters) {
514                            _addParamElement(methodElement, javaParameter, paramDocletTags);
515                    }
516            }
517    
518            private void _addReturnElement(
519                            Element methodElement, JavaMethod javaMethod)
520                    throws Exception {
521    
522                    Type returns = javaMethod.getReturns();
523    
524                    if (returns == null) {
525                            return;
526                    }
527    
528                    String returnsValue = returns.getValue();
529    
530                    if (returnsValue.equals("void")) {
531                            return;
532                    }
533    
534                    DocletTag[] returnDocletTags = javaMethod.getTagsByName("return");
535    
536                    String comment = StringPool.BLANK;
537    
538                    if (returnDocletTags.length > 0) {
539                            DocletTag returnDocletTag = returnDocletTags[0];
540    
541                            comment = GetterUtil.getString(returnDocletTag.getValue());
542                    }
543    
544                    comment = _trimMultilineText(comment);
545    
546                    if (Validator.isNotNull(comment)) {
547                            Element returnElement = methodElement.addElement("return");
548    
549                            Element commentElement = returnElement.addElement("comment");
550    
551                            commentElement.addCDATA(comment);
552                    }
553            }
554    
555            private void _addThrowsElement(
556                    Element methodElement, Type exceptionType,
557                    DocletTag[] throwsDocletTags) {
558    
559                    JavaClass javaClass = exceptionType.getJavaClass();
560    
561                    String name = javaClass.getName();
562    
563                    String value = null;
564    
565                    for (DocletTag throwsDocletTag : throwsDocletTags) {
566                            String curValue = throwsDocletTag.getValue();
567    
568                            if (!curValue.startsWith(name)) {
569                                    continue;
570                            }
571                            else {
572                                    value = curValue;
573    
574                                    break;
575                            }
576                    }
577    
578                    Element throwsElement = methodElement.addElement("throws");
579    
580                    DocUtil.add(throwsElement, "name", name);
581                    DocUtil.add(throwsElement, "type", exceptionType.getValue());
582    
583                    if (value != null) {
584                            value = value.substring(name.length());
585                    }
586    
587                    value = _trimMultilineText(value);
588    
589                    if (Validator.isNotNull(value)) {
590                            Element commentElement = throwsElement.addElement("comment");
591    
592                            commentElement.addCDATA(_getCDATA(value));
593                    }
594            }
595    
596            private void _addThrowsElements(
597                    Element methodElement, JavaMethod javaMethod) {
598    
599                    Type[] exceptionTypes = javaMethod.getExceptions();
600    
601                    DocletTag[] throwsDocletTags = javaMethod.getTagsByName("throws");
602    
603                    for (Type exceptionType : exceptionTypes) {
604                            _addThrowsElement(methodElement, exceptionType, throwsDocletTags);
605                    }
606            }
607    
608            private String _assembleTagComment(
609                    String tagName, String elementName, String comment, String indent,
610                    String tagNameIndent) {
611    
612                    String indentAndTagName = indent + StringPool.AT + tagName;
613    
614                    if (Validator.isNotNull(elementName)) {
615                            if (Validator.isNotNull(comment)) {
616                                    comment = elementName  + StringPool.SPACE + comment;
617                            }
618                            else {
619                                    comment = elementName;
620                            }
621    
622                            // <name indent> elementName [comment]
623    
624                            comment = _wrapText(comment, indent + tagNameIndent);
625    
626                            // * @name <name indent> elementName [comment]
627    
628                            comment =
629                                    indentAndTagName + comment.substring(indentAndTagName.length());
630                    }
631                    else {
632                            if (Validator.isNotNull(comment)) {
633    
634                                    // <name indent> comment
635    
636                                    comment = _wrapText(comment, indent + tagNameIndent);
637    
638                                    // * @name <name indent> comment
639    
640                                    comment =
641                                            indentAndTagName +
642                                                    comment.substring(indentAndTagName.length());
643                            }
644                            else {
645    
646                                    // * @name
647    
648                                    comment = indentAndTagName + "\n";
649                            }
650                    }
651    
652                    return comment;
653            }
654    
655            private void _detachUnnecessaryTypes(Element rootElement) {
656                    List<Element> elements = rootElement.elements();
657    
658                    for (Element element : elements) {
659                            String type = element.elementText("type");
660    
661                            if (!type.contains(".service.") || !type.endsWith("ServiceImpl")) {
662                                    element.detach();
663                            }
664                    }
665            }
666    
667            private void _format(String fileName) throws Exception {
668                    InputStream inputStream = new FileInputStream(_inputDir + fileName);
669    
670                    byte[] bytes = new byte[inputStream.available()];
671    
672                    inputStream.read(bytes);
673    
674                    inputStream.close();
675    
676                    String originalContent = new String(bytes, StringPool.UTF8);
677    
678                    if (fileName.endsWith("JavadocFormatter.java") ||
679                            fileName.endsWith("SourceFormatter.java") ||
680                            _hasGeneratedTag(originalContent)) {
681    
682                            return;
683                    }
684    
685                    JavaClass javaClass = _getJavaClass(
686                            fileName, new UnsyncStringReader(originalContent));
687    
688                    String javadocLessContent = _removeJavadocFromJava(
689                            javaClass, originalContent);
690    
691                    Document document = _getJavadocDocument(javaClass);
692    
693                    _updateJavadocsXmlFile(fileName, javaClass, document);
694    
695                    _updateJavaFromDocument(
696                            fileName, originalContent, javadocLessContent, document);
697            }
698    
699            private String _formatInlines(String text) {
700    
701                    // Capitalize ID
702    
703                    text = text.replaceAll("(?i)\\bid(s)?\\b", "ID$1");
704    
705                    // Wrap special constants in code tags
706    
707                    text = text.replaceAll(
708                            "(?i)(?<!<code>|\\w)(null|false|true)(?!\\w)", "<code>$1</code>");
709    
710                    return text;
711            }
712    
713            private List<JavaClass> _getAncestorJavaClasses(JavaClass javaClass) {
714                    List<JavaClass> ancestorJavaClasses = new ArrayList<JavaClass>();
715    
716                    while ((javaClass = javaClass.getSuperJavaClass()) != null) {
717                            ancestorJavaClasses.add(javaClass);
718                    }
719    
720                    return ancestorJavaClasses;
721            }
722    
723            private String _getCDATA(AbstractJavaEntity abstractJavaEntity) {
724                    return _getCDATA(abstractJavaEntity.getComment());
725            }
726    
727            private String _getCDATA(String cdata) {
728                    if (cdata == null) {
729                            return StringPool.BLANK;
730                    }
731    
732                    cdata = cdata.replaceAll(
733                            "(?s)\\s*<(p|pre|[ou]l)>\\s*(.*?)\\s*</\\1>\\s*",
734                            "\n\n<$1>\n$2\n</$1>\n\n");
735                    cdata = cdata.replaceAll(
736                            "(?s)\\s*<li>\\s*(.*?)\\s*</li>\\s*", "\n<li>\n$1\n</li>\n");
737                    cdata = StringUtil.replace(cdata, "</li>\n\n<li>", "</li>\n<li>");
738                    cdata = cdata.replaceAll("\n\\s+\n", "\n\n");
739                    cdata = cdata.replaceAll(" +", " ");
740    
741                    // Trim whitespace inside paragraph tags or in the first paragraph
742    
743                    Pattern pattern = Pattern.compile(
744                            "(^.*?(?=\n\n|$)+|(?<=<p>\n).*?(?=\n</p>))", Pattern.DOTALL);
745    
746                    Matcher matcher = pattern.matcher(cdata);
747    
748                    StringBuffer sb = new StringBuffer();
749    
750                    while (matcher.find()) {
751                            String trimmed = _trimMultilineText(matcher.group());
752    
753                            // Escape dollar signs so they are not treated as replacement groups
754    
755                            trimmed = trimmed.replaceAll("\\$", "\\\\\\$");
756    
757                            matcher.appendReplacement(sb, trimmed);
758                    }
759    
760                    matcher.appendTail(sb);
761    
762                    cdata = sb.toString();
763    
764                    return cdata.trim();
765            }
766    
767            private String _getClassName(String fileName) {
768                    int pos = fileName.indexOf("src/");
769    
770                    if (pos == -1) {
771                            pos = fileName.indexOf("test/integration/");
772    
773                            if (pos != -1) {
774                                    pos = fileName.indexOf("integration/", pos);
775                            }
776                    }
777    
778                    if (pos == -1) {
779                            pos = fileName.indexOf("test/unit/");
780    
781                            if (pos != -1) {
782                                    pos = fileName.indexOf("unit/", pos);
783                            }
784                    }
785    
786                    if (pos == -1) {
787                            pos = fileName.indexOf("test/");
788                    }
789    
790                    if (pos == -1) {
791                            pos = fileName.indexOf("service/");
792                    }
793    
794                    if (pos == -1) {
795                            throw new RuntimeException(fileName);
796                    }
797    
798                    pos = fileName.indexOf("/", pos);
799    
800                    String srcFile = fileName.substring(pos + 1, fileName.length());
801    
802                    return StringUtil.replace(
803                            srcFile.substring(0, srcFile.length() - 5), "/", ".");
804            }
805    
806            private String _getFieldKey(Element fieldElement) {
807                    return fieldElement.elementText("name");
808            }
809    
810            private String _getFieldKey(JavaField javaField) {
811                    return javaField.getName();
812            }
813    
814            private String _getIndent(
815                    String[] lines, AbstractBaseJavaEntity abstractBaseJavaEntity) {
816    
817                    String line = lines[abstractBaseJavaEntity.getLineNumber() - 1];
818    
819                    String indent = StringPool.BLANK;
820    
821                    for (char c : line.toCharArray()) {
822                            if (Character.isWhitespace(c)) {
823                                    indent += c;
824                            }
825                            else {
826                                    break;
827                            }
828                    }
829    
830                    return indent;
831            }
832    
833            private int _getIndentLength(String indent) {
834                    int indentLength = 0;
835    
836                    for (char c : indent.toCharArray()) {
837                            if (c == '\t') {
838                                    indentLength = indentLength + 4;
839                            }
840                            else {
841                                    indentLength++;
842                            }
843                    }
844    
845                    return indentLength;
846            }
847    
848            private JavaClass _getJavaClass(String fileName, Reader reader)
849                    throws Exception {
850    
851                    String className = _getClassName(fileName);
852    
853                    JavaDocBuilder javadocBuilder = new JavaDocBuilder();
854    
855                    if (reader == null) {
856                            File file = new File(fileName);
857    
858                            if (!file.exists()) {
859                                    return null;
860                            }
861    
862                            javadocBuilder.addSource(file);
863                    }
864                    else {
865                            javadocBuilder.addSource(reader);
866                    }
867    
868                    return javadocBuilder.getClassByName(className);
869            }
870    
871            private String _getJavaClassComment(
872                    Element rootElement, JavaClass javaClass) {
873    
874                    StringBundler sb = new StringBundler();
875    
876                    String indent = StringPool.BLANK;
877    
878                    sb.append("/**\n");
879    
880                    String comment = rootElement.elementText("comment");
881    
882                    if (Validator.isNotNull(comment)) {
883                            sb.append(_wrapText(comment, indent + " * "));
884                    }
885    
886                    String docletTags = _addDocletTags(
887                            rootElement,
888                            new String[] {
889                                    "author", "version", "see", "since", "serial", "deprecated"
890                            },
891                            indent + " * ", _hasPublicModifier(javaClass));
892    
893                    if (Validator.isNotNull(docletTags)) {
894                            if (_initializeMissingJavadocs || Validator.isNotNull(comment)) {
895                                    sb.append(" *\n");
896                            }
897    
898                            sb.append(docletTags);
899                    }
900    
901                    sb.append(" */\n");
902    
903                    return sb.toString();
904            }
905    
906            private int _getJavaClassLineNumber(JavaClass javaClass) {
907                    int lineNumber = javaClass.getLineNumber();
908    
909                    Annotation[] annotations = javaClass.getAnnotations();
910    
911                    if (annotations.length == 0) {
912                            return lineNumber;
913                    }
914    
915                    for (Annotation annotation : annotations) {
916                            int annotationLineNumber = annotation.getLineNumber();
917    
918                            Map<String, String> propertyMap = annotation.getPropertyMap(); 
919    
920                            if (propertyMap.isEmpty()) {
921                                    annotationLineNumber--;
922                            }
923    
924                            if (annotationLineNumber < lineNumber) {
925                                    lineNumber = annotationLineNumber;
926                            }
927                    }
928    
929                    return lineNumber;
930            }
931    
932            private Document _getJavadocDocument(JavaClass javaClass) throws Exception {
933                    Element rootElement = _saxReaderUtil.createElement("javadoc");
934    
935                    Document document = _saxReaderUtil.createDocument(rootElement);
936    
937                    DocUtil.add(rootElement, "name", javaClass.getName());
938                    DocUtil.add(rootElement, "type", javaClass.getFullyQualifiedName());
939    
940                    _addClassCommentElement(rootElement, javaClass);
941                    _addDocletElements(rootElement, javaClass, "author");
942                    _addDocletElements(rootElement, javaClass, "version");
943                    _addDocletElements(rootElement, javaClass, "see");
944                    _addDocletElements(rootElement, javaClass, "since");
945                    _addDocletElements(rootElement, javaClass, "serial");
946                    _addDocletElements(rootElement, javaClass, "deprecated");
947    
948                    JavaMethod[] javaMethods = javaClass.getMethods();
949    
950                    for (JavaMethod javaMethod : javaMethods) {
951                            _addMethodElement(rootElement, javaMethod);
952                    }
953    
954                    JavaField[] javaFields = javaClass.getFields();
955    
956                    for (JavaField javaField : javaFields) {
957                            _addFieldElement(rootElement, javaField);
958                    }
959    
960                    return document;
961            }
962    
963            private Tuple _getJavadocsXmlTuple(String fileName) throws Exception {
964                    File file = new File(_inputDir + fileName);
965    
966                    String absolutePath = file.getAbsolutePath();
967    
968                    absolutePath = StringUtil.replace(absolutePath, "\\", "/");
969                    absolutePath = StringUtil.replace(absolutePath, "/./", "/");
970    
971                    int pos = absolutePath.indexOf("/portal-impl/src/");
972    
973                    String srcDirName = null;
974    
975                    if (pos != -1) {
976                            srcDirName = absolutePath.substring(0, pos + 17);
977                    }
978    
979                    if (srcDirName == null) {
980                            pos = absolutePath.indexOf("/portal-kernel/src/");
981    
982                            if (pos == -1) {
983                                    pos = absolutePath.indexOf("/portal-service/src/");
984                            }
985    
986                            if (pos == -1) {
987                                    pos = absolutePath.indexOf("/util-bridges/src/");
988                            }
989    
990                            if (pos == -1) {
991                                    pos = absolutePath.indexOf("/util-java/src/");
992                            }
993    
994                            if (pos == -1) {
995                                    pos = absolutePath.indexOf("/util-taglib/src/");
996                            }
997    
998                            if (pos != -1) {
999                                    srcDirName =
1000                                            absolutePath.substring(0, pos) + "/portal-impl/src/";
1001                            }
1002                    }
1003    
1004                    if (srcDirName == null) {
1005                            pos = absolutePath.indexOf("/WEB-INF/src/");
1006    
1007                            if (pos != -1) {
1008                                    srcDirName = absolutePath.substring(0, pos + 13);
1009                            }
1010                    }
1011    
1012                    if (srcDirName == null) {
1013                            return null;
1014                    }
1015    
1016                    Tuple tuple = _javadocxXmlTuples.get(srcDirName);
1017    
1018                    if (tuple != null) {
1019                            return tuple;
1020                    }
1021    
1022                    File javadocsXmlFile = new File(
1023                            srcDirName, "META-INF/" + _outputFilePrefix + "-all.xml");
1024    
1025                    if (!javadocsXmlFile.exists()) {
1026                            _fileUtil.write(
1027                                    javadocsXmlFile,
1028                                    "<?xml version=\"1.0\"?>\n\n<javadocs>\n</javadocs>");
1029                    }
1030    
1031                    String javadocsXmlContent = _fileUtil.read(javadocsXmlFile);
1032    
1033                    Document javadocsXmlDocument = _saxReaderUtil.read(javadocsXmlContent);
1034    
1035                    tuple = new Tuple(
1036                            srcDirName, javadocsXmlFile, javadocsXmlContent,
1037                            javadocsXmlDocument);
1038    
1039                    _javadocxXmlTuples.put(srcDirName, tuple);
1040    
1041                    return tuple;
1042            }
1043    
1044            private String _getJavaFieldComment(
1045                    String[] lines, Map<String, Element> fieldElementsMap,
1046                    JavaField javaField) {
1047    
1048                    String fieldKey = _getFieldKey(javaField);
1049    
1050                    Element fieldElement = fieldElementsMap.get(fieldKey);
1051    
1052                    if (fieldElement == null) {
1053                            return null;
1054                    }
1055    
1056                    String indent = _getIndent(lines, javaField);
1057    
1058                    StringBundler sb = new StringBundler();
1059    
1060                    sb.append(indent);
1061                    sb.append("/**\n");
1062    
1063                    String comment = fieldElement.elementText("comment");
1064    
1065                    if (Validator.isNotNull(comment)) {
1066                            sb.append(_wrapText(comment, indent + " * "));
1067                    }
1068    
1069                    String docletTags = _addDocletTags(
1070                            fieldElement,
1071                            new String[] {"version", "see", "since", "deprecated"},
1072                            indent + " * ", _hasPublicModifier(javaField));
1073    
1074                    if (Validator.isNotNull(docletTags)) {
1075                            if (_initializeMissingJavadocs || Validator.isNotNull(comment)) {
1076                                    sb.append(indent);
1077                                    sb.append(" *\n");
1078                            }
1079    
1080                            sb.append(docletTags);
1081                    }
1082    
1083                    sb.append(indent);
1084                    sb.append(" */\n");
1085    
1086                    if (!_initializeMissingJavadocs && Validator.isNull(comment) &&
1087                            Validator.isNull(docletTags)) {
1088    
1089                            return null;
1090                    }
1091    
1092                    if (!_hasPublicModifier(javaField) && Validator.isNull(comment) &&
1093                            Validator.isNull(docletTags)) {
1094    
1095                            return null;
1096                    }
1097    
1098                    return sb.toString();
1099            }
1100    
1101            private String _getJavaMethodComment(
1102                    String[] lines, Map<String, Element> methodElementsMap,
1103                    JavaMethod javaMethod) {
1104    
1105                    String methodKey = _getMethodKey(javaMethod);
1106    
1107                    Element methodElement = methodElementsMap.get(methodKey);
1108    
1109                    if (methodElement == null) {
1110                            return null;
1111                    }
1112    
1113                    String indent = _getIndent(lines, javaMethod);
1114    
1115                    StringBundler sb = new StringBundler();
1116    
1117                    sb.append(indent);
1118                    sb.append("/**\n");
1119    
1120                    String comment = methodElement.elementText("comment");
1121    
1122                    if (Validator.isNotNull(comment)) {
1123                            sb.append(_wrapText(comment, indent + " * "));
1124                    }
1125    
1126                    String docletTags = _addDocletTags(
1127                            methodElement,
1128                            new String[] {
1129                                    "version", "param", "return", "throws", "see", "since",
1130                                    "deprecated"
1131                            },
1132                            indent + " * ", _hasPublicModifier(javaMethod));
1133    
1134                    if (Validator.isNotNull(docletTags)) {
1135                            if (_initializeMissingJavadocs || Validator.isNotNull(comment)) {
1136                                    sb.append(indent);
1137                                    sb.append(" *\n");
1138                            }
1139    
1140                            sb.append(docletTags);
1141                    }
1142    
1143                    sb.append(indent);
1144                    sb.append(" */\n");
1145    
1146                    if (!_initializeMissingJavadocs && Validator.isNull(comment) &&
1147                            Validator.isNull(docletTags)) {
1148    
1149                            return null;
1150                    }
1151    
1152                    if (!_hasPublicModifier(javaMethod) && Validator.isNull(comment) &&
1153                            Validator.isNull(docletTags)) {
1154    
1155                            return null;
1156                    }
1157    
1158                    return sb.toString();
1159            }
1160    
1161            private String _getMethodKey(Element methodElement) {
1162                    StringBundler sb = new StringBundler();
1163    
1164                    sb.append(methodElement.elementText("name"));
1165                    sb.append(StringPool.OPEN_PARENTHESIS);
1166    
1167                    List<Element> paramElements = methodElement.elements("param");
1168    
1169                    for (Element paramElement : paramElements) {
1170                            sb.append(paramElement.elementText("name"));
1171                            sb.append("|");
1172                            sb.append(paramElement.elementText("type"));
1173                            sb.append(",");
1174                    }
1175    
1176                    sb.append(StringPool.CLOSE_PARENTHESIS);
1177    
1178                    return sb.toString();
1179            }
1180    
1181            private String _getMethodKey(JavaMethod javaMethod) {
1182                    StringBundler sb = new StringBundler();
1183    
1184                    sb.append(javaMethod.getName());
1185                    sb.append(StringPool.OPEN_PARENTHESIS);
1186    
1187                    JavaParameter[] javaParameters = javaMethod.getParameters();
1188    
1189                    for (JavaParameter javaParameter : javaParameters) {
1190                            sb.append(javaParameter.getName());
1191                            sb.append("|");
1192                            sb.append(_getTypeValue(javaParameter));
1193                            sb.append(",");
1194                    }
1195    
1196                    sb.append(StringPool.CLOSE_PARENTHESIS);
1197    
1198                    return sb.toString();
1199            }
1200    
1201            private String _getSpacesIndent(int length) {
1202                    String indent = StringPool.BLANK;
1203    
1204                    for (int i = 0; i < length; i++) {
1205                            indent += StringPool.SPACE;
1206                    }
1207    
1208                    return indent;
1209            }
1210    
1211            private String _getTypeValue(JavaParameter javaParameter) {
1212                    Type type = javaParameter.getType();
1213    
1214                    String typeValue = type.getValue();
1215    
1216                    if (type.isArray()) {
1217                            typeValue += "[]";
1218                    }
1219    
1220                    return typeValue;
1221            }
1222    
1223            private boolean _hasAnnotation(
1224                    AbstractBaseJavaEntity abstractBaseJavaEntity, String annotationName) {
1225    
1226                    Annotation[] annotations = abstractBaseJavaEntity.getAnnotations();
1227    
1228                    if (annotations == null) {
1229                            return false;
1230                    }
1231    
1232                    for (int i = 0; i < annotations.length; i++) {
1233                            Type type = annotations[i].getType();
1234    
1235                            JavaClass javaClass = type.getJavaClass();
1236    
1237                            if (annotationName.equals(javaClass.getName())) {
1238                                    return true;
1239                            }
1240                    }
1241    
1242                    return false;
1243            }
1244    
1245            private boolean _hasGeneratedTag(String content) {
1246                    if (content.contains("* @generated") || content.contains("$ANTLR")) {
1247                            return true;
1248                    }
1249                    else {
1250                            return false;
1251                    }
1252            }
1253    
1254            private boolean _hasPublicModifier(AbstractJavaEntity abstractJavaEntity) {
1255                    String[] modifiers = abstractJavaEntity.getModifiers();
1256    
1257                    if (modifiers == null) {
1258                            return false;
1259                    }
1260    
1261                    for (String modifier : modifiers) {
1262                            if (modifier.equals("public")) {
1263                                    return true;
1264                            }
1265                    }
1266    
1267                    return false;
1268            }
1269    
1270            private boolean  _isOverrideMethod(
1271                    JavaClass javaClass, JavaMethod javaMethod,
1272                    Collection<JavaClass> ancestorJavaClasses) {
1273    
1274                    if (javaClass.isInterface() || javaMethod.isConstructor() ||
1275                            javaMethod.isPrivate() || javaMethod.isStatic()) {
1276    
1277                            return false;
1278                    }
1279    
1280                    String methodName = javaMethod.getName();
1281    
1282                    JavaParameter[] javaParameters = javaMethod.getParameters();
1283    
1284                    Type[] types = new Type[javaParameters.length];
1285    
1286                    for (int i = 0; i < javaParameters.length; i++) {
1287                            types[i] = javaParameters[i].getType();
1288                    }
1289    
1290                    // Check for matching method in each ancestor
1291    
1292                    for (JavaClass ancestorJavaClass : ancestorJavaClasses) {
1293                            JavaMethod ancestorJavaMethod =
1294                                    ancestorJavaClass.getMethodBySignature(methodName, types);
1295    
1296                            if (ancestorJavaMethod == null) {
1297                                    continue;
1298                            }
1299    
1300                            boolean samePackage = false;
1301    
1302                            JavaPackage ancestorJavaPackage = ancestorJavaClass.getPackage();
1303    
1304                            if (ancestorJavaPackage != null) {
1305                                    samePackage = ancestorJavaPackage.equals(
1306                                            javaClass.getPackage());
1307                            }
1308    
1309                            // Check if the method is in scope
1310    
1311                            if (samePackage) {
1312                                    return !ancestorJavaMethod.isPrivate();
1313                            }
1314                            else {
1315                                    if (ancestorJavaMethod.isProtected() ||
1316                                            ancestorJavaMethod.isPublic()) {
1317    
1318                                            return true;
1319                                    }
1320                                    else {
1321                                            return false;
1322                                    }
1323                            }
1324                    }
1325    
1326                    return false;
1327            }
1328    
1329            private String _removeJavadocFromJava(
1330                    JavaClass javaClass, String content) {
1331    
1332                    Set<Integer> lineNumbers = new HashSet<Integer>();
1333    
1334                    lineNumbers.add(_getJavaClassLineNumber(javaClass));
1335    
1336                    JavaMethod[] javaMethods = javaClass.getMethods();
1337    
1338                    for (JavaMethod javaMethod : javaMethods) {
1339                            lineNumbers.add(javaMethod.getLineNumber());
1340                    }
1341    
1342                    JavaField[] javaFields = javaClass.getFields();
1343    
1344                    for (JavaField javaField : javaFields) {
1345                            lineNumbers.add(javaField.getLineNumber());
1346                    }
1347    
1348                    String[] lines = StringUtil.splitLines(content);
1349    
1350                    for (int lineNumber : lineNumbers) {
1351                            if (lineNumber == 0) {
1352                                    continue;
1353                            }
1354    
1355                            int pos = lineNumber - 2;
1356    
1357                            String line = lines[pos];
1358    
1359                            if (line == null) {
1360                                    continue;
1361                            }
1362    
1363                            line = line.trim();
1364    
1365                            if (line.endsWith("*/")) {
1366                                    while (true) {
1367                                            lines[pos] = null;
1368    
1369                                            if (line.startsWith("/**") || line.startsWith("/*")) {
1370                                                    break;
1371                                            }
1372    
1373                                            line = lines[--pos].trim();
1374                                    }
1375                            }
1376                    }
1377    
1378                    StringBundler sb = new StringBundler(content.length());
1379    
1380                    for (String line : lines) {
1381                            if (line != null) {
1382                                    sb.append(line);
1383                                    sb.append("\n");
1384                            }
1385                    }
1386    
1387                    return sb.toString().trim();
1388            }
1389    
1390            private String _trimMultilineText(String text) {
1391                    String[] textArray = StringUtil.splitLines(text);
1392    
1393                    for (int i = 0; i < textArray.length; i++) {
1394                            textArray[i] = textArray[i].trim();
1395                    }
1396    
1397                    return StringUtil.merge(textArray, " ");
1398            }
1399    
1400            private void _updateJavadocsXmlFile(
1401                            String fileName, JavaClass javaClass, Document javaClassDocument)
1402                    throws Exception {
1403    
1404                    String javaClassFullyQualifiedName = javaClass.getFullyQualifiedName();
1405    
1406                    /*if (!javaClassFullyQualifiedName.contains(".service.") ||
1407                            !javaClassFullyQualifiedName.endsWith("ServiceImpl")) {
1408    
1409                            return;
1410                    }*/
1411    
1412                    Tuple javadocsXmlTuple = _getJavadocsXmlTuple(fileName);
1413    
1414                    if (javadocsXmlTuple == null) {
1415                            return;
1416                    }
1417    
1418                    Document javadocsXmlDocument = (Document)javadocsXmlTuple.getObject(3);
1419    
1420                    Element javadocsXmlRootElement = javadocsXmlDocument.getRootElement();
1421    
1422                    List<Element> javadocElements = javadocsXmlRootElement.elements(
1423                            "javadoc");
1424    
1425                    for (Element javadocElement : javadocElements) {
1426                            String type = javadocElement.elementText("type");
1427    
1428                            if (type.equals(javaClassFullyQualifiedName)) {
1429                                    Element javaClassRootElement =
1430                                            javaClassDocument.getRootElement();
1431    
1432                                    if (Validator.equals(
1433                                                    javadocElement.formattedString(),
1434                                                    javaClassRootElement.formattedString())) {
1435    
1436                                            return;
1437                                    }
1438    
1439                                    javadocElement.detach();
1440    
1441                                    break;
1442                            }
1443                    }
1444    
1445                    javadocsXmlRootElement.add(javaClassDocument.getRootElement());
1446            }
1447    
1448            private void _updateJavaFromDocument(
1449                            String fileName, String originalContent, String javadocLessContent,
1450                            Document document)
1451                    throws Exception {
1452    
1453                    String[] lines = StringUtil.splitLines(javadocLessContent);
1454    
1455                    JavaClass javaClass = _getJavaClass(
1456                            fileName, new UnsyncStringReader(javadocLessContent));
1457    
1458                    List<JavaClass> ancestorJavaClasses = _getAncestorJavaClasses(
1459                            javaClass);
1460    
1461                    Element rootElement = document.getRootElement();
1462    
1463                    Map<Integer, String> commentsMap = new TreeMap<Integer, String>();
1464    
1465                    commentsMap.put(
1466                            _getJavaClassLineNumber(javaClass),
1467                            _getJavaClassComment(rootElement, javaClass));
1468    
1469                    Map<String, Element> methodElementsMap = new HashMap<String, Element>();
1470    
1471                    List<Element> methodElements = rootElement.elements("method");
1472    
1473                    for (Element methodElement : methodElements) {
1474                            String methodKey = _getMethodKey(methodElement);
1475    
1476                            methodElementsMap.put(methodKey, methodElement);
1477                    }
1478    
1479                    JavaMethod[] javaMethods = javaClass.getMethods();
1480    
1481                    for (JavaMethod javaMethod : javaMethods) {
1482                            if (commentsMap.containsKey(javaMethod.getLineNumber())) {
1483                                    continue;
1484                            }
1485    
1486                            String javaMethodComment = _getJavaMethodComment(
1487                                    lines, methodElementsMap, javaMethod);
1488    
1489                            // Handle override tag insertion
1490    
1491                            if (!_hasAnnotation(javaMethod, "Override")) {
1492                                    if (_isOverrideMethod(
1493                                                    javaClass, javaMethod, ancestorJavaClasses)) {
1494    
1495                                            String overrideLine =
1496                                                    _getIndent(lines, javaMethod) + "@Override\n";
1497    
1498                                            if (Validator.isNotNull(javaMethodComment)) {
1499                                                    javaMethodComment =     javaMethodComment + overrideLine;
1500                                            }
1501                                            else {
1502                                                    javaMethodComment = overrideLine;
1503                                            }
1504                                    }
1505                            }
1506    
1507                            commentsMap.put(javaMethod.getLineNumber(), javaMethodComment);
1508                    }
1509    
1510                    Map<String, Element> fieldElementsMap = new HashMap<String, Element>();
1511    
1512                    List<Element> fieldElements = rootElement.elements("field");
1513    
1514                    for (Element fieldElement : fieldElements) {
1515                            String fieldKey = _getFieldKey(fieldElement);
1516    
1517                            fieldElementsMap.put(fieldKey, fieldElement);
1518                    }
1519    
1520                    JavaField[] javaFields = javaClass.getFields();
1521    
1522                    for (JavaField javaField : javaFields) {
1523                            if (commentsMap.containsKey(javaField.getLineNumber())) {
1524                                    continue;
1525                            }
1526    
1527                            commentsMap.put(
1528                                    javaField.getLineNumber(),
1529                                    _getJavaFieldComment(lines, fieldElementsMap, javaField));
1530                    }
1531    
1532                    StringBundler sb = new StringBundler(javadocLessContent.length());
1533    
1534                    for (int lineNumber = 1; lineNumber <= lines.length; lineNumber++) {
1535                            String line = lines[lineNumber - 1];
1536    
1537                            String comments = commentsMap.get(lineNumber);
1538    
1539                            if (comments != null) {
1540                                    sb.append(comments);
1541                            }
1542    
1543                            sb.append(line);
1544                            sb.append("\n");
1545                    }
1546    
1547                    String formattedContent = sb.toString().trim();
1548    
1549                    if (!originalContent.equals(formattedContent)) {
1550                            File file = new File(_inputDir + fileName);
1551    
1552                            _fileUtil.write(file, formattedContent.getBytes(StringPool.UTF8));
1553    
1554                            System.out.println("Writing " + file);
1555                    }
1556            }
1557    
1558            private String _wrapText(String text, String indent) {
1559                    int indentLength = _getIndentLength(indent);
1560    
1561                    // Do not wrap text inside <pre>
1562    
1563                    if (text.contains("<pre>")) {
1564                            Pattern pattern = Pattern.compile(
1565                                    "(?<=^|</pre>).+?(?=$|<pre>)", Pattern.DOTALL);
1566    
1567                            Matcher matcher = pattern.matcher(text);
1568    
1569                            StringBuffer sb = new StringBuffer();
1570    
1571                            while (matcher.find()) {
1572                                    String wrapped = _formatInlines(matcher.group());
1573    
1574                                    wrapped = StringUtil.wrap(
1575                                            wrapped, 80 - indentLength, "\n");
1576    
1577                                    matcher.appendReplacement(sb, wrapped);
1578                            }
1579    
1580                            matcher.appendTail(sb);
1581    
1582                            sb.append("\n");
1583    
1584                            text = sb.toString();
1585                    }
1586                    else {
1587                            text = _formatInlines(text);
1588    
1589                            text = StringUtil.wrap(text, 80 - indentLength, "\n");
1590                    }
1591    
1592                    text = text.replaceAll("(?m)^", indent);
1593                    text = text.replaceAll("(?m) +$", StringPool.BLANK);
1594    
1595                    return text;
1596            }
1597    
1598            private static FileImpl _fileUtil = FileImpl.getInstance();
1599    
1600            private static SAXReaderImpl _saxReaderUtil = SAXReaderImpl.getInstance();
1601    
1602            private boolean _initializeMissingJavadocs;
1603            private String _inputDir;
1604            private Map<String, Tuple> _javadocxXmlTuples =
1605                    new HashMap<String, Tuple>();
1606            private String _outputFilePrefix;
1607            private boolean _updateJavadocs;
1608    
1609    }