Coverage Report - org.apache.maven.tools.plugin.generator.PluginHelpGenerator
 
Classes in this File Line Coverage Branch Coverage Complexity
PluginHelpGenerator
91%
371/407
59%
49/82
0
 
 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 java.io.File;
 23  
 import java.io.FileOutputStream;
 24  
 import java.io.IOException;
 25  
 import java.io.InputStream;
 26  
 import java.io.OutputStreamWriter;
 27  
 import java.io.Writer;
 28  
 import java.util.ArrayList;
 29  
 import java.util.Date;
 30  
 import java.util.HashMap;
 31  
 import java.util.Iterator;
 32  
 import java.util.List;
 33  
 import java.util.Map;
 34  
 import java.util.Properties;
 35  
 
 36  
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 37  
 import org.apache.maven.plugin.descriptor.Parameter;
 38  
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
 39  
 import org.apache.maven.tools.plugin.DefaultPluginToolsRequest;
 40  
 import org.apache.maven.tools.plugin.PluginToolsRequest;
 41  
 import org.apache.maven.tools.plugin.util.PluginUtils;
 42  
 import org.codehaus.plexus.logging.AbstractLogEnabled;
 43  
 import org.codehaus.plexus.logging.Logger;
 44  
 import org.codehaus.plexus.logging.console.ConsoleLogger;
 45  
 import org.codehaus.plexus.util.IOUtil;
 46  
 import org.codehaus.plexus.util.StringUtils;
 47  
 
 48  
 /**
 49  
  * Generates an <code>HelpMojo</code> class.
 50  
  *
 51  
  * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
 52  
  * @version $Id: PluginHelpGenerator.java 1133707 2011-06-09 08:28:59Z stephenc $
 53  
  * @since 2.4
 54  
  */
 55  
 public class PluginHelpGenerator
 56  
     extends AbstractLogEnabled
 57  
     implements Generator
 58  
 {
 59  
     /** Line separator */
 60  1
     private static final String LS = System.getProperty( "line.separator" );
 61  
 
 62  
     /** Default generated class name */
 63  
     private static final String HELP_MOJO_CLASS_NAME = "HelpMojo";
 64  
 
 65  
     /** Default goal */
 66  
     private static final String HELP_GOAL = "help";
 67  
 
 68  
     private String helpPackageName;
 69  
     
 70  
     /** Flag to indicate if the generated help mojo should use Java 5 features */
 71  
     private boolean useJava5;
 72  
 
 73  
     /**
 74  
      * Default constructor
 75  
      */
 76  
     public PluginHelpGenerator()
 77  1
     {
 78  1
         this.enableLogging( new ConsoleLogger( Logger.LEVEL_INFO, "PluginHelpGenerator" ) );
 79  1
     }
 80  
 
 81  
     // ----------------------------------------------------------------------
 82  
     // Public methods
 83  
     // ----------------------------------------------------------------------
 84  
 
 85  
     /** {@inheritDoc} */
 86  
     public void execute( File destinationDirectory, PluginDescriptor pluginDescriptor )
 87  
         throws IOException
 88  
     {
 89  0
         execute( destinationDirectory, new DefaultPluginToolsRequest( null, pluginDescriptor ) );
 90  0
     }
 91  
     
 92  
     /** {@inheritDoc} */
 93  
     public void execute( File destinationDirectory, PluginToolsRequest request )
 94  
         throws IOException
 95  
     {
 96  1
         PluginDescriptor pluginDescriptor = request.getPluginDescriptor();
 97  
         
 98  1
         if ( pluginDescriptor.getMojos() == null || pluginDescriptor.getMojos().size() < 1 )
 99  
         {
 100  0
             return;
 101  
         }
 102  
 
 103  1
         MojoDescriptor helpDescriptor = makeHelpDescriptor( pluginDescriptor );
 104  
 
 105  
         // Verify that no help goal already exists
 106  
         for ( @SuppressWarnings( "unchecked" )
 107  1
         Iterator<MojoDescriptor> it = pluginDescriptor.getMojos().iterator(); it.hasNext(); )
 108  
         {
 109  1
             MojoDescriptor descriptor = it.next();
 110  
 
 111  1
             if ( descriptor.getGoal().equals( helpDescriptor.getGoal() )
 112  
                 && !descriptor.getImplementation().equals( helpDescriptor.getImplementation() ) )
 113  
             {
 114  0
                 if ( getLogger().isWarnEnabled() )
 115  
                 {
 116  0
                     getLogger().warn(
 117  
                                       "\n\nA help goal (" + descriptor.getImplementation()
 118  
                                           + ") already exists in this plugin. SKIPPED THE "
 119  
                                           + helpDescriptor.getImplementation() + " GENERATION.\n" );
 120  
                 }
 121  
 
 122  0
                 return;
 123  
             }
 124  1
         }
 125  
 
 126  1
         String sourcePath = helpDescriptor.getImplementation().replace( '.', File.separatorChar ) + ".java";
 127  1
         File helpClass = new File( destinationDirectory, sourcePath );
 128  1
         helpClass.getParentFile().mkdirs();
 129  
 
 130  1
         Writer writer = null;
 131  
         try
 132  
         {
 133  1
             writer = new OutputStreamWriter( new FileOutputStream( helpClass ), request.getEncoding() );
 134  1
             writeClass( writer, pluginDescriptor, helpDescriptor, useJava5 );
 135  1
             writer.flush();
 136  
         }
 137  
         finally
 138  
         {
 139  1
             IOUtil.close( writer );
 140  1
         }
 141  1
     }
 142  
 
 143  
     public PluginHelpGenerator setHelpPackageName( String helpPackageName )
 144  
     {
 145  0
         this.helpPackageName = helpPackageName;
 146  0
         return this;
 147  
     }
 148  
 
 149  
     public PluginHelpGenerator setUseJava5( boolean useJava5 )
 150  
     {
 151  0
         this.useJava5 = useJava5;
 152  0
         return this;
 153  
     }
 154  
 
 155  
     // ----------------------------------------------------------------------
 156  
     // Private methods
 157  
     // ----------------------------------------------------------------------
 158  
 
 159  
     /**
 160  
      * Creates a minimalistic mojo descriptor for the generated help goal.
 161  
      *
 162  
      * @param pluginDescriptor The descriptor of the plugin for which to generate a help goal, must not be
 163  
      *            <code>null</code>.
 164  
      * @return The mojo descriptor for the generated help goal, never <code>null</code>.
 165  
      */
 166  
     private MojoDescriptor makeHelpDescriptor( PluginDescriptor pluginDescriptor )
 167  
     {
 168  1
         MojoDescriptor descriptor = new MojoDescriptor();
 169  
 
 170  1
         descriptor.setPluginDescriptor( pluginDescriptor );
 171  
 
 172  1
         descriptor.setLanguage( "java" );
 173  
 
 174  1
         descriptor.setGoal( HELP_GOAL );
 175  
 
 176  1
         String packageName = helpPackageName;
 177  1
         if ( StringUtils.isEmpty( packageName ) )
 178  
         {
 179  1
             packageName = discoverPackageName( pluginDescriptor );
 180  
         }
 181  1
         if ( StringUtils.isNotEmpty( packageName ) )
 182  
         {
 183  1
             descriptor.setImplementation( packageName + '.' + HELP_MOJO_CLASS_NAME );
 184  
         }
 185  
         else
 186  
         {
 187  0
             descriptor.setImplementation( HELP_MOJO_CLASS_NAME );
 188  
         }
 189  
 
 190  1
         descriptor.setDescription( "Display help information on " + pluginDescriptor.getArtifactId()
 191  
             + ".<br/> Call <pre>  mvn " + descriptor.getFullGoalName()
 192  
             + " -Ddetail=true -Dgoal=&lt;goal-name&gt;</pre> to display parameter details." );
 193  
 
 194  
         try
 195  
         {
 196  1
             Parameter param = new Parameter();
 197  1
             param.setName( "detail" );
 198  1
             param.setType( "boolean" );
 199  1
             param.setDescription( "If <code>true</code>, display all settable properties for each goal." );
 200  1
             param.setDefaultValue( "false" );
 201  1
             param.setExpression( "${detail}" );
 202  1
             descriptor.addParameter( param );
 203  
 
 204  1
             param = new Parameter();
 205  1
             param.setName( "goal" );
 206  1
             param.setType( "java.lang.String" );
 207  1
             param.setDescription( "The name of the goal for which to show help."
 208  
                 + " If unspecified, all goals will be displayed." );
 209  1
             param.setExpression( "${goal}" );
 210  1
             descriptor.addParameter( param );
 211  
 
 212  1
             param = new Parameter();
 213  1
             param.setName( "lineLength" );
 214  1
             param.setType( "int" );
 215  1
             param.setDescription( "The maximum length of a display line, should be positive." );
 216  1
             param.setDefaultValue( "80" );
 217  1
             param.setExpression( "${lineLength}" );
 218  1
             descriptor.addParameter( param );
 219  
 
 220  1
             param = new Parameter();
 221  1
             param.setName( "indentSize" );
 222  1
             param.setType( "int" );
 223  1
             param.setDescription( "The number of spaces per indentation level, should be positive." );
 224  1
             param.setDefaultValue( "2" );
 225  1
             param.setExpression( "${indentSize}" );
 226  1
             descriptor.addParameter( param );
 227  
         }
 228  0
         catch ( Exception e )
 229  
         {
 230  0
             throw new RuntimeException( "Failed to setup parameters for help goal", e );
 231  1
         }
 232  
 
 233  1
         return descriptor;
 234  
     }
 235  
 
 236  
     /**
 237  
      * Find the best package name, based on the number of hits of actual Mojo classes.
 238  
      *
 239  
      * @param pluginDescriptor not null
 240  
      * @return the best name of the package for the generated mojo
 241  
      */
 242  
     private static String discoverPackageName( PluginDescriptor pluginDescriptor )
 243  
     {
 244  1
         Map<String, Integer> packageNames = new HashMap<String, Integer>();
 245  
         for ( @SuppressWarnings( "unchecked" )
 246  1
         Iterator<MojoDescriptor> it = pluginDescriptor.getMojos().iterator(); it.hasNext(); )
 247  
         {
 248  1
             MojoDescriptor descriptor = it.next();
 249  
 
 250  1
             String impl = descriptor.getImplementation();
 251  1
             if ( impl.lastIndexOf( '.' ) != -1 )
 252  
             {
 253  1
                 String name = impl.substring( 0, impl.lastIndexOf( '.' ) );
 254  1
                 if ( packageNames.get( name ) != null )
 255  
                 {
 256  0
                     int next = ( (Integer) packageNames.get( name ) ).intValue() + 1;
 257  0
                     packageNames.put( name, new Integer( next ) );
 258  0
                 }
 259  
                 else
 260  
                 {
 261  1
                     packageNames.put( name, new Integer( 1 ) );
 262  
                 }
 263  1
             }
 264  
             else
 265  
             {
 266  0
                 packageNames.put( "", new Integer( 1 ) );
 267  
             }
 268  1
         }
 269  
 
 270  1
         String packageName = "";
 271  1
         int max = 0;
 272  1
         for ( String key : packageNames.keySet() )
 273  
         {
 274  1
             int value = ( (Integer) packageNames.get( key ) ).intValue();
 275  1
             if ( value > max )
 276  
             {
 277  1
                 max = value;
 278  1
                 packageName = key;
 279  
             }
 280  1
         }
 281  
 
 282  1
         return packageName;
 283  
     }
 284  
 
 285  
     /**
 286  
      * Generates the <code>HelpMojo</code> class.
 287  
      *
 288  
      * @param writer not null
 289  
      * @param pluginDescriptor not null
 290  
      * @param helpDescriptor not null
 291  
      * @param useJava5 If the generated code should use Java5 features
 292  
      * @throws IOException if any
 293  
      */
 294  
     private static void writeClass( Writer writer, PluginDescriptor pluginDescriptor, MojoDescriptor helpDescriptor,
 295  
                                     boolean useJava5 )
 296  
         throws IOException
 297  
     {
 298  1
         String packageName = "";
 299  1
         String simpleName = helpDescriptor.getImplementation();
 300  1
         int dot = simpleName.lastIndexOf( '.' );
 301  1
         if ( dot >= 0 )
 302  
         {
 303  1
             packageName = simpleName.substring( 0, dot );
 304  1
             simpleName = simpleName.substring( dot + 1 );
 305  
         }
 306  
 
 307  1
         if ( packageName.length() > 0 )
 308  
         {
 309  1
             writer.write( "package " + packageName + ";" + LS );
 310  1
             writer.write( LS );
 311  
         }
 312  
 
 313  1
         writeImports( writer );
 314  1
         writer.write( LS );
 315  
 
 316  1
         writeMojoJavadoc( writer, pluginDescriptor, helpDescriptor );
 317  
 
 318  1
         if ( useJava5 )
 319  
         {
 320  0
             writer.write( "@SuppressWarnings( \"all\" )" + LS );
 321  
         }
 322  
 
 323  1
         writer.write( "public class " + simpleName + LS );
 324  1
         writer.write( "    extends AbstractMojo" + LS );
 325  1
         writer.write( "{" + LS );
 326  
 
 327  1
         writeVariables( writer, helpDescriptor );
 328  
 
 329  1
         writer.write( LS );
 330  
 
 331  1
         writeExecute( writer, pluginDescriptor, helpDescriptor );
 332  
 
 333  1
         writer.write( LS );
 334  1
         writeUtilities( writer, useJava5 );
 335  1
         writer.write( "}" + LS );
 336  1
     }
 337  
 
 338  
     /**
 339  
      * @param writer not null
 340  
      * @throws IOException if any
 341  
      */
 342  
     private static void writeImports( Writer writer )
 343  
         throws IOException
 344  
     {
 345  1
         writer.write( "import java.util.ArrayList;" + LS );
 346  1
         writer.write( "import java.util.Iterator;" + LS );
 347  1
         writer.write( "import java.util.List;" + LS );
 348  1
         writer.write( LS );
 349  1
         writer.write( "import org.apache.maven.plugin.AbstractMojo;" + LS );
 350  1
         writer.write( "import org.apache.maven.plugin.MojoExecutionException;" + LS );
 351  1
     }
 352  
 
 353  
     /**
 354  
      * @param writer not null
 355  
      * @param pluginDescriptor not null
 356  
      * @param helpDescriptor not null
 357  
      * @throws IOException if any
 358  
      */
 359  
     private static void writeMojoJavadoc( Writer writer, PluginDescriptor pluginDescriptor,
 360  
                                           MojoDescriptor helpDescriptor )
 361  
         throws IOException
 362  
     {
 363  1
         StringBuffer author = new StringBuffer();
 364  1
         author.append( PluginHelpGenerator.class.getName() );
 365  
 
 366  1
         String resource = "META-INF/maven/org.apache.maven.plugin-tools/maven-plugin-tools-api/pom.properties";
 367  1
         InputStream resourceAsStream = PluginHelpGenerator.class.getClassLoader().getResourceAsStream( resource );
 368  
 
 369  1
         if ( resourceAsStream != null )
 370  
         {
 371  
             try
 372  
             {
 373  0
                 Properties properties = new Properties();
 374  0
                 properties.load( resourceAsStream );
 375  
 
 376  0
                 author.append( " (version " ).append( properties.getProperty( "version", "unknown" ) ).append( ")" );
 377  
             }
 378  0
             catch ( IOException e )
 379  
             {
 380  
                 // nope
 381  0
             }
 382  
         }
 383  
 
 384  1
         writer.write( "/**" + LS );
 385  1
         writer.write( " * " + helpDescriptor.getDescription() + LS );
 386  1
         writer.write( " *" + LS );
 387  1
         writer.write( " * @version generated on " + new Date() + LS );
 388  1
         writer.write( " * @author " + author.toString() + LS );
 389  1
         writer.write( " * @goal " + helpDescriptor.getGoal() + LS );
 390  1
         writer.write( " * @requiresProject false" + LS );
 391  1
         writer.write( " * @threadSafe" + LS );
 392  1
         writer.write( " */" + LS );
 393  1
     }
 394  
 
 395  
     /**
 396  
      * @param writer not null
 397  
      * @param helpDescriptor not null
 398  
      * @throws IOException if any
 399  
      */
 400  
     private static void writeVariables( Writer writer, MojoDescriptor helpDescriptor )
 401  
         throws IOException
 402  
     {
 403  
         for ( @SuppressWarnings( "unchecked" )
 404  1
         Iterator<Parameter> it = helpDescriptor.getParameters().iterator(); it.hasNext(); )
 405  
         {
 406  4
             Parameter param = it.next();
 407  4
             writer.write( "    /**" + LS );
 408  4
             writer.write( "     * " + StringUtils.escape( param.getDescription() ) + LS );
 409  4
             writer.write( "     * " + LS );
 410  4
             writer.write( "     * @parameter" );
 411  4
             if ( StringUtils.isNotEmpty( param.getExpression() ) )
 412  
             {
 413  4
                 writer.write( " expression=\"" );
 414  4
                 writer.write( StringUtils.escape( param.getExpression() ) );
 415  4
                 writer.write( "\"" );
 416  
             }
 417  4
             if ( StringUtils.isNotEmpty( param.getDefaultValue() ) )
 418  
             {
 419  3
                 writer.write( " default-value=\"" );
 420  3
                 writer.write( StringUtils.escape( param.getDefaultValue() ) );
 421  3
                 writer.write( "\"" );
 422  
             }
 423  4
             writer.write( LS );
 424  4
             writer.write( "     */" + LS );
 425  4
             writer.write( "    private " + param.getType() + " " + param.getName() + ";" + LS );
 426  4
             writer.write( LS );
 427  4
         }
 428  1
     }
 429  
 
 430  
     /**
 431  
      * @param writer not null
 432  
      * @param pluginDescriptor not null
 433  
      * @param helpDescriptor not null
 434  
      * @throws IOException if any
 435  
      */
 436  
     private static void writeExecute( Writer writer, PluginDescriptor pluginDescriptor, MojoDescriptor helpDescriptor )
 437  
         throws IOException
 438  
     {
 439  1
         List<MojoDescriptor> mojoDescriptors = new ArrayList<MojoDescriptor>();
 440  
 
 441  1
         mojoDescriptors.add( helpDescriptor );
 442  
         for ( @SuppressWarnings( "unchecked" )
 443  1
         Iterator<MojoDescriptor> it = pluginDescriptor.getMojos().iterator(); it.hasNext(); )
 444  
         {
 445  1
             MojoDescriptor mojoDescriptor = it.next();
 446  
 
 447  1
             if ( !helpDescriptor.getGoal().equals( mojoDescriptor.getGoal() ) )
 448  
             {
 449  1
                 mojoDescriptors.add( mojoDescriptor );
 450  
             }
 451  1
         }
 452  
 
 453  1
         PluginUtils.sortMojos( mojoDescriptors );
 454  
 
 455  1
         writer.write( "    /** {@inheritDoc} */" + LS );
 456  1
         writer.write( "    public void execute()" + LS );
 457  1
         writer.write( "        throws MojoExecutionException" + LS );
 458  1
         writer.write( "    {" + LS );
 459  
 
 460  1
         writer.write( "        if ( lineLength <= 0 )" + LS );
 461  1
         writer.write( "        {" + LS );
 462  1
         writer.write( "            getLog().warn( \"The parameter 'lineLength' should be positive, using '80' as "
 463  
             + "default.\" );" + LS );
 464  1
         writer.write( "            lineLength = 80;" + LS );
 465  1
         writer.write( "        }" + LS );
 466  1
         writer.write( "        if ( indentSize <= 0 )" + LS );
 467  1
         writer.write( "        {" + LS );
 468  1
         writer.write( "            getLog().warn( \"The parameter 'indentSize' should be positive, using '2' as "
 469  
             + "default.\" );" + LS );
 470  1
         writer.write( "            indentSize = 2;" + LS );
 471  1
         writer.write( "        }" + LS );
 472  1
         writer.write( LS );
 473  
 
 474  1
         writer.write( "        StringBuffer sb = new StringBuffer();" + LS );
 475  1
         writer.write( LS );
 476  
 
 477  1
         writer.write( "        append( sb, \"" + StringUtils.escape( pluginDescriptor.getId() ) + "\", 0 );" + LS );
 478  1
         writer.write( "        append( sb, \"\", 0 );" + LS );
 479  1
         writer.write( LS );
 480  
 
 481  1
         if ( StringUtils.isNotEmpty( pluginDescriptor.getName() )
 482  
             && ( pluginDescriptor.getName().indexOf( pluginDescriptor.getId() ) != -1 ) )
 483  
         {
 484  0
             writer.write( "        append( sb, \""
 485  
                 + StringUtils.escape( pluginDescriptor.getName() + " " + pluginDescriptor.getVersion() )
 486  
                 + "\", 0 );" + LS );
 487  
         }
 488  
         else
 489  
         {
 490  1
             if ( StringUtils.isNotEmpty( pluginDescriptor.getName() ) )
 491  
             {
 492  0
                 writer.write( "        append( sb, \"" + StringUtils.escape( pluginDescriptor.getName() )
 493  
                     + "\", 0 );" + LS );
 494  
             }
 495  
             else
 496  
             {
 497  1
                 writer.write( "        append( sb, \"" + StringUtils.escape( pluginDescriptor.getId() )
 498  
                     + "\", 0 );" + LS );
 499  
             }
 500  
         }
 501  1
         writer.write( "        append( sb, \"" + toDescription( pluginDescriptor.getDescription() ) + "\", 1 );"
 502  
             + LS );
 503  1
         writer.write( "        append( sb, \"\", 0 );" + LS );
 504  1
         writer.write( LS );
 505  
 
 506  1
         writer.write( "        if ( goal == null || goal.length() <= 0 )" + LS );
 507  1
         writer.write( "        {" + LS );
 508  1
         writer.write( "            append( sb, \"This plugin has " + mojoDescriptors.size() + " "
 509  
             + ( mojoDescriptors.size() > 1 ? "goals" : "goal" ) + ":\", 0 );" + LS );
 510  1
         writer.write( "            append( sb, \"\", 0 );" + LS );
 511  1
         writer.write( "        }" + LS );
 512  
 
 513  1
         writer.write( LS );
 514  
 
 515  1
         for ( Iterator<MojoDescriptor> it = mojoDescriptors.iterator(); it.hasNext(); )
 516  
         {
 517  2
             MojoDescriptor descriptor = it.next();
 518  
 
 519  2
             writeGoal( writer, descriptor );
 520  2
         }
 521  
 
 522  1
         writer.write( "        if ( getLog().isInfoEnabled() )" + LS );
 523  1
         writer.write( "        {" + LS );
 524  1
         writer.write( "            getLog().info( sb.toString() );" + LS );
 525  1
         writer.write( "        }" + LS );
 526  1
         writer.write( "    }" + LS );
 527  1
     }
 528  
 
 529  
     /**
 530  
      * @param writer not null
 531  
      * @param descriptor not null
 532  
      * @throws IOException if any
 533  
      */
 534  
     private static void writeGoal( Writer writer, MojoDescriptor descriptor )
 535  
         throws IOException
 536  
     {
 537  2
         String goalDescription = toDescription( descriptor.getDescription() );
 538  
 
 539  2
         writer.write( "        if ( goal == null || goal.length() <= 0 || \""
 540  
             + StringUtils.escape( descriptor.getGoal() ) + "\".equals( goal ) )" + LS );
 541  2
         writer.write( "        {" + LS );
 542  2
         writer.write( "            append( sb, \"" + StringUtils.escape( descriptor.getFullGoalName() ) + "\", 0 );"
 543  
             + LS );
 544  2
         if ( StringUtils.isNotEmpty( descriptor.getDeprecated() ) )
 545  
         {
 546  0
             writer.write( "            append( sb, \"Deprecated. " + toDescription( descriptor.getDeprecated() )
 547  
                 + "\", 1 );" + LS );
 548  0
             writer.write( "            if ( detail )" + LS );
 549  0
             writer.write( "            {" + LS );
 550  0
             writer.write( "                append( sb, \"\", 0 );" + LS );
 551  0
             writer.write( "                append( sb, \"" + goalDescription + "\", 1 );" + LS );
 552  0
             writer.write( "            }" + LS );
 553  
         }
 554  
         else
 555  
         {
 556  2
             writer.write( "            append( sb, \"" + goalDescription + "\", 1 );" + LS );
 557  
         }
 558  2
         writer.write( "            append( sb, \"\", 0 );" + LS );
 559  
 
 560  2
         if ( descriptor.getParameters() != null && descriptor.getParameters().size() > 0 )
 561  
         {
 562  
             @SuppressWarnings( "unchecked" )
 563  2
             List<Parameter> params = descriptor.getParameters();
 564  
 
 565  2
             PluginUtils.sortMojoParameters( params );
 566  
 
 567  2
             writer.write( "            if ( detail )" + LS );
 568  2
             writer.write( "            {" + LS );
 569  
 
 570  2
             writer.write( "                append( sb, \"Available parameters:\", 1 );" + LS );
 571  2
             writer.write( "                append( sb, \"\", 0 );" + LS );
 572  
 
 573  2
             for ( Parameter parameter : params )
 574  
             {
 575  5
                 if ( parameter.isEditable() )
 576  
                 {
 577  5
                     writer.write( LS );
 578  5
                     writeParameter( writer, parameter );
 579  
                 }
 580  
             }
 581  
 
 582  2
             writer.write( "            }" + LS );
 583  
         }
 584  
 
 585  2
         writer.write( "        }" + LS );
 586  2
         writer.write( LS );
 587  2
     }
 588  
 
 589  
     /**
 590  
      * @param writer not null
 591  
      * @param parameter not null
 592  
      * @throws IOException if any
 593  
      */
 594  
     private static void writeParameter( Writer writer, Parameter parameter )
 595  
         throws IOException
 596  
     {
 597  5
         String expression = parameter.getExpression();
 598  
 
 599  5
         if ( expression == null || !expression.startsWith( "${component." ) )
 600  
         {
 601  5
             String parameterName = StringUtils.escape( parameter.getName() );
 602  5
             String parameterDescription = toDescription( parameter.getDescription() );
 603  5
             String parameterDefaultValue = "";
 604  5
             if ( StringUtils.isNotEmpty( parameter.getDefaultValue() ) )
 605  
             {
 606  4
                 parameterDefaultValue = " (Default: " + StringUtils.escape( parameter.getDefaultValue() ) + ")";
 607  
             }
 608  5
             writer.write( "                append( sb, \"" + parameterName + parameterDefaultValue + "\", 2 );" + LS );
 609  5
             if ( StringUtils.isNotEmpty( parameter.getDeprecated() ) )
 610  
             {
 611  0
                 writer.write( "                append( sb, \"Deprecated. " + toDescription( parameter.getDeprecated() )
 612  
                     + "\", 3 );" + LS );
 613  0
                 writer.write( "                append( sb, \"\", 0 );" + LS );
 614  
             }
 615  5
             writer.write( "                append( sb, \"" + parameterDescription + "\", 3 );" + LS );
 616  5
             if ( parameter.isRequired() )
 617  
             {
 618  1
                 writer.write( "                append( sb, \"Required: Yes\", 3 );" + LS );
 619  
             }
 620  5
             if ( StringUtils.isNotEmpty( parameter.getExpression() ) )
 621  
             {
 622  5
                 writer.write( "                append( sb, \"Expression: "
 623  
                     + StringUtils.escape( parameter.getExpression() ) + "\", 3 );" + LS );
 624  
             }
 625  5
             writer.write( "                append( sb, \"\", 0 );" + LS );
 626  
         }
 627  5
     }
 628  
 
 629  
     /**
 630  
      * @param writer not null
 631  
      * @param useJava5 If the generated code should use Java5 features
 632  
      * @throws IOException if any
 633  
      */
 634  
     private static void writeUtilities( Writer writer, boolean useJava5 )
 635  
         throws IOException
 636  
     {
 637  1
         writer.write( "    /**" + LS );
 638  1
         writer.write( "     * <p>Repeat a String <code>n</code> times to form a new string.</p>" + LS );
 639  1
         writer.write( "     *" + LS );
 640  1
         writer.write( "     * @param str String to repeat" + LS );
 641  1
         writer.write( "     * @param repeat number of times to repeat str" + LS );
 642  1
         writer.write( "     * @return String with repeated String" + LS );
 643  1
         writer.write( "     * @throws NegativeArraySizeException if <code>repeat < 0</code>" + LS );
 644  1
         writer.write( "     * @throws NullPointerException if str is <code>null</code>" + LS );
 645  1
         writer.write( "     */" + LS );
 646  1
         writer.write( "    private static String repeat( String str, int repeat )" + LS );
 647  1
         writer.write( "    {" + LS );
 648  1
         writer.write( "        StringBuffer buffer = new StringBuffer( repeat * str.length() );" + LS );
 649  1
         writer.write( LS );
 650  1
         writer.write( "        for ( int i = 0; i < repeat; i++ )" + LS );
 651  1
         writer.write( "        {" + LS );
 652  1
         writer.write( "            buffer.append( str );" + LS );
 653  1
         writer.write( "        }" + LS );
 654  1
         writer.write( LS );
 655  1
         writer.write( "        return buffer.toString();" + LS );
 656  1
         writer.write( "    }" + LS );
 657  
 
 658  1
         writer.write( LS );
 659  1
         writer.write( "    /** " + LS );
 660  1
         writer.write( "     * Append a description to the buffer by respecting the indentSize and lineLength "
 661  
             + "parameters." + LS );
 662  1
         writer.write( "     * <b>Note</b>: The last character is always a new line." + LS );
 663  1
         writer.write( "     * " + LS );
 664  1
         writer.write( "     * @param sb The buffer to append the description, not <code>null</code>." + LS );
 665  1
         writer.write( "     * @param description The description, not <code>null</code>." + LS );
 666  1
         writer.write( "     * @param indent The base indentation level of each line, must not be negative." + LS );
 667  1
         writer.write( "     */" + LS );
 668  1
         writer.write( "    private void append( StringBuffer sb, String description, int indent )" + LS );
 669  1
         writer.write( "    {" + LS );
 670  1
         writer.write( "        for ( Iterator it = toLines( description, indent, indentSize, lineLength )"
 671  
             + ".iterator(); it.hasNext(); )" + LS );
 672  1
         writer.write( "        {" + LS );
 673  1
         writer.write( "            sb.append( it.next().toString() ).append( '\\n' );" + LS );
 674  1
         writer.write( "        }" + LS );
 675  1
         writer.write( "    }" + LS );
 676  
 
 677  1
         writer.write( LS );
 678  1
         writer.write( "    /** " + LS );
 679  1
         writer.write( "     * Splits the specified text into lines of convenient display length." + LS );
 680  1
         writer.write( "     * " + LS );
 681  1
         writer.write( "     * @param text The text to split into lines, must not be <code>null</code>." + LS );
 682  1
         writer.write( "     * @param indent The base indentation level of each line, must not be negative." + LS );
 683  1
         writer.write( "     * @param indentSize The size of each indentation, must not be negative." + LS );
 684  1
         writer.write( "     * @param lineLength The length of the line, must not be negative." + LS );
 685  1
         writer.write( "     * @return The sequence of display lines, never <code>null</code>." + LS );
 686  1
         writer.write( "     * @throws NegativeArraySizeException if <code>indent < 0</code>" + LS );
 687  1
         writer.write( "     */" + LS );
 688  1
         writer.write( "    private static List toLines( String text, int indent, int indentSize, int lineLength )"
 689  
             + LS );
 690  1
         writer.write( "    {" + LS );
 691  1
         if ( useJava5 )
 692  
         {
 693  0
             writer.write( "        List<String> lines = new ArrayList<String>();" + LS );
 694  
         }
 695  
         else
 696  
         {
 697  1
             writer.write( "        List lines = new ArrayList();" + LS );
 698  
         }
 699  1
         writer.write( LS );
 700  1
         writer.write( "        String ind = repeat( \"\\t\", indent );" + LS );
 701  1
         writer.write( "        String[] plainLines = text.split( \"(\\r\\n)|(\\r)|(\\n)\" );" + LS );
 702  1
         writer.write( "        for ( int i = 0; i < plainLines.length; i++ )" + LS );
 703  1
         writer.write( "        {" + LS );
 704  1
         writer.write( "            toLines( lines, ind + plainLines[i], indentSize, lineLength );" + LS );
 705  1
         writer.write( "        }" + LS );
 706  1
         writer.write( LS );
 707  1
         writer.write( "        return lines;" + LS );
 708  1
         writer.write( "    }" + LS );
 709  
 
 710  1
         writer.write( LS );
 711  1
         writer.write( "    /** " + LS );
 712  1
         writer.write( "     * Adds the specified line to the output sequence, performing line wrapping if necessary."
 713  
             + LS );
 714  1
         writer.write( "     * " + LS );
 715  1
         writer.write( "     * @param lines The sequence of display lines, must not be <code>null</code>." + LS );
 716  1
         writer.write( "     * @param line The line to add, must not be <code>null</code>." + LS );
 717  1
         writer.write( "     * @param indentSize The size of each indentation, must not be negative." + LS );
 718  1
         writer.write( "     * @param lineLength The length of the line, must not be negative." + LS );
 719  1
         writer.write( "     */" + LS );
 720  1
         if ( useJava5 )
 721  
         {
 722  0
             writer.write( "    private static void toLines( List<String> lines, String line, int indentSize, int lineLength )"
 723  
                 + LS );
 724  
         }
 725  
         else
 726  
         {
 727  1
             writer.write( "    private static void toLines( List lines, String line, int indentSize, int lineLength )"
 728  
                 + LS );
 729  
         }
 730  1
         writer.write( "    {" + LS );
 731  1
         writer.write( "        int lineIndent = getIndentLevel( line );" + LS );
 732  1
         writer.write( "        StringBuffer buf = new StringBuffer( 256 );" + LS );
 733  1
         writer.write( "        String[] tokens = line.split( \" +\" );" + LS );
 734  1
         writer.write( "        for ( int i = 0; i < tokens.length; i++ )" + LS );
 735  1
         writer.write( "        {" + LS );
 736  1
         writer.write( "            String token = tokens[i];" + LS );
 737  1
         writer.write( "            if ( i > 0 )" + LS );
 738  1
         writer.write( "            {" + LS );
 739  1
         writer.write( "                if ( buf.length() + token.length() >= lineLength )" + LS );
 740  1
         writer.write( "                {" + LS );
 741  1
         writer.write( "                    lines.add( buf.toString() );" + LS );
 742  1
         writer.write( "                    buf.setLength( 0 );" + LS );
 743  1
         writer.write( "                    buf.append( repeat( \" \", lineIndent * indentSize ) );" + LS );
 744  1
         writer.write( "                }" + LS );
 745  1
         writer.write( "                else" + LS );
 746  1
         writer.write( "                {" + LS );
 747  1
         writer.write( "                    buf.append( ' ' );" + LS );
 748  1
         writer.write( "                }" + LS );
 749  1
         writer.write( "            }" + LS );
 750  1
         writer.write( "            for ( int j = 0; j < token.length(); j++ )" + LS );
 751  1
         writer.write( "            {" + LS );
 752  1
         writer.write( "                char c = token.charAt( j );" + LS );
 753  1
         writer.write( "                if ( c == '\\t' )" + LS );
 754  1
         writer.write( "                {" + LS );
 755  1
         writer.write( "                    buf.append( repeat( \" \", indentSize - buf.length() % indentSize ) );"
 756  
             + LS );
 757  1
         writer.write( "                }" + LS );
 758  1
         writer.write( "                else if ( c == '\\u00A0' )" + LS );
 759  1
         writer.write( "                {" + LS );
 760  1
         writer.write( "                    buf.append( ' ' );" + LS );
 761  1
         writer.write( "                }" + LS );
 762  1
         writer.write( "                else" + LS );
 763  1
         writer.write( "                {" + LS );
 764  1
         writer.write( "                    buf.append( c );" + LS );
 765  1
         writer.write( "                }" + LS );
 766  1
         writer.write( "            }" + LS );
 767  1
         writer.write( "        }" + LS );
 768  1
         writer.write( "        lines.add( buf.toString() );" + LS );
 769  1
         writer.write( "    }" + LS );
 770  
 
 771  1
         writer.write( LS );
 772  1
         writer.write( "    /** " + LS );
 773  1
         writer.write( "     * Gets the indentation level of the specified line." + LS );
 774  1
         writer.write( "     * " + LS );
 775  1
         writer.write( "     * @param line The line whose indentation level should be retrieved, must not be "
 776  
             + "<code>null</code>." + LS );
 777  1
         writer.write( "     * @return The indentation level of the line." + LS );
 778  1
         writer.write( "     */" + LS );
 779  1
         writer.write( "    private static int getIndentLevel( String line )" + LS );
 780  1
         writer.write( "    {" + LS );
 781  1
         writer.write( "        int level = 0;" + LS );
 782  1
         writer.write( "        for ( int i = 0; i < line.length() && line.charAt( i ) == '\\t'; i++ )" + LS );
 783  1
         writer.write( "        {" + LS );
 784  1
         writer.write( "            level++;" + LS );
 785  1
         writer.write( "        }" + LS );
 786  1
         writer.write( "        for ( int i = level + 1; i <= level + 4 && i < line.length(); i++ )" + LS );
 787  1
         writer.write( "        {" + LS );
 788  1
         writer.write( "            if ( line.charAt( i ) == '\\t' )" + LS );
 789  1
         writer.write( "            {" + LS );
 790  1
         writer.write( "                level++;" + LS );
 791  1
         writer.write( "                break;" + LS );
 792  1
         writer.write( "            }" + LS );
 793  1
         writer.write( "        }" + LS );
 794  1
         writer.write( "        return level;" + LS );
 795  1
         writer.write( "    }" + LS );
 796  1
     }
 797  
 
 798  
     /**
 799  
      * Gets the effective string to use for the plugin/mojo/parameter description.
 800  
      *
 801  
      * @param description The description of the element, may be <code>null</code>.
 802  
      * @return The effective description string, never <code>null</code>.
 803  
      */
 804  
     private static String toDescription( String description )
 805  
     {
 806  8
         if ( StringUtils.isNotEmpty( description ) )
 807  
         {
 808  6
             return StringUtils.escape( PluginUtils.toText( description ) );
 809  
         }
 810  
 
 811  2
         return "(no description available)";
 812  
     }
 813  
 
 814  
     /**
 815  
      * Converts a HTML fragment as extracted from a javadoc comment to a plain text string. This method tries to retain
 816  
      * as much of the text formatting as possible by means of the following transformations:
 817  
      * <ul>
 818  
      * <li>List items are converted to leading tabs (U+0009), followed by the item number/bullet, another tab and
 819  
      * finally the item contents. Each tab denotes an increase of indentation.</li>
 820  
      * <li>Flow breaking elements as well as literal line terminators in preformatted text are converted to a newline
 821  
      * (U+000A) to denote a mandatory line break.</li>
 822  
      * <li>Consecutive spaces and line terminators from character data outside of preformatted text will be normalized
 823  
      * to a single space. The resulting space denotes a possible point for line wrapping.</li>
 824  
      * <li>Each space in preformatted text will be converted to a non-breaking space (U+00A0).</li>
 825  
      * </ul>
 826  
      *
 827  
      * @param html The HTML fragment to convert to plain text, may be <code>null</code>.
 828  
      * @return A string with HTML tags converted into pure text, never <code>null</code>.
 829  
      * @deprecated since 2.4.3, using {@link PluginUtils#toText(String)} instead of.
 830  
      */
 831  
     protected static String toText( String html )
 832  
     {
 833  0
         return PluginUtils.toText( html );
 834  
     }
 835  
 }