Coverage Report - org.apache.maven.plugins.pdf.HelpMojo
 
Classes in this File Line Coverage Branch Coverage Complexity
HelpMojo
0 %
0/156
0 %
0/108
5,467
 
 1  
 
 2  
 package org.apache.maven.plugins.pdf;
 3  
 
 4  
 import org.apache.maven.plugin.AbstractMojo;
 5  
 import org.apache.maven.plugin.MojoExecutionException;
 6  
 import org.apache.maven.plugins.annotations.Mojo;
 7  
 import org.apache.maven.plugins.annotations.Parameter;
 8  
 
 9  
 import org.w3c.dom.Document;
 10  
 import org.w3c.dom.Element;
 11  
 import org.w3c.dom.Node;
 12  
 import org.w3c.dom.NodeList;
 13  
 import org.xml.sax.SAXException;
 14  
 
 15  
 import javax.xml.parsers.DocumentBuilder;
 16  
 import javax.xml.parsers.DocumentBuilderFactory;
 17  
 import javax.xml.parsers.ParserConfigurationException;
 18  
 import java.io.IOException;
 19  
 import java.io.InputStream;
 20  
 import java.util.ArrayList;
 21  
 import java.util.List;
 22  
 
 23  
 /**
 24  
  * Display help information on maven-pdf-plugin.<br>
 25  
  * Call <code>mvn pdf:help -Ddetail=true -Dgoal=&lt;goal-name&gt;</code> to display parameter details.
 26  
  * @author maven-plugin-tools
 27  
  */
 28  
 @Mojo( name = "help", requiresProject = false, threadSafe = true )
 29  0
 public class HelpMojo
 30  
     extends AbstractMojo
 31  
 {
 32  
     /**
 33  
      * If <code>true</code>, display all settable properties for each goal.
 34  
      *
 35  
      */
 36  
     @Parameter( property = "detail", defaultValue = "false" )
 37  
     private boolean detail;
 38  
 
 39  
     /**
 40  
      * The name of the goal for which to show help. If unspecified, all goals will be displayed.
 41  
      *
 42  
      */
 43  
     @Parameter( property = "goal" )
 44  
     private java.lang.String goal;
 45  
 
 46  
     /**
 47  
      * The maximum length of a display line, should be positive.
 48  
      *
 49  
      */
 50  
     @Parameter( property = "lineLength", defaultValue = "80" )
 51  
     private int lineLength;
 52  
 
 53  
     /**
 54  
      * The number of spaces per indentation level, should be positive.
 55  
      *
 56  
      */
 57  
     @Parameter( property = "indentSize", defaultValue = "2" )
 58  
     private int indentSize;
 59  
 
 60  
     // groupId/artifactId/plugin-help.xml
 61  
     private static final String PLUGIN_HELP_PATH =
 62  
                     "/META-INF/maven/org.apache.maven.plugins/maven-pdf-plugin/plugin-help.xml";
 63  
 
 64  
     private static final int DEFAULT_LINE_LENGTH = 80;
 65  
 
 66  
     private Document build()
 67  
         throws MojoExecutionException
 68  
     {
 69  0
         getLog().debug( "load plugin-help.xml: " + PLUGIN_HELP_PATH );
 70  0
         InputStream is = null;
 71  
         try
 72  
         {
 73  0
             is = getClass().getResourceAsStream( PLUGIN_HELP_PATH );
 74  0
             DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
 75  0
             DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
 76  0
             return dBuilder.parse( is );
 77  
         }
 78  0
         catch ( IOException e )
 79  
         {
 80  0
             throw new MojoExecutionException( e.getMessage(), e );
 81  
         }
 82  0
         catch ( ParserConfigurationException e )
 83  
         {
 84  0
             throw new MojoExecutionException( e.getMessage(), e );
 85  
         }
 86  0
         catch ( SAXException e )
 87  
         {
 88  0
             throw new MojoExecutionException( e.getMessage(), e );
 89  
         }
 90  
         finally
 91  
         {
 92  0
             if ( is != null )
 93  
             {
 94  
                 try
 95  
                 {
 96  0
                     is.close();
 97  
                 }
 98  0
                 catch ( IOException e )
 99  
                 {
 100  0
                     throw new MojoExecutionException( e.getMessage(), e );
 101  0
                 }
 102  
             }
 103  
         }
 104  
     }
 105  
 
 106  
     /**
 107  
      * {@inheritDoc}
 108  
      */
 109  
     public void execute()
 110  
         throws MojoExecutionException
 111  
     {
 112  0
         if ( lineLength <= 0 )
 113  
         {
 114  0
             getLog().warn( "The parameter 'lineLength' should be positive, using '80' as default." );
 115  0
             lineLength = DEFAULT_LINE_LENGTH;
 116  
         }
 117  0
         if ( indentSize <= 0 )
 118  
         {
 119  0
             getLog().warn( "The parameter 'indentSize' should be positive, using '2' as default." );
 120  0
             indentSize = 2;
 121  
         }
 122  
 
 123  0
         Document doc = build();
 124  
 
 125  0
         StringBuilder sb = new StringBuilder();
 126  0
         Node plugin = getSingleChild( doc, "plugin" );
 127  
 
 128  
 
 129  0
         String name = getValue( plugin, "name" );
 130  0
         String version = getValue( plugin, "version" );
 131  0
         String id = getValue( plugin, "groupId" ) + ":" + getValue( plugin, "artifactId" ) + ":" + version;
 132  0
         if ( isNotEmpty( name ) && !name.contains( id ) )
 133  
         {
 134  0
             append( sb, name + " " + version, 0 );
 135  
         }
 136  
         else
 137  
         {
 138  0
             if ( isNotEmpty( name ) )
 139  
             {
 140  0
                 append( sb, name, 0 );
 141  
             }
 142  
             else
 143  
             {
 144  0
                 append( sb, id, 0 );
 145  
             }
 146  
         }
 147  0
         append( sb, getValue( plugin, "description" ), 1 );
 148  0
         append( sb, "", 0 );
 149  
 
 150  
         //<goalPrefix>plugin</goalPrefix>
 151  0
         String goalPrefix = getValue( plugin, "goalPrefix" );
 152  
 
 153  0
         Node mojos1 = getSingleChild( plugin, "mojos" );
 154  
 
 155  0
         List<Node> mojos = findNamedChild( mojos1, "mojo" );
 156  
 
 157  0
         if ( goal == null || goal.length() <= 0 )
 158  
         {
 159  0
             append( sb, "This plugin has " + mojos.size() + ( mojos.size() > 1 ? " goals:" : " goal:" ), 0 );
 160  0
             append( sb, "", 0 );
 161  
         }
 162  
 
 163  0
         for ( Node mojo : mojos )
 164  
         {
 165  0
             writeGoal( sb, goalPrefix, (Element) mojo );
 166  0
         }
 167  
 
 168  0
         if ( getLog().isInfoEnabled() )
 169  
         {
 170  0
             getLog().info( sb.toString() );
 171  
         }
 172  0
     }
 173  
 
 174  
 
 175  
     private static boolean isNotEmpty( String string )
 176  
     {
 177  0
         return string != null && string.length() > 0;
 178  
     }
 179  
 
 180  
     private String getValue( Node node, String elementName )
 181  
         throws MojoExecutionException
 182  
     {
 183  0
         return getSingleChild( node, elementName ).getTextContent();
 184  
     }
 185  
 
 186  
     private Node getSingleChild( Node node, String elementName )
 187  
         throws MojoExecutionException
 188  
     {
 189  0
         List<Node> namedChild = findNamedChild( node, elementName );
 190  0
         if ( namedChild.isEmpty() )
 191  
         {
 192  0
             throw new MojoExecutionException( "Could not find " + elementName + " in plugin-help.xml" );
 193  
         }
 194  0
         if ( namedChild.size() > 1 )
 195  
         {
 196  0
             throw new MojoExecutionException( "Multiple " + elementName + " in plugin-help.xml" );
 197  
         }
 198  0
         return namedChild.get( 0 );
 199  
     }
 200  
 
 201  
     private List<Node> findNamedChild( Node node, String elementName )
 202  
     {
 203  0
         List<Node> result = new ArrayList<Node>();
 204  0
         NodeList childNodes = node.getChildNodes();
 205  0
         for ( int i = 0; i < childNodes.getLength(); i++ )
 206  
         {
 207  0
             Node item = childNodes.item( i );
 208  0
             if ( elementName.equals( item.getNodeName() ) )
 209  
             {
 210  0
                 result.add( item );
 211  
             }
 212  
         }
 213  0
         return result;
 214  
     }
 215  
 
 216  
     private Node findSingleChild( Node node, String elementName )
 217  
         throws MojoExecutionException
 218  
     {
 219  0
         List<Node> elementsByTagName = findNamedChild( node, elementName );
 220  0
         if ( elementsByTagName.isEmpty() )
 221  
         {
 222  0
             return null;
 223  
         }
 224  0
         if ( elementsByTagName.size() > 1 )
 225  
         {
 226  0
             throw new MojoExecutionException( "Multiple " + elementName + "in plugin-help.xml" );
 227  
         }
 228  0
         return elementsByTagName.get( 0 );
 229  
     }
 230  
 
 231  
     private void writeGoal( StringBuilder sb, String goalPrefix, Element mojo )
 232  
         throws MojoExecutionException
 233  
     {
 234  0
         String mojoGoal = getValue( mojo, "goal" );
 235  0
         Node configurationElement = findSingleChild( mojo, "configuration" );
 236  0
         Node description = findSingleChild( mojo, "description" );
 237  0
         if ( goal == null || goal.length() <= 0 || mojoGoal.equals( goal ) )
 238  
         {
 239  0
             append( sb, goalPrefix + ":" + mojoGoal, 0 );
 240  0
             Node deprecated = findSingleChild( mojo, "deprecated" );
 241  0
             if ( ( deprecated != null ) && isNotEmpty( deprecated.getTextContent() ) )
 242  
             {
 243  0
                 append( sb, "Deprecated. " + deprecated.getTextContent(), 1 );
 244  0
                 if ( detail && description != null )
 245  
                 {
 246  0
                     append( sb, "", 0 );
 247  0
                     append( sb, description.getTextContent(), 1 );
 248  
                 }
 249  
             }
 250  0
             else if ( description != null )
 251  
             {
 252  0
                 append( sb, description.getTextContent(), 1 );
 253  
             }
 254  0
             append( sb, "", 0 );
 255  
 
 256  0
             if ( detail )
 257  
             {
 258  0
                 Node parametersNode = getSingleChild( mojo, "parameters" );
 259  0
                 List<Node> parameters = findNamedChild( parametersNode, "parameter" );
 260  0
                 append( sb, "Available parameters:", 1 );
 261  0
                 append( sb, "", 0 );
 262  
 
 263  0
                 for ( Node parameter : parameters )
 264  
                 {
 265  0
                     writeParameter( sb, parameter, configurationElement );
 266  0
                 }
 267  
             }
 268  
         }
 269  0
     }
 270  
 
 271  
     private void writeParameter( StringBuilder sb, Node parameter, Node configurationElement )
 272  
         throws MojoExecutionException
 273  
     {
 274  0
         String parameterName = getValue( parameter, "name" );
 275  0
         String parameterDescription = getValue( parameter, "description" );
 276  
 
 277  0
         Element fieldConfigurationElement = (Element) findSingleChild( configurationElement, parameterName );
 278  
 
 279  0
         String parameterDefaultValue = "";
 280  0
         if ( fieldConfigurationElement != null && fieldConfigurationElement.hasAttribute( "default-value" ) )
 281  
         {
 282  0
             parameterDefaultValue = " (Default: " + fieldConfigurationElement.getAttribute( "default-value" ) + ")";
 283  
         }
 284  0
         append( sb, parameterName + parameterDefaultValue, 2 );
 285  0
         Node deprecated = findSingleChild( parameter, "deprecated" );
 286  0
         if ( ( deprecated != null ) && isNotEmpty( deprecated.getTextContent() ) )
 287  
         {
 288  0
             append( sb, "Deprecated. " + deprecated.getTextContent(), 3 );
 289  0
             append( sb, "", 0 );
 290  
         }
 291  0
         append( sb, parameterDescription, 3 );
 292  0
         if ( "true".equals( getValue( parameter, "required" ) ) )
 293  
         {
 294  0
             append( sb, "Required: Yes", 3 );
 295  
         }
 296  0
         if ( ( fieldConfigurationElement != null ) && isNotEmpty( fieldConfigurationElement.getTextContent() ) )
 297  
         {
 298  0
             String property = getPropertyFromExpression( fieldConfigurationElement.getTextContent() );
 299  0
             append( sb, "User property: " + property, 3 );
 300  
         }
 301  
 
 302  0
         append( sb, "", 0 );
 303  0
     }
 304  
 
 305  
     /**
 306  
      * <p>Repeat a String <code>n</code> times to form a new string.</p>
 307  
      *
 308  
      * @param str    String to repeat
 309  
      * @param repeat number of times to repeat str
 310  
      * @return String with repeated String
 311  
      * @throws NegativeArraySizeException if <code>repeat < 0</code>
 312  
      * @throws NullPointerException       if str is <code>null</code>
 313  
      */
 314  
     private static String repeat( String str, int repeat )
 315  
     {
 316  0
         StringBuilder buffer = new StringBuilder( repeat * str.length() );
 317  
 
 318  0
         for ( int i = 0; i < repeat; i++ )
 319  
         {
 320  0
             buffer.append( str );
 321  
         }
 322  
 
 323  0
         return buffer.toString();
 324  
     }
 325  
 
 326  
     /**
 327  
      * Append a description to the buffer by respecting the indentSize and lineLength parameters.
 328  
      * <b>Note</b>: The last character is always a new line.
 329  
      *
 330  
      * @param sb          The buffer to append the description, not <code>null</code>.
 331  
      * @param description The description, not <code>null</code>.
 332  
      * @param indent      The base indentation level of each line, must not be negative.
 333  
      */
 334  
     private void append( StringBuilder sb, String description, int indent )
 335  
     {
 336  0
         for ( String line : toLines( description, indent, indentSize, lineLength ) )
 337  
         {
 338  0
             sb.append( line ).append( '\n' );
 339  0
         }
 340  0
     }
 341  
 
 342  
     /**
 343  
      * Splits the specified text into lines of convenient display length.
 344  
      *
 345  
      * @param text       The text to split into lines, must not be <code>null</code>.
 346  
      * @param indent     The base indentation level of each line, must not be negative.
 347  
      * @param indentSize The size of each indentation, must not be negative.
 348  
      * @param lineLength The length of the line, must not be negative.
 349  
      * @return The sequence of display lines, never <code>null</code>.
 350  
      * @throws NegativeArraySizeException if <code>indent < 0</code>
 351  
      */
 352  
     private static List<String> toLines( String text, int indent, int indentSize, int lineLength )
 353  
     {
 354  0
         List<String> lines = new ArrayList<String>();
 355  
 
 356  0
         String ind = repeat( "\t", indent );
 357  
 
 358  0
         String[] plainLines = text.split( "(\r\n)|(\r)|(\n)" );
 359  
 
 360  0
         for ( String plainLine : plainLines )
 361  
         {
 362  0
             toLines( lines, ind + plainLine, indentSize, lineLength );
 363  
         }
 364  
 
 365  0
         return lines;
 366  
     }
 367  
 
 368  
     /**
 369  
      * Adds the specified line to the output sequence, performing line wrapping if necessary.
 370  
      *
 371  
      * @param lines      The sequence of display lines, must not be <code>null</code>.
 372  
      * @param line       The line to add, must not be <code>null</code>.
 373  
      * @param indentSize The size of each indentation, must not be negative.
 374  
      * @param lineLength The length of the line, must not be negative.
 375  
      */
 376  
     private static void toLines( List<String> lines, String line, int indentSize, int lineLength )
 377  
     {
 378  0
         int lineIndent = getIndentLevel( line );
 379  0
         StringBuilder buf = new StringBuilder( 256 );
 380  
 
 381  0
         String[] tokens = line.split( " +" );
 382  
 
 383  0
         for ( String token : tokens )
 384  
         {
 385  0
             if ( buf.length() > 0 )
 386  
             {
 387  0
                 if ( buf.length() + token.length() >= lineLength )
 388  
                 {
 389  0
                     lines.add( buf.toString() );
 390  0
                     buf.setLength( 0 );
 391  0
                     buf.append( repeat( " ", lineIndent * indentSize ) );
 392  
                 }
 393  
                 else
 394  
                 {
 395  0
                     buf.append( ' ' );
 396  
                 }
 397  
             }
 398  
 
 399  0
             for ( int j = 0; j < token.length(); j++ )
 400  
             {
 401  0
                 char c = token.charAt( j );
 402  0
                 if ( c == '\t' )
 403  
                 {
 404  0
                     buf.append( repeat( " ", indentSize - buf.length() % indentSize ) );
 405  
                 }
 406  0
                 else if ( c == '\u00A0' )
 407  
                 {
 408  0
                     buf.append( ' ' );
 409  
                 }
 410  
                 else
 411  
                 {
 412  0
                     buf.append( c );
 413  
                 }
 414  
             }
 415  
         }
 416  0
         lines.add( buf.toString() );
 417  0
     }
 418  
 
 419  
     /**
 420  
      * Gets the indentation level of the specified line.
 421  
      *
 422  
      * @param line The line whose indentation level should be retrieved, must not be <code>null</code>.
 423  
      * @return The indentation level of the line.
 424  
      */
 425  
     private static int getIndentLevel( String line )
 426  
     {
 427  0
         int level = 0;
 428  0
         for ( int i = 0; i < line.length() && line.charAt( i ) == '\t'; i++ )
 429  
         {
 430  0
             level++;
 431  
         }
 432  0
         for ( int i = level + 1; i <= level + 4 && i < line.length(); i++ )
 433  
         {
 434  0
             if ( line.charAt( i ) == '\t' )
 435  
             {
 436  0
                 level++;
 437  0
                 break;
 438  
             }
 439  
         }
 440  0
         return level;
 441  
     }
 442  
     
 443  
     private String getPropertyFromExpression( String expression )
 444  
     {
 445  0
         if ( expression != null && expression.startsWith( "${" ) && expression.endsWith( "}" )
 446  
             && !expression.substring( 2 ).contains( "${" ) )
 447  
         {
 448  
             // expression="${xxx}" -> property="xxx"
 449  0
             return expression.substring( 2, expression.length() - 1 );
 450  
         }
 451  
         // no property can be extracted
 452  0
         return null;
 453  
     }
 454  
 }