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