001
014
015 package com.liferay.portal.tools;
016
017 import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
018 import com.liferay.portal.kernel.util.StringPool;
019 import com.liferay.portal.kernel.util.StringUtil;
020 import com.liferay.portal.kernel.util.Validator;
021 import com.liferay.portal.kernel.xml.Document;
022 import com.liferay.portal.kernel.xml.Element;
023 import com.liferay.portal.kernel.xml.SAXReader;
024 import com.liferay.portal.util.FileImpl;
025 import com.liferay.portal.xml.SAXReaderImpl;
026 import com.liferay.util.xml.DocUtil;
027
028 import com.thoughtworks.qdox.JavaDocBuilder;
029 import com.thoughtworks.qdox.model.AbstractJavaEntity;
030 import com.thoughtworks.qdox.model.DocletTag;
031 import com.thoughtworks.qdox.model.JavaClass;
032 import com.thoughtworks.qdox.model.JavaField;
033 import com.thoughtworks.qdox.model.JavaMethod;
034 import com.thoughtworks.qdox.model.JavaParameter;
035 import com.thoughtworks.qdox.model.Type;
036
037 import jargs.gnu.CmdLineParser;
038
039 import java.io.File;
040 import java.io.Reader;
041
042 import java.util.ArrayList;
043 import java.util.HashMap;
044 import java.util.HashSet;
045 import java.util.List;
046 import java.util.Map;
047 import java.util.Set;
048 import java.util.TreeMap;
049
050 import org.apache.tools.ant.DirectoryScanner;
051
052
055 public class JavadocBuilder {
056
057 public static void main(String[] args) {
058 try {
059 new JavadocBuilder(args);
060 }
061 catch (Exception e) {
062 e.printStackTrace();
063 }
064 }
065
066 public JavadocBuilder(String[] args) throws Exception {
067 CmdLineParser cmdLineParser = new CmdLineParser();
068
069 cmdLineParser.parse(args);
070
071 CmdLineParser.Option commandOption = cmdLineParser.addStringOption(
072 "command");
073
074 String command = (String)cmdLineParser.getOptionValue(commandOption);
075
076 CmdLineParser.Option limitOption = cmdLineParser.addStringOption(
077 "limit");
078
079 String limit = (String)cmdLineParser.getOptionValue(limitOption);
080
081 CmdLineParser.Option ignoreAutogeneratedOption =
082 cmdLineParser.addBooleanOption("ignoreAutogenerated");
083
084 Boolean ignoreAutogenerated = (Boolean)cmdLineParser.getOptionValue(
085 ignoreAutogeneratedOption);
086
087 _process(command, limit, ignoreAutogenerated);
088 }
089
090 private void _addClassCommentElement(
091 Element rootElement, JavaClass javaClass) {
092
093 Element commentElement = rootElement.addElement("comment");
094
095 String comment = _getCDATA(javaClass);
096
097 if (comment.startsWith("Copyright (c) 2000-present Liferay, Inc.")) {
098 comment = StringPool.BLANK;
099 }
100
101 if (comment.startsWith(
102 "<a href=\"" + javaClass.getName() + ".java.html\">")) {
103
104 int pos = comment.indexOf("</a>");
105
106 comment = comment.substring(pos + 4).trim();
107 }
108
109 commentElement.addCDATA(comment);
110 }
111
112 private void _addDocletElements(
113 Element parentElement, AbstractJavaEntity abstractJavaEntity,
114 String name) {
115
116 DocletTag[] docletTags = abstractJavaEntity.getTagsByName(name);
117
118 for (DocletTag docletTag : docletTags) {
119 String value = docletTag.getValue();
120
121 if (name.equals("author") || name.equals("see") ||
122 name.equals("since") || name.equals("version")) {
123
124
127
128 DocUtil.add(parentElement, name, value);
129 }
130 else {
131 Element element = parentElement.addElement(name);
132
133 element.addCDATA(value);
134 }
135 }
136 }
137
138 private void _addDocletTags(
139 Element parentElement, String name, String indent, StringBuilder sb) {
140
141 List<Element> elements = parentElement.elements(name);
142
143 for (Element element : elements) {
144 sb.append(indent);
145 sb.append(" * @");
146 sb.append(name);
147 sb.append(" ");
148
149 Element commentElement = element.element("comment");
150
151 if (commentElement != null) {
152 sb.append(element.elementText("name"));
153 sb.append(" ");
154 sb.append(_getCDATA(element.elementText("comment")));
155 }
156 else {
157 sb.append(_getCDATA(element.getText()));
158 }
159
160 sb.append("\n");
161 }
162 }
163
164 private void _addFieldElement(Element rootElement, JavaField javaField) {
165 Element fieldElement = rootElement.addElement("field");
166
167 DocUtil.add(fieldElement, "name", javaField.getName());
168
169 Element commentElement = fieldElement.addElement("comment");
170
171 commentElement.addCDATA(_getCDATA(javaField));
172
173 _addDocletElements(fieldElement, javaField, "deprecated");
174 _addDocletElements(fieldElement, javaField, "see");
175 _addDocletElements(fieldElement, javaField, "since");
176 _addDocletElements(fieldElement, javaField, "version");
177 }
178
179 private void _addMethodElement(Element rootElement, JavaMethod javaMethod) {
180 Element methodElement = rootElement.addElement("method");
181
182 DocUtil.add(methodElement, "name", javaMethod.getName());
183
184 Element commentElement = methodElement.addElement("comment");
185
186 commentElement.addCDATA(_getCDATA(javaMethod));
187
188 _addDocletElements(methodElement, javaMethod, "deprecated");
189 _addParamElements(methodElement, javaMethod);
190 _addReturnElement(methodElement, javaMethod);
191 _addDocletElements(methodElement, javaMethod, "see");
192 _addDocletElements(methodElement, javaMethod, "since");
193 _addThrowsElements(methodElement, javaMethod);
194 _addDocletElements(methodElement, javaMethod, "version");
195 }
196
197 private void _addParamElement(
198 Element methodElement, JavaParameter javaParameter,
199 DocletTag[] paramDocletTags) {
200
201 String name = javaParameter.getName();
202 String type = javaParameter.getType().getValue();
203 String value = null;
204
205 for (DocletTag paramDocletTag : paramDocletTags) {
206 String curValue = paramDocletTag.getValue();
207
208 if (!curValue.startsWith(name)) {
209 continue;
210 }
211 else {
212 curValue = value;
213
214 break;
215 }
216 }
217
218 Element paramElement = methodElement.addElement("param");
219
220 DocUtil.add(paramElement, "name", name);
221 DocUtil.add(paramElement, "type", type);
222
223 if (value != null) {
224 value = value.substring(name.length());
225 }
226
227 Element commentElement = paramElement.addElement("comment");
228
229 commentElement.addCDATA(_getCDATA(value));
230 }
231
232 private void _addParamElements(
233 Element methodElement, JavaMethod javaMethod) {
234
235 JavaParameter[] javaParameters = javaMethod.getParameters();
236
237 DocletTag[] paramDocletTags = javaMethod.getTagsByName("param");
238
239 for (JavaParameter javaParameter : javaParameters) {
240 _addParamElement(methodElement, javaParameter, paramDocletTags);
241 }
242 }
243
244 private void _addReturnElement(
245 Element methodElement, JavaMethod javaMethod) {
246
247 Type returnType = javaMethod.getReturnType();
248
249 if ((returnType == null) || returnType.getValue().equals("void")) {
250 return;
251 }
252
253 _addDocletElements(methodElement, javaMethod, "return");
254 }
255
256 private void _addThrowsElement(
257 Element methodElement, Type exception, DocletTag[] throwsDocletTags) {
258
259 String name = exception.getJavaClass().getName();
260 String value = null;
261
262 for (DocletTag throwsDocletTag : throwsDocletTags) {
263 String curValue = throwsDocletTag.getValue();
264
265 if (!curValue.startsWith(name)) {
266 continue;
267 }
268 else {
269 curValue = value;
270
271 break;
272 }
273 }
274
275 Element throwsElement = methodElement.addElement("throws");
276
277 DocUtil.add(throwsElement, "name", name);
278 DocUtil.add(throwsElement, "type", exception.getValue());
279
280 if (value != null) {
281 value = value.substring(name.length());
282 }
283
284 Element commentElement = throwsElement.addElement("comment");
285
286 commentElement.addCDATA(_getCDATA(value));
287 }
288
289 private void _addThrowsElements(
290 Element methodElement, JavaMethod javaMethod) {
291
292 Type[] exceptions = javaMethod.getExceptions();
293
294 DocletTag[] throwsDocletTags = javaMethod.getTagsByName("throws");
295
296 for (Type exception : exceptions) {
297 _addThrowsElement(methodElement, exception, throwsDocletTags);
298 }
299 }
300
301 private String _getCDATA(AbstractJavaEntity abstractJavaEntity) {
302 return _getCDATA(abstractJavaEntity.getComment());
303 }
304
305 private String _getCDATA(String cdata) {
306 if (cdata == null) {
307 return StringPool.BLANK;
308 }
309
310 cdata = StringUtil.replace(
311 cdata, new String[] {"\n", "<p>", "</p>"},
312 new String[] {" ", " <p> ", " </p> "});
313
314 while (cdata.contains(" ")) {
315 cdata = StringUtil.replace(cdata, " ", " ");
316 }
317
318 return cdata.trim();
319 }
320
321 private String _getFieldKey(Element fieldElement) {
322 return fieldElement.elementText("name");
323 }
324
325 private String _getFieldKey(JavaField javaField) {
326 return javaField.getName();
327 }
328
329 private JavaClass _getJavaClass(String fileName) throws Exception {
330 return _getJavaClass(fileName, null);
331 }
332
333 private JavaClass _getJavaClass(String fileName, Reader reader)
334 throws Exception {
335
336 int pos = fileName.indexOf("src/");
337
338 if (pos == -1) {
339 pos = fileName.indexOf("test/");
340 }
341
342 if (pos == -1) {
343 throw new RuntimeException(fileName);
344 }
345
346 pos = fileName.indexOf("/", pos);
347
348 String srcFile = fileName.substring(pos + 1);
349
350 String className = StringUtil.replace(
351 srcFile.substring(0, srcFile.length() - 5), '/', '.');
352
353 JavaDocBuilder builder = new JavaDocBuilder();
354
355 if (reader == null) {
356 File file = new File(fileName);
357
358 if (!file.exists()) {
359 return null;
360 }
361
362 builder.addSource(file);
363 }
364 else {
365 builder.addSource(reader);
366 }
367
368 return builder.getClassByName(className);
369 }
370
371 private String _getJavaClassComment(Element rootElement) {
372 StringBuilder sb = new StringBuilder();
373
374 sb.append("\n");
390
391 return sb.toString();
392 }
393
394 private String _getJavadocXml(JavaClass javaClass) throws Exception {
395 Element rootElement = _saxReader.createElement("javadoc");
396
397 Document document = _saxReader.createDocument(rootElement);
398
399 DocUtil.add(rootElement, "name", javaClass.getName());
400 DocUtil.add(rootElement, "type", javaClass.getFullyQualifiedName());
401
402 _addClassCommentElement(rootElement, javaClass);
403 _addDocletElements(rootElement, javaClass, "author");
404 _addDocletElements(rootElement, javaClass, "deprecated");
405 _addDocletElements(rootElement, javaClass, "see");
406 _addDocletElements(rootElement, javaClass, "serial");
407 _addDocletElements(rootElement, javaClass, "since");
408 _addDocletElements(rootElement, javaClass, "version");
409
410 JavaMethod[] javaMethods = javaClass.getMethods();
411
412 for (JavaMethod javaMethod : javaMethods) {
413 _addMethodElement(rootElement, javaMethod);
414 }
415
416 JavaField[] javaFields = javaClass.getFields();
417
418 for (JavaField javaField : javaFields) {
419 _addFieldElement(rootElement, javaField);
420 }
421
422 return document.formattedString();
423 }
424
425 private String _getJavaFieldComment(
426 String[] lines, Map<String, Element> fieldElementsMap,
427 JavaField javaField) {
428
429 String fieldKey = _getFieldKey(javaField);
430
431 Element fieldElement = fieldElementsMap.get(fieldKey);
432
433 if (fieldElement == null) {
434 return null;
435 }
436
437 String line = lines[javaField.getLineNumber() - 1];
438
439 String indent = StringPool.BLANK;
440
441 for (char c : line.toCharArray()) {
442 if (Character.isWhitespace(c)) {
443 indent += c;
444 }
445 else {
446 break;
447 }
448 }
449
450 StringBuilder sb = new StringBuilder();
451
452 sb.append(indent);
453 sb.append("\n");
468
469 return sb.toString();
470 }
471
472 private String _getJavaMethodComment(
473 String[] lines, Map<String, Element> methodElementsMap,
474 JavaMethod javaMethod) {
475
476 String methodKey = _getMethodKey(javaMethod);
477
478 Element methodElement = methodElementsMap.get(methodKey);
479
480 if (methodElement == null) {
481 return null;
482 }
483
484 String line = lines[javaMethod.getLineNumber() - 1];
485
486 String indent = StringPool.BLANK;
487
488 for (char c : line.toCharArray()) {
489 if (Character.isWhitespace(c)) {
490 indent += c;
491 }
492 else {
493 break;
494 }
495 }
496
497 StringBuilder sb = new StringBuilder();
498
499 sb.append(indent);
500 sb.append("\n");
518
519 return sb.toString();
520 }
521
522 private String _getMethodKey(Element methodElement) {
523 StringBuilder sb = new StringBuilder();
524
525 sb.append(methodElement.elementText("name"));
526 sb.append(StringPool.OPEN_PARENTHESIS);
527
528 List<Element> paramElements = methodElement.elements("param");
529
530 for (Element paramElement : paramElements) {
531 sb.append(paramElement.elementText("name"));
532 sb.append("|");
533 sb.append(paramElement.elementText("type"));
534 sb.append(",");
535 }
536
537 sb.append(StringPool.CLOSE_PARENTHESIS);
538
539 return sb.toString();
540 }
541
542 private String _getMethodKey(JavaMethod javaMethod) {
543 StringBuilder sb = new StringBuilder();
544
545 sb.append(javaMethod.getName());
546 sb.append(StringPool.OPEN_PARENTHESIS);
547
548 JavaParameter[] javaParameters = javaMethod.getParameters();
549
550 for (JavaParameter javaParameter : javaParameters) {
551 sb.append(javaParameter.getName());
552 sb.append("|");
553 sb.append(javaParameter.getType().getValue());
554 sb.append(",");
555 }
556
557 sb.append(StringPool.CLOSE_PARENTHESIS);
558
559 return sb.toString();
560 }
561
562 private boolean _isGenerated(String content) {
563 if (content.contains("<javadoc autogenerated=\"true\">")) {
564 return true;
565 }
566 else {
567 return false;
568 }
569 }
570
571 private void _process(
572 String command, String limit, Boolean ignoreAutogenerated)
573 throws Exception {
574
575 DirectoryScanner ds = new DirectoryScanner();
576
577 ds.setBasedir(_BASEDIR);
578 ds.setExcludes(
579 new String[] {
580 "**\\classes\\**", "**\\portal-client\\**", "**\\portal-web\\**"
581 });
582
583 List<String> includes = new ArrayList<>();
584
585 if (Validator.isNotNull(limit) && !limit.startsWith("$")) {
586 String[] limitArray = StringUtil.split(limit, '/');
587
588 for (String curLimit : limitArray) {
589 includes.add(
590 "**\\" + StringUtil.replace(curLimit, '.', '\\') +
591 "\\**\\*.java");
592 includes.add("**\\" + curLimit + ".java");
593 }
594 }
595 else {
596 includes.add("**\\*.java");
597 }
598
599 ds.setIncludes(includes.toArray(new String[includes.size()]));
600
601 ds.scan();
602
603 String[] fileNames = ds.getIncludedFiles();
604
605 for (String fileName : fileNames) {
606 fileName = StringUtil.replace(fileName, '\\', '/');
607
608
611
612 if ((ignoreAutogenerated != null) &&
613 ignoreAutogenerated.booleanValue()) {
614
615 File file = new File(_BASEDIR + fileName);
616
617 if (file.exists()) {
618 String oldContent = _fileUtil.read(
619 _BASEDIR + fileName + "doc");
620
621 if (_isGenerated(oldContent)) {
622 continue;
623 }
624 }
625 }
626
627 if (command.equals("cleanup")) {
628 _processGet(fileName);
629 _processSave(fileName);
630 _processDelete(fileName);
631 }
632 else if (command.equals("commit")) {
633 _processSave(fileName);
634 _processDelete(fileName);
635 }
636 else if (command.equals("delete")) {
637 _processDelete(fileName);
638 }
639 else if (command.equals("get")) {
640 _processGet(fileName);
641 }
642 else if (command.equals("save")) {
643 _processSave(fileName);
644 }
645 }
646 }
647
648 private void _processDelete(String fileName) throws Exception {
649 _removeJavadocFromJava(fileName, true);
650 }
651
652 private void _processGet(String fileName) throws Exception {
653 File javadocFile = new File(_BASEDIR + fileName + "doc");
654
655 if (!javadocFile.exists()) {
656 _updateJavadocFromJava(fileName);
657 }
658
659 String javaWithoutJavadoc = _removeJavadocFromJava(fileName, false);
660
661 _updateJavaFromJavadoc(fileName, javaWithoutJavadoc);
662 }
663
664 private void _processSave(String fileName) throws Exception {
665 _updateJavadocFromJava(fileName);
666 }
667
668 private String _removeJavadocFromJava(String fileName, boolean log)
669 throws Exception {
670
671 File file = new File(_BASEDIR + fileName);
672
673 String oldContent = _fileUtil.read(file);
674
675 String[] lines = StringUtil.splitLines(oldContent);
676
677 JavaClass javaClass = _getJavaClass(
678 fileName, new UnsyncStringReader(oldContent));
679
680 Set<Integer> lineNumbers = new HashSet<>();
681
682 lineNumbers.add(javaClass.getLineNumber());
683
684 JavaMethod[] javaMethods = javaClass.getMethods();
685
686 for (JavaMethod javaMethod : javaMethods) {
687 lineNumbers.add(javaMethod.getLineNumber());
688 }
689
690 JavaField[] javaFields = javaClass.getFields();
691
692 for (JavaField javaField : javaFields) {
693 lineNumbers.add(javaField.getLineNumber());
694 }
695
696 for (int lineNumber : lineNumbers) {
697 int pos = lineNumber - 2;
698
699 String line = lines[pos].trim();
700
701 if (line.endsWith("*/")) {
702 while (true) {
703 lines[pos] = null;
704
705 if (line.startsWith("