Coverage Report - org.apache.maven.plugin.javadoc.JavadocUtil
 
Classes in this File Line Coverage Branch Coverage Complexity
JavadocUtil
79%
390/493
60%
241/396
6.957
JavadocUtil$PathTokenizer
39%
15/38
21%
9/42
6.957
 
 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 org.apache.commons.httpclient.Credentials;
 23  
 import org.apache.commons.httpclient.HttpClient;
 24  
 import org.apache.commons.httpclient.HttpStatus;
 25  
 import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
 26  
 import org.apache.commons.httpclient.UsernamePasswordCredentials;
 27  
 import org.apache.commons.httpclient.auth.AuthScope;
 28  
 import org.apache.commons.httpclient.methods.GetMethod;
 29  
 import org.apache.commons.httpclient.params.HttpClientParams;
 30  
 import org.apache.commons.httpclient.params.HttpMethodParams;
 31  
 import org.apache.commons.lang.SystemUtils;
 32  
 import org.apache.maven.artifact.Artifact;
 33  
 import org.apache.maven.plugin.logging.Log;
 34  
 import org.apache.maven.project.MavenProject;
 35  
 import org.apache.maven.settings.Proxy;
 36  
 import org.apache.maven.settings.Settings;
 37  
 import org.apache.maven.shared.invoker.DefaultInvocationRequest;
 38  
 import org.apache.maven.shared.invoker.DefaultInvoker;
 39  
 import org.apache.maven.shared.invoker.InvocationOutputHandler;
 40  
 import org.apache.maven.shared.invoker.InvocationRequest;
 41  
 import org.apache.maven.shared.invoker.InvocationResult;
 42  
 import org.apache.maven.shared.invoker.Invoker;
 43  
 import org.apache.maven.shared.invoker.MavenInvocationException;
 44  
 import org.apache.maven.shared.invoker.PrintStreamHandler;
 45  
 import org.apache.maven.wagon.proxy.ProxyInfo;
 46  
 import org.apache.maven.wagon.proxy.ProxyUtils;
 47  
 import org.codehaus.plexus.util.DirectoryScanner;
 48  
 import org.codehaus.plexus.util.FileUtils;
 49  
 import org.codehaus.plexus.util.IOUtil;
 50  
 import org.codehaus.plexus.util.Os;
 51  
 import org.codehaus.plexus.util.StringUtils;
 52  
 import org.codehaus.plexus.util.cli.CommandLineException;
 53  
 import org.codehaus.plexus.util.cli.CommandLineUtils;
 54  
 import org.codehaus.plexus.util.cli.Commandline;
 55  
 
 56  
 import java.io.BufferedReader;
 57  
 import java.io.ByteArrayOutputStream;
 58  
 import java.io.File;
 59  
 import java.io.FileInputStream;
 60  
 import java.io.FileNotFoundException;
 61  
 import java.io.FileOutputStream;
 62  
 import java.io.IOException;
 63  
 import java.io.InputStream;
 64  
 import java.io.InputStreamReader;
 65  
 import java.io.OutputStream;
 66  
 import java.io.OutputStreamWriter;
 67  
 import java.io.PrintStream;
 68  
 import java.io.UnsupportedEncodingException;
 69  
 import java.lang.reflect.Modifier;
 70  
 import java.net.SocketTimeoutException;
 71  
 import java.net.URL;
 72  
 import java.net.URLClassLoader;
 73  
 import java.util.ArrayList;
 74  
 import java.util.Arrays;
 75  
 import java.util.Collection;
 76  
 import java.util.Collections;
 77  
 import java.util.List;
 78  
 import java.util.Locale;
 79  
 import java.util.NoSuchElementException;
 80  
 import java.util.Properties;
 81  
 import java.util.Set;
 82  
 import java.util.StringTokenizer;
 83  
 import java.util.jar.JarEntry;
 84  
 import java.util.jar.JarInputStream;
 85  
 import java.util.regex.Matcher;
 86  
 import java.util.regex.Pattern;
 87  
 import java.util.regex.PatternSyntaxException;
 88  
 
 89  
 /**
 90  
  * Set of utilities methods for Javadoc.
 91  
  *
 92  
  * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
 93  
  * @version $Id: JavadocUtil.java 1385116 2012-09-15 16:31:25Z hboutemy $
 94  
  * @since 2.4
 95  
  */
 96  0
 public class JavadocUtil
 97  
 {
 98  
     /** The default timeout used when fetching url, i.e. 2000. */
 99  
     public static final int DEFAULT_TIMEOUT = 2000;
 100  
 
 101  
     /** Error message when VM could not be started using invoker. */
 102  
     protected static final String ERROR_INIT_VM =
 103  
         "Error occurred during initialization of VM, try to reduce the Java heap size for the MAVEN_OPTS "
 104  
         + "environnement variable using -Xms:<size> and -Xmx:<size>.";
 105  
 
 106  
     /**
 107  
      * Method that removes the invalid directories in the specified directories.
 108  
      * <b>Note</b>: All elements in <code>dirs</code> could be an absolute or relative against the project's base
 109  
      * directory <code>String</code> path.
 110  
      *
 111  
      * @param project the current Maven project not null
 112  
      * @param dirs the list of <code>String</code> directories path that will be validated.
 113  
      * @return a List of valid <code>String</code> directories absolute paths.
 114  
      */
 115  
     public static List<String> pruneDirs( MavenProject project, List<String> dirs )
 116  
     {
 117  101
         List<String> pruned = new ArrayList<String>( dirs.size() );
 118  101
         for ( String dir : dirs )
 119  
         {
 120  110
             if ( dir == null )
 121  
             {
 122  0
                 continue;
 123  
             }
 124  
 
 125  110
             File directory = new File( dir );
 126  110
             if ( !directory.isAbsolute() )
 127  
             {
 128  0
                 directory = new File( project.getBasedir(), directory.getPath() );
 129  
             }
 130  
 
 131  110
             if ( directory.isDirectory() && !pruned.contains( directory.getAbsolutePath() ) )
 132  
             {
 133  100
                 pruned.add( directory.getAbsolutePath() );
 134  
             }
 135  110
         }
 136  
 
 137  101
         return pruned;
 138  
     }
 139  
 
 140  
     /**
 141  
      * Method that removes the invalid files in the specified files.
 142  
      * <b>Note</b>: All elements in <code>files</code> should be an absolute <code>String</code> path.
 143  
      *
 144  
      * @param files the list of <code>String</code> files paths that will be validated.
 145  
      * @return a List of valid <code>File</code> objects.
 146  
      */
 147  
     protected static List<String> pruneFiles( List<String> files )
 148  
     {
 149  42
         List<String> pruned = new ArrayList<String>( files.size() );
 150  42
         for ( String f : files )
 151  
         {
 152  2
             if ( !shouldPruneFile( f, pruned ) )
 153  
             {
 154  2
                 pruned.add( f );
 155  
             }
 156  
         }
 157  
  
 158  42
         return pruned;
 159  
     }
 160  
 
 161  
     /**
 162  
      * Determine whether a file should be excluded from the provided list of paths, based on whether
 163  
      * it exists and is already present in the list.
 164  
      */
 165  
     public static boolean shouldPruneFile( String f, List<String> pruned )
 166  
     {
 167  2
         if ( f != null )
 168  
         {
 169  2
             File file = new File( f );
 170  2
             if ( file.isFile() && ( isEmpty( pruned ) || !pruned.contains( f ) ) )
 171  
             {
 172  2
                 return false;
 173  
             }
 174  
         }
 175  
         
 176  0
         return true;
 177  
     }
 178  
 
 179  
     /**
 180  
      * Method that gets all the source files to be excluded from the javadoc on the given
 181  
      * source paths.
 182  
      *
 183  
      * @param sourcePaths      the path to the source files
 184  
      * @param subpackagesList  list of subpackages to be included in the javadoc
 185  
      * @param excludedPackages the package names to be excluded in the javadoc
 186  
      * @return a List of the source files to be excluded in the generated javadoc
 187  
      */
 188  
     protected static List<String> getExcludedNames( List<String> sourcePaths, String[] subpackagesList,
 189  
                                                     String[] excludedPackages )
 190  
     {
 191  1
         List<String> excludedNames = new ArrayList<String>();
 192  1
         for ( String path : sourcePaths )
 193  
         {
 194  2
             for ( int j = 0; j < subpackagesList.length; j++ )
 195  
             {
 196  1
                 List<String> excludes = getExcludedPackages( path, excludedPackages );
 197  1
                 excludedNames.addAll( excludes );
 198  
             }
 199  
         }
 200  
 
 201  1
         return excludedNames;
 202  
     }
 203  
 
 204  
     /**
 205  
      * Copy from {@link org.apache.maven.project.MavenProject#getCompileArtifacts()}
 206  
      * @param artifacts not null
 207  
      * @return list of compile artifacts with compile scope
 208  
      * @deprecated since 2.5, using {@link #getCompileArtifacts(Set, boolean)} instead of.
 209  
      */
 210  
     protected static List<Artifact> getCompileArtifacts( Set<Artifact> artifacts )
 211  
     {
 212  0
         return getCompileArtifacts( artifacts, false );
 213  
     }
 214  
 
 215  
     /**
 216  
      * Copy from {@link org.apache.maven.project.MavenProject#getCompileArtifacts()}
 217  
      * @param artifacts not null
 218  
      * @param withTestScope flag to include or not the artifacts with test scope
 219  
      * @return list of compile artifacts with or without test scope.
 220  
      */
 221  
     protected static List<Artifact> getCompileArtifacts( Set<Artifact> artifacts, boolean withTestScope )
 222  
     {
 223  0
         List<Artifact> list = new ArrayList<Artifact>( artifacts.size() );
 224  
 
 225  0
         for ( Artifact a : artifacts )
 226  
         {
 227  
             // TODO: classpath check doesn't belong here - that's the other method
 228  0
             if ( a.getArtifactHandler().isAddedToClasspath() )
 229  
             {
 230  
                 // TODO: let the scope handler deal with this
 231  0
                 if ( withTestScope )
 232  
                 {
 233  0
                     if ( Artifact.SCOPE_COMPILE.equals( a.getScope() )
 234  
                         || Artifact.SCOPE_PROVIDED.equals( a.getScope() )
 235  
                         || Artifact.SCOPE_SYSTEM.equals( a.getScope() )
 236  
                         || Artifact.SCOPE_TEST.equals( a.getScope() ) )
 237  
                     {
 238  0
                         list.add( a );
 239  
                     }
 240  
                 }
 241  
                 else
 242  
                 {
 243  0
                     if ( Artifact.SCOPE_COMPILE.equals( a.getScope() ) || Artifact.SCOPE_PROVIDED.equals( a.getScope() )
 244  
                         || Artifact.SCOPE_SYSTEM.equals( a.getScope() ) )
 245  
                     {
 246  0
                         list.add( a );
 247  
                     }
 248  
                 }
 249  
             }
 250  
         }
 251  
 
 252  0
         return list;
 253  
     }
 254  
 
 255  
     /**
 256  
      * Convenience method to wrap an argument value in single quotes (i.e. <code>'</code>). Intended for values
 257  
      * which may contain whitespaces.
 258  
      * <br/>
 259  
      * To prevent javadoc error, the line separator (i.e. <code>\n</code>) are skipped.
 260  
      *
 261  
      * @param value the argument value.
 262  
      * @return argument with quote
 263  
      */
 264  
     protected static String quotedArgument( String value )
 265  
     {
 266  534
         String arg = value;
 267  
 
 268  534
         if ( StringUtils.isNotEmpty( arg ) )
 269  
         {
 270  189
             if ( arg.indexOf( "'" ) != -1 )
 271  
             {
 272  0
                 arg = StringUtils.replace( arg, "'", "\\'" );
 273  
             }
 274  189
             arg = "'" + arg + "'";
 275  
 
 276  
             // To prevent javadoc error
 277  189
             arg = StringUtils.replace( arg, "\n", " " );
 278  
         }
 279  
 
 280  534
         return arg;
 281  
     }
 282  
 
 283  
     /**
 284  
      * Convenience method to format a path argument so that it is properly interpreted by the javadoc tool. Intended
 285  
      * for path values which may contain whitespaces.
 286  
      *
 287  
      * @param value the argument value.
 288  
      * @return path argument with quote
 289  
      */
 290  
     protected static String quotedPathArgument( String value )
 291  
     {
 292  396
         String path = value;
 293  
 
 294  396
         if ( StringUtils.isNotEmpty( path ) )
 295  
         {
 296  176
             path = path.replace( '\\', '/' );
 297  176
             if ( path.indexOf( "\'" ) != -1 )
 298  
             {
 299  4
                 String split[] = path.split( "\'" );
 300  4
                 path = "";
 301  
 
 302  12
                 for ( int i = 0; i < split.length; i++ )
 303  
                 {
 304  8
                     if ( i != split.length - 1 )
 305  
                     {
 306  4
                         path = path + split[i] + "\\'";
 307  
                     }
 308  
                     else
 309  
                     {
 310  4
                         path = path + split[i];
 311  
                     }
 312  
                 }
 313  
             }
 314  176
             path = "'" + path + "'";
 315  
         }
 316  
 
 317  396
         return path;
 318  
     }
 319  
 
 320  
     /**
 321  
      * Convenience method that copy all <code>doc-files</code> directories from <code>javadocDir</code>
 322  
      * to the <code>outputDirectory</code>.
 323  
      *
 324  
      * @param outputDirectory the output directory
 325  
      * @param javadocDir the javadoc directory
 326  
      * @throws IOException if any
 327  
      * @deprecated since 2.5, using {@link #copyJavadocResources(File, File, String)} instead of.
 328  
      */
 329  
     protected static void copyJavadocResources( File outputDirectory, File javadocDir )
 330  
         throws IOException
 331  
     {
 332  0
         copyJavadocResources( outputDirectory, javadocDir, null );
 333  0
     }
 334  
 
 335  
     /**
 336  
      * Convenience method that copy all <code>doc-files</code> directories from <code>javadocDir</code>
 337  
      * to the <code>outputDirectory</code>.
 338  
      *
 339  
      * @param outputDirectory the output directory
 340  
      * @param javadocDir the javadoc directory
 341  
      * @param excludedocfilessubdir the excludedocfilessubdir parameter
 342  
      * @throws IOException if any
 343  
      * @since 2.5
 344  
      */
 345  
     protected static void copyJavadocResources( File outputDirectory, File javadocDir, String excludedocfilessubdir )
 346  
         throws IOException
 347  
     {
 348  8
         if ( !javadocDir.isDirectory() )
 349  
         {
 350  1
             return;
 351  
         }
 352  
 
 353  7
         List<String> excludes = new ArrayList<String>();
 354  7
         excludes.addAll( Arrays.asList( FileUtils.getDefaultExcludes() ) );
 355  
 
 356  7
         if ( StringUtils.isNotEmpty( excludedocfilessubdir ) )
 357  
         {
 358  2
             StringTokenizer st = new StringTokenizer( excludedocfilessubdir, ":" );
 359  
             String current;
 360  5
             while ( st.hasMoreTokens() )
 361  
             {
 362  3
                 current = st.nextToken();
 363  3
                 excludes.add( "**/" + current + "/**" );
 364  
             }
 365  
         }
 366  
 
 367  7
         List<String> docFiles =
 368  
             FileUtils.getDirectoryNames( javadocDir, "resources,**/doc-files",
 369  
                                          StringUtils.join( excludes.iterator(), "," ), false, true );
 370  7
         for ( String docFile : docFiles )
 371  
         {
 372  10
             File docFileOutput = new File( outputDirectory, docFile );
 373  10
             FileUtils.mkdir( docFileOutput.getAbsolutePath() );
 374  10
             FileUtils.copyDirectoryStructure( new File( javadocDir, docFile ), docFileOutput );
 375  10
             List<String> files =
 376  
                 FileUtils.getFileAndDirectoryNames( docFileOutput, StringUtils.join( excludes.iterator(), "," ),
 377  
                                                     null, true, true, true, true );
 378  10
             for ( String filename : files )
 379  
             {
 380  11
                 File file = new File( filename );
 381  
 
 382  11
                 if ( file.isDirectory() )
 383  
                 {
 384  3
                     FileUtils.deleteDirectory( file );
 385  
                 }
 386  
                 else
 387  
                 {
 388  8
                     file.delete();
 389  
                 }
 390  11
             }
 391  10
         }
 392  7
     }
 393  
 
 394  
     /**
 395  
      * Method that gets the files or classes that would be included in the javadocs using the subpackages
 396  
      * parameter.
 397  
      *
 398  
      * @param sourceDirectory the directory where the source files are located
 399  
      * @param fileList        the list of all files found in the sourceDirectory
 400  
      * @param excludePackages package names to be excluded in the javadoc
 401  
      * @return a StringBuilder that contains the appended file names of the files to be included in the javadoc
 402  
      */
 403  
     protected static List<String> getIncludedFiles( File sourceDirectory, String[] fileList, String[] excludePackages )
 404  
     {
 405  44
         List<String> files = new ArrayList<String>();
 406  
 
 407  126
         for ( int j = 0; j < fileList.length; j++ )
 408  
         {
 409  82
             boolean include = true;
 410  91
             for ( int k = 0; k < excludePackages.length && include; k++ )
 411  
             {
 412  
                 // handle wildcards (*) in the excludePackageNames
 413  9
                 String[] excludeName = excludePackages[k].split( "[*]" );
 414  
 
 415  9
                 if ( excludeName.length == 0 )
 416  
                 {
 417  0
                     continue;
 418  
                 }
 419  
 
 420  9
                 if ( excludeName.length > 1 )
 421  
                 {
 422  5
                     int u = 0;
 423  15
                     while ( include && u < excludeName.length )
 424  
                     {
 425  10
                         if ( !"".equals( excludeName[u].trim() ) && fileList[j].indexOf( excludeName[u] ) != -1 )
 426  
                         {
 427  1
                             include = false;
 428  
                         }
 429  10
                         u++;
 430  
                     }
 431  5
                 }
 432  
                 else
 433  
                 {
 434  4
                     if ( fileList[j].startsWith( sourceDirectory.toString() + File.separatorChar + excludeName[0] ) )
 435  
                     {
 436  2
                         if ( excludeName[0].endsWith( String.valueOf( File.separatorChar ) ) )
 437  
                         {
 438  2
                             int i = fileList[j].lastIndexOf( File.separatorChar );
 439  2
                             String packageName = fileList[j].substring( 0, i + 1 );
 440  2
                             File currentPackage = new File( packageName );
 441  2
                             File excludedPackage = new File( sourceDirectory, excludeName[0] );
 442  2
                             if ( currentPackage.equals( excludedPackage )
 443  
                                 && fileList[j].substring( i ).indexOf( ".java" ) != -1 )
 444  
                             {
 445  1
                                 include = true;
 446  
                             }
 447  
                             else
 448  
                             {
 449  1
                                 include = false;
 450  
                             }
 451  2
                         }
 452  
                         else
 453  
                         {
 454  0
                             include = false;
 455  
                         }
 456  
                     }
 457  
                 }
 458  
             }
 459  
 
 460  82
             if ( include )
 461  
             {
 462  80
                 files.add( quotedPathArgument( fileList[j] ) );
 463  
             }
 464  
         }
 465  
 
 466  44
         return files;
 467  
     }
 468  
 
 469  
     /**
 470  
      * Method that gets the complete package names (including subpackages) of the packages that were defined
 471  
      * in the excludePackageNames parameter.
 472  
      *
 473  
      * @param sourceDirectory     the directory where the source files are located
 474  
      * @param excludePackagenames package names to be excluded in the javadoc
 475  
      * @return a List of the packagenames to be excluded
 476  
      */
 477  
     protected static List<String> getExcludedPackages( String sourceDirectory, String[] excludePackagenames )
 478  
     {
 479  1
         List<String> files = new ArrayList<String>();
 480  3
         for ( int i = 0; i < excludePackagenames.length; i++ )
 481  
         {
 482  2
             String[] fileList = FileUtils.getFilesFromExtension( sourceDirectory, new String[] { "java" } );
 483  16
             for ( int j = 0; j < fileList.length; j++ )
 484  
             {
 485  14
                 String[] excludeName = excludePackagenames[i].split( "[*]" );
 486  14
                 int u = 0;
 487  28
                 while ( u < excludeName.length )
 488  
                 {
 489  14
                     if ( !"".equals( excludeName[u].trim() ) && fileList[j].indexOf( excludeName[u] ) != -1
 490  
                         && sourceDirectory.indexOf( excludeName[u] ) == -1 )
 491  
                     {
 492  2
                         files.add( fileList[j] );
 493  
                     }
 494  14
                     u++;
 495  
                 }
 496  
             }
 497  
         }
 498  
 
 499  1
         List<String> excluded = new ArrayList<String>();
 500  1
         for ( String file : files )
 501  
         {
 502  2
             int idx = file.lastIndexOf( File.separatorChar );
 503  2
             String tmpStr = file.substring( 0, idx );
 504  2
             tmpStr = tmpStr.replace( '\\', '/' );
 505  2
             String[] srcSplit = tmpStr.split( Pattern.quote( sourceDirectory.replace( '\\', '/' ) + '/' ) );
 506  2
             String excludedPackage = srcSplit[1].replace( '/', '.' );
 507  
 
 508  2
             if ( !excluded.contains( excludedPackage ) )
 509  
             {
 510  2
                 excluded.add( excludedPackage );
 511  
             }
 512  2
         }
 513  
 
 514  1
         return excluded;
 515  
     }
 516  
 
 517  
     /**
 518  
      * Convenience method that gets the files to be included in the javadoc.
 519  
      *
 520  
      * @param sourceDirectory the directory where the source files are located
 521  
      * @param files the variable that contains the appended filenames of the files to be included in the javadoc
 522  
      * @param excludePackages the packages to be excluded in the javadocs
 523  
      */
 524  
     protected static void addFilesFromSource( List<String> files, File sourceDirectory,
 525  
                                               List<String> sourceFileIncludes,
 526  
                                               List<String> sourceFileExcludes,
 527  
                                               String[] excludePackages )
 528  
     {
 529  48
         DirectoryScanner ds = new DirectoryScanner();
 530  48
         if ( sourceFileIncludes == null )
 531  
         {
 532  48
             sourceFileIncludes = Collections.singletonList( "**/*.java" );
 533  
         }
 534  48
         ds.setIncludes( sourceFileIncludes.toArray( new String[sourceFileIncludes.size()] ) );
 535  48
         if ( sourceFileExcludes != null && sourceFileExcludes.size() > 0 )
 536  
         {
 537  1
             ds.setExcludes( sourceFileExcludes.toArray( new String[sourceFileExcludes.size()] ) );
 538  
         }
 539  48
         ds.setBasedir( sourceDirectory );
 540  48
         ds.scan();
 541  
 
 542  48
         String[] fileList = ds.getIncludedFiles();
 543  48
         String[] pathList = new String[fileList.length];
 544  130
         for ( int x = 0; x < fileList.length; x++ )
 545  
         {
 546  82
             pathList[x] = new File( sourceDirectory, fileList[x] ).getAbsolutePath( );
 547  
         }
 548  
 
 549  
 
 550  48
         if (  pathList.length != 0 )
 551  
         {
 552  44
             List<String> tmpFiles = getIncludedFiles( sourceDirectory, pathList, excludePackages );
 553  44
             files.addAll( tmpFiles );
 554  
         }
 555  48
     }
 556  
 
 557  
     /**
 558  
      * Call the Javadoc tool and parse its output to find its version, i.e.:
 559  
      * <pre>
 560  
      * javadoc.exe(or .sh) -J-version
 561  
      * </pre>
 562  
      *
 563  
      * @param javadocExe not null file
 564  
      * @return the javadoc version as float
 565  
      * @throws IOException if javadocExe is null, doesn't exist or is not a file
 566  
      * @throws CommandLineException if any
 567  
      * @throws IllegalArgumentException if no output was found in the command line
 568  
      * @throws PatternSyntaxException if the output contains a syntax error in the regular-expression pattern.
 569  
      * @see #parseJavadocVersion(String)
 570  
      */
 571  
     protected static float getJavadocVersion( File javadocExe )
 572  
         throws IOException, CommandLineException, IllegalArgumentException, PatternSyntaxException
 573  
     {
 574  43
         if ( ( javadocExe == null ) || ( !javadocExe.exists() ) || ( !javadocExe.isFile() ) )
 575  
         {
 576  0
             throw new IOException( "The javadoc executable '" + javadocExe + "' doesn't exist or is not a file. " );
 577  
         }
 578  
 
 579  43
         Commandline cmd = new Commandline();
 580  43
         cmd.setExecutable( javadocExe.getAbsolutePath() );
 581  43
         cmd.setWorkingDirectory( javadocExe.getParentFile() );
 582  43
         cmd.createArg().setValue( "-J-version" );
 583  
 
 584  43
         CommandLineUtils.StringStreamConsumer out = new CommandLineUtils.StringStreamConsumer();
 585  43
         CommandLineUtils.StringStreamConsumer err = new CommandLineUtils.StringStreamConsumer();
 586  
 
 587  43
         int exitCode = CommandLineUtils.executeCommandLine( cmd, out, err );
 588  
 
 589  43
         if ( exitCode != 0 )
 590  
         {
 591  0
             StringBuilder msg = new StringBuilder( "Exit code: " + exitCode + " - " + err.getOutput() );
 592  0
             msg.append( '\n' );
 593  0
             msg.append( "Command line was:" + CommandLineUtils.toString( cmd.getCommandline() ) );
 594  0
             throw new CommandLineException( msg.toString() );
 595  
         }
 596  
 
 597  43
         if ( StringUtils.isNotEmpty( err.getOutput() ) )
 598  
         {
 599  43
             return parseJavadocVersion( err.getOutput() );
 600  
         }
 601  0
         else if ( StringUtils.isNotEmpty( out.getOutput() ) )
 602  
         {
 603  0
             return parseJavadocVersion( out.getOutput() );
 604  
         }
 605  
 
 606  0
         throw new IllegalArgumentException( "No output found from the command line 'javadoc -J-version'" );
 607  
     }
 608  
 
 609  
     /**
 610  
      * Parse the output for 'javadoc -J-version' and return the javadoc version recognized.
 611  
      * <br/>
 612  
      * Here are some output for 'javadoc -J-version' depending the JDK used:
 613  
      * <table>
 614  
      * <tr>
 615  
      *   <th>JDK</th>
 616  
      *   <th>Output for 'javadoc -J-version'</th>
 617  
      * </tr>
 618  
      * <tr>
 619  
      *   <td>Sun 1.4</td>
 620  
      *   <td>java full version "1.4.2_12-b03"</td>
 621  
      * </tr>
 622  
      * <tr>
 623  
      *   <td>Sun 1.5</td>
 624  
      *   <td>java full version "1.5.0_07-164"</td>
 625  
      * </tr>
 626  
      * <tr>
 627  
      *   <td>IBM 1.4</td>
 628  
      *   <td>javadoc full version "J2RE 1.4.2 IBM Windows 32 build cn1420-20040626"</td>
 629  
      * </tr>
 630  
      * <tr>
 631  
      *   <td>IBM 1.5 (French JVM)</td>
 632  
      *   <td>javadoc version complète de "J2RE 1.5.0 IBM Windows 32 build pwi32pdev-20070426a"</td>
 633  
      * </tr>
 634  
      * <tr>
 635  
      *   <td>FreeBSD 1.5</td>
 636  
      *   <td>java full version "diablo-1.5.0-b01"</td>
 637  
      * </tr>
 638  
      * <tr>
 639  
      *   <td>BEA jrockit 1.5</td>
 640  
      *   <td>java full version "1.5.0_11-b03"</td>
 641  
      * </tr>
 642  
      * </table>
 643  
      *
 644  
      * @param output for 'javadoc -J-version'
 645  
      * @return the version of the javadoc for the output.
 646  
      * @throws PatternSyntaxException if the output doesn't match with the output pattern
 647  
      * <tt>(?s).*?([0-9]+\\.[0-9]+)(\\.([0-9]+))?.*</tt>.
 648  
      * @throws IllegalArgumentException if the output is null
 649  
      */
 650  
     protected static float parseJavadocVersion( String output )
 651  
         throws IllegalArgumentException, PatternSyntaxException
 652  
     {
 653  60
         if ( StringUtils.isEmpty( output ) )
 654  
         {
 655  1
             throw new IllegalArgumentException( "The output could not be null." );
 656  
         }
 657  
 
 658  59
         Pattern pattern = Pattern.compile( "(?s).*?([0-9]+\\.[0-9]+)(\\.([0-9]+))?.*" );
 659  
 
 660  59
         Matcher matcher = pattern.matcher( output );
 661  59
         if ( !matcher.matches() )
 662  
         {
 663  1
             throw new PatternSyntaxException( "Unrecognized version of Javadoc: '" + output + "'", pattern.pattern(),
 664  
                                               pattern.toString().length() - 1 );
 665  
         }
 666  
 
 667  58
         String version = matcher.group( 3 );
 668  58
         if ( version == null )
 669  
         {
 670  1
             version = matcher.group( 1 );
 671  
         }
 672  
         else
 673  
         {
 674  57
             version = matcher.group( 1 ) + version;
 675  
         }
 676  
 
 677  58
         return Float.parseFloat( version );
 678  
     }
 679  
 
 680  
     /**
 681  
      * Parse a memory string which be used in the JVM arguments <code>-Xms</code> or <code>-Xmx</code>.
 682  
      * <br/>
 683  
      * Here are some supported memory string depending the JDK used:
 684  
      * <table>
 685  
      * <tr>
 686  
      *   <th>JDK</th>
 687  
      *   <th>Memory argument support for <code>-Xms</code> or <code>-Xmx</code></th>
 688  
      * </tr>
 689  
      * <tr>
 690  
      *   <td>SUN</td>
 691  
      *   <td>1024k | 128m | 1g | 1t</td>
 692  
      * </tr>
 693  
      * <tr>
 694  
      *   <td>IBM</td>
 695  
      *   <td>1024k | 1024b | 128m | 128mb | 1g | 1gb</td>
 696  
      * </tr>
 697  
      * <tr>
 698  
      *   <td>BEA</td>
 699  
      *   <td>1024k | 1024kb | 128m | 128mb | 1g | 1gb</td>
 700  
      * </tr>
 701  
      * </table>
 702  
      *
 703  
      * @param memory the memory to be parsed, not null.
 704  
      * @return the memory parsed with a supported unit. If no unit specified in the <code>memory</code> parameter,
 705  
      * the default unit is <code>m</code>. The units <code>g | gb</code> or <code>t | tb</code> will be converted
 706  
      * in <code>m</code>.
 707  
      * @throws IllegalArgumentException if the <code>memory</code> parameter is null or doesn't match any pattern.
 708  
      */
 709  
     protected static String parseJavadocMemory( String memory )
 710  
         throws IllegalArgumentException
 711  
     {
 712  18
         if ( StringUtils.isEmpty( memory ) )
 713  
         {
 714  1
             throw new IllegalArgumentException( "The memory could not be null." );
 715  
         }
 716  
 
 717  17
         Pattern p = Pattern.compile( "^\\s*(\\d+)\\s*?\\s*$" );
 718  17
         Matcher m = p.matcher( memory );
 719  17
         if ( m.matches() )
 720  
         {
 721  2
             return m.group( 1 ) + "m";
 722  
         }
 723  
 
 724  15
         p = Pattern.compile( "^\\s*(\\d+)\\s*k(b)?\\s*$", Pattern.CASE_INSENSITIVE );
 725  15
         m = p.matcher( memory );
 726  15
         if ( m.matches() )
 727  
         {
 728  2
             return m.group( 1 ) + "k";
 729  
         }
 730  
 
 731  13
         p = Pattern.compile( "^\\s*(\\d+)\\s*m(b)?\\s*$", Pattern.CASE_INSENSITIVE );
 732  13
         m = p.matcher( memory );
 733  13
         if ( m.matches() )
 734  
         {
 735  7
             return m.group( 1 ) + "m";
 736  
         }
 737  
 
 738  6
         p = Pattern.compile( "^\\s*(\\d+)\\s*g(b)?\\s*$", Pattern.CASE_INSENSITIVE );
 739  6
         m = p.matcher( memory );
 740  6
         if ( m.matches() )
 741  
         {
 742  2
             return ( Integer.parseInt( m.group( 1 ) ) * 1024 ) + "m";
 743  
         }
 744  
 
 745  4
         p = Pattern.compile( "^\\s*(\\d+)\\s*t(b)?\\s*$", Pattern.CASE_INSENSITIVE );
 746  4
         m = p.matcher( memory );
 747  4
         if ( m.matches() )
 748  
         {
 749  2
             return ( Integer.parseInt( m.group( 1 ) ) * 1024 * 1024 ) + "m";
 750  
         }
 751  
 
 752  2
         throw new IllegalArgumentException( "Could convert not to a memory size: " + memory );
 753  
     }
 754  
 
 755  
     /**
 756  
      * Validate if a charset is supported on this platform.
 757  
      *
 758  
      * @param charsetName the charsetName to be check.
 759  
      * @return <code>true</code> if the given charset is supported by the JVM, <code>false</code> otherwise.
 760  
      */
 761  
     protected static boolean validateEncoding( String charsetName )
 762  
     {
 763  125
         if ( StringUtils.isEmpty( charsetName ) )
 764  
         {
 765  1
             return false;
 766  
         }
 767  
 
 768  124
         OutputStream ost = new ByteArrayOutputStream();
 769  124
         OutputStreamWriter osw = null;
 770  
         try
 771  
         {
 772  124
             osw = new OutputStreamWriter( ost, charsetName );
 773  
         }
 774  5
         catch ( UnsupportedEncodingException exc )
 775  
         {
 776  5
             return false;
 777  
         }
 778  
         finally
 779  
         {
 780  124
             IOUtil.close( osw );
 781  119
         }
 782  
 
 783  119
         return true;
 784  
     }
 785  
 
 786  
     /**
 787  
      * For security reasons, if an active proxy is defined and needs an authentication by
 788  
      * username/password, hide the proxy password in the command line.
 789  
      *
 790  
      * @param cmdLine a command line, not null
 791  
      * @param settings the user settings
 792  
      * @return the cmdline with '*' for the http.proxyPassword JVM property
 793  
      */
 794  
     protected static String hideProxyPassword( String cmdLine, Settings settings )
 795  
     {
 796  40
         if ( cmdLine == null )
 797  
         {
 798  0
             throw new IllegalArgumentException( "cmdLine could not be null" );
 799  
         }
 800  
 
 801  40
         if ( settings == null )
 802  
         {
 803  36
             return cmdLine;
 804  
         }
 805  
 
 806  4
         Proxy activeProxy = settings.getActiveProxy();
 807  4
         if ( activeProxy != null && StringUtils.isNotEmpty( activeProxy.getHost() )
 808  
             && StringUtils.isNotEmpty( activeProxy.getUsername() )
 809  
             && StringUtils.isNotEmpty( activeProxy.getPassword() ) )
 810  
         {
 811  3
             String pass = "-J-Dhttp.proxyPassword=\"" + activeProxy.getPassword() + "\"";
 812  3
             String hidepass =
 813  
                 "-J-Dhttp.proxyPassword=\"" + StringUtils.repeat( "*", activeProxy.getPassword().length() ) + "\"";
 814  
 
 815  3
             return StringUtils.replace( cmdLine, pass, hidepass );
 816  
         }
 817  
 
 818  1
         return cmdLine;
 819  
     }
 820  
 
 821  
     /**
 822  
      * Auto-detect the class names of the implementation of <code>com.sun.tools.doclets.Taglet</code> class from a
 823  
      * given jar file.
 824  
      * <br/>
 825  
      * <b>Note</b>: <code>JAVA_HOME/lib/tools.jar</code> is a requirement to find
 826  
      * <code>com.sun.tools.doclets.Taglet</code> class.
 827  
      *
 828  
      * @param jarFile not null
 829  
      * @return the list of <code>com.sun.tools.doclets.Taglet</code> class names from a given jarFile.
 830  
      * @throws IOException if jarFile is invalid or not found, or if the <code>JAVA_HOME/lib/tools.jar</code>
 831  
      * is not found.
 832  
      * @throws ClassNotFoundException if any
 833  
      * @throws NoClassDefFoundError if any
 834  
      */
 835  
     protected static List<String> getTagletClassNames( File jarFile )
 836  
         throws IOException, ClassNotFoundException, NoClassDefFoundError
 837  
     {
 838  2
         List<String> classes = getClassNamesFromJar( jarFile );
 839  
         ClassLoader cl;
 840  
 
 841  
         // Needed to find com.sun.tools.doclets.Taglet class
 842  2
         File tools = new File( System.getProperty( "java.home" ), "../lib/tools.jar" );
 843  2
         if ( tools.exists() && tools.isFile() )
 844  
         {
 845  0
             cl = new URLClassLoader( new URL[] { jarFile.toURI().toURL(), tools.toURI().toURL() }, null );
 846  
         }
 847  
         else
 848  
         {
 849  2
             cl = new URLClassLoader( new URL[] { jarFile.toURI().toURL() }, null );
 850  
         }
 851  
 
 852  2
         List<String> tagletClasses = new ArrayList<String>();
 853  
 
 854  2
         Class<?> tagletClass = cl.loadClass( "com.sun.tools.doclets.Taglet" );
 855  2
         for ( String s : classes )
 856  
         {
 857  24
             Class<?> c = cl.loadClass( s );
 858  
 
 859  24
             if ( tagletClass.isAssignableFrom( c ) && !Modifier.isAbstract( c.getModifiers() ) )
 860  
             {
 861  20
                 tagletClasses.add( c.getName() );
 862  
             }
 863  24
         }
 864  
 
 865  2
         return tagletClasses;
 866  
     }
 867  
 
 868  
     /**
 869  
      * Copy the given url to the given file.
 870  
      *
 871  
      * @param url not null url
 872  
      * @param file not null file where the url will be created
 873  
      * @throws IOException if any
 874  
      * @since 2.6
 875  
      */
 876  
     protected static void copyResource( URL url, File file )
 877  
         throws IOException
 878  
     {
 879  4
         if ( file == null )
 880  
         {
 881  0
             throw new IOException( "The file " + file + " can't be null." );
 882  
         }
 883  4
         if ( url == null )
 884  
         {
 885  0
             throw new IOException( "The url " + url + " could not be null." );
 886  
         }
 887  
 
 888  4
         InputStream is = url.openStream();
 889  4
         if ( is == null )
 890  
         {
 891  0
             throw new IOException( "The resource " + url + " doesn't exists." );
 892  
         }
 893  
 
 894  4
         if ( !file.getParentFile().exists() )
 895  
         {
 896  0
             file.getParentFile().mkdirs();
 897  
         }
 898  
 
 899  4
         OutputStream os = null;
 900  
         try
 901  
         {
 902  4
             os = new FileOutputStream( file );
 903  
 
 904  4
             IOUtil.copy( is, os );
 905  
         }
 906  
         finally
 907  
         {
 908  4
             IOUtil.close( is );
 909  
 
 910  4
             IOUtil.close( os );
 911  4
         }
 912  4
     }
 913  
 
 914  
     /**
 915  
      * Invoke Maven for the given project file with a list of goals and properties, the output will be in the
 916  
      * invokerlog file.
 917  
      * <br/>
 918  
      * <b>Note</b>: the Maven Home should be defined in the <code>maven.home</code> Java system property or defined in
 919  
      * <code>M2_HOME</code> system env variables.
 920  
      *
 921  
      * @param log a logger could be null.
 922  
      * @param localRepositoryDir the localRepository not null.
 923  
      * @param projectFile a not null project file.
 924  
      * @param goals a not null goals list.
 925  
      * @param properties the properties for the goals, could be null.
 926  
      * @param invokerLog the log file where the invoker will be written, if null using <code>System.out</code>.
 927  
      * @throws MavenInvocationException if any
 928  
      * @since 2.6
 929  
      */
 930  
     protected static void invokeMaven( Log log, File localRepositoryDir, File projectFile, List<String> goals,
 931  
                                        Properties properties, File invokerLog )
 932  
         throws MavenInvocationException
 933  
     {
 934  6
         if ( projectFile == null )
 935  
         {
 936  0
             throw new IllegalArgumentException( "projectFile should be not null." );
 937  
         }
 938  6
         if ( !projectFile.isFile() )
 939  
         {
 940  0
             throw new IllegalArgumentException( projectFile.getAbsolutePath() + " is not a file." );
 941  
         }
 942  6
         if ( goals == null || goals.size() == 0 )
 943  
         {
 944  0
             throw new IllegalArgumentException( "goals should be not empty." );
 945  
         }
 946  6
         if ( localRepositoryDir == null || !localRepositoryDir.isDirectory() )
 947  
         {
 948  0
             throw new IllegalArgumentException( "localRepositoryDir '" + localRepositoryDir
 949  
                 + "' should be a directory." );
 950  
         }
 951  
 
 952  6
         String mavenHome = getMavenHome( log );
 953  6
         if ( StringUtils.isEmpty( mavenHome ) )
 954  
         {
 955  0
             String msg =
 956  
                 "Could NOT invoke Maven because no Maven Home is defined. You need to have set the M2_HOME "
 957  
                     + "system env variable or a maven.home Java system properties.";
 958  0
             if ( log != null )
 959  
             {
 960  0
                 log.error( msg );
 961  
             }
 962  
             else
 963  
             {
 964  0
                 System.err.println( msg );
 965  
             }
 966  0
             return;
 967  
         }
 968  
 
 969  6
         Invoker invoker = new DefaultInvoker();
 970  6
         invoker.setMavenHome( new File( mavenHome ) );
 971  6
         invoker.setLocalRepositoryDirectory( localRepositoryDir );
 972  
 
 973  6
         InvocationRequest request = new DefaultInvocationRequest();
 974  6
         request.setBaseDirectory( projectFile.getParentFile() );
 975  6
         request.setPomFile( projectFile );
 976  6
         if ( log != null )
 977  
         {
 978  6
             request.setDebug( log.isDebugEnabled() );
 979  
         }
 980  
         else
 981  
         {
 982  0
             request.setDebug( true );
 983  
         }
 984  6
         request.setGoals( goals );
 985  6
         if ( properties != null )
 986  
         {
 987  3
             request.setProperties( properties );
 988  
         }
 989  6
         File javaHome = getJavaHome( log );
 990  6
         if ( javaHome != null )
 991  
         {
 992  6
             request.setJavaHome( javaHome );
 993  
         }
 994  
 
 995  6
         if ( log != null && log.isDebugEnabled() )
 996  
         {
 997  0
             log.debug( "Invoking Maven for the goals: " + goals + " with "
 998  
                 + ( properties == null ? "no properties" : "properties=" + properties ) );
 999  
         }
 1000  6
         InvocationResult result = invoke( log, invoker, request, invokerLog, goals, properties, null );
 1001  
 
 1002  6
         if ( result.getExitCode() != 0 )
 1003  
         {
 1004  0
             String invokerLogContent = readFile( invokerLog, "UTF-8" );
 1005  
 
 1006  
             // see DefaultMaven
 1007  0
             if ( invokerLogContent != null && ( invokerLogContent.indexOf( "Scanning for projects..." ) == -1
 1008  
                 || invokerLogContent.indexOf( OutOfMemoryError.class.getName() ) != -1 ) )
 1009  
             {
 1010  0
                 if ( log != null )
 1011  
                 {
 1012  0
                     log.error( "Error occurred during initialization of VM, trying to use an empty MAVEN_OPTS..." );
 1013  
 
 1014  0
                     if ( log.isDebugEnabled() )
 1015  
                     {
 1016  0
                         log.debug( "Reinvoking Maven for the goals: " + goals + " with an empty MAVEN_OPTS..." );
 1017  
                     }
 1018  
                 }
 1019  0
                 result = invoke( log, invoker, request, invokerLog, goals, properties, "" );
 1020  
             }
 1021  
         }
 1022  
 
 1023  6
         if ( result.getExitCode() != 0 )
 1024  
         {
 1025  0
             String invokerLogContent = readFile( invokerLog, "UTF-8" );
 1026  
 
 1027  
             // see DefaultMaven
 1028  0
             if ( invokerLogContent != null && ( invokerLogContent.indexOf( "Scanning for projects..." ) == -1
 1029  
                 || invokerLogContent.indexOf( OutOfMemoryError.class.getName() ) != -1 ) )
 1030  
             {
 1031  0
                 throw new MavenInvocationException( ERROR_INIT_VM );
 1032  
             }
 1033  
 
 1034  0
             throw new MavenInvocationException( "Error when invoking Maven, consult the invoker log file: "
 1035  
                 + invokerLog.getAbsolutePath() );
 1036  
         }
 1037  6
     }
 1038  
 
 1039  
     /**
 1040  
      * Read the given file and return the content or null if an IOException occurs.
 1041  
      *
 1042  
      * @param javaFile not null
 1043  
      * @param encoding could be null
 1044  
      * @return the content with unified line separator of the given javaFile using the given encoding.
 1045  
      * @see FileUtils#fileRead(File, String)
 1046  
      * @since 2.6.1
 1047  
      */
 1048  
     protected static String readFile( final File javaFile, final String encoding )
 1049  
     {
 1050  
         try
 1051  
         {
 1052  0
             return FileUtils.fileRead( javaFile, encoding );
 1053  
         }
 1054  0
         catch ( IOException e )
 1055  
         {
 1056  0
             return null;
 1057  
         }
 1058  
     }
 1059  
 
 1060  
     /**
 1061  
      * Split the given path with colon and semi-colon, to support Solaris and Windows path.
 1062  
      * Examples:
 1063  
      * <pre>
 1064  
      * splitPath( "/home:/tmp" )     = ["/home", "/tmp"]
 1065  
      * splitPath( "/home;/tmp" )     = ["/home", "/tmp"]
 1066  
      * splitPath( "C:/home:C:/tmp" ) = ["C:/home", "C:/tmp"]
 1067  
      * splitPath( "C:/home;C:/tmp" ) = ["C:/home", "C:/tmp"]
 1068  
      * </pre>
 1069  
      *
 1070  
      * @param path which can contain multiple paths separated with a colon (<code>:</code>) or a
 1071  
      * semi-colon (<code>;</code>), platform independent. Could be null.
 1072  
      * @return the path splitted by colon or semi-colon or <code>null</code> if path was <code>null</code>.
 1073  
      * @since 2.6.1
 1074  
      */
 1075  
     protected static String[] splitPath( final String path )
 1076  
     {
 1077  10
         if ( path == null )
 1078  
         {
 1079  0
             return null;
 1080  
         }
 1081  
 
 1082  10
         List<String> subpaths = new ArrayList<String>();
 1083  10
         PathTokenizer pathTokenizer = new PathTokenizer( path );
 1084  44
         while ( pathTokenizer.hasMoreTokens() )
 1085  
         {
 1086  34
             subpaths.add( pathTokenizer.nextToken() );
 1087  
         }
 1088  
 
 1089  10
         return subpaths.toArray( new String[subpaths.size()] );
 1090  
     }
 1091  
 
 1092  
     /**
 1093  
      * Unify the given path with the current System path separator, to be platform independent.
 1094  
      * Examples:
 1095  
      * <pre>
 1096  
      * unifyPathSeparator( "/home:/tmp" ) = "/home:/tmp" (Solaris box)
 1097  
      * unifyPathSeparator( "/home:/tmp" ) = "/home;/tmp" (Windows box)
 1098  
      * </pre>
 1099  
      *
 1100  
      * @param path which can contain multiple paths by separating them with a colon (<code>:</code>) or a
 1101  
      * semi-colon (<code>;</code>), platform independent. Could be null.
 1102  
      * @return the same path but separated with the current System path separator or <code>null</code> if path was
 1103  
      * <code>null</code>.
 1104  
      * @since 2.6.1
 1105  
      * @see #splitPath(String)
 1106  
      * @see File#pathSeparator
 1107  
      */
 1108  
     protected static String unifyPathSeparator( final String path )
 1109  
     {
 1110  50
         if ( path == null )
 1111  
         {
 1112  42
             return null;
 1113  
         }
 1114  
 
 1115  8
         return StringUtils.join( splitPath( path ), File.pathSeparator );
 1116  
     }
 1117  
 
 1118  
     // ----------------------------------------------------------------------
 1119  
     // private methods
 1120  
     // ----------------------------------------------------------------------
 1121  
 
 1122  
     /**
 1123  
      * @param jarFile not null
 1124  
      * @return all class names from the given jar file.
 1125  
      * @throws IOException if any or if the jarFile is null or doesn't exist.
 1126  
      */
 1127  
     private static List<String> getClassNamesFromJar( File jarFile )
 1128  
         throws IOException
 1129  
     {
 1130  2
         if ( jarFile == null || !jarFile.exists() || !jarFile.isFile() )
 1131  
         {
 1132  0
             throw new IOException( "The jar '" + jarFile + "' doesn't exist or is not a file." );
 1133  
         }
 1134  
 
 1135  2
         List<String> classes = new ArrayList<String>();
 1136  2
         JarInputStream jarStream = null;
 1137  
 
 1138  
         try
 1139  
         {
 1140  2
             jarStream = new JarInputStream( new FileInputStream( jarFile ) );
 1141  2
             JarEntry jarEntry = jarStream.getNextJarEntry();
 1142  48
             while ( jarEntry != null )
 1143  
             {
 1144  46
                 if ( jarEntry.getName().toLowerCase( Locale.ENGLISH ).endsWith( ".class" ) )
 1145  
                 {
 1146  24
                     String name = jarEntry.getName().substring( 0, jarEntry.getName().indexOf( "." ) );
 1147  
 
 1148  24
                     classes.add( name.replaceAll( "/", "\\." ) );
 1149  
                 }
 1150  
 
 1151  46
                 jarStream.closeEntry();
 1152  46
                 jarEntry = jarStream.getNextJarEntry();
 1153  
             }
 1154  
         }
 1155  
         finally
 1156  
         {
 1157  2
             IOUtil.close( jarStream );
 1158  2
         }
 1159  
 
 1160  2
         return classes;
 1161  
     }
 1162  
 
 1163  
     /**
 1164  
      * @param log could be null
 1165  
      * @param invoker not null
 1166  
      * @param request not null
 1167  
      * @param invokerLog not null
 1168  
      * @param goals not null
 1169  
      * @param properties could be null
 1170  
      * @param mavenOpts could be null
 1171  
      * @return the invocation result
 1172  
      * @throws MavenInvocationException if any
 1173  
      * @since 2.6
 1174  
      */
 1175  
     private static InvocationResult invoke( Log log, Invoker invoker, InvocationRequest request, File invokerLog,
 1176  
                                             List<String> goals, Properties properties, String mavenOpts )
 1177  
         throws MavenInvocationException
 1178  
     {
 1179  
         PrintStream ps;
 1180  6
         OutputStream os = null;
 1181  6
         if ( invokerLog != null )
 1182  
         {
 1183  6
             if ( log != null && log.isDebugEnabled() )
 1184  
             {
 1185  0
                 log.debug( "Using " + invokerLog.getAbsolutePath() + " to log the invoker" );
 1186  
             }
 1187  
 
 1188  
             try
 1189  
             {
 1190  6
                 if ( !invokerLog.exists() )
 1191  
                 {
 1192  6
                     invokerLog.getParentFile().mkdirs();
 1193  
                 }
 1194  6
                 os = new FileOutputStream( invokerLog );
 1195  6
                 ps = new PrintStream( os, true, "UTF-8" );
 1196  
             }
 1197  0
             catch ( FileNotFoundException e )
 1198  
             {
 1199  0
                 if ( log != null && log.isErrorEnabled() )
 1200  
                 {
 1201  0
                     log.error( "FileNotFoundException: " + e.getMessage() + ". Using System.out to log the invoker." );
 1202  
                 }
 1203  0
                 ps = System.out;
 1204  
             }
 1205  0
             catch ( UnsupportedEncodingException e )
 1206  
             {
 1207  0
                 if ( log != null && log.isErrorEnabled() )
 1208  
                 {
 1209  0
                     log.error( "UnsupportedEncodingException: " + e.getMessage()
 1210  
                         + ". Using System.out to log the invoker." );
 1211  
                 }
 1212  0
                 ps = System.out;
 1213  6
             }
 1214  
         }
 1215  
         else
 1216  
         {
 1217  0
             if ( log != null && log.isDebugEnabled() )
 1218  
             {
 1219  0
                 log.debug( "Using System.out to log the invoker." );
 1220  
             }
 1221  
 
 1222  0
             ps = System.out;
 1223  
         }
 1224  
 
 1225  6
         if ( mavenOpts != null )
 1226  
         {
 1227  0
             request.setMavenOpts( mavenOpts );
 1228  
         }
 1229  
 
 1230  6
         InvocationOutputHandler outputHandler = new PrintStreamHandler( ps, false );
 1231  6
         request.setOutputHandler( outputHandler );
 1232  
 
 1233  6
         outputHandler.consumeLine( "Invoking Maven for the goals: " + goals + " with "
 1234  
             + ( properties == null ? "no properties" : "properties=" + properties ) );
 1235  6
         outputHandler.consumeLine( "" );
 1236  6
         outputHandler.consumeLine( "M2_HOME=" + getMavenHome( log ) );
 1237  6
         outputHandler.consumeLine( "MAVEN_OPTS=" + getMavenOpts( log ) );
 1238  6
         outputHandler.consumeLine( "JAVA_HOME=" + getJavaHome( log ) );
 1239  6
         outputHandler.consumeLine( "JAVA_OPTS=" + getJavaOpts( log ) );
 1240  6
         outputHandler.consumeLine( "" );
 1241  
 
 1242  
         try
 1243  
         {
 1244  6
             return invoker.execute( request );
 1245  
         }
 1246  
         finally
 1247  
         {
 1248  6
             IOUtil.close( os );
 1249  6
             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 set.
 1257  
      * @since 2.6
 1258  
      */
 1259  
     private static String getMavenHome( Log log )
 1260  
     {
 1261  12
         String mavenHome = System.getProperty( "maven.home" );
 1262  12
         if ( mavenHome == null )
 1263  
         {
 1264  
             try
 1265  
             {
 1266  0
                 mavenHome = CommandLineUtils.getSystemEnvVars().getProperty( "M2_HOME" );
 1267  
             }
 1268  0
             catch ( IOException e )
 1269  
             {
 1270  0
                 if ( log != null && log.isDebugEnabled() )
 1271  
                 {
 1272  0
                     log.debug( "IOException: " + e.getMessage() );
 1273  
                 }
 1274  0
             }
 1275  
         }
 1276  
 
 1277  12
         File m2Home = new File( mavenHome );
 1278  12
         if ( !m2Home.exists() )
 1279  
         {
 1280  0
             if ( log != null && log.isErrorEnabled() )
 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  12
         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  6
         String mavenOpts = null;
 1299  
         try
 1300  
         {
 1301  6
             mavenOpts = CommandLineUtils.getSystemEnvVars().getProperty( "MAVEN_OPTS" );
 1302  
         }
 1303  0
         catch ( IOException e )
 1304  
         {
 1305  0
             if ( log != null && log.isDebugEnabled() )
 1306  
             {
 1307  0
                 log.debug( "IOException: " + e.getMessage() );
 1308  
             }
 1309  6
         }
 1310  
 
 1311  6
         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  12
         if ( SystemUtils.IS_OS_MAC_OSX )
 1325  
         {
 1326  12
             javaHome = SystemUtils.getJavaHome();
 1327  
         }
 1328  
         else
 1329  
         {
 1330  0
             javaHome = new File( SystemUtils.getJavaHome(), ".." );
 1331  
         }
 1332  
 
 1333  12
         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 && log.isDebugEnabled() )
 1342  
                 {
 1343  0
                     log.debug( "IOException: " + e.getMessage() );
 1344  
                 }
 1345  0
             }
 1346  
         }
 1347  
 
 1348  12
         if ( javaHome == null || !javaHome.exists() )
 1349  
         {
 1350  0
             if ( log != null && log.isErrorEnabled() )
 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  12
         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  6
         String javaOpts = null;
 1368  
         try
 1369  
         {
 1370  6
             javaOpts = CommandLineUtils.getSystemEnvVars().getProperty( "JAVA_OPTS" );
 1371  
         }
 1372  0
         catch ( IOException e )
 1373  
         {
 1374  0
             if ( log != null && log.isDebugEnabled() )
 1375  
             {
 1376  0
                 log.debug( "IOException: " + e.getMessage() );
 1377  
             }
 1378  6
         }
 1379  
 
 1380  6
         return javaOpts;
 1381  
     }
 1382  
 
 1383  
     /**
 1384  
      * A Path tokenizer takes a path and returns the components that make up
 1385  
      * that path.
 1386  
      *
 1387  
      * The path can use path separators of either ':' or ';' and file separators
 1388  
      * of either '/' or '\'.
 1389  
      *
 1390  
      * @version revision 439418 taken on 2009-09-12 from Ant Project
 1391  
      * (see http://svn.apache.org/repos/asf/ant/core/trunk/src/main/org/apache/tools/ant/PathTokenizer.java)
 1392  
      */
 1393  0
     private static class PathTokenizer
 1394  
     {
 1395  
         /**
 1396  
          * A tokenizer to break the string up based on the ':' or ';' separators.
 1397  
          */
 1398  
         private StringTokenizer tokenizer;
 1399  
 
 1400  
         /**
 1401  
          * A String which stores any path components which have been read ahead
 1402  
          * due to DOS filesystem compensation.
 1403  
          */
 1404  10
         private String lookahead = null;
 1405  
 
 1406  
         /**
 1407  
          * A boolean that determines if we are running on Novell NetWare, which
 1408  
          * exhibits slightly different path name characteristics (multi-character
 1409  
          * volume / drive names)
 1410  
          */
 1411  10
         private boolean onNetWare = Os.isFamily( "netware" );
 1412  
 
 1413  
         /**
 1414  
          * Flag to indicate whether or not we are running on a platform with a
 1415  
          * DOS style filesystem
 1416  
          */
 1417  
         private boolean dosStyleFilesystem;
 1418  
 
 1419  
         /**
 1420  
          * Constructs a path tokenizer for the specified path.
 1421  
          *
 1422  
          * @param path The path to tokenize. Must not be <code>null</code>.
 1423  
          */
 1424  
         public PathTokenizer( String path )
 1425  10
         {
 1426  10
             if ( onNetWare )
 1427  
             {
 1428  
                 // For NetWare, use the boolean=true mode, so we can use delimiter
 1429  
                 // information to make a better decision later.
 1430  0
                 tokenizer = new StringTokenizer( path, ":;", true );
 1431  
             }
 1432  
             else
 1433  
             {
 1434  
                 // on Windows and Unix, we can ignore delimiters and still have
 1435  
                 // enough information to tokenize correctly.
 1436  10
                 tokenizer = new StringTokenizer( path, ":;", false );
 1437  
             }
 1438  10
             dosStyleFilesystem = File.pathSeparatorChar == ';';
 1439  10
         }
 1440  
 
 1441  
         /**
 1442  
          * Tests if there are more path elements available from this tokenizer's
 1443  
          * path. If this method returns <code>true</code>, then a subsequent call
 1444  
          * to nextToken will successfully return a token.
 1445  
          *
 1446  
          * @return <code>true</code> if and only if there is at least one token
 1447  
          * in the string after the current position; <code>false</code> otherwise.
 1448  
          */
 1449  
         public boolean hasMoreTokens()
 1450  
         {
 1451  44
             if ( lookahead != null )
 1452  
             {
 1453  0
                 return true;
 1454  
             }
 1455  
 
 1456  44
             return tokenizer.hasMoreTokens();
 1457  
         }
 1458  
 
 1459  
         /**
 1460  
          * Returns the next path element from this tokenizer.
 1461  
          *
 1462  
          * @return the next path element from this tokenizer.
 1463  
          *
 1464  
          * @exception NoSuchElementException if there are no more elements in this
 1465  
          *            tokenizer's path.
 1466  
          */
 1467  
         public String nextToken()
 1468  
             throws NoSuchElementException
 1469  
         {
 1470  34
             String token = null;
 1471  34
             if ( lookahead != null )
 1472  
             {
 1473  0
                 token = lookahead;
 1474  0
                 lookahead = null;
 1475  
             }
 1476  
             else
 1477  
             {
 1478  34
                 token = tokenizer.nextToken().trim();
 1479  
             }
 1480  
 
 1481  34
             if ( !onNetWare )
 1482  
             {
 1483  34
                 if ( token.length() == 1 && Character.isLetter( token.charAt( 0 ) ) && dosStyleFilesystem
 1484  
                     && tokenizer.hasMoreTokens() )
 1485  
                 {
 1486  
                     // we are on a dos style system so this path could be a drive
 1487  
                     // spec. We look at the next token
 1488  0
                     String nextToken = tokenizer.nextToken().trim();
 1489  0
                     if ( nextToken.startsWith( "\\" ) || nextToken.startsWith( "/" ) )
 1490  
                     {
 1491  
                         // we know we are on a DOS style platform and the next path
 1492  
                         // starts with a slash or backslash, so we know this is a
 1493  
                         // drive spec
 1494  0
                         token += ":" + nextToken;
 1495  
                     }
 1496  
                     else
 1497  
                     {
 1498  
                         // store the token just read for next time
 1499  0
                         lookahead = nextToken;
 1500  
                     }
 1501  0
                 }
 1502  
             }
 1503  
             else
 1504  
             {
 1505  
                 // we are on NetWare, tokenizing is handled a little differently,
 1506  
                 // due to the fact that NetWare has multiple-character volume names.
 1507  0
                 if ( token.equals( File.pathSeparator ) || token.equals( ":" ) )
 1508  
                 {
 1509  
                     // ignore ";" and get the next token
 1510  0
                     token = tokenizer.nextToken().trim();
 1511  
                 }
 1512  
 
 1513  0
                 if ( tokenizer.hasMoreTokens() )
 1514  
                 {
 1515  
                     // this path could be a drive spec, so look at the next token
 1516  0
                     String nextToken = tokenizer.nextToken().trim();
 1517  
 
 1518  
                     // make sure we aren't going to get the path separator next
 1519  0
                     if ( !nextToken.equals( File.pathSeparator ) )
 1520  
                     {
 1521  0
                         if ( nextToken.equals( ":" ) )
 1522  
                         {
 1523  0
                             if ( !token.startsWith( "/" ) && !token.startsWith( "\\" ) && !token.startsWith( "." )
 1524  
                                 && !token.startsWith( ".." ) )
 1525  
                             {
 1526  
                                 // it indeed is a drive spec, get the next bit
 1527  0
                                 String oneMore = tokenizer.nextToken().trim();
 1528  0
                                 if ( !oneMore.equals( File.pathSeparator ) )
 1529  
                                 {
 1530  0
                                     token += ":" + oneMore;
 1531  
                                 }
 1532  
                                 else
 1533  
                                 {
 1534  0
                                     token += ":";
 1535  0
                                     lookahead = oneMore;
 1536  
                                 }
 1537  0
                             }
 1538  
                             // implicit else: ignore the ':' since we have either a
 1539  
                             // UNIX or a relative path
 1540  
                         }
 1541  
                         else
 1542  
                         {
 1543  
                             // store the token just read for next time
 1544  0
                             lookahead = nextToken;
 1545  
                         }
 1546  
                     }
 1547  
                 }
 1548  
             }
 1549  34
             return token;
 1550  
         }
 1551  
     }
 1552  
     
 1553  
     static List<String> toList( String src )
 1554  
     {
 1555  44
         return toList( src, null, null );
 1556  
     }
 1557  
     
 1558  
     static List<String> toList( String src, String elementPrefix, String elementSuffix )
 1559  
     {
 1560  44
         if ( StringUtils.isEmpty( src ) )
 1561  
         {
 1562  42
             return null;
 1563  
         }
 1564  
         
 1565  2
         List<String> result = new ArrayList<String>();
 1566  
 
 1567  2
         StringTokenizer st = new StringTokenizer( src, "[,:;]" );
 1568  2
         StringBuilder sb = new StringBuilder( 256 );
 1569  6
         while ( st.hasMoreTokens() )
 1570  
         {
 1571  4
             sb.setLength( 0 );
 1572  4
             if ( StringUtils.isNotEmpty( elementPrefix ) )
 1573  
             {
 1574  0
                 sb.append( elementPrefix );
 1575  
             }
 1576  
             
 1577  4
             sb.append( st.nextToken() );
 1578  
             
 1579  4
             if ( StringUtils.isNotEmpty( elementSuffix ) )
 1580  
             {
 1581  0
                 sb.append( elementSuffix );
 1582  
             }
 1583  
             
 1584  4
             result.add( sb.toString() );
 1585  
         }
 1586  
         
 1587  2
         return result;
 1588  
     }
 1589  
     
 1590  
     static <T> List<T> toList( T[] multiple )
 1591  
     {
 1592  264
         return toList( null, multiple );
 1593  
     }
 1594  
     
 1595  
     static <T> List<T> toList( T single, T[] multiple )
 1596  
     {
 1597  352
         if ( single == null && ( multiple == null || multiple.length < 1 ) )
 1598  
         {
 1599  344
             return null;
 1600  
         }
 1601  
         
 1602  8
         List<T> result = new ArrayList<T>();
 1603  8
         if ( single != null )
 1604  
         {
 1605  2
             result.add( single );
 1606  
         }
 1607  
         
 1608  8
         if ( multiple != null && multiple.length > 0 )
 1609  
         {
 1610  6
             result.addAll( Arrays.asList( multiple ) );
 1611  
         }
 1612  
         
 1613  8
         return result;
 1614  
     }
 1615  
     
 1616  
     // TODO: move to plexus-utils or use something appropriate from there
 1617  
     public static String toRelative( File basedir, String absolutePath )
 1618  
     {
 1619  
         String relative;
 1620  
 
 1621  16
         absolutePath = absolutePath.replace( '\\', '/' );
 1622  16
         String basedirPath = basedir.getAbsolutePath().replace( '\\', '/' );
 1623  
 
 1624  16
         if ( absolutePath.startsWith( basedirPath ) )
 1625  
         {
 1626  16
             relative = absolutePath.substring( basedirPath.length() );
 1627  16
             if ( relative.startsWith( "/" ) )
 1628  
             {
 1629  16
                 relative = relative.substring( 1 );
 1630  
             }
 1631  16
             if ( relative.length() <= 0 )
 1632  
             {
 1633  0
                 relative = ".";
 1634  
             }
 1635  
         }
 1636  
         else
 1637  
         {
 1638  0
             relative = absolutePath;
 1639  
         }
 1640  
 
 1641  16
         return relative;
 1642  
     }
 1643  
     
 1644  
     /**
 1645  
      * Convenience method to determine that a collection is not empty or null.
 1646  
      */
 1647  
     public static boolean isNotEmpty( final Collection<?> collection )
 1648  
     {
 1649  78
         return collection != null && !collection.isEmpty();
 1650  
     }
 1651  
     
 1652  
     /**
 1653  
      * Convenience method to determine that a collection is empty or null.
 1654  
      */
 1655  
     public static boolean isEmpty( final Collection<?> collection )
 1656  
     {
 1657  150
         return collection == null || collection.isEmpty();
 1658  
     }
 1659  
 
 1660  
     /**
 1661  
      * Validates an <code>URL</code> to point to a valid <code>package-list</code> resource.
 1662  
      *
 1663  
      * @param url The URL to validate.
 1664  
      * @param settings The user settings used to configure the connection to the URL or {@code null}.
 1665  
      * @param validateContent <code>true</code> to validate the content of the <code>package-list</code> resource;
 1666  
      * <code>false</code> to only check the existence of the <code>package-list</code> resource.
 1667  
      *
 1668  
      * @return <code>true</code> if <code>url</code> points to a valid <code>package-list</code> resource;
 1669  
      * <code>false</code> else.
 1670  
      *
 1671  
      * @throws IOException if reading the resource fails.
 1672  
      *
 1673  
      * @see #createHttpClient(org.apache.maven.settings.Settings, java.net.URL)
 1674  
      *
 1675  
      * @since 2.8
 1676  
      */
 1677  
     protected static boolean isValidPackageList( URL url, Settings settings, boolean validateContent )
 1678  
         throws IOException
 1679  
     {
 1680  14
         if ( url == null )
 1681  
         {
 1682  1
             throw new IllegalArgumentException( "The url is null" );
 1683  
         }
 1684  
 
 1685  13
         BufferedReader reader = null;
 1686  13
         GetMethod httpMethod = null;
 1687  
 
 1688  
         try
 1689  
         {
 1690  13
             if ( "file".equals( url.getProtocol() ) )
 1691  
             {
 1692  
                 // Intentionally using the platform default encoding here since this is what Javadoc uses internally.
 1693  4
                 reader = new BufferedReader( new InputStreamReader( url.openStream() ) );
 1694  
             }
 1695  
             else
 1696  
             {
 1697  
                 // http, https...
 1698  9
                 HttpClient httpClient = createHttpClient( settings, url );
 1699  
 
 1700  9
                 httpMethod = new GetMethod( url.toString() );
 1701  
                 int status;
 1702  
                 try
 1703  
                 {
 1704  9
                     status = httpClient.executeMethod( httpMethod );
 1705  
                 }
 1706  1
                 catch ( SocketTimeoutException e )
 1707  
                 {
 1708  
                     // could be a sporadic failure, one more retry before we give up
 1709  1
                     status = httpClient.executeMethod( httpMethod );
 1710  8
                 }
 1711  
 
 1712  8
                 if ( status != HttpStatus.SC_OK )
 1713  
                 {
 1714  4
                     throw new FileNotFoundException(
 1715  
                         "Unexpected HTTP status code " + status + " getting resource " + url.toExternalForm() + "." );
 1716  
 
 1717  
                 }
 1718  
 
 1719  
                 // Intentionally using the platform default encoding here since this is what Javadoc uses internally.
 1720  4
                 reader = new BufferedReader( new InputStreamReader( httpMethod.getResponseBodyAsStream() ) );
 1721  
             }
 1722  
 
 1723  8
             if ( validateContent )
 1724  
             {
 1725  
                 String line;
 1726  21
                 while ( ( line = reader.readLine() ) != null )
 1727  
                 {
 1728  17
                     if ( !isValidPackageName( line ) )
 1729  
                     {
 1730  1
                         return false;
 1731  
                     }
 1732  
                 }
 1733  
             }
 1734  
 
 1735  7
             return true;
 1736  
         }
 1737  
         finally
 1738  
         {
 1739  13
             IOUtil.close( reader );
 1740  
 
 1741  13
             if ( httpMethod != null )
 1742  
             {
 1743  9
                 httpMethod.releaseConnection();
 1744  
             }
 1745  
         }
 1746  
     }
 1747  
 
 1748  
     private static boolean isValidPackageName( String str )
 1749  
     {
 1750  17
         if ( StringUtils.isEmpty( str ) )
 1751  
         {
 1752  0
             return false;
 1753  
         }
 1754  
 
 1755  
         int idx;
 1756  101
         while ( ( idx = str.indexOf( '.' ) ) != -1 )
 1757  
         {
 1758  85
             if ( !isValidClassName( str.substring( 0, idx ) ) )
 1759  
             {
 1760  1
                 return false;
 1761  
             }
 1762  
 
 1763  84
             str = str.substring( idx + 1 );
 1764  
         }
 1765  
 
 1766  16
         return isValidClassName( str );
 1767  
     }
 1768  
 
 1769  
     private static boolean isValidClassName( String str )
 1770  
     {
 1771  101
         if ( StringUtils.isEmpty( str ) || !Character.isJavaIdentifierStart( str.charAt( 0 ) ) )
 1772  
         {
 1773  1
             return false;
 1774  
         }
 1775  
 
 1776  544
         for ( int i = str.length() - 1; i > 0; i-- )
 1777  
         {
 1778  444
             if ( !Character.isJavaIdentifierPart( str.charAt( i ) ) )
 1779  
             {
 1780  0
                 return false;
 1781  
             }
 1782  
         }
 1783  
 
 1784  100
         return true;
 1785  
     }
 1786  
 
 1787  
     /**
 1788  
      * Creates a new {@code HttpClient} instance.
 1789  
      *
 1790  
      * @param settings The settings to use for setting up the client or {@code null}.
 1791  
      * @param url The {@code URL} to use for setting up the client or {@code null}.
 1792  
      *
 1793  
      * @return A new {@code HttpClient} instance.
 1794  
      *
 1795  
      * @see #DEFAULT_TIMEOUT
 1796  
      * @since 2.8
 1797  
      */
 1798  
     private static HttpClient createHttpClient( Settings settings, URL url )
 1799  
     {
 1800  9
         HttpClient httpClient = new HttpClient( new MultiThreadedHttpConnectionManager() );
 1801  9
         httpClient.getHttpConnectionManager().getParams().setConnectionTimeout( DEFAULT_TIMEOUT );
 1802  9
         httpClient.getHttpConnectionManager().getParams().setSoTimeout( DEFAULT_TIMEOUT );
 1803  9
         httpClient.getParams().setBooleanParameter( HttpClientParams.ALLOW_CIRCULAR_REDIRECTS, true );
 1804  
 
 1805  
         // Some web servers don't allow the default user-agent sent by httpClient
 1806  9
         httpClient.getParams().setParameter( HttpMethodParams.USER_AGENT,
 1807  
                                              "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" );
 1808  
 
 1809  9
         if ( settings != null && settings.getActiveProxy() != null )
 1810  
         {
 1811  5
             Proxy activeProxy = settings.getActiveProxy();
 1812  
 
 1813  5
             ProxyInfo proxyInfo = new ProxyInfo();
 1814  5
             proxyInfo.setNonProxyHosts( activeProxy.getNonProxyHosts() );
 1815  
 
 1816  5
             if ( StringUtils.isNotEmpty( activeProxy.getHost() )
 1817  
                  && ( url == null || !ProxyUtils.validateNonProxyHosts( proxyInfo, url.getHost() ) ) )
 1818  
             {
 1819  4
                 httpClient.getHostConfiguration().setProxy( activeProxy.getHost(), activeProxy.getPort() );
 1820  
 
 1821  4
                 if ( StringUtils.isNotEmpty( activeProxy.getUsername() ) && activeProxy.getPassword() != null )
 1822  
                 {
 1823  3
                     Credentials credentials =
 1824  
                         new UsernamePasswordCredentials( activeProxy.getUsername(), activeProxy.getPassword() );
 1825  
 
 1826  3
                     httpClient.getState().setProxyCredentials( AuthScope.ANY, credentials );
 1827  
                 }
 1828  
             }
 1829  
         }
 1830  
 
 1831  9
         return httpClient;
 1832  
     }
 1833  
 
 1834  
     static boolean equalsIgnoreCase( String value, String... strings )
 1835  
     {
 1836  6
         for ( String s : strings )
 1837  
         {
 1838  6
             if ( s.equalsIgnoreCase( value ) )
 1839  
             {
 1840  3
                 return true;
 1841  
             }
 1842  
         }
 1843  0
         return false;
 1844  
     }
 1845  
 
 1846  
     static boolean equals( String value, String... strings )
 1847  
     {
 1848  2
         for ( String s : strings )
 1849  
         {
 1850  2
             if ( s.equals( value ) )
 1851  
             {
 1852  2
                 return true;
 1853  
             }
 1854  
         }
 1855  0
         return false;
 1856  
     }
 1857  
 }