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-2010 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 returns = javaMethod.getReturns();
248
249 if ((returns == null) || returns.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 String className = StringUtil.replace(
350 srcFile.substring(0, srcFile.length() - 5), "/", ".");
351
352 JavaDocBuilder builder = new JavaDocBuilder();
353
354 if (reader == null) {
355 File file = new File(fileName);
356
357 if (!file.exists()) {
358 return null;
359 }
360
361 builder.addSource(file);
362 }
363 else {
364 builder.addSource(reader);
365 }
366
367 return builder.getClassByName(className);
368 }
369
370 private String _getJavaClassComment(
371 Element rootElement, JavaClass javaClass) {
372
373 StringBuilder sb = new StringBuilder();
374
375 sb.append("\n");
391
392 return sb.toString();
393 }
394
395 private String _getJavadocXml(JavaClass javaClass) throws Exception {
396 Element rootElement = _saxReader.createElement("javadoc");
397
398 Document document = _saxReader.createDocument(rootElement);
399
400 DocUtil.add(rootElement, "name", javaClass.getName());
401 DocUtil.add(rootElement, "type", javaClass.getFullyQualifiedName());
402
403 _addClassCommentElement(rootElement, javaClass);
404 _addDocletElements(rootElement, javaClass, "author");
405 _addDocletElements(rootElement, javaClass, "deprecated");
406 _addDocletElements(rootElement, javaClass, "see");
407 _addDocletElements(rootElement, javaClass, "serial");
408 _addDocletElements(rootElement, javaClass, "since");
409 _addDocletElements(rootElement, javaClass, "version");
410
411 JavaMethod[] javaMethods = javaClass.getMethods();
412
413 for (JavaMethod javaMethod : javaMethods) {
414 _addMethodElement(rootElement, javaMethod);
415 }
416
417 JavaField[] javaFields = javaClass.getFields();
418
419 for (JavaField javaField : javaFields) {
420 _addFieldElement(rootElement, javaField);
421 }
422
423 return document.formattedString();
424 }
425
426 private String _getJavaFieldComment(
427 String[] lines, Map<String, Element> fieldElementsMap,
428 JavaField javaField) {
429
430 String fieldKey = _getFieldKey(javaField);
431
432 Element fieldElement = fieldElementsMap.get(fieldKey);
433
434 if (fieldElement == null) {
435 return null;
436 }
437
438 String line = lines[javaField.getLineNumber() - 1];
439
440 String indent = StringPool.BLANK;
441
442 for (char c : line.toCharArray()) {
443 if (Character.isWhitespace(c)) {
444 indent += c;
445 }
446 else {
447 break;
448 }
449 }
450
451 StringBuilder sb = new StringBuilder();
452
453 sb.append(indent);
454 sb.append("\n");
469
470 return sb.toString();
471 }
472
473 private String _getJavaMethodComment(
474 String[] lines, Map<String, Element> methodElementsMap,
475 JavaMethod javaMethod) {
476
477 String methodKey = _getMethodKey(javaMethod);
478
479 Element methodElement = methodElementsMap.get(methodKey);
480
481 if (methodElement == null) {
482 return null;
483 }
484
485 String line = lines[javaMethod.getLineNumber() - 1];
486
487 String indent = StringPool.BLANK;
488
489 for (char c : line.toCharArray()) {
490 if (Character.isWhitespace(c)) {
491 indent += c;
492 }
493 else {
494 break;
495 }
496 }
497
498 StringBuilder sb = new StringBuilder();
499
500 sb.append(indent);
501 sb.append("\n");
519
520 return sb.toString();
521 }
522
523 private String _getMethodKey(Element methodElement) {
524 StringBuilder sb = new StringBuilder();
525
526 sb.append(methodElement.elementText("name"));
527 sb.append(StringPool.OPEN_PARENTHESIS);
528
529 List<Element> paramElements = methodElement.elements("param");
530
531 for (Element paramElement : paramElements) {
532 sb.append(paramElement.elementText("name"));
533 sb.append("|");
534 sb.append(paramElement.elementText("type"));
535 sb.append(",");
536 }
537
538 sb.append(StringPool.CLOSE_PARENTHESIS);
539
540 return sb.toString();
541 }
542
543 private String _getMethodKey(JavaMethod javaMethod) {
544 StringBuilder sb = new StringBuilder();
545
546 sb.append(javaMethod.getName());
547 sb.append(StringPool.OPEN_PARENTHESIS);
548
549 JavaParameter[] javaParameters = javaMethod.getParameters();
550
551 for (JavaParameter javaParameter : javaParameters) {
552 sb.append(javaParameter.getName());
553 sb.append("|");
554 sb.append(javaParameter.getType().getValue());
555 sb.append(",");
556 }
557
558 sb.append(StringPool.CLOSE_PARENTHESIS);
559
560 return sb.toString();
561 }
562
563 private boolean _isGenerated(String content) {
564 if (content.contains("<javadoc autogenerated=\"true\">")) {
565 return true;
566 }
567 else {
568 return false;
569 }
570 }
571
572 private void _process(
573 String command, String limit, Boolean ignoreAutogenerated)
574 throws Exception {
575
576 DirectoryScanner ds = new DirectoryScanner();
577
578 ds.setBasedir(_basedir);
579 ds.setExcludes(
580 new String[] {
581 "**\\classes\\**", "**\\portal-client\\**", "**\\portal-web\\**"
582 });
583
584 List<String> includes = new ArrayList<String>();
585
586 if (Validator.isNotNull(limit) && !limit.startsWith("$")) {
587 String[] limitArray = StringUtil.split(limit, '/');
588
589 for (String curLimit : limitArray) {
590 includes.add(
591 "**\\" + StringUtil.replace(curLimit, ".", "\\") +
592 "\\**\\*.java");
593 includes.add("**\\" + curLimit + ".java");
594 }
595 }
596 else {
597 includes.add("**\\*.java");
598 }
599
600 ds.setIncludes(includes.toArray(new String[includes.size()]));
601
602 ds.scan();
603
604 String[] fileNames = ds.getIncludedFiles();
605
606 for (String fileName : fileNames) {
607 fileName = StringUtil.replace(fileName, "\\", "/");
608
609
612
613 if ((ignoreAutogenerated != null) &&
614 ignoreAutogenerated.booleanValue()) {
615
616 File file = new File(_basedir + fileName);
617
618 if (file.exists()) {
619 String oldContent = _fileUtil.read(
620 _basedir + fileName + "doc");
621
622 if (_isGenerated(oldContent)) {
623 continue;
624 }
625 }
626 }
627
628 if (command.equals("cleanup")) {
629 _processGet(fileName);
630 _processSave(fileName);
631 _processDelete(fileName);
632 }
633 else if (command.equals("commit")) {
634 _processSave(fileName);
635 _processDelete(fileName);
636 }
637 else if (command.equals("delete")) {
638 _processDelete(fileName);
639 }
640 else if (command.equals("get")) {
641 _processGet(fileName);
642 }
643 else if (command.equals("save")) {
644 _processSave(fileName);
645 }
646 }
647 }
648
649 private void _processDelete(String fileName) throws Exception {
650 _removeJavadocFromJava(fileName, true);
651 }
652
653 private void _processGet(String fileName) throws Exception {
654 File javadocFile = new File(_basedir + fileName + "doc");
655
656 if (!javadocFile.exists()) {
657 _updateJavadocFromJava(fileName);
658 }
659
660 String javaWithoutJavadoc = _removeJavadocFromJava(fileName, false);
661
662 _updateJavaFromJavadoc(fileName, javaWithoutJavadoc);
663 }
664
665 private void _processSave(String fileName) throws Exception {
666 _updateJavadocFromJava(fileName);
667 }
668
669 private String _removeJavadocFromJava(String fileName, boolean log)
670 throws Exception {
671
672 File file = new File(_basedir + fileName);
673
674 String oldContent = _fileUtil.read(file);
675
676 String[] lines = StringUtil.splitLines(oldContent);
677
678 JavaClass javaClass = _getJavaClass(
679 fileName, new UnsyncStringReader(oldContent));
680
681 Set<Integer> lineNumbers = new HashSet<Integer>();
682
683 lineNumbers.add(javaClass.getLineNumber());
684
685 JavaMethod[] javaMethods = javaClass.getMethods();
686
687 for (JavaMethod javaMethod : javaMethods) {
688 lineNumbers.add(javaMethod.getLineNumber());
689 }
690
691 JavaField[] javaFields = javaClass.getFields();
692
693 for (JavaField javaField : javaFields) {
694 lineNumbers.add(javaField.getLineNumber());
695 }
696
697 for (int lineNumber : lineNumbers) {
698 int pos = lineNumber - 2;
699
700 String line = lines[pos].trim();
701
702 if (line.endsWith("*/")) {
703 while (true) {
704 lines[pos] = null;
705
706 if (line.startsWith("