Coverage Report - org.apache.maven.plugin.checkstyle.DefaultCheckstyleExecutor
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultCheckstyleExecutor
64%
109/170
48%
55/114
0
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *   http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package org.apache.maven.plugin.checkstyle;
 20  
 
 21  
 import java.io.ByteArrayInputStream;
 22  
 import java.io.File;
 23  
 import java.io.FileInputStream;
 24  
 import java.io.IOException;
 25  
 import java.net.MalformedURLException;
 26  
 import java.net.URL;
 27  
 import java.net.URLClassLoader;
 28  
 import java.util.ArrayList;
 29  
 import java.util.Collections;
 30  
 import java.util.List;
 31  
 import java.util.Properties;
 32  
 
 33  
 import org.apache.maven.artifact.DependencyResolutionRequiredException;
 34  
 import org.apache.maven.project.MavenProject;
 35  
 import org.codehaus.plexus.logging.AbstractLogEnabled;
 36  
 import org.codehaus.plexus.resource.ResourceManager;
 37  
 import org.codehaus.plexus.resource.loader.FileResourceCreationException;
 38  
 import org.codehaus.plexus.resource.loader.FileResourceLoader;
 39  
 import org.codehaus.plexus.resource.loader.ResourceNotFoundException;
 40  
 import org.codehaus.plexus.util.FileUtils;
 41  
 import org.codehaus.plexus.util.StringUtils;
 42  
 
 43  
 import com.puppycrawl.tools.checkstyle.Checker;
 44  
 import com.puppycrawl.tools.checkstyle.ConfigurationLoader;
 45  
 import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
 46  
 import com.puppycrawl.tools.checkstyle.PackageNamesLoader;
 47  
 import com.puppycrawl.tools.checkstyle.PropertiesExpander;
 48  
 import com.puppycrawl.tools.checkstyle.api.AuditListener;
 49  
 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
 50  
 import com.puppycrawl.tools.checkstyle.api.Configuration;
 51  
 import com.puppycrawl.tools.checkstyle.api.FilterSet;
 52  
 import com.puppycrawl.tools.checkstyle.filters.SuppressionsLoader;
 53  
 
 54  
 /**
 55  
  * @author <a href="mailto:olamy@apache.org">olamy</a>
 56  
  * @plexus.component role="org.apache.maven.plugin.checkstyle.CheckstyleExecutor" role-hint="default" instantiation-strategy="per-lookup"
 57  
  * @since 2.5
 58  
  * @version $Id: org.apache.maven.plugin.checkstyle.DefaultCheckstyleExecutor.html 816660 2012-05-08 13:58:21Z hboutemy $
 59  
  */
 60  28
 public class DefaultCheckstyleExecutor
 61  
     extends AbstractLogEnabled
 62  
     implements CheckstyleExecutor
 63  
 {
 64  
 
 65  
     /**
 66  
      * @plexus.requirement role="org.codehaus.plexus.resource.ResourceManager" role-hint="default"
 67  
      */
 68  
     private ResourceManager locator;
 69  
 
 70  2
     private static final File[] EMPTY_FILE_ARRAY = new File[0];
 71  
 
 72  
     public CheckstyleResults executeCheckstyle( CheckstyleExecutorRequest request )
 73  
         throws CheckstyleExecutorException, CheckstyleException
 74  
     {
 75  
         // checkstyle will always use the context classloader in order
 76  
         // to load resources (dtds),
 77  
         // so we have to fix it
 78  
         // olamy this hack is not anymore needed in maven 3.x
 79  32
         ClassLoader checkstyleClassLoader = PackageNamesLoader.class.getClassLoader();
 80  32
         Thread.currentThread().setContextClassLoader( checkstyleClassLoader );
 81  
 
 82  32
         if ( getLogger().isDebugEnabled() )
 83  
         {
 84  0
             getLogger().debug( "executeCheckstyle start headerLocation : " + request.getHeaderLocation() );
 85  
         }
 86  32
         locator.setOutputDirectory( new File( request.getProject().getBuild().getDirectory() ) );
 87  
         File[] files;
 88  
         try
 89  
         {
 90  32
             files = getFilesToProcess( request );
 91  
         }
 92  0
         catch ( IOException e )
 93  
         {
 94  0
             throw new CheckstyleExecutorException( "Error getting files to process", e );
 95  32
         }
 96  
 
 97  32
         FilterSet filterSet = getSuppressions( request );
 98  
 
 99  32
         Checker checker = new Checker();
 100  
 
 101  
         // setup classloader, needed to avoid "Unable to get class information
 102  
         // for ..." errors
 103  32
         List<String> classPathStrings = new ArrayList<String>();
 104  32
         List<String> outputDirectories = new ArrayList<String>();
 105  
         try
 106  
         {
 107  32
             classPathStrings = request.getProject().getCompileClasspathElements();
 108  30
             outputDirectories.add( request.getProject().getBuild().getOutputDirectory() );
 109  
 
 110  30
             if ( request.isIncludeTestSourceDirectory() && ( request.getSourceDirectory() != null )
 111  
                 && ( request.getTestSourceDirectory().exists() ) && ( request.getTestSourceDirectory().isDirectory() ) )
 112  
             {
 113  0
                 classPathStrings = request.getProject().getTestClasspathElements();
 114  0
                 outputDirectories.add( request.getProject().getBuild().getTestOutputDirectory() );
 115  
             }
 116  
         }
 117  2
         catch ( DependencyResolutionRequiredException e )
 118  
         {
 119  2
             throw new CheckstyleExecutorException( e.getMessage(), e );
 120  30
         }
 121  
 
 122  30
         if ( classPathStrings == null )
 123  
         {
 124  0
             classPathStrings = Collections.EMPTY_LIST;
 125  
         }
 126  
 
 127  30
         List<URL> urls = new ArrayList<URL>( classPathStrings.size() );
 128  
 
 129  30
         for ( String path : classPathStrings )
 130  
         {
 131  
             try
 132  
             {
 133  30
                 urls.add( new File( path ).toURL() );
 134  
             }
 135  0
             catch ( MalformedURLException e )
 136  
             {
 137  0
                 throw new CheckstyleExecutorException( e.getMessage(), e );
 138  30
             }
 139  
         }
 140  
 
 141  30
         for ( String outputDirectoryString : outputDirectories )
 142  
         {
 143  
             try
 144  
             {
 145  30
                 if ( outputDirectoryString != null )
 146  
                 {
 147  0
                     File outputDirectoryFile = new File( outputDirectoryString );
 148  0
                     if ( outputDirectoryFile.exists() )
 149  
                     {
 150  0
                         URL outputDirectoryUrl = outputDirectoryFile.toURL();
 151  0
                         request.getLog().debug(
 152  
                                                 "Adding the outputDirectory " + outputDirectoryUrl.toString()
 153  
                                                     + " to the Checkstyle class path" );
 154  0
                         urls.add( outputDirectoryUrl );
 155  
                     }
 156  
                 }
 157  
             }
 158  0
             catch ( MalformedURLException e )
 159  
             {
 160  0
                 throw new CheckstyleExecutorException( e.getMessage(), e );
 161  30
             }
 162  
         }
 163  
 
 164  30
         URLClassLoader projectClassLoader = new URLClassLoader( (URL[]) urls.toArray( new URL[urls.size()] ), null );
 165  30
         checker.setClassloader( projectClassLoader );
 166  
 
 167  30
         checker.setModuleClassLoader( Thread.currentThread().getContextClassLoader() );
 168  
 
 169  30
         if ( filterSet != null )
 170  
         {
 171  0
             checker.addFilter( filterSet );
 172  
         }
 173  30
         Configuration configuration = getConfiguration( request );
 174  30
         checker.configure( configuration );
 175  
 
 176  30
         AuditListener listener = request.getListener();
 177  
 
 178  30
         if ( listener != null )
 179  
         {
 180  30
             checker.addListener( listener );
 181  
         }
 182  
 
 183  30
         if ( request.isConsoleOutput() )
 184  
         {
 185  8
             checker.addListener( request.getConsoleListener() );
 186  
         }
 187  
 
 188  30
         CheckstyleReportListener sinkListener = new CheckstyleReportListener( request.getSourceDirectory(), configuration );
 189  30
         if ( request.isIncludeTestSourceDirectory() && ( request.getTestSourceDirectory() != null )
 190  
             && ( request.getTestSourceDirectory().exists() ) && ( request.getTestSourceDirectory().isDirectory() ) )
 191  
         {
 192  0
             sinkListener.addSourceDirectory( request.getTestSourceDirectory() );
 193  
         }
 194  
 
 195  30
         checker.addListener( sinkListener );
 196  
 
 197  30
         List<File> filesList = new ArrayList<File>();
 198  60
         for ( int i = 0; i < files.length; i++ )
 199  
         {
 200  30
             filesList.add( files[i] );
 201  
         }
 202  30
         int nbErrors = checker.process( filesList );
 203  
 
 204  30
         checker.destroy();
 205  
 
 206  30
         if ( request.getStringOutputStream() != null )
 207  
         {
 208  26
             request.getLog().info( request.getStringOutputStream().toString() );
 209  
         }
 210  
 
 211  30
         if ( request.isFailsOnError() && nbErrors > 0 )
 212  
         {
 213  
             // TODO: should be a failure, not an error. Report is not meant to
 214  
             // throw an exception here (so site would
 215  
             // work regardless of config), but should record this information
 216  2
             throw new CheckstyleExecutorException( "There are " + nbErrors + " checkstyle errors." );
 217  
         }
 218  28
         else if ( nbErrors > 0 )
 219  
         {
 220  28
             request.getLog().info( "There are " + nbErrors + " checkstyle errors." );
 221  
         }
 222  
 
 223  28
         return sinkListener.getResults();
 224  
     }
 225  
 
 226  
     public Configuration getConfiguration( CheckstyleExecutorRequest request )
 227  
         throws CheckstyleExecutorException
 228  
     {
 229  
         try
 230  
         {
 231  
             // checkstyle will always use the context classloader in order
 232  
             // to load resources (dtds),
 233  
             // so we have to fix it
 234  30
             ClassLoader checkstyleClassLoader = PackageNamesLoader.class.getClassLoader();
 235  30
             Thread.currentThread().setContextClassLoader( checkstyleClassLoader );
 236  30
             String configFile = getConfigFile( request );
 237  30
             Properties overridingProperties = getOverridingProperties( request );
 238  30
             Configuration config = ConfigurationLoader
 239  
                 .loadConfiguration( configFile, new PropertiesExpander( overridingProperties ) );
 240  30
             String effectiveEncoding = StringUtils.isNotEmpty( request.getEncoding() ) ? request.getEncoding() : System
 241  
                 .getProperty( "file.encoding", "UTF-8" );
 242  30
             if ( StringUtils.isEmpty( request.getEncoding() ) )
 243  
             {
 244  0
                 request.getLog().warn(
 245  
                                        "File encoding has not been set, using platform encoding " + effectiveEncoding
 246  
                                            + ", i.e. build is platform dependent!" );
 247  
             }
 248  30
             Configuration[] modules = config.getChildren();
 249  228
             for ( int i = 0; i < modules.length; i++ )
 250  
             {
 251  198
                 Configuration module = modules[i];
 252  198
                 if ( "Checker".equals( module.getName() )
 253  
                     || "com.puppycrawl.tools.checkstyle.Checker".equals( module.getName() ) )
 254  
                 {
 255  0
                     if ( module instanceof DefaultConfiguration )
 256  
                     {
 257  0
                         ( (DefaultConfiguration) module ).addAttribute( "charset", effectiveEncoding );
 258  
                     }
 259  
                     else
 260  
                     {
 261  0
                         request.getLog().warn( "Failed to configure file encoding on module " + module );
 262  
                     }
 263  
                 }
 264  198
                 if ( "TreeWalker".equals( module.getName() )
 265  
                     || "com.puppycrawl.tools.checkstyle.TreeWalker".equals( module.getName() ) )
 266  
                 {
 267  30
                     if ( module instanceof DefaultConfiguration )
 268  
                     {
 269  30
                         ( (DefaultConfiguration) module ).addAttribute( "cacheFile", request.getCacheFile() );
 270  
                     }
 271  
                     else
 272  
                     {
 273  0
                         request.getLog().warn( "Failed to configure cache file on module " + module );
 274  
                     }
 275  
                 }
 276  
             }
 277  30
             return config;
 278  
         }
 279  0
         catch ( CheckstyleException e )
 280  
         {
 281  0
             throw new CheckstyleExecutorException( "Failed during checkstyle configuration", e );
 282  
         }
 283  
     }
 284  
 
 285  
     private Properties getOverridingProperties( CheckstyleExecutorRequest request )
 286  
         throws CheckstyleExecutorException
 287  
     {
 288  30
         Properties p = new Properties();
 289  
 
 290  
         try
 291  
         {
 292  30
             if ( request.getPropertiesLocation() != null )
 293  
             {
 294  0
                 if ( getLogger().isDebugEnabled() )
 295  
                 {
 296  0
                     getLogger().debug( "request.getPropertiesLocation() " + request.getPropertiesLocation() );
 297  
                 }
 298  
 
 299  0
                 File propertiesFile = locator.getResourceAsFile( request.getPropertiesLocation(),
 300  
                                                                  "checkstyle-checker.properties" );
 301  
 
 302  0
                 if ( propertiesFile != null )
 303  
                 {
 304  0
                     p.load( new FileInputStream( propertiesFile ) );
 305  
                 }
 306  
             }
 307  
 
 308  30
             if ( StringUtils.isNotEmpty( request.getPropertyExpansion() ) )
 309  
             {
 310  0
                 String propertyExpansion = request.getPropertyExpansion();
 311  
                 // Convert \ to \\, so that p.load will convert it back properly
 312  0
                 propertyExpansion = StringUtils.replace( propertyExpansion, "\\", "\\\\" );
 313  0
                 p.load( new ByteArrayInputStream( propertyExpansion.getBytes() ) );
 314  
             }
 315  
 
 316  
             // Workaround for MCHECKSTYLE-48
 317  
             // Make sure that "config/maven-header.txt" is the default value
 318  
             // for headerLocation, if configLocation="config/maven_checks.xml"
 319  30
             String headerLocation = request.getHeaderLocation();
 320  30
             if ( "config/maven_checks.xml".equals( request.getConfigLocation() ) )
 321  
             {
 322  
 
 323  4
                 if ( "LICENSE.txt".equals( request.getHeaderLocation() ) )
 324  
                 {
 325  0
                     headerLocation = "config/maven-header.txt";
 326  
                 }
 327  
             }
 328  30
             if ( getLogger().isDebugEnabled() )
 329  
             {
 330  0
                 getLogger().debug( "headerLocation " + headerLocation );
 331  
             }
 332  
 
 333  30
             if ( StringUtils.isNotEmpty( headerLocation ) )
 334  
             {
 335  
                 try
 336  
                 {
 337  30
                     File headerFile = locator.getResourceAsFile( headerLocation, "checkstyle-header.txt" );
 338  
 
 339  30
                     if ( headerFile != null )
 340  
                     {
 341  30
                         p.setProperty( "checkstyle.header.file", headerFile.getAbsolutePath() );
 342  
                     }
 343  
                 }
 344  0
                 catch ( FileResourceCreationException e )
 345  
                 {
 346  0
                     throw new CheckstyleExecutorException( "Unable to process header location: " + headerLocation, e );
 347  
                 }
 348  0
                 catch ( ResourceNotFoundException e )
 349  
                 {
 350  0
                     throw new CheckstyleExecutorException( "Unable to process header location: " + headerLocation, e );
 351  30
                 }
 352  
             }
 353  
 
 354  30
             if ( request.getCacheFile() != null )
 355  
             {
 356  30
                 p.setProperty( "checkstyle.cache.file", request.getCacheFile() );
 357  
             }
 358  
         }
 359  0
         catch ( IOException e )
 360  
         {
 361  0
             throw new CheckstyleExecutorException( "Failed to get overriding properties", e );
 362  
         }
 363  0
         catch ( FileResourceCreationException e )
 364  
         {
 365  0
             throw new CheckstyleExecutorException( "Failed to get overriding properties", e );
 366  
         }
 367  0
         catch ( ResourceNotFoundException e )
 368  
         {
 369  0
             throw new CheckstyleExecutorException( "Failed to get overriding properties", e );
 370  30
         }
 371  30
         if ( request.getSuppressionsFileExpression() != null )
 372  
         {
 373  0
             String suppresionFile = request.getSuppressionsFileExpression();
 374  
 
 375  0
             if ( suppresionFile != null )
 376  
             {
 377  0
                 p.setProperty( request.getSuppressionsFileExpression(), suppresionFile );
 378  
             }
 379  
         }
 380  
 
 381  30
         return p;
 382  
     }
 383  
 
 384  
     private File[] getFilesToProcess( CheckstyleExecutorRequest request )
 385  
         throws IOException
 386  
     {
 387  32
         StringBuffer excludesStr = new StringBuffer();
 388  
 
 389  32
         if ( StringUtils.isNotEmpty( request.getExcludes() ) )
 390  
         {
 391  0
             excludesStr.append( request.getExcludes() );
 392  
         }
 393  
 
 394  32
         String[] defaultExcludes = FileUtils.getDefaultExcludes();
 395  1216
         for ( int i = 0; i < defaultExcludes.length; i++ )
 396  
         {
 397  1184
             if ( excludesStr.length() > 0 )
 398  
             {
 399  1152
                 excludesStr.append( "," );
 400  
             }
 401  
 
 402  1184
             excludesStr.append( defaultExcludes[i] );
 403  
         }
 404  
 
 405  32
         if (request.getSourceDirectory() == null || !request.getSourceDirectory().exists())
 406  
         {
 407  0
             return EMPTY_FILE_ARRAY;
 408  
         }
 409  
 
 410  32
         List<File> files =
 411  
             FileUtils.getFiles( request.getSourceDirectory(), request.getIncludes(), excludesStr.toString() );
 412  32
         if ( request.isIncludeTestSourceDirectory() && ( request.getTestSourceDirectory() != null )
 413  
             && ( request.getTestSourceDirectory().exists() ) && ( request.getTestSourceDirectory().isDirectory() ) )
 414  
         {
 415  0
             files.addAll( FileUtils.getFiles( request.getTestSourceDirectory(), request.getIncludes(),
 416  
                                               excludesStr.toString() ) );
 417  
         }
 418  
 
 419  32
         return (File[]) files.toArray( EMPTY_FILE_ARRAY );
 420  
     }
 421  
 
 422  
     private FilterSet getSuppressions( CheckstyleExecutorRequest request )
 423  
         throws CheckstyleExecutorException
 424  
     {
 425  
         try
 426  
         {
 427  32
             File suppressionsFile = locator.resolveLocation( request.getSuppressionsLocation(),
 428  
                                                              "checkstyle-suppressions.xml" );
 429  
 
 430  32
             if ( suppressionsFile == null )
 431  
             {
 432  32
                 return null;
 433  
             }
 434  
 
 435  0
             return SuppressionsLoader.loadSuppressions( suppressionsFile.getAbsolutePath() );
 436  
         }
 437  0
         catch ( CheckstyleException ce )
 438  
         {
 439  0
             throw new CheckstyleExecutorException( "failed to load suppressions location: "
 440  
                 + request.getSuppressionsLocation(), ce );
 441  
         }
 442  0
         catch ( IOException e )
 443  
         {
 444  0
             throw new CheckstyleExecutorException( "Failed to process supressions location: "
 445  
                 + request.getSuppressionsLocation(), e );
 446  
         }
 447  
     }
 448  
 
 449  
     private String getConfigFile( CheckstyleExecutorRequest request )
 450  
         throws CheckstyleExecutorException
 451  
     {
 452  
         try
 453  
         {
 454  30
             if ( getLogger().isDebugEnabled() )
 455  
             {
 456  0
                 getLogger().debug( "request.getConfigLocation() " + request.getConfigLocation() );
 457  
             }
 458  
             
 459  30
             MavenProject parent = request.getProject();
 460  60
             while ( parent != null && parent.getFile() != null )
 461  
             {
 462  
                 // MCHECKSTYLE-131 ( olamy ) I don't like this hack.
 463  
                 // (dkulp) Me either.   It really pollutes the location stuff
 464  
                 // by allowing searches of stuff outside the current module.
 465  30
                 File dir = parent.getFile().getParentFile();
 466  30
                 locator.addSearchPath( FileResourceLoader.ID, dir.getAbsolutePath() );
 467  30
                 parent = parent.getParent();
 468  30
             }
 469  30
             locator.addSearchPath( "url", "" );
 470  
 
 471  30
             File configFile = locator.getResourceAsFile( request.getConfigLocation(), "checkstyle-checker.xml" );
 472  30
             if ( configFile == null )
 473  
             {
 474  0
                 throw new CheckstyleExecutorException( "Unable to process config location: "
 475  
                     + request.getConfigLocation() );
 476  
             }
 477  30
             return configFile.getAbsolutePath();
 478  
         }
 479  0
         catch ( org.codehaus.plexus.resource.loader.ResourceNotFoundException e )
 480  
         {
 481  0
             throw new CheckstyleExecutorException( "Unable to find configuration file at location "
 482  
                 + request.getConfigLocation(), e );
 483  
         }
 484  0
         catch ( FileResourceCreationException e )
 485  
         {
 486  0
             throw new CheckstyleExecutorException( "Unable to process configuration file location "
 487  
                 + request.getConfigLocation(), e );
 488  
         }
 489  
 
 490  
     }
 491  
 }