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