Coverage Report - org.apache.maven.plugin.AbstractCompilerMojo
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractCompilerMojo
77 %
146/189
57 %
70/122
5,75
 
 1  
 package org.apache.maven.plugin;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import org.apache.maven.execution.MavenSession;
 23  
 import org.apache.maven.toolchain.Toolchain;
 24  
 import org.apache.maven.toolchain.ToolchainManager;
 25  
 import org.codehaus.plexus.compiler.Compiler;
 26  
 import org.codehaus.plexus.compiler.CompilerConfiguration;
 27  
 import org.codehaus.plexus.compiler.CompilerError;
 28  
 import org.codehaus.plexus.compiler.CompilerException;
 29  
 import org.codehaus.plexus.compiler.CompilerOutputStyle;
 30  
 import org.codehaus.plexus.compiler.manager.CompilerManager;
 31  
 import org.codehaus.plexus.compiler.manager.NoSuchCompilerException;
 32  
 import org.codehaus.plexus.compiler.util.scan.InclusionScanException;
 33  
 import org.codehaus.plexus.compiler.util.scan.SourceInclusionScanner;
 34  
 import org.codehaus.plexus.compiler.util.scan.mapping.SingleTargetSourceMapping;
 35  
 import org.codehaus.plexus.compiler.util.scan.mapping.SourceMapping;
 36  
 import org.codehaus.plexus.compiler.util.scan.mapping.SuffixMapping;
 37  
 import org.codehaus.plexus.util.ReaderFactory;
 38  
 import org.codehaus.plexus.util.StringUtils;
 39  
 
 40  
 import java.io.File;
 41  
 import java.util.ArrayList;
 42  
 import java.util.HashSet;
 43  
 import java.util.LinkedHashMap;
 44  
 import java.util.List;
 45  
 import java.util.Map;
 46  
 import java.util.Set;
 47  
 
 48  
 /**
 49  
  * TODO: At least one step could be optimized, currently the plugin will do two
 50  
  * scans of all the source code if the compiler has to have the entire set of
 51  
  * sources. This is currently the case for at least the C# compiler and most
 52  
  * likely all the other .NET compilers too.
 53  
  *
 54  
  * @author others
 55  
  * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
 56  
  * @version $Id: org.apache.maven.plugin.AbstractCompilerMojo.html 816619 2012-05-08 13:09:26Z hboutemy $
 57  
  * @since 2.0
 58  
  */
 59  15
 public abstract class AbstractCompilerMojo
 60  
     extends AbstractMojo
 61  
 {
 62  
     // ----------------------------------------------------------------------
 63  
     // Configurables
 64  
     // ----------------------------------------------------------------------
 65  
 
 66  
     /**
 67  
      * Indicates whether the build will continue even if there are compilation errors.
 68  
      *
 69  
      * @parameter expression="${maven.compiler.failOnError}" default-value="true"
 70  
      * @since 2.0.2
 71  
      */
 72  15
     private boolean failOnError = true;
 73  
 
 74  
     /**
 75  
      * Set to <code>true</code> to include debugging information in the compiled class files.
 76  
      *
 77  
      * @parameter expression="${maven.compiler.debug}" default-value="true"
 78  
      */
 79  15
     private boolean debug = true;
 80  
 
 81  
     /**
 82  
      * Set to <code>true</code> to show messages about what the compiler is doing.
 83  
      *
 84  
      * @parameter expression="${maven.compiler.verbose}" default-value="false"
 85  
      */
 86  
     private boolean verbose;
 87  
 
 88  
     /**
 89  
      * Sets whether to show source locations where deprecated APIs are used.
 90  
      *
 91  
      * @parameter expression="${maven.compiler.showDeprecation}" default-value="false"
 92  
      */
 93  
     private boolean showDeprecation;
 94  
 
 95  
     /**
 96  
      * Set to <code>true</code> to optimize the compiled code using the compiler's optimization methods.
 97  
      *
 98  
      * @parameter expression="${maven.compiler.optimize}" default-value="false"
 99  
      */
 100  
     private boolean optimize;
 101  
 
 102  
     /**
 103  
      * Set to <code>true</code> to show compilation warnings.
 104  
      *
 105  
      * @parameter expression="${maven.compiler.showWarnings}" default-value="false"
 106  
      */
 107  
     private boolean showWarnings;
 108  
 
 109  
     /**
 110  
      * The -source argument for the Java compiler.
 111  
      *
 112  
      * @parameter expression="${maven.compiler.source}" default-value="1.5"
 113  
      */
 114  
     protected String source;
 115  
 
 116  
     /**
 117  
      * The -target argument for the Java compiler.
 118  
      *
 119  
      * @parameter expression="${maven.compiler.target}" default-value="1.5"
 120  
      */
 121  
     protected String target;
 122  
 
 123  
     /**
 124  
      * The -encoding argument for the Java compiler.
 125  
      *
 126  
      * @parameter expression="${encoding}" default-value="${project.build.sourceEncoding}"
 127  
      * @since 2.1
 128  
      */
 129  
     private String encoding;
 130  
 
 131  
     /**
 132  
      * Sets the granularity in milliseconds of the last modification
 133  
      * date for testing whether a source needs recompilation.
 134  
      *
 135  
      * @parameter expression="${lastModGranularityMs}" default-value="0"
 136  
      */
 137  
     private int staleMillis;
 138  
 
 139  
     /**
 140  
      * The compiler id of the compiler to use. See this
 141  
      * <a href="non-javac-compilers.html">guide</a> for more information.
 142  
      *
 143  
      * @parameter expression="${maven.compiler.compilerId}" default-value="javac"
 144  
      */
 145  
     private String compilerId;
 146  
 
 147  
     /**
 148  
      * Version of the compiler to use, ex. "1.3", "1.5", if {@link #fork} is set to <code>true</code>.
 149  
      *
 150  
      * @parameter expression="${maven.compiler.compilerVersion}"
 151  
      */
 152  
     private String compilerVersion;
 153  
 
 154  
     /**
 155  
      * Allows running the compiler in a separate process.
 156  
      * If <code>false</code> it uses the built in compiler, while if <code>true</code> it will use an executable.
 157  
      *
 158  
      * @parameter expression="${maven.compiler.fork}" default-value="false"
 159  
      */
 160  
     private boolean fork;
 161  
 
 162  
     /**
 163  
      * Initial size, in megabytes, of the memory allocation pool, ex. "64", "64m"
 164  
      * if {@link #fork} is set to <code>true</code>.
 165  
      *
 166  
      * @parameter expression="${maven.compiler.meminitial}"
 167  
      * @since 2.0.1
 168  
      */
 169  
     private String meminitial;
 170  
 
 171  
     /**
 172  
      * Sets the maximum size, in megabytes, of the memory allocation pool, ex. "128", "128m"
 173  
      * if {@link #fork} is set to <code>true</code>.
 174  
      *
 175  
      * @parameter expression="${maven.compiler.maxmem}"
 176  
      * @since 2.0.1
 177  
      */
 178  
     private String maxmem;
 179  
 
 180  
     /**
 181  
      * Sets the executable of the compiler to use when {@link #fork} is <code>true</code>.
 182  
      *
 183  
      * @parameter expression="${maven.compiler.executable}"
 184  
      */
 185  
     private String executable;
 186  
 
 187  
     /**
 188  
      * <p>
 189  
      * Sets whether annotation processing is performed or not. Only applies to JDK 1.6+
 190  
      * If not set, both compilation and annotation processing are performed at the same time.
 191  
      * </p>
 192  
      * <p>
 193  
      * Allowed values are:
 194  
      * none - no annotation processing is performed.
 195  
      * only - only annotation processing is done, no compilation.
 196  
      * </p>
 197  
      *
 198  
      * @parameter
 199  
      * @since 2.2
 200  
      */
 201  
     private String proc;
 202  
 
 203  
     /**
 204  
      * <p>
 205  
      * Names of annotation processors to run. Only applies to JDK 1.6+
 206  
      * If not set, the default annotation processors discovery process applies.
 207  
      * </p>
 208  
      *
 209  
      * @parameter
 210  
      * @since 2.2
 211  
      */
 212  
     private String[] annotationProcessors;
 213  
 
 214  
     /**
 215  
      * <p>
 216  
      * Sets the arguments to be passed to the compiler (prepending a dash) if {@link #fork} is set to <code>true</code>.
 217  
      * </p>
 218  
      * <p>
 219  
      * This is because the list of valid arguments passed to a Java compiler
 220  
      * varies based on the compiler version.
 221  
      * </p>
 222  
      * <p>
 223  
      * To pass <code>-Xmaxerrs 1000 -Xlint -Xlint:-path -Averbose=true</code> you should include the following:
 224  
      * </p>
 225  
      * <pre>
 226  
      * &lt;compilerArguments&gt;
 227  
      *   &lt;Xmaxerrs&gt;1000&lt;/Xmaxerrs&gt;
 228  
      *   &lt;Xlint/&gt;
 229  
      *   &lt;Xlint:-path/&gt;
 230  
      *   &lt;Averbose&gt;true&lt;/Averbose&gt;
 231  
      * &lt;/compilerArguments&gt;
 232  
      * </pre>
 233  
      *
 234  
      * @parameter
 235  
      * @since 2.0.1
 236  
      */
 237  
     protected Map<String, String> compilerArguments;
 238  
 
 239  
     /**
 240  
      * <p>
 241  
      * Sets the unformatted single argument string to be passed to the compiler if {@link #fork} is set to <code>true</code>.
 242  
      * To pass multiple arguments such as <code>-Xmaxerrs 1000</code> (which are actually two arguments) you have to use {@link #compilerArguments}.
 243  
      * </p>
 244  
      * <p>
 245  
      * This is because the list of valid arguments passed to a Java compiler
 246  
      * varies based on the compiler version.
 247  
      * </p>
 248  
      *
 249  
      * @parameter
 250  
      */
 251  
     protected String compilerArgument;
 252  
 
 253  
     /**
 254  
      * Sets the name of the output file when compiling a set of
 255  
      * sources to a single file.
 256  
      *
 257  
      * @parameter expression="${project.build.finalName}"
 258  
      */
 259  
     private String outputFileName;
 260  
 
 261  
     /**
 262  
      * Keyword list to be appended to the -g  command-line switch. Legal values are none or a comma-separated list of the following keywords: lines, vars, and source.
 263  
      * If debuglevel is not specified, by default, nothing will be appended to -g. If debug is not turned on, this attribute will be ignored.
 264  
      *
 265  
      * @parameter expression="${maven.compiler.debuglevel}"
 266  
      * @since 2.1
 267  
      */
 268  
     private String debuglevel;
 269  
 
 270  
     /**
 271  
      * @component
 272  
      */
 273  
     private ToolchainManager toolchainManager;
 274  
 
 275  
     // ----------------------------------------------------------------------
 276  
     // Read-only parameters
 277  
     // ----------------------------------------------------------------------
 278  
 
 279  
     /**
 280  
      * The directory to run the compiler from if fork is true.
 281  
      *
 282  
      * @parameter default-value="${basedir}"
 283  
      * @required
 284  
      * @readonly
 285  
      */
 286  
     private File basedir;
 287  
 
 288  
     /**
 289  
      * The target directory of the compiler if fork is true.
 290  
      *
 291  
      * @parameter default-value="${project.build.directory}"
 292  
      * @required
 293  
      * @readonly
 294  
      */
 295  
     private File buildDirectory;
 296  
 
 297  
     /**
 298  
      * Plexus compiler manager.
 299  
      *
 300  
      * @component
 301  
      */
 302  
     private CompilerManager compilerManager;
 303  
 
 304  
     /**
 305  
      * The current build session instance. This is used for
 306  
      * toolchain manager API calls.
 307  
      *
 308  
      * @parameter default-value="${session}"
 309  
      * @required
 310  
      * @readonly
 311  
      */
 312  
     private MavenSession session;
 313  
 
 314  
     protected abstract SourceInclusionScanner getSourceInclusionScanner( int staleMillis );
 315  
 
 316  
     protected abstract SourceInclusionScanner getSourceInclusionScanner( String inputFileEnding );
 317  
 
 318  
     protected abstract List<String> getClasspathElements();
 319  
 
 320  
     protected abstract List<String> getCompileSourceRoots();
 321  
 
 322  
     protected abstract File getOutputDirectory();
 323  
 
 324  
     protected abstract String getSource();
 325  
 
 326  
     protected abstract String getTarget();
 327  
 
 328  
     protected abstract String getCompilerArgument();
 329  
 
 330  
     protected abstract Map<String, String> getCompilerArguments();
 331  
 
 332  
     protected abstract File getGeneratedSourcesDirectory();
 333  
 
 334  
     @SuppressWarnings( "unchecked" )
 335  
     public void execute()
 336  
         throws MojoExecutionException, CompilationFailureException
 337  
     {
 338  
         // ----------------------------------------------------------------------
 339  
         // Look up the compiler. This is done before other code than can
 340  
         // cause the mojo to return before the lookup is done possibly resulting
 341  
         // in misconfigured POMs still building.
 342  
         // ----------------------------------------------------------------------
 343  
 
 344  
         Compiler compiler;
 345  
 
 346  15
         getLog().debug( "Using compiler '" + compilerId + "'." );
 347  
 
 348  
         try
 349  
         {
 350  15
             compiler = compilerManager.getCompiler( compilerId );
 351  
         }
 352  0
         catch ( NoSuchCompilerException e )
 353  
         {
 354  0
             throw new MojoExecutionException( "No such compiler '" + e.getCompilerId() + "'." );
 355  15
         }
 356  
 
 357  
         //-----------toolchains start here ----------------------------------
 358  
         //use the compilerId as identifier for toolchains as well.
 359  15
         Toolchain tc = getToolchain();
 360  15
         if ( tc != null )
 361  
         {
 362  0
             getLog().info( "Toolchain in compiler-plugin: " + tc );
 363  0
             if ( executable != null )
 364  
             {
 365  0
                 getLog().warn( "Toolchains are ignored, 'executable' parameter is set to " + executable );
 366  
             }
 367  
             else
 368  
             {
 369  0
                 fork = true;
 370  
                 //TODO somehow shaky dependency between compilerId and tool executable.
 371  0
                 executable = tc.findTool( compilerId );
 372  
             }
 373  
         }
 374  
         // ----------------------------------------------------------------------
 375  
         //
 376  
         // ----------------------------------------------------------------------
 377  
 
 378  15
         List<String> compileSourceRoots = removeEmptyCompileSourceRoots( getCompileSourceRoots() );
 379  
 
 380  15
         if ( compileSourceRoots.isEmpty() )
 381  
         {
 382  2
             getLog().info( "No sources to compile" );
 383  
 
 384  2
             return;
 385  
         }
 386  
 
 387  13
         if ( getLog().isDebugEnabled() )
 388  
         {
 389  13
             getLog().debug( "Source directories: " + compileSourceRoots.toString().replace( ',', '\n' ) );
 390  13
             getLog().debug( "Classpath: " + getClasspathElements().toString().replace( ',', '\n' ) );
 391  13
             getLog().debug( "Output directory: " + getOutputDirectory() );
 392  
         }
 393  
 
 394  
         // ----------------------------------------------------------------------
 395  
         // Create the compiler configuration
 396  
         // ----------------------------------------------------------------------
 397  
 
 398  13
         CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
 399  
 
 400  13
         compilerConfiguration.setOutputLocation( getOutputDirectory().getAbsolutePath() );
 401  
 
 402  13
         compilerConfiguration.setClasspathEntries( getClasspathElements() );
 403  
 
 404  13
         compilerConfiguration.setSourceLocations( compileSourceRoots );
 405  
 
 406  13
         compilerConfiguration.setOptimize( optimize );
 407  
 
 408  13
         compilerConfiguration.setDebug( debug );
 409  
 
 410  13
         if ( debug && StringUtils.isNotEmpty( debuglevel ) )
 411  
         {
 412  0
             String[] split = StringUtils.split( debuglevel, "," );
 413  0
             for ( int i = 0; i < split.length; i++ )
 414  
             {
 415  0
                 if ( !( split[i].equalsIgnoreCase( "none" ) || split[i].equalsIgnoreCase( "lines" )
 416  
                     || split[i].equalsIgnoreCase( "vars" ) || split[i].equalsIgnoreCase( "source" ) ) )
 417  
                 {
 418  0
                     throw new IllegalArgumentException( "The specified debug level: '" + split[i] + "' is unsupported. "
 419  
                                                             + "Legal values are 'none', 'lines', 'vars', and 'source'." );
 420  
                 }
 421  
             }
 422  0
             compilerConfiguration.setDebugLevel( debuglevel );
 423  
         }
 424  
 
 425  13
         compilerConfiguration.setVerbose( verbose );
 426  
 
 427  13
         compilerConfiguration.setShowWarnings( showWarnings );
 428  
 
 429  13
         compilerConfiguration.setShowDeprecation( showDeprecation );
 430  
 
 431  13
         compilerConfiguration.setSourceVersion( getSource() );
 432  
 
 433  13
         compilerConfiguration.setTargetVersion( getTarget() );
 434  
 
 435  13
         compilerConfiguration.setProc( proc );
 436  
 
 437  13
         compilerConfiguration.setGeneratedSourcesDirectory( getGeneratedSourcesDirectory() );
 438  
 
 439  13
         compilerConfiguration.setAnnotationProcessors( annotationProcessors );
 440  
 
 441  13
         compilerConfiguration.setSourceEncoding( encoding );
 442  
 
 443  13
         Map<String, String> effectiveCompilerArguments = getCompilerArguments();
 444  
 
 445  13
         String effectiveCompilerArgument = getCompilerArgument();
 446  
 
 447  13
         if ( ( effectiveCompilerArguments != null ) || ( effectiveCompilerArgument != null ) )
 448  
         {
 449  1
             LinkedHashMap<String, String> cplrArgsCopy = new LinkedHashMap<String, String>();
 450  1
             if ( effectiveCompilerArguments != null )
 451  
             {
 452  1
                 for ( Map.Entry<String, String> me : effectiveCompilerArguments.entrySet() )
 453  
                 {
 454  1
                     String key = me.getKey();
 455  1
                     String value = me.getValue();
 456  1
                     if ( !key.startsWith( "-" ) )
 457  
                     {
 458  1
                         key = "-" + key;
 459  
                     }
 460  
 
 461  1
                     if ( key.startsWith( "-A" ) && StringUtils.isNotEmpty( value ) )
 462  
                     {
 463  0
                         cplrArgsCopy.put( key + "=" + value, null );
 464  
                     }
 465  
                     else
 466  
                     {
 467  1
                         cplrArgsCopy.put( key, value );
 468  
                     }
 469  1
                 }
 470  
             }
 471  1
             if ( !StringUtils.isEmpty( effectiveCompilerArgument ) )
 472  
             {
 473  1
                 cplrArgsCopy.put( effectiveCompilerArgument, null );
 474  
             }
 475  1
             compilerConfiguration.setCustomCompilerArguments( cplrArgsCopy );
 476  
         }
 477  
 
 478  13
         compilerConfiguration.setFork( fork );
 479  
 
 480  13
         if ( fork )
 481  
         {
 482  2
             if ( !StringUtils.isEmpty( meminitial ) )
 483  
             {
 484  2
                 String value = getMemoryValue( meminitial );
 485  
 
 486  2
                 if ( value != null )
 487  
                 {
 488  2
                     compilerConfiguration.setMeminitial( value );
 489  
                 }
 490  
                 else
 491  
                 {
 492  0
                     getLog().info( "Invalid value for meminitial '" + meminitial + "'. Ignoring this option." );
 493  
                 }
 494  
             }
 495  
 
 496  2
             if ( !StringUtils.isEmpty( maxmem ) )
 497  
             {
 498  2
                 String value = getMemoryValue( maxmem );
 499  
 
 500  2
                 if ( value != null )
 501  
                 {
 502  2
                     compilerConfiguration.setMaxmem( value );
 503  
                 }
 504  
                 else
 505  
                 {
 506  0
                     getLog().info( "Invalid value for maxmem '" + maxmem + "'. Ignoring this option." );
 507  
                 }
 508  
             }
 509  
         }
 510  
 
 511  13
         compilerConfiguration.setExecutable( executable );
 512  
 
 513  13
         compilerConfiguration.setWorkingDirectory( basedir );
 514  
 
 515  13
         compilerConfiguration.setCompilerVersion( compilerVersion );
 516  
 
 517  13
         compilerConfiguration.setBuildDirectory( buildDirectory );
 518  
 
 519  13
         compilerConfiguration.setOutputFileName( outputFileName );
 520  
 
 521  
         // TODO: have an option to always compile (without need to clean)
 522  
         Set<File> staleSources;
 523  
 
 524  
         boolean canUpdateTarget;
 525  
 
 526  
         try
 527  
         {
 528  13
             staleSources =
 529  
                 computeStaleSources( compilerConfiguration, compiler, getSourceInclusionScanner( staleMillis ) );
 530  
 
 531  13
             canUpdateTarget = compiler.canUpdateTarget( compilerConfiguration );
 532  
 
 533  13
             if ( compiler.getCompilerOutputStyle().equals( CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES )
 534  
                 && !canUpdateTarget )
 535  
             {
 536  7
                 getLog().info( "RESCANNING!" );
 537  
                 // TODO: This second scan for source files is sub-optimal
 538  7
                 String inputFileEnding = compiler.getInputFileEnding( compilerConfiguration );
 539  
 
 540  7
                 Set<File> sources = computeStaleSources( compilerConfiguration, compiler,
 541  
                                                          getSourceInclusionScanner( inputFileEnding ) );
 542  
 
 543  7
                 compilerConfiguration.setSourceFiles( sources );
 544  7
             }
 545  
             else
 546  
             {
 547  6
                 compilerConfiguration.setSourceFiles( staleSources );
 548  
             }
 549  
         }
 550  0
         catch ( CompilerException e )
 551  
         {
 552  0
             throw new MojoExecutionException( "Error while computing stale sources.", e );
 553  13
         }
 554  
 
 555  13
         if ( staleSources.isEmpty() )
 556  
         {
 557  6
             getLog().info( "Nothing to compile - all classes are up to date" );
 558  
 
 559  6
             return;
 560  
         }
 561  
 
 562  
         // ----------------------------------------------------------------------
 563  
         // Dump configuration
 564  
         // ----------------------------------------------------------------------
 565  
 
 566  7
         if ( getLog().isDebugEnabled() )
 567  
         {
 568  7
             getLog().debug( "Classpath:" );
 569  
 
 570  7
             for ( String s : getClasspathElements() )
 571  
             {
 572  4
                 getLog().debug( " " + s );
 573  
             }
 574  
 
 575  7
             getLog().debug( "Source roots:" );
 576  
 
 577  7
             for ( String root : getCompileSourceRoots() )
 578  
             {
 579  7
                 getLog().debug( " " + root );
 580  
             }
 581  
 
 582  
             try
 583  
             {
 584  7
                 if ( fork )
 585  
                 {
 586  0
                     if ( compilerConfiguration.getExecutable() != null )
 587  
                     {
 588  0
                         getLog().debug( "Excutable: " );
 589  0
                         getLog().debug( " " + compilerConfiguration.getExecutable() );
 590  
                     }
 591  
                 }
 592  
 
 593  7
                 String[] cl = compiler.createCommandLine( compilerConfiguration );
 594  7
                 if ( cl != null && cl.length > 0 )
 595  
                 {
 596  0
                     StringBuilder sb = new StringBuilder();
 597  0
                     sb.append( cl[0] );
 598  0
                     for ( int i = 1; i < cl.length; i++ )
 599  
                     {
 600  0
                         sb.append( " " );
 601  0
                         sb.append( cl[i] );
 602  
                     }
 603  0
                     getLog().debug( "Command line options:" );
 604  0
                     getLog().debug( sb );
 605  
                 }
 606  
             }
 607  0
             catch ( CompilerException ce )
 608  
             {
 609  0
                 getLog().debug( ce );
 610  7
             }
 611  
         }
 612  
 
 613  
         // ----------------------------------------------------------------------
 614  
         // Compile!
 615  
         // ----------------------------------------------------------------------
 616  
 
 617  7
         if ( StringUtils.isEmpty( compilerConfiguration.getSourceEncoding() ) )
 618  
         {
 619  7
             getLog().warn( "File encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING
 620  
                                + ", i.e. build is platform dependent!" );
 621  
         }
 622  
 
 623  
         List<CompilerError> messages;
 624  
 
 625  
         try
 626  
         {
 627  7
             messages = compiler.compile( compilerConfiguration );
 628  
         }
 629  0
         catch ( Exception e )
 630  
         {
 631  
             // TODO: don't catch Exception
 632  0
             throw new MojoExecutionException( "Fatal error compiling", e );
 633  7
         }
 634  
 
 635  7
         List<CompilerError> warnings = new ArrayList<CompilerError>();
 636  7
         List<CompilerError> errors = new ArrayList<CompilerError>();
 637  7
         if ( messages != null )
 638  
         {
 639  7
             for ( CompilerError message : messages )
 640  
             {
 641  7
                 if ( message.isError() )
 642  
                 {
 643  2
                     errors.add( message );
 644  
                 }
 645  
                 else
 646  
                 {
 647  5
                     warnings.add( message );
 648  
                 }
 649  
             }
 650  
         }
 651  
 
 652  7
         if ( failOnError && !errors.isEmpty() )
 653  
         {
 654  1
             if ( !warnings.isEmpty() )
 655  
             {
 656  0
                 getLog().info( "-------------------------------------------------------------" );
 657  0
                 getLog().warn( "COMPILATION WARNING : " );
 658  0
                 getLog().info( "-------------------------------------------------------------" );
 659  0
                 for ( CompilerError warning : warnings )
 660  
                 {
 661  0
                     getLog().warn( warning.toString() );
 662  
                 }
 663  0
                 getLog().info( warnings.size() + ( ( warnings.size() > 1 ) ? " warnings " : " warning" ) );
 664  0
                 getLog().info( "-------------------------------------------------------------" );
 665  
             }
 666  
 
 667  1
             getLog().info( "-------------------------------------------------------------" );
 668  1
             getLog().error( "COMPILATION ERROR : " );
 669  1
             getLog().info( "-------------------------------------------------------------" );
 670  
 
 671  1
             for ( CompilerError error : errors )
 672  
             {
 673  1
                 getLog().error( error.toString() );
 674  
             }
 675  1
             getLog().info( errors.size() + ( ( errors.size() > 1 ) ? " errors " : " error" ) );
 676  1
             getLog().info( "-------------------------------------------------------------" );
 677  
 
 678  1
             throw new CompilationFailureException( errors );
 679  
         }
 680  
         else
 681  
         {
 682  6
             for ( CompilerError message : messages )
 683  
             {
 684  6
                 getLog().warn( message.toString() );
 685  
             }
 686  
         }
 687  6
     }
 688  
 
 689  
     private String getMemoryValue( String setting )
 690  
     {
 691  4
         String value = null;
 692  
 
 693  
         // Allow '128' or '128m'
 694  4
         if ( isDigits( setting ) )
 695  
         {
 696  0
             value = setting + "m";
 697  
         }
 698  
         else
 699  
         {
 700  4
             if ( ( isDigits( setting.substring( 0, setting.length() - 1 ) ) ) && ( setting.toLowerCase().endsWith(
 701  
                 "m" ) ) )
 702  
             {
 703  4
                 value = setting;
 704  
             }
 705  
         }
 706  4
         return value;
 707  
     }
 708  
 
 709  
     //TODO remove the part with ToolchainManager lookup once we depend on
 710  
     //3.0.9 (have it as prerequisite). Define as regular component field then.
 711  
     private Toolchain getToolchain()
 712  
     {
 713  15
         Toolchain tc = null;
 714  15
         if ( toolchainManager != null )
 715  
         {
 716  15
             tc = toolchainManager.getToolchainFromBuildContext( "jdk", session );
 717  
         }
 718  15
         return tc;
 719  
     }
 720  
 
 721  
     private boolean isDigits( String string )
 722  
     {
 723  28
         for ( int i = 0; i < string.length(); i++ )
 724  
         {
 725  24
             if ( !Character.isDigit( string.charAt( i ) ) )
 726  
             {
 727  4
                 return false;
 728  
             }
 729  
         }
 730  4
         return true;
 731  
     }
 732  
 
 733  
     @SuppressWarnings( "unchecked" )
 734  
     private Set<File> computeStaleSources( CompilerConfiguration compilerConfiguration, Compiler compiler,
 735  
                                            SourceInclusionScanner scanner )
 736  
         throws MojoExecutionException, CompilerException
 737  
     {
 738  20
         CompilerOutputStyle outputStyle = compiler.getCompilerOutputStyle();
 739  
 
 740  
         SourceMapping mapping;
 741  
 
 742  
         File outputDirectory;
 743  
 
 744  20
         if ( outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_PER_INPUT_FILE )
 745  
         {
 746  6
             mapping = new SuffixMapping( compiler.getInputFileEnding( compilerConfiguration ),
 747  
                                          compiler.getOutputFileEnding( compilerConfiguration ) );
 748  
 
 749  6
             outputDirectory = getOutputDirectory();
 750  
         }
 751  14
         else if ( outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES )
 752  
         {
 753  14
             mapping = new SingleTargetSourceMapping( compiler.getInputFileEnding( compilerConfiguration ),
 754  
                                                      compiler.getOutputFile( compilerConfiguration ) );
 755  
 
 756  14
             outputDirectory = buildDirectory;
 757  
         }
 758  
         else
 759  
         {
 760  0
             throw new MojoExecutionException( "Unknown compiler output style: '" + outputStyle + "'." );
 761  
         }
 762  
 
 763  20
         scanner.addSourceMapping( mapping );
 764  
 
 765  20
         Set<File> staleSources = new HashSet<File>();
 766  
 
 767  20
         for ( String sourceRoot : getCompileSourceRoots() )
 768  
         {
 769  20
             File rootFile = new File( sourceRoot );
 770  
 
 771  20
             if ( !rootFile.isDirectory() )
 772  
             {
 773  0
                 continue;
 774  
             }
 775  
 
 776  
             try
 777  
             {
 778  20
                 staleSources.addAll( scanner.getIncludedSources( rootFile, outputDirectory ) );
 779  
             }
 780  0
             catch ( InclusionScanException e )
 781  
             {
 782  0
                 throw new MojoExecutionException(
 783  
                     "Error scanning source root: \'" + sourceRoot + "\' " + "for stale files to recompile.", e );
 784  20
             }
 785  20
         }
 786  
 
 787  20
         return staleSources;
 788  
     }
 789  
 
 790  
     /**
 791  
      * @todo also in ant plugin. This should be resolved at some point so that it does not need to
 792  
      * be calculated continuously - or should the plugins accept empty source roots as is?
 793  
      */
 794  
     private static List<String> removeEmptyCompileSourceRoots( List<String> compileSourceRootsList )
 795  
     {
 796  15
         List<String> newCompileSourceRootsList = new ArrayList<String>();
 797  15
         if ( compileSourceRootsList != null )
 798  
         {
 799  
             // copy as I may be modifying it
 800  15
             for ( String srcDir : compileSourceRootsList )
 801  
             {
 802  15
                 if ( !newCompileSourceRootsList.contains( srcDir ) && new File( srcDir ).exists() )
 803  
                 {
 804  13
                     newCompileSourceRootsList.add( srcDir );
 805  
                 }
 806  
             }
 807  
         }
 808  15
         return newCompileSourceRootsList;
 809  
     }
 810  
 }