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( "h4" );
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 addedUl = addUl( w, addedUl, parameter.getAlias() );
548 writeDetail( getString( "pluginxdoc.mojodescriptor.parameter.alias" ), escapeXml( parameter.getAlias() ),
549 w );
550
551 if ( addedUl )
552 {
553 w.endElement();
554 }
555
556 if ( parameters.hasNext() )
557 {
558 w.writeMarkup( "<hr/>" );
559 }
560 }
561
562 w.endElement();
563 }
564
565 private boolean addUl( XMLWriter w, boolean addedUl, String content )
566 {
567 if ( StringUtils.isNotEmpty( content ) )
568 {
569 return addUl( w, addedUl );
570 }
571 return addedUl;
572 }
573
574 private boolean addUl( XMLWriter w, boolean addedUl )
575 {
576 if ( !addedUl )
577 {
578 w.startElement( "ul" );
579 addedUl = true;
580 }
581 return addedUl;
582 }
583
584 private String getPropertyFromExpression( String expression )
585 {
586 if ( StringUtils.isNotEmpty( expression ) && expression.startsWith( "${" ) && expression.endsWith( "}" )
587 && !expression.substring( 2 ).contains( "${" ) )
588 {
589
590 return expression.substring( 2, expression.length() - 1 );
591 }
592
593 return null;
594 }
595
596
597
598
599
600
601 private void writeDetail( String param, String value, XMLWriter w )
602 {
603 if ( StringUtils.isNotEmpty( value ) )
604 {
605 w.startElement( "li" );
606 w.writeMarkup( format( "pluginxdoc.detail", new String[]{ param, value } ) );
607 w.endElement();
608 }
609 }
610
611
612
613
614
615
616 private void writeParameterSummary( MojoDescriptor mojoDescriptor, List<Parameter> parameterList, XMLWriter w )
617 {
618 List<Parameter> requiredParams = getParametersByRequired( true, parameterList );
619 if ( requiredParams.size() > 0 )
620 {
621 writeParameterList( mojoDescriptor, getString( "pluginxdoc.mojodescriptor.requiredParameters" ),
622 requiredParams, w );
623 }
624
625 List<Parameter> optionalParams = getParametersByRequired( false, parameterList );
626 if ( optionalParams.size() > 0 )
627 {
628 writeParameterList( mojoDescriptor, getString( "pluginxdoc.mojodescriptor.optionalParameters" ),
629 optionalParams, w );
630 }
631 }
632
633
634
635
636
637
638
639 private void writeParameterList( MojoDescriptor mojoDescriptor, String title, List<Parameter> parameterList,
640 XMLWriter w )
641 {
642 w.startElement( "subsection" );
643 w.addAttribute( "name", title );
644
645 w.startElement( "table" );
646 w.addAttribute( "border", "0" );
647
648 w.startElement( "tr" );
649 w.startElement( "th" );
650 w.writeText( getString( "pluginxdoc.mojodescriptor.parameter.name" ) );
651 w.endElement();
652 w.startElement( "th" );
653 w.writeText( getString( "pluginxdoc.mojodescriptor.parameter.type" ) );
654 w.endElement();
655 w.startElement( "th" );
656 w.writeText( getString( "pluginxdoc.mojodescriptor.parameter.since" ) );
657 w.endElement();
658 w.startElement( "th" );
659 w.writeText( getString( "pluginxdoc.mojodescriptor.parameter.description" ) );
660 w.endElement();
661 w.endElement();
662
663 for ( Parameter parameter : parameterList )
664 {
665 w.startElement( "tr" );
666
667
668 w.startElement( "td" );
669 w.writeMarkup( format( "pluginxdoc.mojodescriptor.parameter.name_link", parameter.getName() ) );
670 w.endElement();
671
672
673 w.startElement( "td" );
674 int index = parameter.getType().lastIndexOf( "." );
675 w.writeMarkup( "<code>" + parameter.getType().substring( index + 1 ) + "</code>" );
676 w.endElement();
677
678
679 w.startElement( "td" );
680 if ( StringUtils.isNotEmpty( parameter.getSince() ) )
681 {
682 w.writeMarkup( "<code>" + parameter.getSince() + "</code>" );
683 }
684 else
685 {
686 if ( StringUtils.isNotEmpty( mojoDescriptor.getSince() ) )
687 {
688 w.writeMarkup( "<code>" + mojoDescriptor.getSince() + "</code>" );
689 }
690 else
691 {
692 w.writeMarkup( "<code>-</code>" );
693 }
694 }
695 w.endElement();
696
697
698 w.startElement( "td" );
699 String description;
700 if ( StringUtils.isNotEmpty( parameter.getDeprecated() ) )
701 {
702 description = format( "pluginxdoc.mojodescriptor.parameter.deprecated",
703 GeneratorUtils.makeHtmlValid( parameter.getDeprecated() ) );
704 }
705 else if ( StringUtils.isNotEmpty( parameter.getDescription() ) )
706 {
707 description = GeneratorUtils.makeHtmlValid( parameter.getDescription() );
708 }
709 else
710 {
711 description = getString( "pluginxdoc.nodescription" );
712 }
713 w.writeMarkup( description + "<br/>" );
714
715 if ( StringUtils.isNotEmpty( parameter.getDefaultValue() ) )
716 {
717 w.writeMarkup( format( "pluginxdoc.mojodescriptor.parameter.defaultValue",
718 escapeXml( parameter.getDefaultValue() ) ) );
719 w.writeMarkup( "<br/>" );
720 }
721
722 String property = getPropertyFromExpression( parameter.getExpression() );
723 if ( property != null )
724 {
725 w.writeMarkup( format( "pluginxdoc.mojodescriptor.parameter.property.description", property ) );
726 w.writeMarkup( "<br/>" );
727 }
728
729 if ( StringUtils.isNotEmpty( parameter.getAlias() ) )
730 {
731 w.writeMarkup( format( "pluginxdoc.mojodescriptor.parameter.alias.description",
732 escapeXml( parameter.getAlias() ) ) );
733 }
734
735 w.endElement();
736 w.endElement();
737 }
738
739 w.endElement();
740 w.endElement();
741 }
742
743
744
745
746
747
748 private List<Parameter> getParametersByRequired( boolean required, List<Parameter> parameterList )
749 {
750 List<Parameter> list = new ArrayList<Parameter>();
751
752 for ( Parameter parameter : parameterList )
753 {
754 if ( parameter.isRequired() == required )
755 {
756 list.add( parameter );
757 }
758 }
759
760 return list;
761 }
762
763
764
765
766
767
768 private ResourceBundle getBundle()
769 {
770 return ResourceBundle.getBundle( "pluginxdoc", locale, getClass().getClassLoader() );
771 }
772
773
774
775
776
777
778 private String getString( String key )
779 {
780 return getBundle().getString( key );
781 }
782
783
784
785
786
787
788
789
790
791 private String format( String key, Object arg1 )
792 {
793 return format( key, new Object[]{ arg1 } );
794 }
795
796
797
798
799
800
801
802
803
804 private String format( String key, Object[] args )
805 {
806 String pattern = getString( key );
807
808 pattern = StringUtils.replace( pattern, "'", "''" );
809
810 MessageFormat messageFormat = new MessageFormat( "" );
811 messageFormat.setLocale( locale );
812 messageFormat.applyPattern( pattern );
813
814 return messageFormat.format( args );
815 }
816
817
818
819
820
821 private String escapeXml( String text )
822 {
823 if ( text != null )
824 {
825 text = text.replaceAll( "&", "&" );
826 text = text.replaceAll( "<", "<" );
827 text = text.replaceAll( ">", ">" );
828 text = text.replaceAll( "\"", """ );
829 text = text.replaceAll( "\'", "'" );
830 }
831 return text;
832 }
833
834 }