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.equals(name) || curValue.startsWith(name + " ")) {
564 value = curValue;
565
566 break;
567 }
568 }
569
570 Element paramElement = methodElement.addElement("param");
571
572 DocUtil.add(paramElement, "name", name);
573 DocUtil.add(paramElement, "type", _getTypeValue(javaParameter));
574
575 if (value != null) {
576 value = value.substring(name.length());
577
578 DocUtil.add(paramElement, "required", true);
579 }
580
581 value = _trimMultilineText(value);
582
583 Element commentElement = paramElement.addElement("comment");
584
585 commentElement.addCDATA(value);
586 }
587
588 private void _addParamElements(
589 Element methodElement, JavaMethod javaMethod) {
590
591 JavaParameter[] javaParameters = javaMethod.getParameters();
592
593 DocletTag[] paramDocletTags = javaMethod.getTagsByName("param");
594
595 for (JavaParameter javaParameter : javaParameters) {
596 _addParamElement(methodElement, javaParameter, paramDocletTags);
597 }
598 }
599
600 private void _addReturnElement(Element methodElement, JavaMethod javaMethod)
601 throws Exception {
602
603 Type returns = javaMethod.getReturns();
604
605 if (returns == null) {
606 return;
607 }
608
609 String returnsValue = returns.getValue();
610
611 if (returnsValue.equals("void")) {
612 return;
613 }
614
615 Element returnElement = methodElement.addElement("return");
616
617 DocletTag[] returnDocletTags = javaMethod.getTagsByName("return");
618
619 String comment = StringPool.BLANK;
620
621 if (returnDocletTags.length > 0) {
622 DocletTag returnDocletTag = returnDocletTags[0];
623
624 comment = GetterUtil.getString(returnDocletTag.getValue());
625
626 DocUtil.add(returnElement, "required", true);
627 }
628
629 comment = _trimMultilineText(comment);
630
631 Element commentElement = returnElement.addElement("comment");
632
633 commentElement.addCDATA(comment);
634 }
635
636 private void _addThrowsElement(
637 Element methodElement, Type exceptionType,
638 DocletTag[] throwsDocletTags) {
639
640 JavaClass javaClass = exceptionType.getJavaClass();
641
642 String name = javaClass.getName();
643
644 String value = null;
645
646 for (DocletTag throwsDocletTag : throwsDocletTags) {
647 String curValue = throwsDocletTag.getValue();
648
649 if (!curValue.startsWith(name)) {
650 continue;
651 }
652 else {
653 value = curValue;
654
655 break;
656 }
657 }
658
659 Element throwsElement = methodElement.addElement("throws");
660
661 DocUtil.add(throwsElement, "name", name);
662 DocUtil.add(throwsElement, "type", exceptionType.getValue());
663
664 if (value != null) {
665 value = value.substring(name.length());
666
667 DocUtil.add(throwsElement, "required", true);
668 }
669
670 value = _trimMultilineText(value);
671
672 Element commentElement = throwsElement.addElement("comment");
673
674 commentElement.addCDATA(_getCDATA(value));
675 }
676
677 private void _addThrowsElements(
678 Element methodElement, JavaMethod javaMethod) {
679
680 Type[] exceptionTypes = javaMethod.getExceptions();
681
682 DocletTag[] throwsDocletTags = javaMethod.getTagsByName("throws");
683
684 for (Type exceptionType : exceptionTypes) {
685 _addThrowsElement(methodElement, exceptionType, throwsDocletTags);
686 }
687 }
688
689 private String _assembleTagComment(
690 String tagName, String elementName, String comment, String indent,
691 String tagNameIndent) {
692
693 String indentAndTagName = indent + StringPool.AT + tagName;
694
695 if (Validator.isNotNull(elementName)) {
696 if (Validator.isNotNull(comment)) {
697 comment = elementName + StringPool.SPACE + comment;
698 }
699 else {
700 comment = elementName;
701 }
702
703
704
705 comment = _wrapText(comment, indent + tagNameIndent);
706
707
708
709 comment =
710 indentAndTagName + comment.substring(indentAndTagName.length());
711 }
712 else {
713 if (Validator.isNotNull(comment)) {
714
715
716
717 comment = _wrapText(comment, indent + tagNameIndent);
718
719
720
721 comment =
722 indentAndTagName +
723 comment.substring(indentAndTagName.length());
724 }
725 else {
726
727
728
729 comment = indentAndTagName + "\n";
730 }
731 }
732
733 return comment;
734 }
735
736 private void _detachUnnecessaryTypes(Element rootElement) {
737 List<Element> elements = rootElement.elements();
738
739 for (Element element : elements) {
740 String type = element.elementText("type");
741
742 if (!type.contains(".service.") || !type.endsWith("ServiceImpl")) {
743 element.detach();
744 }
745 }
746 }
747
748 private void _format(String fileName) throws Exception {
749 InputStream inputStream = new FileInputStream(_inputDir + fileName);
750
751 byte[] bytes = new byte[inputStream.available()];
752
753 inputStream.read(bytes);
754
755 inputStream.close();
756
757 String originalContent = new String(bytes, StringPool.UTF8);
758
759 if (fileName.endsWith("JavadocFormatter.java") ||
760 fileName.endsWith("SourceFormatter.java") ||
761 _hasGeneratedTag(originalContent)) {
762
763 return;
764 }
765
766 JavaClass javaClass = _getJavaClass(
767 fileName, new UnsyncStringReader(originalContent));
768
769 String javadocLessContent = _removeJavadocFromJava(
770 javaClass, originalContent);
771
772 Document document = _getJavadocDocument(javaClass);
773
774 _updateJavadocsXmlFile(fileName, javaClass, document);
775
776 _updateJavaFromDocument(
777 fileName, originalContent, javadocLessContent, document);
778 }
779
780 private String _formatCDATA(String cdata) {
781 cdata = cdata.replaceAll(
782 "(?s)\\s*<(p|[ou]l)>\\s*(.*?)\\s*</\\1>\\s*",
783 "\n\n<$1>\n$2\n</$1>\n\n");
784 cdata = cdata.replaceAll(
785 "(?s)\\s*<li>\\s*(.*?)\\s*</li>\\s*", "\n<li>\n$1\n</li>\n");
786 cdata = StringUtil.replace(cdata, "</li>\n\n<li>", "</li>\n<li>");
787 cdata = cdata.replaceAll("\n\\s+\n", "\n\n");
788 cdata = cdata.replaceAll(" +", " ");
789
790
791
792 Matcher matcher = _paragraphTagPattern.matcher(cdata);
793
794 StringBuffer sb = new StringBuffer();
795
796 while (matcher.find()) {
797 String trimmed = _trimMultilineText(matcher.group());
798
799
800
801 trimmed = trimmed.replaceAll("\\$", "\\\\\\$");
802
803 matcher.appendReplacement(sb, trimmed);
804 }
805
806 matcher.appendTail(sb);
807
808 cdata = sb.toString();
809
810 return cdata.trim();
811 }
812
813 private String _formatInlines(String text) {
814
815
816
817 text = text.replaceAll("[?@param id](?i)\\bid(s)?\\b", " ID$1");
818
819
820
821 text = text.replaceAll(
822 "(?i)(?<!<code>|\\w)(null|false|true)(?!\\w)", "<code>$1</code>");
823
824 return text;
825 }
826
827 private String _getCDATA(AbstractJavaEntity abstractJavaEntity) {
828 return _getCDATA(abstractJavaEntity.getComment());
829 }
830
831 private String _getCDATA(String cdata) {
832 StringBundler sb = new StringBundler();
833
834 if ((cdata == null) || cdata.isEmpty()) {
835 return StringPool.BLANK;
836 }
837
838 int cdataBeginIndex = 0;
839
840 while (!cdata.isEmpty()) {
841 int preTagIndex = cdata.indexOf("<pre>");
842 int tableTagIndex = cdata.indexOf("<table>");
843
844 boolean hasPreTag = (preTagIndex != -1) ? true : false;
845 boolean hasTableTag = (tableTagIndex != -1) ? true : false;
846
847 if (!hasPreTag && !hasTableTag) {
848 sb.append(_formatCDATA(cdata));
849
850 break;
851 }
852
853 boolean startsWithPreTag = (preTagIndex == 0) ? true : false;
854 boolean startsWithTableTag = (tableTagIndex == 0) ? true : false;
855
856 if (startsWithPreTag || startsWithTableTag) {
857 sb.append("\n");
858
859 String tagName = null;
860
861 if (preTagIndex == 0) {
862 tagName = "pre";
863 }
864 else {
865 tagName = "table";
866 }
867
868 String startTag = "<" + tagName + ">";
869 String endTag = "</" + tagName + ">";
870
871 int startTagLength = startTag.length();
872 int endTagLength = endTag.length();
873
874 int endTagIndex = cdata.indexOf(endTag, startTagLength - 1);
875
876 sb.append(cdata.substring(0, endTagIndex + endTagLength));
877
878 sb.append("\n");
879
880 cdataBeginIndex = endTagIndex + endTagLength;
881 }
882 else {
883
884
885
886 int startTagIndex = 0;
887
888 if (hasPreTag && hasTableTag) {
889 if (preTagIndex < tableTagIndex) {
890 startTagIndex = preTagIndex;
891 }
892 else {
893 startTagIndex = tableTagIndex;
894 }
895 }
896 else if (hasPreTag && !hasTableTag) {
897 startTagIndex = preTagIndex;
898 }
899 else {
900
901
902
903 startTagIndex = tableTagIndex;
904 }
905
906 sb.append(_formatCDATA(cdata.substring(0, startTagIndex)));
907
908 cdataBeginIndex = startTagIndex;
909 }
910
911 cdata = cdata.substring(cdataBeginIndex);
912 }
913
914 cdata = sb.toString();
915
916 return cdata.trim();
917 }
918
919 private String _getClassName(String fileName) {
920 int pos = fileName.indexOf("src/");
921
922 if (pos == -1) {
923 pos = fileName.indexOf("test/integration/");
924
925 if (pos != -1) {
926 pos = fileName.indexOf("integration/", pos);
927 }
928 }
929
930 if (pos == -1) {
931 pos = fileName.indexOf("test/unit/");
932
933 if (pos != -1) {
934 pos = fileName.indexOf("unit/", pos);
935 }
936 }
937
938 if (pos == -1) {
939 pos = fileName.indexOf("test/");
940 }
941
942 if (pos == -1) {
943 pos = fileName.indexOf("service/");
944 }
945
946 if (pos == -1) {
947 throw new RuntimeException(fileName);
948 }
949
950 pos = fileName.indexOf("/", pos);
951
952 String srcFile = fileName.substring(pos + 1, fileName.length());
953
954 return StringUtil.replace(
955 srcFile.substring(0, srcFile.length() - 5), "/", ".");
956 }
957
958 private String _getFieldKey(Element fieldElement) {
959 return fieldElement.elementText("name");
960 }
961
962 private String _getFieldKey(JavaField javaField) {
963 return javaField.getName();
964 }
965
966 private String _getIndent(
967 String[] lines, AbstractBaseJavaEntity abstractBaseJavaEntity) {
968
969 String line = lines[abstractBaseJavaEntity.getLineNumber() - 1];
970
971 String indent = StringPool.BLANK;
972
973 for (char c : line.toCharArray()) {
974 if (Character.isWhitespace(c)) {
975 indent += c;
976 }
977 else {
978 break;
979 }
980 }
981
982 return indent;
983 }
984
985 private int _getIndentLength(String indent) {
986 int indentLength = 0;
987
988 for (char c : indent.toCharArray()) {
989 if (c == '\t') {
990 indentLength = indentLength + 4;
991 }
992 else {
993 indentLength++;
994 }
995 }
996
997 return indentLength;
998 }
999
1000 private JavaClass _getJavaClass(String fileName, Reader reader)
1001 throws Exception {
1002
1003 String className = _getClassName(fileName);
1004
1005 JavaDocBuilder javadocBuilder = new JavaDocBuilder();
1006
1007 if (reader == null) {
1008 File file = new File(fileName);
1009
1010 if (!file.exists()) {
1011 return null;
1012 }
1013
1014 javadocBuilder.addSource(file);
1015 }
1016 else {
1017 javadocBuilder.addSource(reader);
1018 }
1019
1020 return javadocBuilder.getClassByName(className);
1021 }
1022
1023 private String _getJavaClassComment(
1024 Element rootElement, JavaClass javaClass) {
1025
1026 StringBundler sb = new StringBundler();
1027
1028 String indent = StringPool.BLANK;
1029
1030 sb.append("\n");
1054
1055 return sb.toString();
1056 }
1057
1058 private int _getJavaClassLineNumber(JavaClass javaClass) {
1059 int lineNumber = javaClass.getLineNumber();
1060
1061 Annotation[] annotations = javaClass.getAnnotations();
1062
1063 if (annotations.length == 0) {
1064 return lineNumber;
1065 }
1066
1067 for (Annotation annotation : annotations) {
1068 int annotationLineNumber = annotation.getLineNumber();
1069
1070 Map<String, String> propertyMap = annotation.getPropertyMap();
1071
1072 if (propertyMap.isEmpty()) {
1073 annotationLineNumber--;
1074 }
1075
1076 if (annotationLineNumber < lineNumber) {
1077 lineNumber = annotationLineNumber;
1078 }
1079 }
1080
1081 return lineNumber;
1082 }
1083
1084 private Document _getJavadocDocument(JavaClass javaClass) throws Exception {
1085 Element rootElement = _saxReaderUtil.createElement("javadoc");
1086
1087 Document document = _saxReaderUtil.createDocument(rootElement);
1088
1089 DocUtil.add(rootElement, "name", javaClass.getName());
1090 DocUtil.add(rootElement, "type", javaClass.getFullyQualifiedName());
1091
1092 _addClassCommentElement(rootElement, javaClass);
1093 _addDocletElements(rootElement, javaClass, "author");
1094 _addDocletElements(rootElement, javaClass, "version");
1095 _addDocletElements(rootElement, javaClass, "see");
1096 _addDocletElements(rootElement, javaClass, "since");
1097 _addDocletElements(rootElement, javaClass, "serial");
1098 _addDocletElements(rootElement, javaClass, "deprecated");
1099
1100 JavaMethod[] javaMethods = javaClass.getMethods();
1101
1102 for (JavaMethod javaMethod : javaMethods) {
1103 _addMethodElement(rootElement, javaMethod);
1104 }
1105
1106 JavaField[] javaFields = javaClass.getFields();
1107
1108 for (JavaField javaField : javaFields) {
1109 _addFieldElement(rootElement, javaField);
1110 }
1111
1112 return document;
1113 }
1114
1115 private Tuple _getJavadocsXmlTuple(String fileName) throws Exception {
1116 File file = new File(_inputDir + fileName);
1117
1118 String absolutePath = file.getAbsolutePath();
1119
1120 absolutePath = StringUtil.replace(absolutePath, "\\", "/");
1121 absolutePath = StringUtil.replace(absolutePath, "/./", "/");
1122
1123 int pos = absolutePath.indexOf("/portal-impl/src/");
1124
1125 String srcDirName = null;
1126
1127 if (pos != -1) {
1128 srcDirName = absolutePath.substring(0, pos + 17);
1129 }
1130
1131 if (srcDirName == null) {
1132 pos = absolutePath.indexOf("/portal-kernel/src/");
1133
1134 if (pos == -1) {
1135 pos = absolutePath.indexOf("/portal-service/src/");
1136 }
1137
1138 if (pos == -1) {
1139 pos = absolutePath.indexOf("/util-bridges/src/");
1140 }
1141
1142 if (pos == -1) {
1143 pos = absolutePath.indexOf("/util-java/src/");
1144 }
1145
1146 if (pos == -1) {
1147 pos = absolutePath.indexOf("/util-taglib/src/");
1148 }
1149
1150 if (pos != -1) {
1151 srcDirName =
1152 absolutePath.substring(0, pos) + "/portal-impl/src/";
1153 }
1154 }
1155
1156 if (srcDirName == null) {
1157 pos = absolutePath.indexOf("/WEB-INF/src/");
1158
1159 if (pos != -1) {
1160 srcDirName = absolutePath.substring(0, pos + 13);
1161 }
1162 }
1163
1164 if (srcDirName == null) {
1165 return null;
1166 }
1167
1168 Tuple tuple = _javadocxXmlTuples.get(srcDirName);
1169
1170 if (tuple != null) {
1171 return tuple;
1172 }
1173
1174 File javadocsXmlFile = new File(
1175 srcDirName, "META-INF/" + _outputFilePrefix + "-all.xml");
1176
1177 if (!javadocsXmlFile.exists()) {
1178 _fileUtil.write(
1179 javadocsXmlFile,
1180 "<?xml version=\"1.0\"?>\n\n<javadocs>\n</javadocs>");
1181 }
1182
1183 String javadocsXmlContent = _fileUtil.read(javadocsXmlFile);
1184
1185 Document javadocsXmlDocument = _saxReaderUtil.read(javadocsXmlContent);
1186
1187 tuple = new Tuple(
1188 srcDirName, javadocsXmlFile, javadocsXmlContent,
1189 javadocsXmlDocument);
1190
1191 _javadocxXmlTuples.put(srcDirName, tuple);
1192
1193 return tuple;
1194 }
1195
1196 private String _getJavaFieldComment(
1197 String[] lines, Map<String, Element> fieldElementsMap,
1198 JavaField javaField) {
1199
1200 String fieldKey = _getFieldKey(javaField);
1201
1202 Element fieldElement = fieldElementsMap.get(fieldKey);
1203
1204 if (fieldElement == null) {
1205 return null;
1206 }
1207
1208 String indent = _getIndent(lines, javaField);
1209
1210 StringBundler sb = new StringBundler();
1211
1212 sb.append(indent);
1213 sb.append("\n");
1237
1238 if (!_initializeMissingJavadocs && Validator.isNull(comment) &&
1239 Validator.isNull(docletTags)) {
1240
1241 return null;
1242 }
1243
1244 if (!_hasPublicModifier(javaField) && Validator.isNull(comment) &&
1245 Validator.isNull(docletTags)) {
1246
1247 return null;
1248 }
1249
1250 return sb.toString();
1251 }
1252
1253 private String _getJavaMethodComment(
1254 String[] lines, Map<String, Element> methodElementsMap,
1255 JavaMethod javaMethod) {
1256
1257 String methodKey = _getMethodKey(javaMethod);
1258
1259 Element methodElement = methodElementsMap.get(methodKey);
1260
1261 if (methodElement == null) {
1262 return null;
1263 }
1264
1265 String indent = _getIndent(lines, javaMethod);
1266
1267 StringBundler sb = new StringBundler();
1268
1269 sb.append(indent);
1270 sb.append("\n");
1297
1298 if (!_initializeMissingJavadocs && Validator.isNull(comment) &&
1299 Validator.isNull(docletTags)) {
1300
1301 return null;
1302 }
1303
1304 if (!_hasPublicModifier(javaMethod) && Validator.isNull(comment) &&
1305 Validator.isNull(docletTags)) {
1306
1307 return null;
1308 }
1309
1310 return sb.toString();
1311 }
1312
1313 private String _getMethodKey(Element methodElement) {
1314 StringBundler sb = new StringBundler();
1315
1316 sb.append(methodElement.elementText("name"));
1317 sb.append(StringPool.OPEN_PARENTHESIS);
1318
1319 List<Element> paramElements = methodElement.elements("param");
1320
1321 for (Element paramElement : paramElements) {
1322 sb.append(paramElement.elementText("name"));
1323 sb.append("|");
1324 sb.append(paramElement.elementText("type"));
1325 sb.append(",");
1326 }
1327
1328 sb.append(StringPool.CLOSE_PARENTHESIS);
1329
1330 return sb.toString();
1331 }
1332
1333 private String _getMethodKey(JavaMethod javaMethod) {
1334 StringBundler sb = new StringBundler();
1335
1336 sb.append(javaMethod.getName());
1337 sb.append(StringPool.OPEN_PARENTHESIS);
1338
1339 JavaParameter[] javaParameters = javaMethod.getParameters();
1340
1341 for (JavaParameter javaParameter : javaParameters) {
1342 sb.append(javaParameter.getName());
1343 sb.append("|");
1344 sb.append(_getTypeValue(javaParameter));
1345 sb.append(",");
1346 }
1347
1348 sb.append(StringPool.CLOSE_PARENTHESIS);
1349
1350 return sb.toString();
1351 }
1352
1353 private String _getSpacesIndent(int length) {
1354 String indent = StringPool.BLANK;
1355
1356 for (int i = 0; i < length; i++) {
1357 indent += StringPool.SPACE;
1358 }
1359
1360 return indent;
1361 }
1362
1363 private String _getTypeValue(JavaParameter javaParameter) {
1364 Type type = javaParameter.getType();
1365
1366 String typeValue = type.getValue();
1367
1368 if (type.isArray()) {
1369 typeValue += "[]";
1370 }
1371
1372 return typeValue;
1373 }
1374
1375 private boolean _hasAnnotation(
1376 AbstractBaseJavaEntity abstractBaseJavaEntity, String annotationName) {
1377
1378 Annotation[] annotations = abstractBaseJavaEntity.getAnnotations();
1379
1380 if (annotations == null) {
1381 return false;
1382 }
1383
1384 for (int i = 0; i < annotations.length; i++) {
1385 Type type = annotations[i].getType();
1386
1387 JavaClass javaClass = type.getJavaClass();
1388
1389 if (annotationName.equals(javaClass.getName())) {
1390 return true;
1391 }
1392 }
1393
1394 return false;
1395 }
1396
1397 private boolean _hasGeneratedTag(String content) {
1398 if (content.contains("* @generated") || content.contains("$ANTLR")) {
1399 return true;
1400 }
1401 else {
1402 return false;
1403 }
1404 }
1405
1406 private boolean _hasPublicModifier(AbstractJavaEntity abstractJavaEntity) {
1407 String[] modifiers = abstractJavaEntity.getModifiers();
1408
1409 if (modifiers == null) {
1410 return false;
1411 }
1412
1413 for (String modifier : modifiers) {
1414 if (modifier.equals("public")) {
1415 return true;
1416 }
1417 }
1418
1419 return false;
1420 }
1421
1422 private boolean _isOverrideMethod(
1423 JavaClass javaClass, JavaMethod javaMethod,
1424 Collection<Tuple> ancestorJavaClassTuples) {
1425
1426 if (javaMethod.isConstructor() || javaMethod.isPrivate() ||
1427 javaMethod.isStatic() ||
1428 _overridesHigherJavaAPIVersion(javaMethod)) {
1429
1430 return false;
1431 }
1432
1433 String methodName = javaMethod.getName();
1434
1435 JavaParameter[] javaParameters = javaMethod.getParameters();
1436
1437 Type[] types = new Type[javaParameters.length];
1438
1439 for (int i = 0; i < javaParameters.length; i++) {
1440 types[i] = javaParameters[i].getType();
1441 }
1442
1443
1444
1445 for (Tuple ancestorJavaClassTuple : ancestorJavaClassTuples) {
1446 JavaClass ancestorJavaClass =
1447 (JavaClass)ancestorJavaClassTuple.getObject(0);
1448
1449 JavaMethod ancestorJavaMethod = null;
1450
1451 if (ancestorJavaClassTuple.getSize() > 1) {
1452
1453
1454
1455 Type[] ancestorActualTypeArguments =
1456 (Type[])ancestorJavaClassTuple.getObject(1);
1457
1458 Type[] genericTypes = new Type[types.length];
1459
1460 for (int i = 0; i < types.length; i++) {
1461 Type type = types[i];
1462
1463 String typeValue = type.getValue();
1464
1465 boolean useGenericType = false;
1466
1467 for (int j = 0; j < ancestorActualTypeArguments.length;
1468 j++) {
1469
1470 if (typeValue.equals(
1471 ancestorActualTypeArguments[j].getValue())) {
1472
1473 useGenericType = true;
1474
1475 break;
1476 }
1477 }
1478
1479 if (useGenericType) {
1480 genericTypes[i] = new Type("java.lang.Object");
1481 }
1482 else {
1483 genericTypes[i] = type;
1484 }
1485 }
1486
1487 ancestorJavaMethod = ancestorJavaClass.getMethodBySignature(
1488 methodName, genericTypes);
1489 }
1490 else {
1491 ancestorJavaMethod = ancestorJavaClass.getMethodBySignature(
1492 methodName, types);
1493 }
1494
1495 if (ancestorJavaMethod == null) {
1496 continue;
1497 }
1498
1499 boolean samePackage = false;
1500
1501 JavaPackage ancestorJavaPackage = ancestorJavaClass.getPackage();
1502
1503 if (ancestorJavaPackage != null) {
1504 samePackage = ancestorJavaPackage.equals(
1505 javaClass.getPackage());
1506 }
1507
1508
1509
1510 if (samePackage) {
1511 return !ancestorJavaMethod.isPrivate();
1512 }
1513
1514 if (ancestorJavaMethod.isProtected() ||
1515 ancestorJavaMethod.isPublic()) {
1516
1517 return true;
1518 }
1519 else {
1520 return false;
1521 }
1522
1523 }
1524
1525 return false;
1526 }
1527
1528 private boolean _overridesHigherJavaAPIVersion(JavaMethod javaMethod) {
1529 Annotation[] annotations = javaMethod.getAnnotations();
1530
1531 if (annotations == null) {
1532 return false;
1533 }
1534
1535 for (Annotation annotation : annotations) {
1536 Type type = annotation.getType();
1537
1538 JavaClass javaClass = type.getJavaClass();
1539
1540 String javaClassName = javaClass.getFullyQualifiedName();
1541
1542 if (javaClassName.equals(SinceJava.class.getName())) {
1543 AnnotationValue value = annotation.getProperty("value");
1544
1545 double sinceJava = GetterUtil.getDouble(
1546 value.getParameterValue());
1547
1548 if (sinceJava > _LOWEST_SUPPORTED_JAVA_VERSION) {
1549 return true;
1550 }
1551 }
1552 }
1553
1554 return false;
1555 }
1556
1557 private String _removeJavadocFromJava(JavaClass javaClass, String content) {
1558 Set<Integer> lineNumbers = new HashSet<Integer>();
1559
1560 lineNumbers.add(_getJavaClassLineNumber(javaClass));
1561
1562 JavaMethod[] javaMethods = javaClass.getMethods();
1563
1564 for (JavaMethod javaMethod : javaMethods) {
1565 lineNumbers.add(javaMethod.getLineNumber());
1566 }
1567
1568 JavaField[] javaFields = javaClass.getFields();
1569
1570 for (JavaField javaField : javaFields) {
1571 lineNumbers.add(javaField.getLineNumber());
1572 }
1573
1574 String[] lines = StringUtil.splitLines(content);
1575
1576 for (int lineNumber : lineNumbers) {
1577 if (lineNumber == 0) {
1578 continue;
1579 }
1580
1581 int pos = lineNumber - 2;
1582
1583 String line = lines[pos];
1584
1585 if (line == null) {
1586 continue;
1587 }
1588
1589 line = line.trim();
1590
1591 if (line.endsWith("*/")) {
1592 while (true) {
1593 lines[pos] = null;
1594
1595 if (line.startsWith("