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