001package org.apache.maven.tools.plugin.generator;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.apache.maven.plugin.descriptor.MojoDescriptor;
023import org.apache.maven.plugin.descriptor.Parameter;
024import org.apache.maven.project.MavenProject;
025import org.apache.maven.tools.plugin.ExtendedMojoDescriptor;
026import org.apache.maven.tools.plugin.PluginToolsRequest;
027import org.codehaus.plexus.util.IOUtil;
028import org.codehaus.plexus.util.StringUtils;
029import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
030import org.codehaus.plexus.util.xml.XMLWriter;
031
032import java.io.File;
033import java.io.FileOutputStream;
034import java.io.IOException;
035import java.io.OutputStreamWriter;
036import java.io.PrintWriter;
037import java.io.Writer;
038import java.text.MessageFormat;
039import java.util.ArrayList;
040import java.util.Iterator;
041import java.util.List;
042import java.util.Locale;
043import java.util.ResourceBundle;
044
045/**
046 * Generate xdoc documentation for each mojo.
047 *
048 * @version $Id: PluginXdocGenerator.html 934731 2015-01-01 22:17:21Z hboutemy $
049 */
050public class PluginXdocGenerator
051    implements Generator
052{
053    /**
054     * locale
055     */
056    private final Locale locale;
057
058    /**
059     * project
060     */
061    private final MavenProject project;
062
063    /**
064     * Default constructor using <code>Locale.ENGLISH</code> as locale.
065     * Used only in test cases.
066     */
067    public PluginXdocGenerator()
068    {
069        this.project = null;
070        this.locale = Locale.ENGLISH;
071    }
072
073    /**
074     * Constructor using <code>Locale.ENGLISH</code> as locale.
075     *
076     * @param project not null Maven project.
077     */
078    public PluginXdocGenerator( MavenProject project )
079    {
080        this.project = project;
081        this.locale = Locale.ENGLISH;
082    }
083
084    /**
085     * @param project not null.
086     * @param locale  not null wanted locale.
087     */
088    public PluginXdocGenerator( MavenProject project, Locale locale )
089    {
090        this.project = project;
091        if ( locale == null )
092        {
093            this.locale = Locale.ENGLISH;
094        }
095        else
096        {
097            this.locale = locale;
098        }
099    }
100
101
102    /**
103     * {@inheritDoc}
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     * @param mojoDescriptor       not null
130     * @param destinationDirectory not null
131     * @throws IOException if any
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     * @param mojo not null
156     * @param ext  not null
157     * @return the output file name
158     */
159    private String getMojoFilename( MojoDescriptor mojo, String ext )
160    {
161        return mojo.getGoal() + "-mojo." + ext;
162    }
163
164    /**
165     * @param mojoDescriptor not null
166     * @param w              not null
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(); // title
185
186        w.endElement(); // properties
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(); //p
203        w.startElement( "p" );
204        w.writeMarkup( mojoDescriptor.getPluginDescriptor().getGroupId() + ":"
205                           + mojoDescriptor.getPluginDescriptor().getArtifactId() + ":"
206                           + mojoDescriptor.getPluginDescriptor().getVersion() + ":" + mojoDescriptor.getGoal() );
207        w.endElement(); //p
208
209        if ( StringUtils.isNotEmpty( mojoDescriptor.getDeprecated() ) )
210        {
211            w.startElement( "p" );
212            w.writeMarkup( getString( "pluginxdoc.mojodescriptor.deprecated" ) );
213            w.endElement(); // p
214            w.startElement( "div" );
215            w.writeMarkup( GeneratorUtils.makeHtmlValid( mojoDescriptor.getDeprecated() ) );
216            w.endElement(); // div
217        }
218
219        w.startElement( "p" );
220        w.writeMarkup( getString( "pluginxdoc.description" ) );
221        w.endElement(); //p
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(); // div
232
233        writeGoalAttributes( mojoDescriptor, w );
234
235        writeGoalParameterTable( mojoDescriptor, w );
236
237        w.endElement(); // section
238
239        w.endElement(); // body
240
241        w.endElement(); // document
242    }
243
244    /**
245     * @param mojoDescriptor not null
246     * @param w              not null
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(); //p
256        }
257    }
258
259    /**
260     * @param mojoDescriptor not null
261     * @param w              not null
262     */
263    private void writeGoalAttributes( MojoDescriptor mojoDescriptor, XMLWriter w )
264    {
265        w.startElement( "p" );
266        w.writeMarkup( getString( "pluginxdoc.mojodescriptor.attributes" ) );
267        w.endElement(); //p
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(); //li
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(); // li
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(); //li
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(); //li
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(); //li
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(); //li
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(); //li
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(); //li
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(); //li
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(); //li
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(); //li
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(); //li
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(); //li
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(); //li
394        }
395
396        if ( addedUl )
397        {
398            w.endElement(); //ul
399        }
400    }
401
402    /**
403     * @param mojoDescriptor not null
404     * @param w              not null
405     */
406    private void writeGoalParameterTable( MojoDescriptor mojoDescriptor, XMLWriter w )
407    {
408        @SuppressWarnings( "unchecked" )
409        List<Parameter> parameterList = mojoDescriptor.getParameters();
410
411        // remove components and read-only parameters
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(); //p
428
429            w.endElement();
430        }
431    }
432
433    /**
434     * Filter parameters to only retain those which must be documented, ie not components nor readonly.
435     *
436     * @param parameterList not null
437     * @return the parameters list without components.
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     * @param mojoDescriptor not null
464     * @param parameterList  not null
465     * @param w              not null
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(); //p
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(); // div
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(); // div
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(); //ul
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            // expression="${xxx}" -> property="xxx"
586            return expression.substring( 2, expression.length() - 1 );
587        }
588        // no property can be extracted
589        return null;
590    }
591    
592    /**
593     * @param param not null
594     * @param value could be null
595     * @param w     not null
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(); //li
604        }
605    }
606
607    /**
608     * @param mojoDescriptor not null
609     * @param parameterList  not null
610     * @param w              not null
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     * @param mojoDescriptor not null
631     * @param title          not null
632     * @param parameterList  not null
633     * @param w              not null
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(); //th
648        w.startElement( "th" );
649        w.writeText( getString( "pluginxdoc.mojodescriptor.parameter.type" ) );
650        w.endElement(); //th
651        w.startElement( "th" );
652        w.writeText( getString( "pluginxdoc.mojodescriptor.parameter.since" ) );
653        w.endElement(); //th
654        w.startElement( "th" );
655        w.writeText( getString( "pluginxdoc.mojodescriptor.parameter.description" ) );
656        w.endElement(); //th
657        w.endElement(); //tr
658
659        for ( Parameter parameter : parameterList )
660        {
661            w.startElement( "tr" );
662
663            // name
664            w.startElement( "td" );
665            w.writeMarkup( format( "pluginxdoc.mojodescriptor.parameter.name_link", parameter.getName() ) );
666            w.endElement(); //td
667
668            //type
669            w.startElement( "td" );
670            int index = parameter.getType().lastIndexOf( "." );
671            w.writeMarkup( "<code>" + parameter.getType().substring( index + 1 ) + "</code>" );
672            w.endElement(); //td
673
674            // since
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(); //td
692
693            // description
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(); //td
725            w.endElement(); //tr
726        }
727
728        w.endElement(); //table
729        w.endElement(); //section
730    }
731
732    /**
733     * @param required      <code>true</code> for required parameters, <code>false</code> otherwise.
734     * @param parameterList not null
735     * @return list of parameters depending the value of <code>required</code>
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     * Gets the resource bundle for the <code>locale</code> instance variable.
754     *
755     * @return The resource bundle for the <code>locale</code> instance variable.
756     */
757    private ResourceBundle getBundle()
758    {
759        return ResourceBundle.getBundle( "pluginxdoc", locale, getClass().getClassLoader() );
760    }
761
762    /**
763     * @param key not null
764     * @return Localized, text identified by <code>key</code>.
765     * @see #getBundle()
766     */
767    private String getString( String key )
768    {
769        return getBundle().getString( key );
770    }
771
772    /**
773     * Convenience method.
774     *
775     * @param key  not null
776     * @param arg1 not null
777     * @return Localized, formatted text identified by <code>key</code>.
778     * @see #format(String, Object[])
779     */
780    private String format( String key, Object arg1 )
781    {
782        return format( key, new Object[]{ arg1 } );
783    }
784
785    /**
786     * Looks up the value for <code>key</code> in the <code>ResourceBundle</code>,
787     * then formats that value for the specified <code>Locale</code> using <code>args</code>.
788     *
789     * @param key  not null
790     * @param args not null
791     * @return Localized, formatted text identified by <code>key</code>.
792     */
793    private String format( String key, Object[] args )
794    {
795        String pattern = getString( key );
796        // we don't need quoting so spare us the confusion in the resource bundle to double them up in some keys
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     * @param text the string to escape
808     * @return A string escaped with XML entities
809     */
810    private String escapeXml( String text )
811    {
812        if ( text != null )
813        {
814            text = text.replaceAll( "&", "&amp;" );
815            text = text.replaceAll( "<", "&lt;" );
816            text = text.replaceAll( ">", "&gt;" );
817            text = text.replaceAll( "\"", "&quot;" );
818            text = text.replaceAll( "\'", "&apos;" );
819        }
820        return text;
821    }
822
823}