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/");
772                    }
773    
774                    if (pos == -1) {
775                            pos = fileName.indexOf("service/");
776                    }
777    
778                    if (pos == -1) {
779                            throw new RuntimeException(fileName);
780                    }
781    
782                    pos = fileName.indexOf("/", pos);
783    
784                    String srcFile = fileName.substring(pos + 1, fileName.length());
785    
786                    return StringUtil.replace(
787                            srcFile.substring(0, srcFile.length() - 5), "/", ".");
788            }
789    
790            private String _getFieldKey(Element fieldElement) {
791                    return fieldElement.elementText("name");
792            }
793    
794            private String _getFieldKey(JavaField javaField) {
795                    return javaField.getName();
796            }
797    
798            private String _getIndent(
799                    String[] lines, AbstractBaseJavaEntity abstractBaseJavaEntity) {
800    
801                    String line = lines[abstractBaseJavaEntity.getLineNumber() - 1];
802    
803                    String indent = StringPool.BLANK;
804    
805                    for (char c : line.toCharArray()) {
806                            if (Character.isWhitespace(c)) {
807                                    indent += c;
808                            }
809                            else {
810                                    break;
811                            }
812                    }
813    
814                    return indent;
815            }
816    
817            private int _getIndentLength(String indent) {
818                    int indentLength = 0;
819    
820                    for (char c : indent.toCharArray()) {
821                            if (c == '\t') {
822                                    indentLength = indentLength + 4;
823                            }
824                            else {
825                                    indentLength++;
826                            }
827                    }
828    
829                    return indentLength;
830            }
831    
832            private JavaClass _getJavaClass(String fileName, Reader reader)
833                    throws Exception {
834    
835                    String className = _getClassName(fileName);
836    
837                    JavaDocBuilder javadocBuilder = new JavaDocBuilder();
838    
839                    if (reader == null) {
840                            File file = new File(fileName);
841    
842                            if (!file.exists()) {
843                                    return null;
844                            }
845    
846                            javadocBuilder.addSource(file);
847                    }
848                    else {
849                            javadocBuilder.addSource(reader);
850                    }
851    
852                    return javadocBuilder.getClassByName(className);
853            }
854    
855            private String _getJavaClassComment(
856                    Element rootElement, JavaClass javaClass) {
857    
858                    StringBundler sb = new StringBundler();
859    
860                    String indent = StringPool.BLANK;
861    
862                    sb.append("/**\n");
863    
864                    String comment = rootElement.elementText("comment");
865    
866                    if (_initializeMissingJavadocs || Validator.isNotNull(comment)) {
867                            sb.append(_wrapText(comment, indent + " * "));
868                    }
869    
870                    String docletTags = _addDocletTags(
871                            rootElement,
872                            new String[] {
873                                    "author", "version", "see", "since", "serial", "deprecated"
874                            },
875                            indent + " * ", _hasPublicModifier(javaClass));
876    
877                    if (Validator.isNotNull(docletTags)) {
878                            if (_initializeMissingJavadocs || Validator.isNotNull(comment)) {
879                                    sb.append(" *\n");
880                            }
881    
882                            sb.append(docletTags);
883                    }
884    
885                    sb.append(" */\n");
886    
887                    return sb.toString();
888            }
889    
890            private int _getJavaClassLineNumber(JavaClass javaClass) {
891                    int lineNumber = javaClass.getLineNumber();
892    
893                    Annotation[] annotations = javaClass.getAnnotations();
894    
895                    if (annotations.length == 0) {
896                            return lineNumber;
897                    }
898    
899                    for (Annotation annotation : annotations) {
900                            int annotationLineNumber = annotation.getLineNumber();
901    
902                            Map<String, String> propertyMap = annotation.getPropertyMap(); 
903    
904                            if (propertyMap.isEmpty()) {
905                                    annotationLineNumber--;
906                            }
907    
908                            if (annotationLineNumber < lineNumber) {
909                                    lineNumber = annotationLineNumber;
910                            }
911                    }
912    
913                    return lineNumber;
914            }
915    
916            private Document _getJavadocDocument(JavaClass javaClass) throws Exception {
917                    Element rootElement = _saxReaderUtil.createElement("javadoc");
918    
919                    Document document = _saxReaderUtil.createDocument(rootElement);
920    
921                    DocUtil.add(rootElement, "name", javaClass.getName());
922                    DocUtil.add(rootElement, "type", javaClass.getFullyQualifiedName());
923    
924                    _addClassCommentElement(rootElement, javaClass);
925                    _addDocletElements(rootElement, javaClass, "author");
926                    _addDocletElements(rootElement, javaClass, "version");
927                    _addDocletElements(rootElement, javaClass, "see");
928                    _addDocletElements(rootElement, javaClass, "since");
929                    _addDocletElements(rootElement, javaClass, "serial");
930                    _addDocletElements(rootElement, javaClass, "deprecated");
931    
932                    JavaMethod[] javaMethods = javaClass.getMethods();
933    
934                    for (JavaMethod javaMethod : javaMethods) {
935                            _addMethodElement(rootElement, javaMethod);
936                    }
937    
938                    JavaField[] javaFields = javaClass.getFields();
939    
940                    for (JavaField javaField : javaFields) {
941                            _addFieldElement(rootElement, javaField);
942                    }
943    
944                    return document;
945            }
946    
947            private Tuple _getJavadocsXmlTuple(String fileName) throws Exception {
948                    File file = new File(_inputDir + fileName);
949    
950                    String absolutePath = file.getAbsolutePath();
951    
952                    absolutePath = StringUtil.replace(absolutePath, "\\", "/");
953                    absolutePath = StringUtil.replace(absolutePath, "/./", "/");
954    
955                    int pos = absolutePath.indexOf("/portal-impl/src/");
956    
957                    String srcDirName = null;
958    
959                    if (pos != -1) {
960                            srcDirName = absolutePath.substring(0, pos + 17);
961                    }
962    
963                    if (srcDirName == null) {
964                            pos = absolutePath.indexOf("/portal-kernel/src/");
965    
966                            if (pos == -1) {
967                                    pos = absolutePath.indexOf("/portal-service/src/");
968                            }
969    
970                            if (pos == -1) {
971                                    pos = absolutePath.indexOf("/util-bridges/src/");
972                            }
973    
974                            if (pos == -1) {
975                                    pos = absolutePath.indexOf("/util-java/src/");
976                            }
977    
978                            if (pos == -1) {
979                                    pos = absolutePath.indexOf("/util-taglib/src/");
980                            }
981    
982                            if (pos != -1) {
983                                    srcDirName =
984                                            absolutePath.substring(0, pos) + "/portal-impl/src/";
985                            }
986                    }
987    
988                    if (srcDirName == null) {
989                            pos = absolutePath.indexOf("/WEB-INF/src/");
990    
991                            if (pos != -1) {
992                                    srcDirName = absolutePath.substring(0, pos + 13);
993                            }
994                    }
995    
996                    if (srcDirName == null) {
997                            return null;
998                    }
999    
1000                    Tuple tuple = _javadocxXmlTuples.get(srcDirName);
1001    
1002                    if (tuple != null) {
1003                            return tuple;
1004                    }
1005    
1006                    File javadocsXmlFile = new File(
1007                            srcDirName, "META-INF/" + _outputFilePrefix + "-all.xml");
1008    
1009                    if (!javadocsXmlFile.exists()) {
1010                            _fileUtil.write(
1011                                    javadocsXmlFile,
1012                                    "<?xml version=\"1.0\"?>\n\n<javadocs>\n</javadocs>");
1013                    }
1014    
1015                    String javadocsXmlContent = _fileUtil.read(javadocsXmlFile);
1016    
1017                    Document javadocsXmlDocument = _saxReaderUtil.read(javadocsXmlContent);
1018    
1019                    tuple = new Tuple(
1020                            srcDirName, javadocsXmlFile, javadocsXmlContent,
1021                            javadocsXmlDocument);
1022    
1023                    _javadocxXmlTuples.put(srcDirName, tuple);
1024    
1025                    return tuple;
1026            }
1027    
1028            private String _getJavaFieldComment(
1029                    String[] lines, Map<String, Element> fieldElementsMap,
1030                    JavaField javaField) {
1031    
1032                    String fieldKey = _getFieldKey(javaField);
1033    
1034                    Element fieldElement = fieldElementsMap.get(fieldKey);
1035    
1036                    if (fieldElement == null) {
1037                            return null;
1038                    }
1039    
1040                    String indent = _getIndent(lines, javaField);
1041    
1042                    StringBundler sb = new StringBundler();
1043    
1044                    sb.append(indent);
1045                    sb.append("/**\n");
1046    
1047                    String comment = fieldElement.elementText("comment");
1048    
1049                    if (_initializeMissingJavadocs || Validator.isNotNull(comment)) {
1050                            sb.append(_wrapText(comment, indent + " * "));
1051                    }
1052    
1053                    String docletTags = _addDocletTags(
1054                            fieldElement,
1055                            new String[] {"version", "see", "since", "deprecated"},
1056                            indent + " * ", _hasPublicModifier(javaField));
1057    
1058                    if (Validator.isNotNull(docletTags)) {
1059                            if (_initializeMissingJavadocs || Validator.isNotNull(comment)) {
1060                                    sb.append(indent);
1061                                    sb.append(" *\n");
1062                            }
1063    
1064                            sb.append(docletTags);
1065                    }
1066    
1067                    sb.append(indent);
1068                    sb.append(" */\n");
1069    
1070                    if (!_initializeMissingJavadocs && Validator.isNull(comment) &&
1071                            Validator.isNull(docletTags)) {
1072    
1073                            return null;
1074                    }
1075    
1076                    if (!_hasPublicModifier(javaField) && Validator.isNull(comment) &&
1077                            Validator.isNull(docletTags)) {
1078    
1079                            return null;
1080                    }
1081    
1082                    return sb.toString();
1083            }
1084    
1085            private String _getJavaMethodComment(
1086                    String[] lines, Map<String, Element> methodElementsMap,
1087                    JavaMethod javaMethod) {
1088    
1089                    String methodKey = _getMethodKey(javaMethod);
1090    
1091                    Element methodElement = methodElementsMap.get(methodKey);
1092    
1093                    if (methodElement == null) {
1094                            return null;
1095                    }
1096    
1097                    String indent = _getIndent(lines, javaMethod);
1098    
1099                    StringBundler sb = new StringBundler();
1100    
1101                    sb.append(indent);
1102                    sb.append("/**\n");
1103    
1104                    String comment = methodElement.elementText("comment");
1105    
1106                    if (_initializeMissingJavadocs || Validator.isNotNull(comment)) {
1107                            sb.append(_wrapText(comment, indent + " * "));
1108                    }
1109    
1110                    String docletTags = _addDocletTags(
1111                            methodElement,
1112                            new String[] {
1113                                    "version", "param", "return", "throws", "see", "since",
1114                                    "deprecated"
1115                            },
1116                            indent + " * ", _hasPublicModifier(javaMethod));
1117    
1118                    if (Validator.isNotNull(docletTags)) {
1119                            if (_initializeMissingJavadocs || Validator.isNotNull(comment)) {
1120                                    sb.append(indent);
1121                                    sb.append(" *\n");
1122                            }
1123    
1124                            sb.append(docletTags);
1125                    }
1126    
1127                    sb.append(indent);
1128                    sb.append(" */\n");
1129    
1130                    if (!_initializeMissingJavadocs && Validator.isNull(comment) &&
1131                            Validator.isNull(docletTags)) {
1132    
1133                            return null;
1134                    }
1135    
1136                    if (!_hasPublicModifier(javaMethod) && Validator.isNull(comment) &&
1137                            Validator.isNull(docletTags)) {
1138    
1139                            return null;
1140                    }
1141    
1142                    return sb.toString();
1143            }
1144    
1145            private String _getMethodKey(Element methodElement) {
1146                    StringBundler sb = new StringBundler();
1147    
1148                    sb.append(methodElement.elementText("name"));
1149                    sb.append("(");
1150    
1151                    List<Element> paramElements = methodElement.elements("param");
1152    
1153                    for (Element paramElement : paramElements) {
1154                            sb.append(paramElement.elementText("name"));
1155                            sb.append("|");
1156                            sb.append(paramElement.elementText("type"));
1157                            sb.append(",");
1158                    }
1159    
1160                    sb.append(")");
1161    
1162                    return sb.toString();
1163            }
1164    
1165            private String _getMethodKey(JavaMethod javaMethod) {
1166                    StringBundler sb = new StringBundler();
1167    
1168                    sb.append(javaMethod.getName());
1169                    sb.append("(");
1170    
1171                    JavaParameter[] javaParameters = javaMethod.getParameters();
1172    
1173                    for (JavaParameter javaParameter : javaParameters) {
1174                            sb.append(javaParameter.getName());
1175                            sb.append("|");
1176                            sb.append(_getTypeValue(javaParameter));
1177                            sb.append(",");
1178                    }
1179    
1180                    sb.append(")");
1181    
1182                    return sb.toString();
1183            }
1184    
1185            private String _getSpacesIndent(int length) {
1186                    String indent = StringPool.BLANK;
1187    
1188                    for (int i = 0; i < length; i++) {
1189                            indent += StringPool.SPACE;
1190                    }
1191    
1192                    return indent;
1193            }
1194    
1195            private String _getTypeValue(JavaParameter javaParameter) {
1196                    Type type = javaParameter.getType();
1197    
1198                    String typeValue = type.getValue();
1199    
1200                    if (type.isArray()) {
1201                            typeValue += "[]";
1202                    }
1203    
1204                    return typeValue;
1205            }
1206    
1207            private boolean _hasAnnotation(
1208                    AbstractBaseJavaEntity abstractBaseJavaEntity, String annotationName) {
1209    
1210                    Annotation[] annotations = abstractBaseJavaEntity.getAnnotations();
1211    
1212                    if (annotations == null) {
1213                            return false;
1214                    }
1215    
1216                    for (int i = 0; i < annotations.length; i++) {
1217                            Type type = annotations[i].getType();
1218    
1219                            JavaClass javaClass = type.getJavaClass();
1220    
1221                            if (annotationName.equals(javaClass.getName())) {
1222                                    return true;
1223                            }
1224                    }
1225    
1226                    return false;
1227            }
1228    
1229            private boolean _hasGeneratedTag(String content) {
1230                    if (content.contains("* @generated") || content.contains("$ANTLR")) {
1231                            return true;
1232                    }
1233                    else {
1234                            return false;
1235                    }
1236            }
1237    
1238            private boolean _hasPublicModifier(AbstractJavaEntity abstractJavaEntity) {
1239                    String[] modifiers = abstractJavaEntity.getModifiers();
1240    
1241                    if (modifiers == null) {
1242                            return false;
1243                    }
1244    
1245                    for (String modifier : modifiers) {
1246                            if (modifier.equals("public")) {
1247                                    return true;
1248                            }
1249                    }
1250    
1251                    return false;
1252            }
1253    
1254            private boolean  _isOverrideMethod(
1255                    JavaClass javaClass, JavaMethod javaMethod,
1256                    Collection<JavaClass> ancestorJavaClasses) {
1257    
1258                    if (javaClass.isInterface() || javaMethod.isConstructor() ||
1259                            javaMethod.isPrivate() || javaMethod.isStatic()) {
1260    
1261                            return false;
1262                    }
1263    
1264                    String methodName = javaMethod.getName();
1265    
1266                    JavaParameter[] javaParameters = javaMethod.getParameters();
1267    
1268                    Type[] types = new Type[javaParameters.length];
1269    
1270                    for (int i = 0; i < javaParameters.length; i++) {
1271                            types[i] = javaParameters[i].getType();
1272                    }
1273    
1274                    // Check for matching method in each ancestor
1275    
1276                    for (JavaClass ancestorJavaClass : ancestorJavaClasses) {
1277                            JavaMethod ancestorJavaMethod =
1278                                    ancestorJavaClass.getMethodBySignature(methodName, types);
1279    
1280                            if (ancestorJavaMethod == null) {
1281                                    continue;
1282                            }
1283    
1284                            boolean samePackage = false;
1285    
1286                            JavaPackage ancestorJavaPackage = ancestorJavaClass.getPackage();
1287    
1288                            if (ancestorJavaPackage != null) {
1289                                    samePackage = ancestorJavaPackage.equals(
1290                                            javaClass.getPackage());
1291                            }
1292    
1293                            // Check if the method is in scope
1294    
1295                            if (samePackage) {
1296                                    return !ancestorJavaMethod.isPrivate();
1297                            }
1298                            else {
1299                                    if (ancestorJavaMethod.isProtected() ||
1300                                            ancestorJavaMethod.isPublic()) {
1301    
1302                                            return true;
1303                                    }
1304                                    else {
1305                                            return false;
1306                                    }
1307                            }
1308                    }
1309    
1310                    return false;
1311            }
1312    
1313            private String _removeJavadocFromJava(
1314                    JavaClass javaClass, String content) {
1315    
1316                    Set<Integer> lineNumbers = new HashSet<Integer>();
1317    
1318                    lineNumbers.add(_getJavaClassLineNumber(javaClass));
1319    
1320                    JavaMethod[] javaMethods = javaClass.getMethods();
1321    
1322                    for (JavaMethod javaMethod : javaMethods) {
1323                            lineNumbers.add(javaMethod.getLineNumber());
1324                    }
1325    
1326                    JavaField[] javaFields = javaClass.getFields();
1327    
1328                    for (JavaField javaField : javaFields) {
1329                            lineNumbers.add(javaField.getLineNumber());
1330                    }
1331    
1332                    String[] lines = StringUtil.splitLines(content);
1333    
1334                    for (int lineNumber : lineNumbers) {
1335                            if (lineNumber == 0) {
1336                                    continue;
1337                            }
1338    
1339                            int pos = lineNumber - 2;
1340    
1341                            String line = lines[pos];
1342    
1343                            if (line == null) {
1344                                    continue;
1345                            }
1346    
1347                            line = line.trim();
1348    
1349                            if (line.endsWith("*/")) {
1350                                    while (true) {
1351                                            lines[pos] = null;
1352    
1353                                            if (line.startsWith("/**") || line.startsWith("/*")) {
1354                                                    break;
1355                                            }
1356    
1357                                            line = lines[--pos].trim();
1358                                    }
1359                            }
1360                    }
1361    
1362                    StringBundler sb = new StringBundler(content.length());
1363    
1364                    for (String line : lines) {
1365                            if (line != null) {
1366                                    sb.append(line);
1367                                    sb.append("\n");
1368                            }
1369                    }
1370    
1371                    return sb.toString().trim();
1372            }
1373    
1374            private String _trimMultilineText(String text) {
1375                    String[] textArray = StringUtil.splitLines(text);
1376    
1377                    for (int i = 0; i < textArray.length; i++) {
1378                            textArray[i] = textArray[i].trim();
1379                    }
1380    
1381                    return StringUtil.merge(textArray, " ");
1382            }
1383    
1384            private void _updateJavadocsXmlFile(
1385                            String fileName, JavaClass javaClass, Document javaClassDocument)
1386                    throws Exception {
1387    
1388                    String javaClassFullyQualifiedName = javaClass.getFullyQualifiedName();
1389    
1390                    /*if (!javaClassFullyQualifiedName.contains(".service.") ||
1391                            !javaClassFullyQualifiedName.endsWith("ServiceImpl")) {
1392    
1393                            return;
1394                    }*/
1395    
1396                    Tuple javadocsXmlTuple = _getJavadocsXmlTuple(fileName);
1397    
1398                    if (javadocsXmlTuple == null) {
1399                            return;
1400                    }
1401    
1402                    Document javadocsXmlDocument = (Document)javadocsXmlTuple.getObject(3);
1403    
1404                    Element javadocsXmlRootElement = javadocsXmlDocument.getRootElement();
1405    
1406                    List<Element> javadocElements = javadocsXmlRootElement.elements(
1407                            "javadoc");
1408    
1409                    for (Element javadocElement : javadocElements) {
1410                            String type = javadocElement.elementText("type");
1411    
1412                            if (type.equals(javaClassFullyQualifiedName)) {
1413                                    Element javaClassRootElement =
1414                                            javaClassDocument.getRootElement();
1415    
1416                                    if (Validator.equals(
1417                                                    javadocElement.formattedString(),
1418                                                    javaClassRootElement.formattedString())) {
1419    
1420                                            return;
1421                                    }
1422    
1423                                    javadocElement.detach();
1424    
1425                                    break;
1426                            }
1427                    }
1428    
1429                    javadocsXmlRootElement.add(javaClassDocument.getRootElement());
1430            }
1431    
1432            private void _updateJavaFromDocument(
1433                            String fileName, String originalContent, String javadocLessContent,
1434                            Document document)
1435                    throws Exception {
1436    
1437                    String[] lines = StringUtil.splitLines(javadocLessContent);
1438    
1439                    JavaClass javaClass = _getJavaClass(
1440                            fileName, new UnsyncStringReader(javadocLessContent));
1441    
1442                    List<JavaClass> ancestorJavaClasses = _getAncestorJavaClasses(
1443                            javaClass);
1444    
1445                    Element rootElement = document.getRootElement();
1446    
1447                    Map<Integer, String> commentsMap = new TreeMap<Integer, String>();
1448    
1449                    commentsMap.put(
1450                            _getJavaClassLineNumber(javaClass),
1451                            _getJavaClassComment(rootElement, javaClass));
1452    
1453                    Map<String, Element> methodElementsMap = new HashMap<String, Element>();
1454    
1455                    List<Element> methodElements = rootElement.elements("method");
1456    
1457                    for (Element methodElement : methodElements) {
1458                            String methodKey = _getMethodKey(methodElement);
1459    
1460                            methodElementsMap.put(methodKey, methodElement);
1461                    }
1462    
1463                    JavaMethod[] javaMethods = javaClass.getMethods();
1464    
1465                    for (JavaMethod javaMethod : javaMethods) {
1466                            if (commentsMap.containsKey(javaMethod.getLineNumber())) {
1467                                    continue;
1468                            }
1469    
1470                            String javaMethodComment = _getJavaMethodComment(
1471                                    lines, methodElementsMap, javaMethod);
1472    
1473                            // Handle override tag insertion
1474    
1475                            if (!_hasAnnotation(javaMethod, "Override")) {
1476                                    if (_isOverrideMethod(
1477                                                    javaClass, javaMethod, ancestorJavaClasses)) {
1478    
1479                                            String overrideLine =
1480                                                    _getIndent(lines, javaMethod) + "@Override\n";
1481    
1482                                            if (Validator.isNotNull(javaMethodComment)) {
1483                                                    javaMethodComment =     javaMethodComment + overrideLine;
1484                                            }
1485                                            else {
1486                                                    javaMethodComment = overrideLine;
1487                                            }
1488                                    }
1489                            }
1490    
1491                            commentsMap.put(javaMethod.getLineNumber(), javaMethodComment);
1492                    }
1493    
1494                    Map<String, Element> fieldElementsMap = new HashMap<String, Element>();
1495    
1496                    List<Element> fieldElements = rootElement.elements("field");
1497    
1498                    for (Element fieldElement : fieldElements) {
1499                            String fieldKey = _getFieldKey(fieldElement);
1500    
1501                            fieldElementsMap.put(fieldKey, fieldElement);
1502                    }
1503    
1504                    JavaField[] javaFields = javaClass.getFields();
1505    
1506                    for (JavaField javaField : javaFields) {
1507                            if (commentsMap.containsKey(javaField.getLineNumber())) {
1508                                    continue;
1509                            }
1510    
1511                            commentsMap.put(
1512                                    javaField.getLineNumber(),
1513                                    _getJavaFieldComment(lines, fieldElementsMap, javaField));
1514                    }
1515    
1516                    StringBundler sb = new StringBundler(javadocLessContent.length());
1517    
1518                    for (int lineNumber = 1; lineNumber <= lines.length; lineNumber++) {
1519                            String line = lines[lineNumber - 1];
1520    
1521                            String comments = commentsMap.get(lineNumber);
1522    
1523                            if (comments != null) {
1524                                    sb.append(comments);
1525                            }
1526    
1527                            sb.append(line);
1528                            sb.append("\n");
1529                    }
1530    
1531                    String formattedContent = sb.toString().trim();
1532    
1533                    if (!originalContent.equals(formattedContent)) {
1534                            File file = new File(_inputDir + fileName);
1535    
1536                            _fileUtil.write(file, formattedContent.getBytes(StringPool.UTF8));
1537    
1538                            System.out.println("Writing " + file);
1539                    }
1540            }
1541    
1542            private String _wrapText(String text, String indent) {
1543                    int indentLength = _getIndentLength(indent);
1544    
1545                    // Do not wrap text inside <pre>
1546    
1547                    if (text.contains("<pre>")) {
1548                            Pattern pattern = Pattern.compile(
1549                                    "(?<=^|</pre>).+?(?=$|<pre>)", Pattern.DOTALL);
1550    
1551                            Matcher matcher = pattern.matcher(text);
1552    
1553                            StringBuffer sb = new StringBuffer();
1554    
1555                            while (matcher.find()) {
1556                                    String wrapped = _formatInlines(matcher.group());
1557    
1558                                    wrapped = StringUtil.wrap(
1559                                            wrapped, 80 - indentLength, "\n");
1560    
1561                                    matcher.appendReplacement(sb, wrapped);
1562                            }
1563    
1564                            matcher.appendTail(sb);
1565    
1566                            sb.append("\n");
1567    
1568                            text = sb.toString();
1569                    }
1570                    else {
1571                            text = _formatInlines(text);
1572    
1573                            text = StringUtil.wrap(text, 80 - indentLength, "\n");
1574                    }
1575    
1576                    text = text.replaceAll("(?m)^", indent);
1577                    text = text.replaceAll("(?m) +$", StringPool.BLANK);
1578    
1579                    return text;
1580            }
1581    
1582            private static FileImpl _fileUtil = FileImpl.getInstance();
1583    
1584            private static SAXReaderImpl _saxReaderUtil = SAXReaderImpl.getInstance();
1585    
1586            private boolean _initializeMissingJavadocs;
1587            private String _inputDir;
1588            private Map<String, Tuple> _javadocxXmlTuples =
1589                    new HashMap<String, Tuple>();
1590            private String _outputFilePrefix;
1591            private boolean _updateJavadocs;
1592    
1593    }