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