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