Coverage Report - org.apache.maven.plugin.javadoc.JavadocUtil
 
Classes in this File Line Coverage Branch Coverage Complexity
JavadocUtil
76 %
331/433
61 %
175/286
6,815
 
 1  
 package org.apache.maven.plugin.javadoc;
 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.ByteArrayOutputStream;
 23  
 import java.io.File;
 24  
 import java.io.FileInputStream;
 25  
 import java.io.FileNotFoundException;
 26  
 import java.io.FileOutputStream;
 27  
 import java.io.IOException;
 28  
 import java.io.InputStream;
 29  
 import java.io.OutputStream;
 30  
 import java.io.OutputStreamWriter;
 31  
 import java.io.PrintStream;
 32  
 import java.io.Reader;
 33  
 import java.io.UnsupportedEncodingException;
 34  
 import java.lang.reflect.Modifier;
 35  
 import java.net.URL;
 36  
 import java.net.URLClassLoader;
 37  
 import java.util.ArrayList;
 38  
 import java.util.Arrays;
 39  
 import java.util.Iterator;
 40  
 import java.util.List;
 41  
 import java.util.Locale;
 42  
 import java.util.Properties;
 43  
 import java.util.Set;
 44  
 import java.util.StringTokenizer;
 45  
 import java.util.jar.JarEntry;
 46  
 import java.util.jar.JarInputStream;
 47  
 import java.util.regex.Matcher;
 48  
 import java.util.regex.Pattern;
 49  
 import java.util.regex.PatternSyntaxException;
 50  
 
 51  
 import org.apache.commons.httpclient.HttpClient;
 52  
 import org.apache.commons.httpclient.UsernamePasswordCredentials;
 53  
 import org.apache.commons.httpclient.auth.AuthScope;
 54  
 import org.apache.commons.httpclient.methods.GetMethod;
 55  
 import org.apache.commons.lang.SystemUtils;
 56  
 import org.apache.maven.artifact.Artifact;
 57  
 import org.apache.maven.plugin.logging.Log;
 58  
 import org.apache.maven.project.MavenProject;
 59  
 import org.apache.maven.settings.Proxy;
 60  
 import org.apache.maven.settings.Settings;
 61  
 import org.apache.maven.shared.invoker.DefaultInvocationRequest;
 62  
 import org.apache.maven.shared.invoker.DefaultInvoker;
 63  
 import org.apache.maven.shared.invoker.InvocationOutputHandler;
 64  
 import org.apache.maven.shared.invoker.InvocationRequest;
 65  
 import org.apache.maven.shared.invoker.InvocationResult;
 66  
 import org.apache.maven.shared.invoker.Invoker;
 67  
 import org.apache.maven.shared.invoker.MavenInvocationException;
 68  
 import org.apache.maven.shared.invoker.PrintStreamHandler;
 69  
 import org.codehaus.plexus.util.FileUtils;
 70  
 import org.codehaus.plexus.util.IOUtil;
 71  
 import org.codehaus.plexus.util.ReaderFactory;
 72  
 import org.codehaus.plexus.util.StringUtils;
 73  
 import org.codehaus.plexus.util.cli.CommandLineException;
 74  
 import org.codehaus.plexus.util.cli.CommandLineUtils;
 75  
 import org.codehaus.plexus.util.cli.Commandline;
 76  
 
 77  
 /**
 78  
  * Set of utilities methods for Javadoc.
 79  
  *
 80  
  * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
 81  
  * @version $Id$
 82  
  * @since 2.4
 83  
  */
 84  0
 public class JavadocUtil
 85  
 {
 86  
     /** The default timeout used when fetching url, i.e. 2000. */
 87  
     public static final int DEFAULT_TIMEOUT = 2000;
 88  
 
 89  
     /**
 90  
      * Method that removes the invalid directories in the specified directories.
 91  
      * <b>Note</b>: All elements in <code>dirs</code> could be an absolute or relative against the project's base
 92  
      * directory <code>String</code> path.
 93  
      *
 94  
      * @param project the current Maven project not null
 95  
      * @param dirs the list of <code>String</code> directories path that will be validated.
 96  
      * @return a List of valid <code>String</code> directories absolute paths.
 97  
      */
 98  
     protected static List pruneDirs( MavenProject project, List dirs )
 99  
     {
 100  86
         List pruned = new ArrayList( dirs.size() );
 101  86
         for ( Iterator i = dirs.iterator(); i.hasNext(); )
 102  
         {
 103  95
             String dir = (String) i.next();
 104  
 
 105  95
             if ( dir == null )
 106  
             {
 107  0
                 continue;
 108  
             }
 109  
 
 110  95
             File directory = new File( dir );
 111  95
             if ( !directory.isAbsolute() )
 112  
             {
 113  0
                 directory = new File( project.getBasedir(), directory.getPath() );
 114  
             }
 115  
 
 116  95
             if ( directory.isDirectory() && !pruned.contains( directory.getAbsolutePath() ) )
 117  
             {
 118  86
                 pruned.add( directory.getAbsolutePath() );
 119  
             }
 120  95
         }
 121  
 
 122  86
         return pruned;
 123  
     }
 124  
 
 125  
     /**
 126  
      * Method that removes the invalid files in the specified files.
 127  
      * <b>Note</b>: All elements in <code>files</code> should be an absolute <code>String</code> path.
 128  
      *
 129  
      * @param files the list of <code>String</code> files paths that will be validated.
 130  
      * @return a List of valid <code>File</code> objects.
 131  
      */
 132  
     protected static List pruneFiles( List files )
 133  
     {
 134  2
         List pruned = new ArrayList( files.size() );
 135  2
         for ( Iterator i = files.iterator(); i.hasNext(); )
 136  
         {
 137  94
             String f = (String) i.next();
 138  
 
 139  94
             if ( f == null )
 140  
             {
 141  0
                 continue;
 142  
             }
 143  
 
 144  94
             File file = new File( f );
 145  94
             if ( file.isFile() && !pruned.contains( f ) )
 146  
             {
 147  68
                 pruned.add( f );
 148  
             }
 149  94
         }
 150  
 
 151  2
         return pruned;
 152  
     }
 153  
 
 154  
     /**
 155  
      * Method that gets all the source files to be excluded from the javadoc on the given
 156  
      * source paths.
 157  
      *
 158  
      * @param sourcePaths      the path to the source files
 159  
      * @param subpackagesList  list of subpackages to be included in the javadoc
 160  
      * @param excludedPackages the package names to be excluded in the javadoc
 161  
      * @return a List of the source files to be excluded in the generated javadoc
 162  
      */
 163  
     protected static List getExcludedNames( List sourcePaths, String[] subpackagesList, String[] excludedPackages )
 164  
     {
 165  1
         List excludedNames = new ArrayList();
 166  1
         for ( Iterator i = sourcePaths.iterator(); i.hasNext(); )
 167  
         {
 168  1
             String path = (String) i.next();
 169  2
             for ( int j = 0; j < subpackagesList.length; j++ )
 170  
             {
 171  1
                 List excludes = getExcludedPackages( path, excludedPackages );
 172  1
                 excludedNames.addAll( excludes );
 173  
             }
 174  1
         }
 175  
 
 176  1
         return excludedNames;
 177  
     }
 178  
 
 179  
     /**
 180  
      * Copy from {@link org.apache.maven.project.MavenProject#getCompileArtifacts()}
 181  
      * @param artifacts not null
 182  
      * @return list of compile artifacts with compile scope
 183  
      * @deprecated since 2.5, using {@link #getCompileArtifacts(Set, boolean)} instead of.
 184  
      */
 185  
     protected static List getCompileArtifacts( Set artifacts )
 186  
     {
 187  0
         return getCompileArtifacts( artifacts, false );
 188  
     }
 189  
 
 190  
     /**
 191  
      * Copy from {@link org.apache.maven.project.MavenProject#getCompileArtifacts()}
 192  
      * @param artifacts not null
 193  
      * @param withTestScope flag to include or not the artifacts with test scope
 194  
      * @return list of compile artifacts with or without test scope.
 195  
      */
 196  
     protected static List getCompileArtifacts( Set artifacts, boolean withTestScope )
 197  
     {
 198  0
         List list = new ArrayList( artifacts.size() );
 199  
 
 200  0
         for ( Iterator i = artifacts.iterator(); i.hasNext(); )
 201  
         {
 202  0
             Artifact a = (Artifact) i.next();
 203  
 
 204  
             // TODO: classpath check doesn't belong here - that's the other method
 205  0
             if ( a.getArtifactHandler().isAddedToClasspath() )
 206  
             {
 207  
                 // TODO: let the scope handler deal with this
 208  0
                 if ( withTestScope )
 209  
                 {
 210  0
                     if ( Artifact.SCOPE_COMPILE.equals( a.getScope() )
 211  
                         || Artifact.SCOPE_PROVIDED.equals( a.getScope() )
 212  
                         || Artifact.SCOPE_SYSTEM.equals( a.getScope() )
 213  
                         || Artifact.SCOPE_TEST.equals( a.getScope() ) )
 214  
                     {
 215  0
                         list.add( a );
 216  
                     }
 217  
                 }
 218  
                 else
 219  
                 {
 220  0
                     if ( Artifact.SCOPE_COMPILE.equals( a.getScope() ) || Artifact.SCOPE_PROVIDED.equals( a.getScope() )
 221  
                         || Artifact.SCOPE_SYSTEM.equals( a.getScope() ) )
 222  
                     {
 223  0
                         list.add( a );
 224  
                     }
 225  
                 }
 226  
             }
 227  0
         }
 228  
 
 229  0
         return list;
 230  
     }
 231  
 
 232  
     /**
 233  
      * Convenience method to wrap an argument value in single quotes (i.e. <code>'</code>). Intended for values
 234  
      * which may contain whitespaces.
 235  
      * <br/>
 236  
      * To prevent javadoc error, the line separator (i.e. <code>\n</code>) are skipped.
 237  
      *
 238  
      * @param value the argument value.
 239  
      * @return argument with quote
 240  
      */
 241  
     protected static String quotedArgument( String value )
 242  
     {
 243  472
         String arg = value;
 244  
 
 245  472
         if ( StringUtils.isNotEmpty( arg ) )
 246  
         {
 247  167
             if ( arg.indexOf( "'" ) != -1 )
 248  
             {
 249  0
                 arg = StringUtils.replace( arg, "'", "\\'" );
 250  
             }
 251  167
             arg = "'" + arg + "'";
 252  
 
 253  
             // To prevent javadoc error
 254  167
             arg = StringUtils.replace( arg, "\n", " " );
 255  
         }
 256  
 
 257  472
         return arg;
 258  
     }
 259  
 
 260  
     /**
 261  
      * Convenience method to format a path argument so that it is properly interpreted by the javadoc tool. Intended
 262  
      * for path values which may contain whitespaces.
 263  
      *
 264  
      * @param value the argument value.
 265  
      * @return path argument with quote
 266  
      */
 267  
     protected static String quotedPathArgument( String value )
 268  
     {
 269  353
         String path = value;
 270  
 
 271  353
         if ( StringUtils.isNotEmpty( path ) )
 272  
         {
 273  164
             path = path.replace( '\\', '/' );
 274  164
             if ( path.indexOf( "\'" ) != -1 )
 275  
             {
 276  4
                 String split[] = path.split( "\'" );
 277  4
                 path = "";
 278  
 
 279  12
                 for ( int i = 0; i < split.length; i++ )
 280  
                 {
 281  8
                     if ( i != split.length - 1 )
 282  
                     {
 283  4
                         path = path + split[i] + "\\'";
 284  
                     }
 285  
                     else
 286  
                     {
 287  4
                         path = path + split[i];
 288  
                     }
 289  
                 }
 290  
             }
 291  164
             path = "'" + path + "'";
 292  
         }
 293  
 
 294  353
         return path;
 295  
     }
 296  
 
 297  
     /**
 298  
      * Convenience method that copy all <code>doc-files</code> directories from <code>javadocDir</code>
 299  
      * to the <code>outputDirectory</code>.
 300  
      *
 301  
      * @param outputDirectory the output directory
 302  
      * @param javadocDir the javadoc directory
 303  
      * @throws IOException if any
 304  
      * @deprecated since 2.5, using {@link #copyJavadocResources(File, File, String)} instead of.
 305  
      */
 306  
     protected static void copyJavadocResources( File outputDirectory, File javadocDir )
 307  
         throws IOException
 308  
     {
 309  0
         copyJavadocResources( outputDirectory, javadocDir, null );
 310  0
     }
 311  
 
 312  
     /**
 313  
      * Convenience method that copy all <code>doc-files</code> directories from <code>javadocDir</code>
 314  
      * to the <code>outputDirectory</code>.
 315  
      *
 316  
      * @param outputDirectory the output directory
 317  
      * @param javadocDir the javadoc directory
 318  
      * @param excludedocfilessubdir the excludedocfilessubdir parameter
 319  
      * @throws IOException if any
 320  
      * @since 2.5
 321  
      */
 322  
     protected static void copyJavadocResources( File outputDirectory, File javadocDir, String excludedocfilessubdir )
 323  
         throws IOException
 324  
     {
 325  7
         List excludes = new ArrayList();
 326  7
         excludes.addAll( Arrays.asList( FileUtils.getDefaultExcludes() ) );
 327  
 
 328  7
         if ( StringUtils.isNotEmpty( excludedocfilessubdir ) )
 329  
         {
 330  2
             StringTokenizer st = new StringTokenizer( excludedocfilessubdir, ":" );
 331  
             String current;
 332  5
             while ( st.hasMoreTokens() )
 333  
             {
 334  3
                 current = st.nextToken();
 335  3
                 excludes.add( "**/" + current + "/**" );
 336  
             }
 337  
         }
 338  
 
 339  7
         if ( javadocDir.exists() && javadocDir.isDirectory() )
 340  
         {
 341  6
             List docFiles =
 342  
                 FileUtils.getDirectoryNames( javadocDir, "**/doc-files", StringUtils.join( excludes.iterator(),
 343  
                                                                                            "," ), false, true );
 344  6
             for ( Iterator it = docFiles.iterator(); it.hasNext(); )
 345  
             {
 346  6
                 String docFile = (String) it.next();
 347  
 
 348  6
                 File docFileOutput = new File( outputDirectory, docFile );
 349  6
                 FileUtils.mkdir( docFileOutput.getAbsolutePath() );
 350  6
                 FileUtils.copyDirectoryStructure( new File( javadocDir, docFile ), docFileOutput );
 351  6
                 List files =
 352  
                     FileUtils.getFileAndDirectoryNames( docFileOutput,
 353  
                                                         StringUtils.join( excludes.iterator(), "," ), null, true,
 354  
                                                         true, true, true );
 355  6
                 for ( Iterator it2 = files.iterator(); it2.hasNext(); )
 356  
                 {
 357  168
                     File file = new File( it2.next().toString() );
 358  
 
 359  168
                     if ( file.isDirectory() )
 360  
                     {
 361  14
                         FileUtils.deleteDirectory( file );
 362  
                     }
 363  
                     else
 364  
                     {
 365  154
                         file.delete();
 366  
                     }
 367  168
                 }
 368  6
             }
 369  
         }
 370  7
     }
 371  
 
 372  
     /**
 373  
      * Method that gets the files or classes that would be included in the javadocs using the subpackages
 374  
      * parameter.
 375  
      *
 376  
      * @param sourceDirectory the directory where the source files are located
 377  
      * @param fileList        the list of all files found in the sourceDirectory
 378  
      * @param excludePackages package names to be excluded in the javadoc
 379  
      * @return a StringBuffer that contains the appended file names of the files to be included in the javadoc
 380  
      */
 381  
     protected static List getIncludedFiles( File sourceDirectory, String[] fileList, String[] excludePackages )
 382  
     {
 383  37
         List files = new ArrayList();
 384  
 
 385  102
         for ( int j = 0; j < fileList.length; j++ )
 386  
         {
 387  65
             boolean include = true;
 388  74
             for ( int k = 0; k < excludePackages.length && include; k++ )
 389  
             {
 390  
                 // handle wildcards (*) in the excludePackageNames
 391  9
                 String[] excludeName = excludePackages[k].split( "[*]" );
 392  
 
 393  9
                 if ( excludeName.length == 0 )
 394  
                 {
 395  0
                     continue;
 396  
                 }
 397  
 
 398  9
                 if ( excludeName.length > 1 )
 399  
                 {
 400  5
                     int u = 0;
 401  15
                     while ( include && u < excludeName.length )
 402  
                     {
 403  10
                         if ( !"".equals( excludeName[u].trim() ) && fileList[j].indexOf( excludeName[u] ) != -1 )
 404  
                         {
 405  1
                             include = false;
 406  
                         }
 407  10
                         u++;
 408  
                     }
 409  5
                 }
 410  
                 else
 411  
                 {
 412  4
                     if ( fileList[j].startsWith( sourceDirectory.toString() + File.separatorChar + excludeName[0] ) )
 413  
                     {
 414  2
                         if ( excludeName[0].endsWith( String.valueOf( File.separatorChar ) ) )
 415  
                         {
 416  2
                             int i = fileList[j].lastIndexOf( File.separatorChar );
 417  2
                             String packageName = fileList[j].substring( 0, i + 1 );
 418  2
                             File currentPackage = new File( packageName );
 419  2
                             File excludedPackage = new File( sourceDirectory, excludeName[0] );
 420  2
                             if ( currentPackage.equals( excludedPackage )
 421  
                                 && fileList[j].substring( i ).indexOf( ".java" ) != -1 )
 422  
                             {
 423  1
                                 include = true;
 424  
                             }
 425  
                             else
 426  
                             {
 427  1
                                 include = false;
 428  
                             }
 429  2
                         }
 430  
                         else
 431  
                         {
 432  0
                             include = false;
 433  
                         }
 434  
                     }
 435  
                 }
 436  
             }
 437  
 
 438  65
             if ( include )
 439  
             {
 440  63
                 files.add( quotedPathArgument( fileList[j] ) );
 441  
             }
 442  
         }
 443  
 
 444  37
         return files;
 445  
     }
 446  
 
 447  
     /**
 448  
      * Method that gets the complete package names (including subpackages) of the packages that were defined
 449  
      * in the excludePackageNames parameter.
 450  
      *
 451  
      * @param sourceDirectory     the directory where the source files are located
 452  
      * @param excludePackagenames package names to be excluded in the javadoc
 453  
      * @return a List of the packagenames to be excluded
 454  
      */
 455  
     protected static List getExcludedPackages( String sourceDirectory, String[] excludePackagenames )
 456  
     {
 457  1
         List files = new ArrayList();
 458  3
         for ( int i = 0; i < excludePackagenames.length; i++ )
 459  
         {
 460  2
             String[] fileList = FileUtils.getFilesFromExtension( sourceDirectory, new String[] { "java" } );
 461  14
             for ( int j = 0; j < fileList.length; j++ )
 462  
             {
 463  12
                 String[] excludeName = excludePackagenames[i].split( "[*]" );
 464  12
                 int u = 0;
 465  24
                 while ( u < excludeName.length )
 466  
                 {
 467  12
                     if ( !"".equals( excludeName[u].trim() ) && fileList[j].indexOf( excludeName[u] ) != -1
 468  
                         && sourceDirectory.indexOf( excludeName[u] ) == -1 )
 469  
                     {
 470  2
                         files.add( fileList[j] );
 471  
                     }
 472  12
                     u++;
 473  
                 }
 474  
             }
 475  
         }
 476  
 
 477  1
         List excluded = new ArrayList();
 478  1
         for ( Iterator it = files.iterator(); it.hasNext(); )
 479  
         {
 480  2
             String file = (String) it.next();
 481  2
             int idx = file.lastIndexOf( File.separatorChar );
 482  2
             String tmpStr = file.substring( 0, idx );
 483  2
             tmpStr = tmpStr.replace( '\\', '/' );
 484  2
             String[] srcSplit = tmpStr.split( sourceDirectory.replace( '\\', '/' ) + '/' );
 485  2
             String excludedPackage = srcSplit[1].replace( '/', '.' );
 486  
 
 487  2
             if ( !excluded.contains( excludedPackage ) )
 488  
             {
 489  2
                 excluded.add( excludedPackage );
 490  
             }
 491  2
         }
 492  
 
 493  1
         return excluded;
 494  
     }
 495  
 
 496  
     /**
 497  
      * Convenience method that gets the files to be included in the javadoc.
 498  
      *
 499  
      * @param sourceDirectory the directory where the source files are located
 500  
      * @param files the variable that contains the appended filenames of the files to be included in the javadoc
 501  
      * @param excludePackages the packages to be excluded in the javadocs
 502  
      */
 503  
     protected static void addFilesFromSource( List files, File sourceDirectory, String[] excludePackages )
 504  
     {
 505  41
         String[] fileList = FileUtils.getFilesFromExtension( sourceDirectory.getPath(), new String[] { "java" } );
 506  41
         if ( fileList != null && fileList.length != 0 )
 507  
         {
 508  37
             List tmpFiles = getIncludedFiles( sourceDirectory, fileList, excludePackages );
 509  37
             files.addAll( tmpFiles );
 510  
         }
 511  41
     }
 512  
 
 513  
     /**
 514  
      * Call the Javadoc tool and parse its output to find its version, i.e.:
 515  
      * <pre>
 516  
      * javadoc.exe(or .sh) -J-version
 517  
      * </pre>
 518  
      *
 519  
      * @param javadocExe not null file
 520  
      * @return the javadoc version as float
 521  
      * @throws IOException if javadocExe is null, doesn't exist or is not a file
 522  
      * @throws CommandLineException if any
 523  
      * @throws IllegalArgumentException if no output was found in the command line
 524  
      * @throws PatternSyntaxException if the output contains a syntax error in the regular-expression pattern.
 525  
      * @see #parseJavadocVersion(String)
 526  
      */
 527  
     protected static float getJavadocVersion( File javadocExe )
 528  
         throws IOException, CommandLineException, IllegalArgumentException, PatternSyntaxException
 529  
     {
 530  36
         if ( ( javadocExe == null ) || ( !javadocExe.exists() ) || ( !javadocExe.isFile() ) )
 531  
         {
 532  0
             throw new IOException( "The javadoc executable '" + javadocExe + "' doesn't exist or is not a file. " );
 533  
         }
 534  
 
 535  36
         Commandline cmd = new Commandline();
 536  36
         cmd.setExecutable( javadocExe.getAbsolutePath() );
 537  36
         cmd.setWorkingDirectory( javadocExe.getParentFile() );
 538  36
         cmd.createArg().setValue( "-J-version" );
 539  
 
 540  36
         CommandLineUtils.StringStreamConsumer out = new CommandLineUtils.StringStreamConsumer();
 541  36
         CommandLineUtils.StringStreamConsumer err = new CommandLineUtils.StringStreamConsumer();
 542  
 
 543  36
         int exitCode = CommandLineUtils.executeCommandLine( cmd, out, err );
 544  
 
 545  36
         if ( exitCode != 0 )
 546  
         {
 547  0
             StringBuffer msg = new StringBuffer( "Exit code: " + exitCode + " - " + err.getOutput() );
 548  0
             msg.append( '\n' );
 549  0
             msg.append( "Command line was:" + CommandLineUtils.toString( cmd.getCommandline() ) );
 550  0
             throw new CommandLineException( msg.toString() );
 551  
         }
 552  
 
 553  36
         if ( StringUtils.isNotEmpty( err.getOutput() ) )
 554  
         {
 555  36
             return parseJavadocVersion( err.getOutput() );
 556  
         }
 557  0
         else if ( StringUtils.isNotEmpty( out.getOutput() ) )
 558  
         {
 559  0
             return parseJavadocVersion( out.getOutput() );
 560  
         }
 561  
 
 562  0
         throw new IllegalArgumentException( "No output found from the command line 'javadoc -J-version'" );
 563  
     }
 564  
 
 565  
     /**
 566  
      * Parse the output for 'javadoc -J-version' and return the javadoc version recognized.
 567  
      * <br/>
 568  
      * Here are some output for 'javadoc -J-version' depending the JDK used:
 569  
      * <table>
 570  
      * <tr>
 571  
      *   <th>JDK</th>
 572  
      *   <th>Output for 'javadoc -J-version'</th>
 573  
      * </tr>
 574  
      * <tr>
 575  
      *   <td>Sun 1.4</td>
 576  
      *   <td>java full version "1.4.2_12-b03"</td>
 577  
      * </tr>
 578  
      * <tr>
 579  
      *   <td>Sun 1.5</td>
 580  
      *   <td>java full version "1.5.0_07-164"</td>
 581  
      * </tr>
 582  
      * <tr>
 583  
      *   <td>IBM 1.4</td>
 584  
      *   <td>javadoc full version "J2RE 1.4.2 IBM Windows 32 build cn1420-20040626"</td>
 585  
      * </tr>
 586  
      * <tr>
 587  
      *   <td>IBM 1.5 (French JVM)</td>
 588  
      *   <td>javadoc version complète de "J2RE 1.5.0 IBM Windows 32 build pwi32pdev-20070426a"</td>
 589  
      * </tr>
 590  
      * <tr>
 591  
      *   <td>FreeBSD 1.5</td>
 592  
      *   <td>java full version "diablo-1.5.0-b01"</td>
 593  
      * </tr>
 594  
      * <tr>
 595  
      *   <td>BEA jrockit 1.5</td>
 596  
      *   <td>java full version "1.5.0_11-b03"</td>
 597  
      * </tr>
 598  
      * </table>
 599  
      *
 600  
      * @param output for 'javadoc -J-version'
 601  
      * @return the version of the javadoc for the output.
 602  
      * @throws PatternSyntaxException if the output doesn't match with the output pattern
 603  
      * <tt>(?s).*?([0-9]+\\.[0-9]+)(\\.([0-9]+))?.*</tt>.
 604  
      * @throws IllegalArgumentException if the output is null
 605  
      */
 606  
     protected static float parseJavadocVersion( String output )
 607  
         throws IllegalArgumentException, PatternSyntaxException
 608  
     {
 609  53
         if ( StringUtils.isEmpty( output ) )
 610  
         {
 611  1
             throw new IllegalArgumentException( "The output could not be null." );
 612  
         }
 613  
 
 614  52
         Pattern pattern = Pattern.compile( "(?s).*?([0-9]+\\.[0-9]+)(\\.([0-9]+))?.*" );
 615  
 
 616  52
         Matcher matcher = pattern.matcher( output );
 617  52
         if ( !matcher.matches() )
 618  
         {
 619  1
             throw new PatternSyntaxException( "Unrecognized version of Javadoc: '" + output + "'", pattern.pattern(),
 620  
                                               pattern.toString().length() - 1 );
 621  
         }
 622  
 
 623  51
         String version = matcher.group( 3 );
 624  51
         if ( version == null )
 625  
         {
 626  1
             version = matcher.group( 1 );
 627  
         }
 628  
         else
 629  
         {
 630  50
             version = matcher.group( 1 ) + version;
 631  
         }
 632  
 
 633  51
         return Float.parseFloat( version );
 634  
     }
 635  
 
 636  
     /**
 637  
      * Parse a memory string which be used in the JVM arguments <code>-Xms</code> or <code>-Xmx</code>.
 638  
      * <br/>
 639  
      * Here are some supported memory string depending the JDK used:
 640  
      * <table>
 641  
      * <tr>
 642  
      *   <th>JDK</th>
 643  
      *   <th>Memory argument support for <code>-Xms</code> or <code>-Xmx</code></th>
 644  
      * </tr>
 645  
      * <tr>
 646  
      *   <td>SUN</td>
 647  
      *   <td>1024k | 128m | 1g | 1t</td>
 648  
      * </tr>
 649  
      * <tr>
 650  
      *   <td>IBM</td>
 651  
      *   <td>1024k | 1024b | 128m | 128mb | 1g | 1gb</td>
 652  
      * </tr>
 653  
      * <tr>
 654  
      *   <td>BEA</td>
 655  
      *   <td>1024k | 1024kb | 128m | 128mb | 1g | 1gb</td>
 656  
      * </tr>
 657  
      * </table>
 658  
      *
 659  
      * @param memory the memory to be parsed, not null.
 660  
      * @return the memory parsed with a supported unit. If no unit specified in the <code>memory</code> parameter,
 661  
      * the default unit is <code>m</code>. The units <code>g | gb</code> or <code>t | tb</code> will be converted
 662  
      * in <code>m</code>.
 663  
      * @throws IllegalArgumentException if the <code>memory</code> parameter is null or doesn't match any pattern.
 664  
      */
 665  
     protected static String parseJavadocMemory( String memory )
 666  
         throws IllegalArgumentException
 667  
     {
 668  18
         if ( StringUtils.isEmpty( memory ) )
 669  
         {
 670  1
             throw new IllegalArgumentException( "The memory could not be null." );
 671  
         }
 672  
 
 673  17
         Pattern p = Pattern.compile( "^\\s*(\\d+)\\s*?\\s*$" );
 674  17
         Matcher m = p.matcher( memory );
 675  17
         if ( m.matches() )
 676  
         {
 677  2
             return m.group( 1 ) + "m";
 678  
         }
 679  
 
 680  15
         p = Pattern.compile( "^\\s*(\\d+)\\s*k(b)?\\s*$", Pattern.CASE_INSENSITIVE );
 681  15
         m = p.matcher( memory );
 682  15
         if ( m.matches() )
 683  
         {
 684  2
             return m.group( 1 ) + "k";
 685  
         }
 686  
 
 687  13
         p = Pattern.compile( "^\\s*(\\d+)\\s*m(b)?\\s*$", Pattern.CASE_INSENSITIVE );
 688  13
         m = p.matcher( memory );
 689  13
         if ( m.matches() )
 690  
         {
 691  7
             return m.group( 1 ) + "m";
 692  
         }
 693  
 
 694  6
         p = Pattern.compile( "^\\s*(\\d+)\\s*g(b)?\\s*$", Pattern.CASE_INSENSITIVE );
 695  6
         m = p.matcher( memory );
 696  6
         if ( m.matches() )
 697  
         {
 698  2
             return ( Integer.parseInt( m.group( 1 ) ) * 1024 ) + "m";
 699  
         }
 700  
 
 701  4
         p = Pattern.compile( "^\\s*(\\d+)\\s*t(b)?\\s*$", Pattern.CASE_INSENSITIVE );
 702  4
         m = p.matcher( memory );
 703  4
         if ( m.matches() )
 704  
         {
 705  2
             return ( Integer.parseInt( m.group( 1 ) ) * 1024 * 1024 ) + "m";
 706  
         }
 707  
 
 708  2
         throw new IllegalArgumentException( "Could convert not to a memory size: " + memory );
 709  
     }
 710  
 
 711  
     /**
 712  
      * Fetch an URL
 713  
      *
 714  
      * @param settings the user settings used to fetch the url with an active proxy, if defined.
 715  
      * @param url the url to fetch
 716  
      * @throws IOException if any
 717  
      * @see #DEFAULT_TIMEOUT
 718  
      */
 719  
     protected static void fetchURL( Settings settings, URL url )
 720  
         throws IOException
 721  
     {
 722  30
         if ( url == null )
 723  
         {
 724  1
             throw new IllegalArgumentException( "The url is null" );
 725  
         }
 726  
 
 727  29
         HttpClient httpClient = null;
 728  29
         if ( !"file".equals( url.getProtocol() ) )
 729  
         {
 730  26
             httpClient = new HttpClient();
 731  26
             httpClient.getHttpConnectionManager().getParams().setConnectionTimeout( DEFAULT_TIMEOUT );
 732  26
             httpClient.getHttpConnectionManager().getParams().setSoTimeout( DEFAULT_TIMEOUT );
 733  
 
 734  26
             if ( settings != null )
 735  
             {
 736  9
                 Proxy activeProxy = settings.getActiveProxy();
 737  
 
 738  9
                 if ( activeProxy != null )
 739  
                 {
 740  7
                     String proxyHost = settings.getActiveProxy().getHost();
 741  7
                     int proxyPort = settings.getActiveProxy().getPort();
 742  
 
 743  7
                     String proxyUser = settings.getActiveProxy().getUsername();
 744  7
                     String proxyPass = settings.getActiveProxy().getPassword();
 745  
 
 746  7
                     if ( StringUtils.isNotEmpty( proxyHost ) )
 747  
                     {
 748  7
                         httpClient.getHostConfiguration().setProxy( proxyHost, proxyPort );
 749  
                     }
 750  
 
 751  7
                     if ( StringUtils.isNotEmpty( proxyUser ) )
 752  
                     {
 753  5
                         AuthScope authScope =
 754  
                             new AuthScope( AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM,
 755  
                                            AuthScope.ANY_SCHEME );
 756  5
                         UsernamePasswordCredentials usernamePasswordCredentials =
 757  
                             new UsernamePasswordCredentials( proxyUser, proxyPass );
 758  5
                         httpClient.getState().setProxyCredentials( authScope, usernamePasswordCredentials );
 759  
                     }
 760  
                 }
 761  
             }
 762  
         }
 763  
 
 764  29
         InputStream in = null;
 765  
         try
 766  
         {
 767  29
             if ( httpClient != null )
 768  
             {
 769  26
                 GetMethod getMethod = new GetMethod( url.toString() );
 770  
 
 771  
                 try
 772  
                 {
 773  26
                     int status = httpClient.executeMethod( getMethod );
 774  24
                     if ( status != 200 )
 775  
                     {
 776  4
                         throw new FileNotFoundException( url.toString() );
 777  
                     }
 778  
                 }
 779  
                 finally
 780  
                 {
 781  26
                     getMethod.releaseConnection();
 782  20
                 }
 783  20
             }
 784  
             else
 785  
             {
 786  3
                 in = url.openStream();
 787  
             }
 788  
         }
 789  
         finally
 790  
         {
 791  29
             IOUtil.close( in );
 792  23
         }
 793  23
     }
 794  
 
 795  
     /**
 796  
      * Validate if a charset is supported on this platform.
 797  
      *
 798  
      * @param charsetName the charsetName to be check.
 799  
      * @return <code>true</code> if the charset is supported by the JVM, <code>false</code> otherwise.
 800  
      */
 801  
     protected static boolean validateEncoding( String charsetName )
 802  
     {
 803  74
         if ( StringUtils.isEmpty( charsetName ) )
 804  
         {
 805  1
             return false;
 806  
         }
 807  
 
 808  73
         OutputStream ost = new ByteArrayOutputStream();
 809  73
         OutputStreamWriter osw = null;
 810  
         try
 811  
         {
 812  73
             osw = new OutputStreamWriter( ost, charsetName );
 813  
         }
 814  3
         catch ( UnsupportedEncodingException exc )
 815  
         {
 816  3
             return false;
 817  
         }
 818  
         finally
 819  
         {
 820  73
             IOUtil.close( osw );
 821  70
         }
 822  70
         return true;
 823  
     }
 824  
 
 825  
     /**
 826  
      * For security reasons, if an active proxy is defined and needs an authentication by
 827  
      * username/password, hide the proxy password in the command line.
 828  
      *
 829  
      * @param cmdLine a command line, not null
 830  
      * @param settings the user settings
 831  
      * @return the cmdline with '*' for the http.proxyPassword JVM property
 832  
      */
 833  
     protected static String hideProxyPassword( String cmdLine, Settings settings )
 834  
     {
 835  3
         if ( cmdLine == null )
 836  
         {
 837  0
             throw new IllegalArgumentException( "cmdLine could not be null" );
 838  
         }
 839  
 
 840  3
         if ( settings == null )
 841  
         {
 842  2
             return cmdLine;
 843  
         }
 844  
 
 845  1
         Proxy activeProxy = settings.getActiveProxy();
 846  1
         if ( activeProxy != null && StringUtils.isNotEmpty( activeProxy.getHost() )
 847  
             && StringUtils.isNotEmpty( activeProxy.getUsername() )
 848  
             && StringUtils.isNotEmpty( activeProxy.getPassword() ) )
 849  
         {
 850  1
             String pass = "-J-Dhttp.proxyPassword=\"" + activeProxy.getPassword() + "\"";
 851  1
             String hidepass =
 852  
                 "-J-Dhttp.proxyPassword=\"" + StringUtils.repeat( "*", activeProxy.getPassword().length() ) + "\"";
 853  
 
 854  1
             return StringUtils.replace( cmdLine, pass, hidepass );
 855  
         }
 856  
 
 857  0
         return cmdLine;
 858  
     }
 859  
 
 860  
     /**
 861  
      * Auto-detect the class names of the implementation of <code>com.sun.tools.doclets.Taglet</code> class from a
 862  
      * given jar file.
 863  
      * <br/>
 864  
      * <b>Note</b>: <code>JAVA_HOME/lib/tools.jar</code> is a requirement to find
 865  
      * <code>com.sun.tools.doclets.Taglet</code> class.
 866  
      *
 867  
      * @param jarFile not null
 868  
      * @return the list of <code>com.sun.tools.doclets.Taglet</code> class names from a given jarFile.
 869  
      * @throws IOException if jarFile is invalid or not found, or if the <code>JAVA_HOME/lib/tools.jar</code>
 870  
      * is not found.
 871  
      * @throws ClassNotFoundException if any
 872  
      * @throws NoClassDefFoundError if any
 873  
      */
 874  
     protected static List getTagletClassNames( File jarFile )
 875  
         throws IOException, ClassNotFoundException, NoClassDefFoundError
 876  
     {
 877  2
         List classes = getClassNamesFromJar( jarFile );
 878  
         ClassLoader cl;
 879  
 
 880  
         // Needed to find com.sun.tools.doclets.Taglet class
 881  2
         File tools = new File( System.getProperty( "java.home" ), "../lib/tools.jar" );
 882  2
         if ( tools.exists() && tools.isFile() )
 883  
         {
 884  2
             cl = new URLClassLoader( new URL[] { jarFile.toURI().toURL(), tools.toURI().toURL() }, null );
 885  
         }
 886  
         else
 887  
         {
 888  0
             cl = new URLClassLoader( new URL[] { jarFile.toURI().toURL() }, null );
 889  
         }
 890  
 
 891  2
         List tagletClasses = new ArrayList();
 892  
 
 893  2
         Class tagletClass = cl.loadClass( "com.sun.tools.doclets.Taglet" );
 894  2
         for ( Iterator it = classes.iterator(); it.hasNext(); )
 895  
         {
 896  24
             String s = (String) it.next();
 897  
 
 898  24
             Class c = cl.loadClass( s );
 899  
 
 900  24
             if ( tagletClass.isAssignableFrom( c ) && !Modifier.isAbstract( c.getModifiers() ) )
 901  
             {
 902  20
                 tagletClasses.add( c.getName() );
 903  
             }
 904  24
         }
 905  
 
 906  2
         return tagletClasses;
 907  
     }
 908  
 
 909  
     /**
 910  
      * Copy the given url to the given file.
 911  
      *
 912  
      * @param url not null url
 913  
      * @param file not null file where the url will be created
 914  
      * @throws IOException if any
 915  
      * @since 2.6
 916  
      */
 917  
     protected static void copyResource( URL url, File file )
 918  
         throws IOException
 919  
     {
 920  4
         if ( file == null )
 921  
         {
 922  0
             throw new IOException( "The file " + file + " can't be null." );
 923  
         }
 924  4
         if ( url == null )
 925  
         {
 926  0
             throw new IOException( "The url " + url + " could not be null." );
 927  
         }
 928  
 
 929  4
         InputStream is = url.openStream();
 930  4
         if ( is == null )
 931  
         {
 932  0
             throw new IOException( "The resource " + url + " doesn't exists." );
 933  
         }
 934  
 
 935  4
         if ( !file.getParentFile().exists() )
 936  
         {
 937  0
             file.getParentFile().mkdirs();
 938  
         }
 939  
 
 940  4
         FileOutputStream os = null;
 941  
         try
 942  
         {
 943  4
             os = new FileOutputStream( file );
 944  
 
 945  4
             IOUtil.copy( is, os );
 946  
         }
 947  
         finally
 948  
         {
 949  4
             IOUtil.close( is );
 950  
 
 951  4
             IOUtil.close( os );
 952  4
         }
 953  4
     }
 954  
 
 955  
     /**
 956  
      * Invoke Maven for the given project file with a list of goals and properties, the output will be in the
 957  
      * invokerlog file.
 958  
      * <br/>
 959  
      * <b>Note</b>: the Maven Home should be defined in the <code>maven.home</code> Java system property or defined in
 960  
      * <code>M2_HOME</code> system env variables.
 961  
      *
 962  
      * @param log a logger could be null.
 963  
      * @param localRepositoryDir the localRepository not null.
 964  
      * @param projectFile a not null project file.
 965  
      * @param goals a not null goals list.
 966  
      * @param properties the properties for the goals, could be null.
 967  
      * @param invokerLog the log file where the invoker will be written, if null using <code>System.out</code>.
 968  
      * @since 2.6
 969  
      */
 970  
     protected static void invokeMaven( Log log, File localRepositoryDir, File projectFile, List goals,
 971  
                                        Properties properties, File invokerLog )
 972  
     {
 973  4
         if ( projectFile == null )
 974  
         {
 975  0
             throw new IllegalArgumentException( "projectFile should be not null." );
 976  
         }
 977  4
         if ( !projectFile.isFile() )
 978  
         {
 979  0
             throw new IllegalArgumentException( projectFile.getAbsolutePath() + " is not a file." );
 980  
         }
 981  4
         if ( goals == null || goals.size() == 0 )
 982  
         {
 983  0
             throw new IllegalArgumentException( "goals should be not empty." );
 984  
         }
 985  4
         if ( localRepositoryDir == null || !localRepositoryDir.isDirectory() )
 986  
         {
 987  0
             throw new IllegalArgumentException( "localRepositoryDir '" + localRepositoryDir
 988  
                 + "' should be a directory." );
 989  
         }
 990  
 
 991  4
         String mavenHome = getMavenHome( log );
 992  4
         if ( StringUtils.isEmpty( mavenHome ) )
 993  
         {
 994  0
             String msg =
 995  
                 "Could NOT invoke Maven because no Maven Home is defined. You need to have set the M2_HOME "
 996  
                     + "system env variable or a maven.home Java system properties.";
 997  0
             if ( log != null )
 998  
             {
 999  0
                 log.error( msg );
 1000  
             }
 1001  
             else
 1002  
             {
 1003  0
                 System.err.println( msg );
 1004  
             }
 1005  0
             return;
 1006  
         }
 1007  
 
 1008  4
         Invoker invoker = new DefaultInvoker();
 1009  4
         invoker.setMavenHome( new File( mavenHome ) );
 1010  4
         invoker.setLocalRepositoryDirectory( localRepositoryDir );
 1011  
 
 1012  4
         InvocationRequest request = new DefaultInvocationRequest();
 1013  4
         request.setBaseDirectory( projectFile.getParentFile() );
 1014  4
         request.setPomFile( projectFile );
 1015  4
         if ( log != null )
 1016  
         {
 1017  4
             request.setDebug( log.isDebugEnabled() );
 1018  
         }
 1019  
         else
 1020  
         {
 1021  0
             request.setDebug( true );
 1022  
         }
 1023  4
         request.setGoals( goals );
 1024  4
         if ( properties != null )
 1025  
         {
 1026  2
             request.setProperties( properties );
 1027  
         }
 1028  4
         File javaHome = getJavaHome( log );
 1029  4
         if ( javaHome != null )
 1030  
         {
 1031  4
             request.setJavaHome( javaHome );
 1032  
         }
 1033  
 
 1034  
         InvocationResult result;
 1035  
         try
 1036  
         {
 1037  4
             if ( log != null )
 1038  
             {
 1039  4
                 log.debug( "Invoking Maven for the goals: " + goals + " with properties=" + properties );
 1040  
             }
 1041  4
             result = invoke( log, invoker, request, invokerLog, goals, properties, null );
 1042  
         }
 1043  0
         catch ( MavenInvocationException e )
 1044  
         {
 1045  0
             if ( log != null )
 1046  
             {
 1047  0
                 if ( log.isDebugEnabled() )
 1048  
                 {
 1049  0
                     log.error( "MavenInvocationException: " + e.getMessage(), e );
 1050  
                 }
 1051  
                 else
 1052  
                 {
 1053  0
                     log.error( "MavenInvocationException: " + e.getMessage() );
 1054  
                 }
 1055  0
                 log.error( "Error when invoking Maven, consult the invoker log." );
 1056  
             }
 1057  0
             return;
 1058  4
         }
 1059  
 
 1060  4
         String invokerLogContent = null;
 1061  4
         Reader reader = null;
 1062  
         try
 1063  
         {
 1064  4
             reader = ReaderFactory.newReader( invokerLog, "UTF-8" );
 1065  4
             invokerLogContent = IOUtil.toString( reader );
 1066  
         }
 1067  0
         catch ( IOException e )
 1068  
         {
 1069  0
             if ( log != null )
 1070  
             {
 1071  0
                 log.error( "IOException: " + e.getMessage() );
 1072  
             }
 1073  
         }
 1074  
         finally
 1075  
         {
 1076  4
             IOUtil.close( reader );
 1077  4
         }
 1078  
 
 1079  4
         if ( invokerLogContent != null
 1080  
             && invokerLogContent.indexOf( "Error occurred during initialization of VM" ) != -1 )
 1081  
         {
 1082  0
             if ( log != null )
 1083  
             {
 1084  0
                 log.info( "Error occurred during initialization of VM, try to use an empty MAVEN_OPTS." );
 1085  
 
 1086  0
                 log.debug( "Reinvoking Maven for the goals: " + goals + " with an empty MAVEN_OPTS" );
 1087  
             }
 1088  
             try
 1089  
             {
 1090  0
                 result = invoke( log, invoker, request, invokerLog, goals, properties, "" );
 1091  
             }
 1092  0
             catch ( MavenInvocationException e )
 1093  
             {
 1094  0
                 if ( log != null )
 1095  
                 {
 1096  0
                     if ( log.isDebugEnabled() )
 1097  
                     {
 1098  0
                         log.error( "MavenInvocationException: " + e.getMessage(), e );
 1099  
                     }
 1100  
                     else
 1101  
                     {
 1102  0
                         log.error( "MavenInvocationException: " + e.getMessage() );
 1103  
                     }
 1104  0
                     log.error( "Error when reinvoking Maven, consult the invoker log." );
 1105  
                 }
 1106  0
                 return;
 1107  0
             }
 1108  
         }
 1109  
 
 1110  4
         if ( result.getExitCode() != 0 )
 1111  
         {
 1112  0
             if ( log != null )
 1113  
             {
 1114  0
                 log.error( "Error when invoking Maven, consult the invoker log file: "
 1115  
                     + invokerLog.getAbsolutePath() );
 1116  
             }
 1117  
         }
 1118  4
     }
 1119  
 
 1120  
     // ----------------------------------------------------------------------
 1121  
     // private methods
 1122  
     // ----------------------------------------------------------------------
 1123  
 
 1124  
     /**
 1125  
      * @param jarFile not null
 1126  
      * @return all class names from the given jar file.
 1127  
      * @throws IOException if any or if the jarFile is null or doesn't exist.
 1128  
      */
 1129  
     private static List getClassNamesFromJar( File jarFile )
 1130  
         throws IOException
 1131  
     {
 1132  2
         if ( jarFile == null || !jarFile.exists() || !jarFile.isFile() )
 1133  
         {
 1134  0
             throw new IOException( "The jar '" + jarFile + "' doesn't exist or is not a file." );
 1135  
         }
 1136  
 
 1137  2
         List classes = new ArrayList();
 1138  2
         JarInputStream jarStream = null;
 1139  
 
 1140  
         try
 1141  
         {
 1142  2
             jarStream = new JarInputStream( new FileInputStream( jarFile ) );
 1143  2
             JarEntry jarEntry = jarStream.getNextJarEntry();
 1144  48
             while ( jarEntry != null )
 1145  
             {
 1146  46
                 if ( jarEntry == null )
 1147  
                 {
 1148  0
                     break;
 1149  
                 }
 1150  
 
 1151  46
                 if ( jarEntry.getName().toLowerCase( Locale.ENGLISH ).endsWith( ".class" ) )
 1152  
                 {
 1153  24
                     String name = jarEntry.getName().substring( 0, jarEntry.getName().indexOf( "." ) );
 1154  
 
 1155  24
                     classes.add( name.replaceAll( "/", "\\." ) );
 1156  
                 }
 1157  
 
 1158  46
                 jarStream.closeEntry();
 1159  46
                 jarEntry = jarStream.getNextJarEntry();
 1160  
             }
 1161  
         }
 1162  
         finally
 1163  
         {
 1164  2
             IOUtil.close( jarStream );
 1165  2
         }
 1166  
 
 1167  2
         return classes;
 1168  
     }
 1169  
 
 1170  
     /**
 1171  
      * @param log could be null
 1172  
      * @param invoker not null
 1173  
      * @param request not null
 1174  
      * @param invokerLog not null
 1175  
      * @param goals not null
 1176  
      * @param properties could be null
 1177  
      * @param mavenOpts could be null
 1178  
      * @return the invocation result
 1179  
      * @throws MavenInvocationException if any
 1180  
      * @since 2.6
 1181  
      */
 1182  
     private static InvocationResult invoke( Log log, Invoker invoker, InvocationRequest request, File invokerLog,
 1183  
                                             List goals, Properties properties, String mavenOpts )
 1184  
         throws MavenInvocationException
 1185  
     {
 1186  
         PrintStream ps;
 1187  4
         OutputStream os = null;
 1188  4
         if ( invokerLog != null )
 1189  
         {
 1190  4
             log.debug( "Using " + invokerLog.getAbsolutePath() + " to log the invoker" );
 1191  
 
 1192  
             try
 1193  
             {
 1194  4
                 if ( !invokerLog.exists() )
 1195  
                 {
 1196  2
                     invokerLog.getParentFile().mkdirs();
 1197  
                 }
 1198  4
                 os = new FileOutputStream( invokerLog );
 1199  4
                 ps = new PrintStream( os, true, "UTF-8" );
 1200  
             }
 1201  0
             catch ( FileNotFoundException e )
 1202  
             {
 1203  0
                 if ( log != null )
 1204  
                 {
 1205  0
                     log.error( "FileNotFoundException: " + e.getMessage() + ". Using System.out to log the invoker." );
 1206  
                 }
 1207  0
                 ps = System.out;
 1208  
             }
 1209  0
             catch ( UnsupportedEncodingException e )
 1210  
             {
 1211  0
                 if ( log != null )
 1212  
                 {
 1213  0
                     log.error( "UnsupportedEncodingException: " + e.getMessage()
 1214  
                         + ". Using System.out to log the invoker." );
 1215  
                 }
 1216  0
                 ps = System.out;
 1217  4
             }
 1218  
         }
 1219  
         else
 1220  
         {
 1221  0
             log.debug( "Using System.out to log the invoker." );
 1222  
 
 1223  0
             ps = System.out;
 1224  
         }
 1225  
 
 1226  4
         if ( mavenOpts != null )
 1227  
         {
 1228  0
             request.setMavenOpts( mavenOpts );
 1229  
         }
 1230  
 
 1231  4
         InvocationOutputHandler outputHandler = new PrintStreamHandler( ps, false );
 1232  4
         request.setOutputHandler( outputHandler );
 1233  
 
 1234  4
         outputHandler.consumeLine( "Invoking Maven for the goals: " + goals + " with properties=" + properties );
 1235  4
         outputHandler.consumeLine( "" );
 1236  4
         outputHandler.consumeLine( "M2_HOME=" + getMavenHome( log ) );
 1237  4
         outputHandler.consumeLine( "MAVEN_OPTS=" + getMavenOpts( log ) );
 1238  4
         outputHandler.consumeLine( "JAVA_HOME=" + getJavaHome( log ) );
 1239  4
         outputHandler.consumeLine( "JAVA_OPTS=" + getJavaOpts( log ) );
 1240  4
         outputHandler.consumeLine( "" );
 1241  
 
 1242  
         try
 1243  
         {
 1244  4
             return invoker.execute( request );
 1245  
         }
 1246  
         finally
 1247  
         {
 1248  4
             IOUtil.close( os );
 1249  4
             ps = null;
 1250  
         }
 1251  
     }
 1252  
 
 1253  
     /**
 1254  
      * @param log a logger could be null
 1255  
      * @return the Maven home defined in the <code>maven.home</code> system property or defined
 1256  
      * in <code>M2_HOME</code> system env variables or null if never setted.
 1257  
      * @since 2.6
 1258  
      */
 1259  
     private static String getMavenHome( Log log )
 1260  
     {
 1261  8
         String mavenHome = System.getProperty( "maven.home" );
 1262  8
         if ( mavenHome == null )
 1263  
         {
 1264  
             try
 1265  
             {
 1266  8
                 mavenHome = CommandLineUtils.getSystemEnvVars().getProperty( "M2_HOME" );
 1267  
             }
 1268  0
             catch ( IOException e )
 1269  
             {
 1270  0
                 if ( log != null )
 1271  
                 {
 1272  0
                     log.debug( "IOException: " + e.getMessage() );
 1273  
                 }
 1274  8
             }
 1275  
         }
 1276  
 
 1277  8
         File m2Home = new File( mavenHome );
 1278  8
         if ( !m2Home.exists() )
 1279  
         {
 1280  0
             if ( log != null )
 1281  
             {
 1282  0
                 log
 1283  
                    .error( "Cannot find Maven application directory. Either specify \'maven.home\' system property, or "
 1284  
                        + "M2_HOME environment variable." );
 1285  
             }
 1286  
         }
 1287  
 
 1288  8
         return mavenHome;
 1289  
     }
 1290  
 
 1291  
     /**
 1292  
      * @param log a logger could be null
 1293  
      * @return the <code>MAVEN_OPTS</code> env variable value
 1294  
      * @since 2.6
 1295  
      */
 1296  
     private static String getMavenOpts( Log log )
 1297  
     {
 1298  4
         String mavenOpts = null;
 1299  
         try
 1300  
         {
 1301  4
             mavenOpts = CommandLineUtils.getSystemEnvVars().getProperty( "MAVEN_OPTS" );
 1302  
         }
 1303  0
         catch ( IOException e )
 1304  
         {
 1305  0
             if ( log != null )
 1306  
             {
 1307  0
                 log.debug( "IOException: " + e.getMessage() );
 1308  
             }
 1309  4
         }
 1310  
 
 1311  4
         return mavenOpts;
 1312  
     }
 1313  
 
 1314  
     /**
 1315  
      * @param log a logger could be null
 1316  
      * @return the <code>JAVA_HOME</code> from System.getProperty( "java.home" )
 1317  
      * By default, <code>System.getProperty( "java.home" ) = JRE_HOME</code> and <code>JRE_HOME</code>
 1318  
      * should be in the <code>JDK_HOME</code>
 1319  
      * @since 2.6
 1320  
      */
 1321  
     private static File getJavaHome( Log log )
 1322  
     {
 1323  
         File javaHome;
 1324  8
         if ( SystemUtils.IS_OS_MAC_OSX )
 1325  
         {
 1326  0
             javaHome = SystemUtils.getJavaHome();
 1327  
         }
 1328  
         else
 1329  
         {
 1330  8
             javaHome = new File( SystemUtils.getJavaHome(), ".." );
 1331  
         }
 1332  
 
 1333  8
         if ( javaHome == null || !javaHome.exists() )
 1334  
         {
 1335  
             try
 1336  
             {
 1337  0
                 javaHome = new File( CommandLineUtils.getSystemEnvVars().getProperty( "JAVA_HOME" ) );
 1338  
             }
 1339  0
             catch ( IOException e )
 1340  
             {
 1341  0
                 if ( log != null )
 1342  
                 {
 1343  0
                     log.debug( "IOException: " + e.getMessage() );
 1344  
                 }
 1345  0
             }
 1346  
         }
 1347  
 
 1348  8
         if ( javaHome == null || !javaHome.exists() )
 1349  
         {
 1350  0
             if ( log != null )
 1351  
             {
 1352  0
                 log.error( "Cannot find Java application directory. Either specify \'java.home\' system property, or "
 1353  
                     + "JAVA_HOME environment variable." );
 1354  
             }
 1355  
         }
 1356  
 
 1357  8
         return javaHome;
 1358  
     }
 1359  
 
 1360  
     /**
 1361  
      * @param log a logger could be null
 1362  
      * @return the <code>JAVA_OPTS</code> env variable value
 1363  
      * @since 2.6
 1364  
      */
 1365  
     private static String getJavaOpts( Log log )
 1366  
     {
 1367  4
         String javaOpts = null;
 1368  
         try
 1369  
         {
 1370  4
             javaOpts = CommandLineUtils.getSystemEnvVars().getProperty( "JAVA_OPTS" );
 1371  
         }
 1372  0
         catch ( IOException e )
 1373  
         {
 1374  0
             if ( log != null )
 1375  
             {
 1376  0
                 log.debug( "IOException: " + e.getMessage() );
 1377  
             }
 1378  4
         }
 1379  
 
 1380  4
         return javaOpts;
 1381  
     }
 1382  
 }