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