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