1 package org.apache.maven.tools.plugin.generator;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.plugin.descriptor.MojoDescriptor;
23 import org.apache.maven.plugin.descriptor.Parameter;
24 import org.apache.maven.project.MavenProject;
25 import org.apache.maven.tools.plugin.ExtendedMojoDescriptor;
26 import org.apache.maven.tools.plugin.PluginToolsRequest;
27 import org.codehaus.plexus.util.IOUtil;
28 import org.codehaus.plexus.util.StringUtils;
29 import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
30 import org.codehaus.plexus.util.xml.XMLWriter;
31
32 import java.io.File;
33 import java.io.FileOutputStream;
34 import java.io.IOException;
35 import java.io.OutputStreamWriter;
36 import java.io.PrintWriter;
37 import java.io.Writer;
38 import java.text.MessageFormat;
39 import java.util.ArrayList;
40 import java.util.Iterator;
41 import java.util.List;
42 import java.util.Locale;
43 import java.util.ResourceBundle;
44
45
46
47
48
49
50
51 public class PluginXdocGenerator
52 implements Generator
53 {
54
55
56
57 private final Locale locale;
58
59
60
61
62 private final MavenProject project;
63
64
65
66
67
68 public PluginXdocGenerator()
69 {
70 this.project = null;
71 this.locale = Locale.ENGLISH;
72 }
73
74
75
76
77
78
79 public PluginXdocGenerator( MavenProject project )
80 {
81 this.project = project;
82 this.locale = Locale.ENGLISH;
83 }
84
85
86
87
88
89 public PluginXdocGenerator( MavenProject project, Locale locale )
90 {
91 this.project = project;
92 if ( locale == null )
93 {
94 this.locale = Locale.ENGLISH;
95 }
96 else
97 {
98 this.locale = locale;
99 }
100 }
101
102
103
104
105
106 public void execute( File destinationDirectory, PluginToolsRequest request )
107 throws GeneratorException
108 {
109 try
110 {
111 if ( request.getPluginDescriptor().getMojos() != null )
112 {
113 @SuppressWarnings( "unchecked" )
114 List<MojoDescriptor> mojos = request.getPluginDescriptor().getMojos();
115
116 for ( MojoDescriptor descriptor : mojos )
117 {
118 processMojoDescriptor( descriptor, destinationDirectory );
119 }
120 }
121 }
122 catch ( IOException e )
123 {
124 throw new GeneratorException( e.getMessage(), e );
125 }
126
127 }
128
129
130
131
132
133
134 protected void processMojoDescriptor( MojoDescriptor mojoDescriptor, File destinationDirectory )
135 throws IOException
136 {
137 File outputFile = new File( destinationDirectory, getMojoFilename( mojoDescriptor, "xml" ) );
138 String encoding = "UTF-8";
139 Writer writer = null;
140 try
141 {
142 writer = new OutputStreamWriter( new FileOutputStream( outputFile ), encoding );
143
144 XMLWriter w = new PrettyPrintXMLWriter( new PrintWriter( writer ), encoding, null );
145 writeBody( mojoDescriptor, w );
146
147 writer.flush();
148 }
149 finally
150 {
151 IOUtil.close( writer );
152 }
153 }
154
155
156
157
158
159
160 private String getMojoFilename( MojoDescriptor mojo, String ext )
161 {
162 return mojo.getGoal() + "-mojo." + ext;
163 }
164
165
166
167
168
169 private void writeBody( MojoDescriptor mojoDescriptor, XMLWriter w )
170 {
171 w.startElement( "document" );
172 w.addAttribute( "xmlns", "http://maven.apache.org/XDOC/2.0" );
173 w.addAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" );
174 w.addAttribute( "xsi:schemaLocation",
175 "http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd" );
176
177
178
179
180
181 w.startElement( "properties" );
182
183 w.startElement( "title" );
184 w.writeText( mojoDescriptor.getFullGoalName() );
185 w.endElement();
186
187 w.endElement();
188
189
190
191
192
193 w.startElement( "body" );
194
195 w.startElement( "section" );
196
197 w.addAttribute( "name", mojoDescriptor.getFullGoalName() );
198
199 writeReportNotice( mojoDescriptor, w );
200
201 w.startElement( "p" );
202 w.writeMarkup( getString( "pluginxdoc.mojodescriptor.fullname" ) );
203 w.endElement();
204 w.startElement( "p" );
205 w.writeMarkup( mojoDescriptor.getPluginDescriptor().getGroupId() + ":"
206 + mojoDescriptor.getPluginDescriptor().getArtifactId() + ":"
207 + mojoDescriptor.getPluginDescriptor().getVersion() + ":" + mojoDescriptor.getGoal() );
208 w.endElement();
209
210 if ( StringUtils.isNotEmpty( mojoDescriptor.getDeprecated() ) )
211 {
212 w.startElement( "p" );
213 w.writeMarkup( getString( "pluginxdoc.mojodescriptor.deprecated" ) );
214 w.endElement();
215 w.startElement( "div" );
216 w.writeMarkup( GeneratorUtils.makeHtmlValid( mojoDescriptor.getDeprecated() ) );
217 w.endElement();
218 }
219
220 w.startElement( "p" );
221 w.writeMarkup( getString( "pluginxdoc.description" ) );
222 w.endElement();
223 w.startElement( "div" );
224 if ( StringUtils.isNotEmpty( mojoDescriptor.getDescription() ) )
225 {
226 w.writeMarkup( GeneratorUtils.makeHtmlValid( mojoDescriptor.getDescription() ) );
227 }
228 else
229 {
230 w.writeText( getString( "pluginxdoc.nodescription" ) );
231 }
232 w.endElement();
233
234 writeGoalAttributes( mojoDescriptor, w );
235
236 writeGoalParameterTable( mojoDescriptor, w );
237
238 w.endElement();
239
240 w.endElement();
241
242 w.endElement();
243 }
244
245
246
247
248
249 private void writeReportNotice( MojoDescriptor mojoDescriptor, XMLWriter w )
250 {
251 if ( GeneratorUtils.isMavenReport( mojoDescriptor.getImplementation(), project ) )
252 {
253 w.startElement( "p" );
254 w.writeMarkup( getString( "pluginxdoc.mojodescriptor.notice.note" ) );
255 w.writeText( getString( "pluginxdoc.mojodescriptor.notice.isMavenReport" ) );
256 w.endElement();
257 }
258 }
259
260
261
262
263
264 private void writeGoalAttributes( MojoDescriptor mojoDescriptor, XMLWriter w )
265 {
266 w.startElement( "p" );
267 w.writeMarkup( getString( "pluginxdoc.mojodescriptor.attributes" ) );
268 w.endElement();
269
270 boolean addedUl = false;
271 String value;
272 if ( mojoDescriptor.isProjectRequired() )
273 {
274 addedUl = addUl( w, addedUl );
275 w.startElement( "li" );
276 w.writeMarkup( getString( "pluginxdoc.mojodescriptor.projectRequired" ) );
277 w.endElement();
278 }
279
280 if ( mojoDescriptor.isRequiresReports() )
281 {
282 addedUl = addUl( w, addedUl );
283 w.startElement( "li" );
284 w.writeMarkup( getString( "pluginxdoc.mojodescriptor.reportingMojo" ) );
285 w.endElement();
286 }
287
288 if ( mojoDescriptor.isAggregator() )
289 {
290 addedUl = addUl( w, addedUl );
291 w.startElement( "li" );
292 w.writeMarkup( getString( "pluginxdoc.mojodescriptor.aggregator" ) );
293 w.endElement();
294 }
295
296 if ( mojoDescriptor.isDirectInvocationOnly() )
297 {
298 addedUl = addUl( w, addedUl );
299 w.startElement( "li" );
300 w.writeMarkup( getString( "pluginxdoc.mojodescriptor.directInvocationOnly" ) );
301 w.endElement();
302 }
303
304 value = mojoDescriptor.isDependencyResolutionRequired();
305 if ( StringUtils.isNotEmpty( value ) )
306 {
307 addedUl = addUl( w, addedUl );
308 w.startElement( "li" );
309 w.writeMarkup( format( "pluginxdoc.mojodescriptor.dependencyResolutionRequired", value ) );
310 w.endElement();
311 }
312
313 if ( mojoDescriptor instanceof ExtendedMojoDescriptor )
314 {
315 ExtendedMojoDescriptor extendedMojoDescriptor = (ExtendedMojoDescriptor) mojoDescriptor;
316
317 value = extendedMojoDescriptor.getDependencyCollectionRequired();
318 if ( StringUtils.isNotEmpty( value ) )
319 {
320 addedUl = addUl( w, addedUl );
321 w.startElement( "li" );
322 w.writeMarkup( format( "pluginxdoc.mojodescriptor.dependencyCollectionRequired", value ) );
323 w.endElement();
324 }
325
326 if ( extendedMojoDescriptor.isThreadSafe() )
327 {
328 addedUl = addUl( w, addedUl );
329 w.startElement( "li" );
330 w.writeMarkup( getString( "pluginxdoc.mojodescriptor.threadSafe" ) );
331 w.endElement();
332 }
333
334 }
335
336 value = mojoDescriptor.getSince();
337 if ( StringUtils.isNotEmpty( value ) )
338 {
339 addedUl = addUl( w, addedUl );
340 w.startElement( "li" );
341 w.writeMarkup( format( "pluginxdoc.mojodescriptor.since", value ) );
342 w.endElement();
343 }
344
345 value = mojoDescriptor.getPhase();
346 if ( StringUtils.isNotEmpty( value ) )
347 {
348 addedUl = addUl( w, addedUl );
349 w.startElement( "li" );
350 w.writeMarkup( format( "pluginxdoc.mojodescriptor.phase", value ) );
351 w.endElement();
352 }
353
354 value = mojoDescriptor.getExecutePhase();
355 if ( StringUtils.isNotEmpty( value ) )
356 {
357 addedUl = addUl( w, addedUl );
358 w.startElement( "li" );
359 w.writeMarkup( format( "pluginxdoc.mojodescriptor.executePhase", value ) );
360 w.endElement();
361 }
362
363 value = mojoDescriptor.getExecuteGoal();
364 if ( StringUtils.isNotEmpty( value ) )
365 {
366 addedUl = addUl( w, addedUl );
367 w.startElement( "li" );
368 w.writeMarkup( format( "pluginxdoc.mojodescriptor.executeGoal", value ) );
369 w.endElement();
370 }
371
372 value = mojoDescriptor.getExecuteLifecycle();
373 if ( StringUtils.isNotEmpty( value ) )
374 {
375 addedUl = addUl( w, addedUl );
376 w.startElement( "li" );
377 w.writeMarkup( format( "pluginxdoc.mojodescriptor.executeLifecycle", value ) );
378 w.endElement();
379 }
380
381 if ( mojoDescriptor.isOnlineRequired() )
382 {
383 addedUl = addUl( w, addedUl );
384 w.startElement( "li" );
385 w.writeMarkup( getString( "pluginxdoc.mojodescriptor.onlineRequired" ) );
386 w.endElement();
387 }
388
389 if ( !mojoDescriptor.isInheritedByDefault() )
390 {
391 addedUl = addUl( w, addedUl );
392 w.startElement( "li" );
393 w.writeMarkup( getString( "pluginxdoc.mojodescriptor.inheritedByDefault" ) );
394 w.endElement();
395 }
396
397 if ( addedUl )
398 {
399 w.endElement();
400 }
401 }
402
403
404
405
406
407 private void writeGoalParameterTable( MojoDescriptor mojoDescriptor, XMLWriter w )
408 {
409 @SuppressWarnings( "unchecked" )
410 List<Parameter> parameterList = mojoDescriptor.getParameters();
411
412
413 List<Parameter> list = filterParameters( parameterList );
414
415 if ( list != null && list.size() > 0 )
416 {
417 writeParameterSummary( mojoDescriptor, list, w );
418
419 writeParameterDetails( mojoDescriptor, list, w );
420 }
421 else
422 {
423 w.startElement( "subsection" );
424 w.addAttribute( "name", getString( "pluginxdoc.mojodescriptor.parameters" ) );
425
426 w.startElement( "p" );
427 w.writeMarkup( getString( "pluginxdoc.mojodescriptor.noParameter" ) );
428 w.endElement();
429
430 w.endElement();
431 }
432 }
433
434
435
436
437
438
439
440 private List<Parameter> filterParameters( List<Parameter> parameterList )
441 {
442 List<Parameter> filtered = new ArrayList<Parameter>();
443
444 if ( parameterList != null )
445 {
446 for ( Parameter parameter : parameterList )
447 {
448 if ( parameter.isEditable() )
449 {
450 String expression = parameter.getExpression();
451
452 if ( expression == null || !expression.startsWith( "${component." ) )
453 {
454 filtered.add( parameter );
455 }
456 }
457 }
458 }
459
460 return filtered;
461 }
462
463
464
465
466
467
468 private void writeParameterDetails( MojoDescriptor mojoDescriptor, List<Parameter> parameterList, XMLWriter w )
469 {
470 w.startElement( "subsection" );
471 w.addAttribute( "name", getString( "pluginxdoc.mojodescriptor.parameter.details" ) );
472
473 for ( Iterator<Parameter> parameters = parameterList.iterator(); parameters.hasNext(); )
474 {
475 Parameter parameter = parameters.next();
476
477 w.startElement( "p" );
478 w.writeMarkup( format( "pluginxdoc.mojodescriptor.parameter.name_internal", parameter.getName() ) );
479 w.endElement();
480
481 if ( StringUtils.isNotEmpty( parameter.getDeprecated() ) )
482 {
483 w.startElement( "div" );
484 w.writeMarkup( format( "pluginxdoc.mojodescriptor.parameter.deprecated",
485 GeneratorUtils.makeHtmlValid( parameter.getDeprecated() ) ) );
486 w.endElement();
487 }
488
489 w.startElement( "div" );
490 if ( StringUtils.isNotEmpty( parameter.getDescription() ) )
491 {
492 w.writeMarkup( GeneratorUtils.makeHtmlValid( parameter.getDescription() ) );
493 }
494 else
495 {
496 w.writeMarkup( getString( "pluginxdoc.nodescription" ) );
497 }
498 w.endElement();
499
500 boolean addedUl = false;
501 addedUl = addUl( w, addedUl, parameter.getType() );
502 writeDetail( getString( "pluginxdoc.mojodescriptor.parameter.type" ), parameter.getType(), w );
503
504 if ( StringUtils.isNotEmpty( parameter.getSince() ) )
505 {
506 addedUl = addUl( w, addedUl );
507 writeDetail( getString( "pluginxdoc.mojodescriptor.parameter.since" ), parameter.getSince(), w );
508 }
509 else
510 {
511 if ( StringUtils.isNotEmpty( mojoDescriptor.getSince() ) )
512 {
513 addedUl = addUl( w, addedUl );
514 writeDetail( getString( "pluginxdoc.mojodescriptor.parameter.since" ), mojoDescriptor.getSince(),
515 w );
516 }
517 }
518
519 if ( parameter.isRequired() )
520 {
521 addedUl = addUl( w, addedUl );
522 writeDetail( getString( "pluginxdoc.mojodescriptor.parameter.required" ), getString( "pluginxdoc.yes" ),
523 w );
524 }
525 else
526 {
527 addedUl = addUl( w, addedUl );
528 writeDetail( getString( "pluginxdoc.mojodescriptor.parameter.required" ), getString( "pluginxdoc.no" ),
529 w );
530 }
531
532 String expression = parameter.getExpression();
533 addedUl = addUl( w, addedUl, expression );
534 String property = getPropertyFromExpression( expression );
535 if ( property == null )
536 {
537 writeDetail( getString( "pluginxdoc.mojodescriptor.parameter.expression" ), expression, w );
538 }
539 else
540 {
541 writeDetail( getString( "pluginxdoc.mojodescriptor.parameter.property" ), property, w );
542 }
543
544 addedUl = addUl( w, addedUl, parameter.getDefaultValue() );
545 writeDetail( getString( "pluginxdoc.mojodescriptor.parameter.default" ),
546 escapeXml( parameter.getDefaultValue() ), w );
547
548 if ( addedUl )
549 {
550 w.endElement();
551 }
552
553 if ( parameters.hasNext() )
554 {
555 w.writeMarkup( "<hr/>" );
556 }
557 }
558
559 w.endElement();
560 }
561
562 private boolean addUl( XMLWriter w, boolean addedUl, String content )
563 {
564 if ( StringUtils.isNotEmpty( content ) )
565 {
566 return addUl( w, addedUl );
567 }
568 return addedUl;
569 }
570
571 private boolean addUl( XMLWriter w, boolean addedUl )
572 {
573 if ( !addedUl )
574 {
575 w.startElement( "ul" );
576 addedUl = true;
577 }
578 return addedUl;
579 }
580
581 private String getPropertyFromExpression( String expression )
582 {
583 if ( StringUtils.isNotEmpty( expression ) && expression.startsWith( "${" ) && expression.endsWith( "}" )
584 && !expression.substring( 2 ).contains( "${" ) )
585 {
586
587 return expression.substring( 2, expression.length() - 1 );
588 }
589
590 return null;
591 }
592
593
594
595
596
597
598 private void writeDetail( String param, String value, XMLWriter w )
599 {
600 if ( StringUtils.isNotEmpty( value ) )
601 {
602 w.startElement( "li" );
603 w.writeMarkup( format( "pluginxdoc.detail", new String[]{ param, value } ) );
604 w.endElement();
605 }
606 }
607
608
609
610
611
612
613 private void writeParameterSummary( MojoDescriptor mojoDescriptor, List<Parameter> parameterList, XMLWriter w )
614 {
615 List<Parameter> requiredParams = getParametersByRequired( true, parameterList );
616 if ( requiredParams.size() > 0 )
617 {
618 writeParameterList( mojoDescriptor, getString( "pluginxdoc.mojodescriptor.requiredParameters" ),
619 requiredParams, w );
620 }
621
622 List<Parameter> optionalParams = getParametersByRequired( false, parameterList );
623 if ( optionalParams.size() > 0 )
624 {
625 writeParameterList( mojoDescriptor, getString( "pluginxdoc.mojodescriptor.optionalParameters" ),
626 optionalParams, w );
627 }
628 }
629
630
631
632
633
634
635
636 private void writeParameterList( MojoDescriptor mojoDescriptor, String title, List<Parameter> parameterList,
637 XMLWriter w )
638 {
639 w.startElement( "subsection" );
640 w.addAttribute( "name", title );
641
642 w.startElement( "table" );
643 w.addAttribute( "border", "0" );
644
645 w.startElement( "tr" );
646 w.startElement( "th" );
647 w.writeText( getString( "pluginxdoc.mojodescriptor.parameter.name" ) );
648 w.endElement();
649 w.startElement( "th" );
650 w.writeText( getString( "pluginxdoc.mojodescriptor.parameter.type" ) );
651 w.endElement();
652 w.startElement( "th" );
653 w.writeText( getString( "pluginxdoc.mojodescriptor.parameter.since" ) );
654 w.endElement();
655 w.startElement( "th" );
656 w.writeText( getString( "pluginxdoc.mojodescriptor.parameter.description" ) );
657 w.endElement();
658 w.endElement();
659
660 for ( Parameter parameter : parameterList )
661 {
662 w.startElement( "tr" );
663
664
665 w.startElement( "td" );
666 w.writeMarkup( format( "pluginxdoc.mojodescriptor.parameter.name_link", parameter.getName() ) );
667 w.endElement();
668
669
670 w.startElement( "td" );
671 int index = parameter.getType().lastIndexOf( "." );
672 w.writeMarkup( "<code>" + parameter.getType().substring( index + 1 ) + "</code>" );
673 w.endElement();
674
675
676 w.startElement( "td" );
677 if ( StringUtils.isNotEmpty( parameter.getSince() ) )
678 {
679 w.writeMarkup( "<code>" + parameter.getSince() + "</code>" );
680 }
681 else
682 {
683 if ( StringUtils.isNotEmpty( mojoDescriptor.getSince() ) )
684 {
685 w.writeMarkup( "<code>" + mojoDescriptor.getSince() + "</code>" );
686 }
687 else
688 {
689 w.writeMarkup( "<code>-</code>" );
690 }
691 }
692 w.endElement();
693
694
695 w.startElement( "td" );
696 String description;
697 if ( StringUtils.isNotEmpty( parameter.getDeprecated() ) )
698 {
699 description = format( "pluginxdoc.mojodescriptor.parameter.deprecated",
700 GeneratorUtils.makeHtmlValid( parameter.getDeprecated() ) );
701 }
702 else if ( StringUtils.isNotEmpty( parameter.getDescription() ) )
703 {
704 description = GeneratorUtils.makeHtmlValid( parameter.getDescription() );
705 }
706 else
707 {
708 description = getString( "pluginxdoc.nodescription" );
709 }
710 w.writeMarkup( description + "<br/>" );
711
712 if ( StringUtils.isNotEmpty( parameter.getDefaultValue() ) )
713 {
714 w.writeMarkup( format( "pluginxdoc.mojodescriptor.parameter.defaultValue",
715 escapeXml( parameter.getDefaultValue() ) ) );
716 w.writeMarkup( "<br/>" );
717 }
718
719 String property = getPropertyFromExpression( parameter.getExpression() );
720 if ( property != null )
721 {
722 w.writeMarkup( format( "pluginxdoc.mojodescriptor.parameter.property.description", property ) );
723 }
724
725 w.endElement();
726 w.endElement();
727 }
728
729 w.endElement();
730 w.endElement();
731 }
732
733
734
735
736
737
738 private List<Parameter> getParametersByRequired( boolean required, List<Parameter> parameterList )
739 {
740 List<Parameter> list = new ArrayList<Parameter>();
741
742 for ( Parameter parameter : parameterList )
743 {
744 if ( parameter.isRequired() == required )
745 {
746 list.add( parameter );
747 }
748 }
749
750 return list;
751 }
752
753
754
755
756
757
758 private ResourceBundle getBundle()
759 {
760 return ResourceBundle.getBundle( "pluginxdoc", locale, getClass().getClassLoader() );
761 }
762
763
764
765
766
767
768 private String getString( String key )
769 {
770 return getBundle().getString( key );
771 }
772
773
774
775
776
777
778
779
780
781 private String format( String key, Object arg1 )
782 {
783 return format( key, new Object[]{ arg1 } );
784 }
785
786
787
788
789
790
791
792
793
794 private String format( String key, Object[] args )
795 {
796 String pattern = getString( key );
797
798 pattern = StringUtils.replace( pattern, "'", "''" );
799
800 MessageFormat messageFormat = new MessageFormat( "" );
801 messageFormat.setLocale( locale );
802 messageFormat.applyPattern( pattern );
803
804 return messageFormat.format( args );
805 }
806
807
808
809
810
811 private String escapeXml( String text )
812 {
813 if ( text != null )
814 {
815 text = text.replaceAll( "&", "&" );
816 text = text.replaceAll( "<", "<" );
817 text = text.replaceAll( ">", ">" );
818 text = text.replaceAll( "\"", """ );
819 text = text.replaceAll( "\'", "'" );
820 }
821 return text;
822 }
823
824 }