Coverage Report - org.owasp.dependencycheck.maven.HelpMojo
 
Classes in this File Line Coverage Branch Coverage Complexity
HelpMojo
0%
0/159
0%
0/110
5.533
 
 1  
 
 2  
 package org.owasp.dependencycheck.maven;
 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 dependency-check-maven.<br>
 25  
  * Call <code>mvn dependency-check: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.owasp/dependency-check-maven/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 = null;
 278  0
         if ( configurationElement != null )
 279  
         {
 280  0
           fieldConfigurationElement =  (Element) findSingleChild( configurationElement, parameterName );
 281  
         }
 282  
 
 283  0
         String parameterDefaultValue = "";
 284  0
         if ( fieldConfigurationElement != null && fieldConfigurationElement.hasAttribute( "default-value" ) )
 285  
         {
 286  0
             parameterDefaultValue = " (Default: " + fieldConfigurationElement.getAttribute( "default-value" ) + ")";
 287  
         }
 288  0
         append( sb, parameterName + parameterDefaultValue, 2 );
 289  0
         Node deprecated = findSingleChild( parameter, "deprecated" );
 290  0
         if ( ( deprecated != null ) && isNotEmpty( deprecated.getTextContent() ) )
 291  
         {
 292  0
             append( sb, "Deprecated. " + deprecated.getTextContent(), 3 );
 293  0
             append( sb, "", 0 );
 294  
         }
 295  0
         append( sb, parameterDescription, 3 );
 296  0
         if ( "true".equals( getValue( parameter, "required" ) ) )
 297  
         {
 298  0
             append( sb, "Required: Yes", 3 );
 299  
         }
 300  0
         if ( ( fieldConfigurationElement != null ) && isNotEmpty( fieldConfigurationElement.getTextContent() ) )
 301  
         {
 302  0
             String property = getPropertyFromExpression( fieldConfigurationElement.getTextContent() );
 303  0
             append( sb, "User property: " + property, 3 );
 304  
         }
 305  
 
 306  0
         append( sb, "", 0 );
 307  0
     }
 308  
 
 309  
     /**
 310  
      * <p>Repeat a String <code>n</code> times to form a new string.</p>
 311  
      *
 312  
      * @param str    String to repeat
 313  
      * @param repeat number of times to repeat str
 314  
      * @return String with repeated String
 315  
      * @throws NegativeArraySizeException if <code>repeat &lt; 0</code>
 316  
      * @throws NullPointerException       if str is <code>null</code>
 317  
      */
 318  
     private static String repeat( String str, int repeat )
 319  
     {
 320  0
         StringBuilder buffer = new StringBuilder( repeat * str.length() );
 321  
 
 322  0
         for ( int i = 0; i < repeat; i++ )
 323  
         {
 324  0
             buffer.append( str );
 325  
         }
 326  
 
 327  0
         return buffer.toString();
 328  
     }
 329  
 
 330  
     /**
 331  
      * Append a description to the buffer by respecting the indentSize and lineLength parameters.
 332  
      * <b>Note</b>: The last character is always a new line.
 333  
      *
 334  
      * @param sb          The buffer to append the description, not <code>null</code>.
 335  
      * @param description The description, not <code>null</code>.
 336  
      * @param indent      The base indentation level of each line, must not be negative.
 337  
      */
 338  
     private void append( StringBuilder sb, String description, int indent )
 339  
     {
 340  0
         for ( String line : toLines( description, indent, indentSize, lineLength ) )
 341  
         {
 342  0
             sb.append( line ).append( '\n' );
 343  0
         }
 344  0
     }
 345  
 
 346  
     /**
 347  
      * Splits the specified text into lines of convenient display length.
 348  
      *
 349  
      * @param text       The text to split into lines, must not be <code>null</code>.
 350  
      * @param indent     The base indentation level of each line, must not be negative.
 351  
      * @param indentSize The size of each indentation, must not be negative.
 352  
      * @param lineLength The length of the line, must not be negative.
 353  
      * @return The sequence of display lines, never <code>null</code>.
 354  
      * @throws NegativeArraySizeException if <code>indent < 0</code>
 355  
      */
 356  
     private static List<String> toLines( String text, int indent, int indentSize, int lineLength )
 357  
     {
 358  0
         List<String> lines = new ArrayList<String>();
 359  
 
 360  0
         String ind = repeat( "\t", indent );
 361  
 
 362  0
         String[] plainLines = text.split( "(\r\n)|(\r)|(\n)" );
 363  
 
 364  0
         for ( String plainLine : plainLines )
 365  
         {
 366  0
             toLines( lines, ind + plainLine, indentSize, lineLength );
 367  
         }
 368  
 
 369  0
         return lines;
 370  
     }
 371  
 
 372  
     /**
 373  
      * Adds the specified line to the output sequence, performing line wrapping if necessary.
 374  
      *
 375  
      * @param lines      The sequence of display lines, must not be <code>null</code>.
 376  
      * @param line       The line to add, must not be <code>null</code>.
 377  
      * @param indentSize The size of each indentation, must not be negative.
 378  
      * @param lineLength The length of the line, must not be negative.
 379  
      */
 380  
     private static void toLines( List<String> lines, String line, int indentSize, int lineLength )
 381  
     {
 382  0
         int lineIndent = getIndentLevel( line );
 383  0
         StringBuilder buf = new StringBuilder( 256 );
 384  
 
 385  0
         String[] tokens = line.split( " +" );
 386  
 
 387  0
         for ( String token : tokens )
 388  
         {
 389  0
             if ( buf.length() > 0 )
 390  
             {
 391  0
                 if ( buf.length() + token.length() >= lineLength )
 392  
                 {
 393  0
                     lines.add( buf.toString() );
 394  0
                     buf.setLength( 0 );
 395  0
                     buf.append( repeat( " ", lineIndent * indentSize ) );
 396  
                 }
 397  
                 else
 398  
                 {
 399  0
                     buf.append( ' ' );
 400  
                 }
 401  
             }
 402  
 
 403  0
             for ( int j = 0; j < token.length(); j++ )
 404  
             {
 405  0
                 char c = token.charAt( j );
 406  0
                 if ( c == '\t' )
 407  
                 {
 408  0
                     buf.append( repeat( " ", indentSize - buf.length() % indentSize ) );
 409  
                 }
 410  0
                 else if ( c == '\u00A0' )
 411  
                 {
 412  0
                     buf.append( ' ' );
 413  
                 }
 414  
                 else
 415  
                 {
 416  0
                     buf.append( c );
 417  
                 }
 418  
             }
 419  
         }
 420  0
         lines.add( buf.toString() );
 421  0
     }
 422  
 
 423  
     /**
 424  
      * Gets the indentation level of the specified line.
 425  
      *
 426  
      * @param line The line whose indentation level should be retrieved, must not be <code>null</code>.
 427  
      * @return The indentation level of the line.
 428  
      */
 429  
     private static int getIndentLevel( String line )
 430  
     {
 431  0
         int level = 0;
 432  0
         for ( int i = 0; i < line.length() && line.charAt( i ) == '\t'; i++ )
 433  
         {
 434  0
             level++;
 435  
         }
 436  0
         for ( int i = level + 1; i <= level + 4 && i < line.length(); i++ )
 437  
         {
 438  0
             if ( line.charAt( i ) == '\t' )
 439  
             {
 440  0
                 level++;
 441  0
                 break;
 442  
             }
 443  
         }
 444  0
         return level;
 445  
     }
 446  
     
 447  
     private String getPropertyFromExpression( String expression )
 448  
     {
 449  0
         if ( expression != null && expression.startsWith( "${" ) && expression.endsWith( "}" )
 450  0
             && !expression.substring( 2 ).contains( "${" ) )
 451  
         {
 452  
             // expression="${xxx}" -> property="xxx"
 453  0
             return expression.substring( 2, expression.length() - 1 );
 454  
         }
 455  
         // no property can be extracted
 456  0
         return null;
 457  
     }
 458  
 }