1 package org.apache.maven.plugin.javadoc;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
91
92
93
94
95
96 public class JavadocUtil
97 {
98
99 public static final int DEFAULT_TIMEOUT = 2000;
100
101
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
108
109
110
111
112
113
114
115 public static List<String> pruneDirs( MavenProject project, List<String> dirs )
116 {
117 List<String> pruned = new ArrayList<String>( dirs.size() );
118 for ( String dir : dirs )
119 {
120 if ( dir == null )
121 {
122 continue;
123 }
124
125 File directory = new File( dir );
126 if ( !directory.isAbsolute() )
127 {
128 directory = new File( project.getBasedir(), directory.getPath() );
129 }
130
131 if ( directory.isDirectory() && !pruned.contains( directory.getAbsolutePath() ) )
132 {
133 pruned.add( directory.getAbsolutePath() );
134 }
135 }
136
137 return pruned;
138 }
139
140
141
142
143
144
145
146
147 protected static List<String> pruneFiles( List<String> files )
148 {
149 List<String> pruned = new ArrayList<String>( files.size() );
150 for ( String f : files )
151 {
152 if ( !shouldPruneFile( f, pruned ) )
153 {
154 pruned.add( f );
155 }
156 }
157
158 return pruned;
159 }
160
161
162
163
164
165 public static boolean shouldPruneFile( String f, List<String> pruned )
166 {
167 if ( f != null )
168 {
169 File file = new File( f );
170 if ( file.isFile() && ( isEmpty( pruned ) || !pruned.contains( f ) ) )
171 {
172 return false;
173 }
174 }
175
176 return true;
177 }
178
179
180
181
182
183
184
185
186
187
188 protected static List<String> getExcludedNames( List<String> sourcePaths, String[] subpackagesList,
189 String[] excludedPackages )
190 {
191 List<String> excludedNames = new ArrayList<String>();
192 for ( String path : sourcePaths )
193 {
194 for ( int j = 0; j < subpackagesList.length; j++ )
195 {
196 List<String> excludes = getExcludedPackages( path, excludedPackages );
197 excludedNames.addAll( excludes );
198 }
199 }
200
201 return excludedNames;
202 }
203
204
205
206
207
208
209
210 protected static List<Artifact> getCompileArtifacts( Set<Artifact> artifacts )
211 {
212 return getCompileArtifacts( artifacts, false );
213 }
214
215
216
217
218
219
220
221 protected static List<Artifact> getCompileArtifacts( Set<Artifact> artifacts, boolean withTestScope )
222 {
223 List<Artifact> list = new ArrayList<Artifact>( artifacts.size() );
224
225 for ( Artifact a : artifacts )
226 {
227
228 if ( a.getArtifactHandler().isAddedToClasspath() )
229 {
230
231 if ( withTestScope )
232 {
233 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 list.add( a );
239 }
240 }
241 else
242 {
243 if ( Artifact.SCOPE_COMPILE.equals( a.getScope() ) || Artifact.SCOPE_PROVIDED.equals( a.getScope() )
244 || Artifact.SCOPE_SYSTEM.equals( a.getScope() ) )
245 {
246 list.add( a );
247 }
248 }
249 }
250 }
251
252 return list;
253 }
254
255
256
257
258
259
260
261
262
263
264 protected static String quotedArgument( String value )
265 {
266 String arg = value;
267
268 if ( StringUtils.isNotEmpty( arg ) )
269 {
270 if ( arg.indexOf( "'" ) != -1 )
271 {
272 arg = StringUtils.replace( arg, "'", "\\'" );
273 }
274 arg = "'" + arg + "'";
275
276
277 arg = StringUtils.replace( arg, "\n", " " );
278 }
279
280 return arg;
281 }
282
283
284
285
286
287
288
289
290 protected static String quotedPathArgument( String value )
291 {
292 String path = value;
293
294 if ( StringUtils.isNotEmpty( path ) )
295 {
296 path = path.replace( '\\', '/' );
297 if ( path.indexOf( "\'" ) != -1 )
298 {
299 String split[] = path.split( "\'" );
300 path = "";
301
302 for ( int i = 0; i < split.length; i++ )
303 {
304 if ( i != split.length - 1 )
305 {
306 path = path + split[i] + "\\'";
307 }
308 else
309 {
310 path = path + split[i];
311 }
312 }
313 }
314 path = "'" + path + "'";
315 }
316
317 return path;
318 }
319
320
321
322
323
324
325
326
327
328
329 protected static void copyJavadocResources( File outputDirectory, File javadocDir )
330 throws IOException
331 {
332 copyJavadocResources( outputDirectory, javadocDir, null );
333 }
334
335
336
337
338
339
340
341
342
343
344
345 protected static void copyJavadocResources( File outputDirectory, File javadocDir, String excludedocfilessubdir )
346 throws IOException
347 {
348 if ( !javadocDir.isDirectory() )
349 {
350 return;
351 }
352
353 List<String> excludes = new ArrayList<String>();
354 excludes.addAll( Arrays.asList( FileUtils.getDefaultExcludes() ) );
355
356 if ( StringUtils.isNotEmpty( excludedocfilessubdir ) )
357 {
358 StringTokenizer st = new StringTokenizer( excludedocfilessubdir, ":" );
359 String current;
360 while ( st.hasMoreTokens() )
361 {
362 current = st.nextToken();
363 excludes.add( "**/" + current + "/**" );
364 }
365 }
366
367 List<String> docFiles =
368 FileUtils.getDirectoryNames( javadocDir, "resources,**/doc-files",
369 StringUtils.join( excludes.iterator(), "," ), false, true );
370 for ( String docFile : docFiles )
371 {
372 File docFileOutput = new File( outputDirectory, docFile );
373 FileUtils.mkdir( docFileOutput.getAbsolutePath() );
374 FileUtils.copyDirectoryStructure( new File( javadocDir, docFile ), docFileOutput );
375 List<String> files =
376 FileUtils.getFileAndDirectoryNames( docFileOutput, StringUtils.join( excludes.iterator(), "," ),
377 null, true, true, true, true );
378 for ( String filename : files )
379 {
380 File file = new File( filename );
381
382 if ( file.isDirectory() )
383 {
384 FileUtils.deleteDirectory( file );
385 }
386 else
387 {
388 file.delete();
389 }
390 }
391 }
392 }
393
394
395
396
397
398
399
400
401
402
403 protected static List<String> getIncludedFiles( File sourceDirectory, String[] fileList, String[] excludePackages )
404 {
405 List<String> files = new ArrayList<String>();
406
407 for ( int j = 0; j < fileList.length; j++ )
408 {
409 boolean include = true;
410 for ( int k = 0; k < excludePackages.length && include; k++ )
411 {
412
413 String[] excludeName = excludePackages[k].split( "[*]" );
414
415 if ( excludeName.length == 0 )
416 {
417 continue;
418 }
419
420 if ( excludeName.length > 1 )
421 {
422 int u = 0;
423 while ( include && u < excludeName.length )
424 {
425 if ( !"".equals( excludeName[u].trim() ) && fileList[j].indexOf( excludeName[u] ) != -1 )
426 {
427 include = false;
428 }
429 u++;
430 }
431 }
432 else
433 {
434 if ( fileList[j].startsWith( sourceDirectory.toString() + File.separatorChar + excludeName[0] ) )
435 {
436 if ( excludeName[0].endsWith( String.valueOf( File.separatorChar ) ) )
437 {
438 int i = fileList[j].lastIndexOf( File.separatorChar );
439 String packageName = fileList[j].substring( 0, i + 1 );
440 File currentPackage = new File( packageName );
441 File excludedPackage = new File( sourceDirectory, excludeName[0] );
442 if ( currentPackage.equals( excludedPackage )
443 && fileList[j].substring( i ).indexOf( ".java" ) != -1 )
444 {
445 include = true;
446 }
447 else
448 {
449 include = false;
450 }
451 }
452 else
453 {
454 include = false;
455 }
456 }
457 }
458 }
459
460 if ( include )
461 {
462 files.add( quotedPathArgument( fileList[j] ) );
463 }
464 }
465
466 return files;
467 }
468
469
470
471
472
473
474
475
476
477 protected static List<String> getExcludedPackages( String sourceDirectory, String[] excludePackagenames )
478 {
479 List<String> files = new ArrayList<String>();
480 for ( int i = 0; i < excludePackagenames.length; i++ )
481 {
482 String[] fileList = FileUtils.getFilesFromExtension( sourceDirectory, new String[] { "java" } );
483 for ( int j = 0; j < fileList.length; j++ )
484 {
485 String[] excludeName = excludePackagenames[i].split( "[*]" );
486 int u = 0;
487 while ( u < excludeName.length )
488 {
489 if ( !"".equals( excludeName[u].trim() ) && fileList[j].indexOf( excludeName[u] ) != -1
490 && sourceDirectory.indexOf( excludeName[u] ) == -1 )
491 {
492 files.add( fileList[j] );
493 }
494 u++;
495 }
496 }
497 }
498
499 List<String> excluded = new ArrayList<String>();
500 for ( String file : files )
501 {
502 int idx = file.lastIndexOf( File.separatorChar );
503 String tmpStr = file.substring( 0, idx );
504 tmpStr = tmpStr.replace( '\\', '/' );
505 String[] srcSplit = tmpStr.split( Pattern.quote( sourceDirectory.replace( '\\', '/' ) + '/' ) );
506 String excludedPackage = srcSplit[1].replace( '/', '.' );
507
508 if ( !excluded.contains( excludedPackage ) )
509 {
510 excluded.add( excludedPackage );
511 }
512 }
513
514 return excluded;
515 }
516
517
518
519
520
521
522
523
524 protected static void addFilesFromSource( List<String> files, File sourceDirectory,
525 List<String> sourceFileIncludes,
526 List<String> sourceFileExcludes,
527 String[] excludePackages )
528 {
529 DirectoryScanner ds = new DirectoryScanner();
530 if ( sourceFileIncludes == null )
531 {
532 sourceFileIncludes = Collections.singletonList( "**/*.java" );
533 }
534 ds.setIncludes( sourceFileIncludes.toArray( new String[sourceFileIncludes.size()] ) );
535 if ( sourceFileExcludes != null && sourceFileExcludes.size() > 0 )
536 {
537 ds.setExcludes( sourceFileExcludes.toArray( new String[sourceFileExcludes.size()] ) );
538 }
539 ds.setBasedir( sourceDirectory );
540 ds.scan();
541
542 String[] fileList = ds.getIncludedFiles();
543 String[] pathList = new String[fileList.length];
544 for ( int x = 0; x < fileList.length; x++ )
545 {
546 pathList[x] = new File( sourceDirectory, fileList[x] ).getAbsolutePath( );
547 }
548
549
550 if ( pathList.length != 0 )
551 {
552 List<String> tmpFiles = getIncludedFiles( sourceDirectory, pathList, excludePackages );
553 files.addAll( tmpFiles );
554 }
555 }
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571 protected static float getJavadocVersion( File javadocExe )
572 throws IOException, CommandLineException, IllegalArgumentException, PatternSyntaxException
573 {
574 if ( ( javadocExe == null ) || ( !javadocExe.exists() ) || ( !javadocExe.isFile() ) )
575 {
576 throw new IOException( "The javadoc executable '" + javadocExe + "' doesn't exist or is not a file. " );
577 }
578
579 Commandline cmd = new Commandline();
580 cmd.setExecutable( javadocExe.getAbsolutePath() );
581 cmd.setWorkingDirectory( javadocExe.getParentFile() );
582 cmd.createArg().setValue( "-J-version" );
583
584 CommandLineUtils.StringStreamConsumer out = new CommandLineUtils.StringStreamConsumer();
585 CommandLineUtils.StringStreamConsumer err = new CommandLineUtils.StringStreamConsumer();
586
587 int exitCode = CommandLineUtils.executeCommandLine( cmd, out, err );
588
589 if ( exitCode != 0 )
590 {
591 StringBuilder msg = new StringBuilder( "Exit code: " + exitCode + " - " + err.getOutput() );
592 msg.append( '\n' );
593 msg.append( "Command line was:" + CommandLineUtils.toString( cmd.getCommandline() ) );
594 throw new CommandLineException( msg.toString() );
595 }
596
597 if ( StringUtils.isNotEmpty( err.getOutput() ) )
598 {
599 return parseJavadocVersion( err.getOutput() );
600 }
601 else if ( StringUtils.isNotEmpty( out.getOutput() ) )
602 {
603 return parseJavadocVersion( out.getOutput() );
604 }
605
606 throw new IllegalArgumentException( "No output found from the command line 'javadoc -J-version'" );
607 }
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650 protected static float parseJavadocVersion( String output )
651 throws IllegalArgumentException, PatternSyntaxException
652 {
653 if ( StringUtils.isEmpty( output ) )
654 {
655 throw new IllegalArgumentException( "The output could not be null." );
656 }
657
658 Pattern pattern = Pattern.compile( "(?s).*?([0-9]+\\.[0-9]+)(\\.([0-9]+))?.*" );
659
660 Matcher matcher = pattern.matcher( output );
661 if ( !matcher.matches() )
662 {
663 throw new PatternSyntaxException( "Unrecognized version of Javadoc: '" + output + "'", pattern.pattern(),
664 pattern.toString().length() - 1 );
665 }
666
667 String version = matcher.group( 3 );
668 if ( version == null )
669 {
670 version = matcher.group( 1 );
671 }
672 else
673 {
674 version = matcher.group( 1 ) + version;
675 }
676
677 return Float.parseFloat( version );
678 }
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709 protected static String parseJavadocMemory( String memory )
710 throws IllegalArgumentException
711 {
712 if ( StringUtils.isEmpty( memory ) )
713 {
714 throw new IllegalArgumentException( "The memory could not be null." );
715 }
716
717 Pattern p = Pattern.compile( "^\\s*(\\d+)\\s*?\\s*$" );
718 Matcher m = p.matcher( memory );
719 if ( m.matches() )
720 {
721 return m.group( 1 ) + "m";
722 }
723
724 p = Pattern.compile( "^\\s*(\\d+)\\s*k(b)?\\s*$", Pattern.CASE_INSENSITIVE );
725 m = p.matcher( memory );
726 if ( m.matches() )
727 {
728 return m.group( 1 ) + "k";
729 }
730
731 p = Pattern.compile( "^\\s*(\\d+)\\s*m(b)?\\s*$", Pattern.CASE_INSENSITIVE );
732 m = p.matcher( memory );
733 if ( m.matches() )
734 {
735 return m.group( 1 ) + "m";
736 }
737
738 p = Pattern.compile( "^\\s*(\\d+)\\s*g(b)?\\s*$", Pattern.CASE_INSENSITIVE );
739 m = p.matcher( memory );
740 if ( m.matches() )
741 {
742 return ( Integer.parseInt( m.group( 1 ) ) * 1024 ) + "m";
743 }
744
745 p = Pattern.compile( "^\\s*(\\d+)\\s*t(b)?\\s*$", Pattern.CASE_INSENSITIVE );
746 m = p.matcher( memory );
747 if ( m.matches() )
748 {
749 return ( Integer.parseInt( m.group( 1 ) ) * 1024 * 1024 ) + "m";
750 }
751
752 throw new IllegalArgumentException( "Could convert not to a memory size: " + memory );
753 }
754
755
756
757
758
759
760
761 protected static boolean validateEncoding( String charsetName )
762 {
763 if ( StringUtils.isEmpty( charsetName ) )
764 {
765 return false;
766 }
767
768 OutputStream ost = new ByteArrayOutputStream();
769 OutputStreamWriter osw = null;
770 try
771 {
772 osw = new OutputStreamWriter( ost, charsetName );
773 }
774 catch ( UnsupportedEncodingException exc )
775 {
776 return false;
777 }
778 finally
779 {
780 IOUtil.close( osw );
781 }
782
783 return true;
784 }
785
786
787
788
789
790
791
792
793
794 protected static String hideProxyPassword( String cmdLine, Settings settings )
795 {
796 if ( cmdLine == null )
797 {
798 throw new IllegalArgumentException( "cmdLine could not be null" );
799 }
800
801 if ( settings == null )
802 {
803 return cmdLine;
804 }
805
806 Proxy activeProxy = settings.getActiveProxy();
807 if ( activeProxy != null && StringUtils.isNotEmpty( activeProxy.getHost() )
808 && StringUtils.isNotEmpty( activeProxy.getUsername() )
809 && StringUtils.isNotEmpty( activeProxy.getPassword() ) )
810 {
811 String pass = "-J-Dhttp.proxyPassword=\"" + activeProxy.getPassword() + "\"";
812 String hidepass =
813 "-J-Dhttp.proxyPassword=\"" + StringUtils.repeat( "*", activeProxy.getPassword().length() ) + "\"";
814
815 return StringUtils.replace( cmdLine, pass, hidepass );
816 }
817
818 return cmdLine;
819 }
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835 protected static List<String> getTagletClassNames( File jarFile )
836 throws IOException, ClassNotFoundException, NoClassDefFoundError
837 {
838 List<String> classes = getClassNamesFromJar( jarFile );
839 ClassLoader cl;
840
841
842 File tools = new File( System.getProperty( "java.home" ), "../lib/tools.jar" );
843 if ( tools.exists() && tools.isFile() )
844 {
845 cl = new URLClassLoader( new URL[] { jarFile.toURI().toURL(), tools.toURI().toURL() }, null );
846 }
847 else
848 {
849 cl = new URLClassLoader( new URL[] { jarFile.toURI().toURL() }, null );
850 }
851
852 List<String> tagletClasses = new ArrayList<String>();
853
854 Class<?> tagletClass = cl.loadClass( "com.sun.tools.doclets.Taglet" );
855 for ( String s : classes )
856 {
857 Class<?> c = cl.loadClass( s );
858
859 if ( tagletClass.isAssignableFrom( c ) && !Modifier.isAbstract( c.getModifiers() ) )
860 {
861 tagletClasses.add( c.getName() );
862 }
863 }
864
865 return tagletClasses;
866 }
867
868
869
870
871
872
873
874
875
876 protected static void copyResource( URL url, File file )
877 throws IOException
878 {
879 if ( file == null )
880 {
881 throw new IOException( "The file " + file + " can't be null." );
882 }
883 if ( url == null )
884 {
885 throw new IOException( "The url " + url + " could not be null." );
886 }
887
888 InputStream is = url.openStream();
889 if ( is == null )
890 {
891 throw new IOException( "The resource " + url + " doesn't exists." );
892 }
893
894 if ( !file.getParentFile().exists() )
895 {
896 file.getParentFile().mkdirs();
897 }
898
899 OutputStream os = null;
900 try
901 {
902 os = new FileOutputStream( file );
903
904 IOUtil.copy( is, os );
905 }
906 finally
907 {
908 IOUtil.close( is );
909
910 IOUtil.close( os );
911 }
912 }
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
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 if ( projectFile == null )
935 {
936 throw new IllegalArgumentException( "projectFile should be not null." );
937 }
938 if ( !projectFile.isFile() )
939 {
940 throw new IllegalArgumentException( projectFile.getAbsolutePath() + " is not a file." );
941 }
942 if ( goals == null || goals.size() == 0 )
943 {
944 throw new IllegalArgumentException( "goals should be not empty." );
945 }
946 if ( localRepositoryDir == null || !localRepositoryDir.isDirectory() )
947 {
948 throw new IllegalArgumentException( "localRepositoryDir '" + localRepositoryDir
949 + "' should be a directory." );
950 }
951
952 String mavenHome = getMavenHome( log );
953 if ( StringUtils.isEmpty( mavenHome ) )
954 {
955 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 if ( log != null )
959 {
960 log.error( msg );
961 }
962 else
963 {
964 System.err.println( msg );
965 }
966 return;
967 }
968
969 Invoker invoker = new DefaultInvoker();
970 invoker.setMavenHome( new File( mavenHome ) );
971 invoker.setLocalRepositoryDirectory( localRepositoryDir );
972
973 InvocationRequest request = new DefaultInvocationRequest();
974 request.setBaseDirectory( projectFile.getParentFile() );
975 request.setPomFile( projectFile );
976 if ( log != null )
977 {
978 request.setDebug( log.isDebugEnabled() );
979 }
980 else
981 {
982 request.setDebug( true );
983 }
984 request.setGoals( goals );
985 if ( properties != null )
986 {
987 request.setProperties( properties );
988 }
989 File javaHome = getJavaHome( log );
990 if ( javaHome != null )
991 {
992 request.setJavaHome( javaHome );
993 }
994
995 if ( log != null && log.isDebugEnabled() )
996 {
997 log.debug( "Invoking Maven for the goals: " + goals + " with "
998 + ( properties == null ? "no properties" : "properties=" + properties ) );
999 }
1000 InvocationResult result = invoke( log, invoker, request, invokerLog, goals, properties, null );
1001
1002 if ( result.getExitCode() != 0 )
1003 {
1004 String invokerLogContent = readFile( invokerLog, "UTF-8" );
1005
1006
1007 if ( invokerLogContent != null && ( invokerLogContent.indexOf( "Scanning for projects..." ) == -1
1008 || invokerLogContent.indexOf( OutOfMemoryError.class.getName() ) != -1 ) )
1009 {
1010 if ( log != null )
1011 {
1012 log.error( "Error occurred during initialization of VM, trying to use an empty MAVEN_OPTS..." );
1013
1014 if ( log.isDebugEnabled() )
1015 {
1016 log.debug( "Reinvoking Maven for the goals: " + goals + " with an empty MAVEN_OPTS..." );
1017 }
1018 }
1019 result = invoke( log, invoker, request, invokerLog, goals, properties, "" );
1020 }
1021 }
1022
1023 if ( result.getExitCode() != 0 )
1024 {
1025 String invokerLogContent = readFile( invokerLog, "UTF-8" );
1026
1027
1028 if ( invokerLogContent != null && ( invokerLogContent.indexOf( "Scanning for projects..." ) == -1
1029 || invokerLogContent.indexOf( OutOfMemoryError.class.getName() ) != -1 ) )
1030 {
1031 throw new MavenInvocationException( ERROR_INIT_VM );
1032 }
1033
1034 throw new MavenInvocationException( "Error when invoking Maven, consult the invoker log file: "
1035 + invokerLog.getAbsolutePath() );
1036 }
1037 }
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048 protected static String readFile( final File javaFile, final String encoding )
1049 {
1050 try
1051 {
1052 return FileUtils.fileRead( javaFile, encoding );
1053 }
1054 catch ( IOException e )
1055 {
1056 return null;
1057 }
1058 }
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075 protected static String[] splitPath( final String path )
1076 {
1077 if ( path == null )
1078 {
1079 return null;
1080 }
1081
1082 List<String> subpaths = new ArrayList<String>();
1083 PathTokenizer pathTokenizer = new PathTokenizer( path );
1084 while ( pathTokenizer.hasMoreTokens() )
1085 {
1086 subpaths.add( pathTokenizer.nextToken() );
1087 }
1088
1089 return subpaths.toArray( new String[subpaths.size()] );
1090 }
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108 protected static String unifyPathSeparator( final String path )
1109 {
1110 if ( path == null )
1111 {
1112 return null;
1113 }
1114
1115 return StringUtils.join( splitPath( path ), File.pathSeparator );
1116 }
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127 private static List<String> getClassNamesFromJar( File jarFile )
1128 throws IOException
1129 {
1130 if ( jarFile == null || !jarFile.exists() || !jarFile.isFile() )
1131 {
1132 throw new IOException( "The jar '" + jarFile + "' doesn't exist or is not a file." );
1133 }
1134
1135 List<String> classes = new ArrayList<String>();
1136 JarInputStream jarStream = null;
1137
1138 try
1139 {
1140 jarStream = new JarInputStream( new FileInputStream( jarFile ) );
1141 JarEntry jarEntry = jarStream.getNextJarEntry();
1142 while ( jarEntry != null )
1143 {
1144 if ( jarEntry.getName().toLowerCase( Locale.ENGLISH ).endsWith( ".class" ) )
1145 {
1146 String name = jarEntry.getName().substring( 0, jarEntry.getName().indexOf( "." ) );
1147
1148 classes.add( name.replaceAll( "/", "\\." ) );
1149 }
1150
1151 jarStream.closeEntry();
1152 jarEntry = jarStream.getNextJarEntry();
1153 }
1154 }
1155 finally
1156 {
1157 IOUtil.close( jarStream );
1158 }
1159
1160 return classes;
1161 }
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
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 OutputStream os = null;
1181 if ( invokerLog != null )
1182 {
1183 if ( log != null && log.isDebugEnabled() )
1184 {
1185 log.debug( "Using " + invokerLog.getAbsolutePath() + " to log the invoker" );
1186 }
1187
1188 try
1189 {
1190 if ( !invokerLog.exists() )
1191 {
1192 invokerLog.getParentFile().mkdirs();
1193 }
1194 os = new FileOutputStream( invokerLog );
1195 ps = new PrintStream( os, true, "UTF-8" );
1196 }
1197 catch ( FileNotFoundException e )
1198 {
1199 if ( log != null && log.isErrorEnabled() )
1200 {
1201 log.error( "FileNotFoundException: " + e.getMessage() + ". Using System.out to log the invoker." );
1202 }
1203 ps = System.out;
1204 }
1205 catch ( UnsupportedEncodingException e )
1206 {
1207 if ( log != null && log.isErrorEnabled() )
1208 {
1209 log.error( "UnsupportedEncodingException: " + e.getMessage()
1210 + ". Using System.out to log the invoker." );
1211 }
1212 ps = System.out;
1213 }
1214 }
1215 else
1216 {
1217 if ( log != null && log.isDebugEnabled() )
1218 {
1219 log.debug( "Using System.out to log the invoker." );
1220 }
1221
1222 ps = System.out;
1223 }
1224
1225 if ( mavenOpts != null )
1226 {
1227 request.setMavenOpts( mavenOpts );
1228 }
1229
1230 InvocationOutputHandler outputHandler = new PrintStreamHandler( ps, false );
1231 request.setOutputHandler( outputHandler );
1232
1233 outputHandler.consumeLine( "Invoking Maven for the goals: " + goals + " with "
1234 + ( properties == null ? "no properties" : "properties=" + properties ) );
1235 outputHandler.consumeLine( "" );
1236 outputHandler.consumeLine( "M2_HOME=" + getMavenHome( log ) );
1237 outputHandler.consumeLine( "MAVEN_OPTS=" + getMavenOpts( log ) );
1238 outputHandler.consumeLine( "JAVA_HOME=" + getJavaHome( log ) );
1239 outputHandler.consumeLine( "JAVA_OPTS=" + getJavaOpts( log ) );
1240 outputHandler.consumeLine( "" );
1241
1242 try
1243 {
1244 return invoker.execute( request );
1245 }
1246 finally
1247 {
1248 IOUtil.close( os );
1249 ps = null;
1250 }
1251 }
1252
1253
1254
1255
1256
1257
1258
1259 private static String getMavenHome( Log log )
1260 {
1261 String mavenHome = System.getProperty( "maven.home" );
1262 if ( mavenHome == null )
1263 {
1264 try
1265 {
1266 mavenHome = CommandLineUtils.getSystemEnvVars().getProperty( "M2_HOME" );
1267 }
1268 catch ( IOException e )
1269 {
1270 if ( log != null && log.isDebugEnabled() )
1271 {
1272 log.debug( "IOException: " + e.getMessage() );
1273 }
1274 }
1275 }
1276
1277 File m2Home = new File( mavenHome );
1278 if ( !m2Home.exists() )
1279 {
1280 if ( log != null && log.isErrorEnabled() )
1281 {
1282 log
1283 .error( "Cannot find Maven application directory. Either specify \'maven.home\' system property, or "
1284 + "M2_HOME environment variable." );
1285 }
1286 }
1287
1288 return mavenHome;
1289 }
1290
1291
1292
1293
1294
1295
1296 private static String getMavenOpts( Log log )
1297 {
1298 String mavenOpts = null;
1299 try
1300 {
1301 mavenOpts = CommandLineUtils.getSystemEnvVars().getProperty( "MAVEN_OPTS" );
1302 }
1303 catch ( IOException e )
1304 {
1305 if ( log != null && log.isDebugEnabled() )
1306 {
1307 log.debug( "IOException: " + e.getMessage() );
1308 }
1309 }
1310
1311 return mavenOpts;
1312 }
1313
1314
1315
1316
1317
1318
1319
1320
1321 private static File getJavaHome( Log log )
1322 {
1323 File javaHome;
1324 if ( SystemUtils.IS_OS_MAC_OSX )
1325 {
1326 javaHome = SystemUtils.getJavaHome();
1327 }
1328 else
1329 {
1330 javaHome = new File( SystemUtils.getJavaHome(), ".." );
1331 }
1332
1333 if ( javaHome == null || !javaHome.exists() )
1334 {
1335 try
1336 {
1337 javaHome = new File( CommandLineUtils.getSystemEnvVars().getProperty( "JAVA_HOME" ) );
1338 }
1339 catch ( IOException e )
1340 {
1341 if ( log != null && log.isDebugEnabled() )
1342 {
1343 log.debug( "IOException: " + e.getMessage() );
1344 }
1345 }
1346 }
1347
1348 if ( javaHome == null || !javaHome.exists() )
1349 {
1350 if ( log != null && log.isErrorEnabled() )
1351 {
1352 log.error( "Cannot find Java application directory. Either specify \'java.home\' system property, or "
1353 + "JAVA_HOME environment variable." );
1354 }
1355 }
1356
1357 return javaHome;
1358 }
1359
1360
1361
1362
1363
1364
1365 private static String getJavaOpts( Log log )
1366 {
1367 String javaOpts = null;
1368 try
1369 {
1370 javaOpts = CommandLineUtils.getSystemEnvVars().getProperty( "JAVA_OPTS" );
1371 }
1372 catch ( IOException e )
1373 {
1374 if ( log != null && log.isDebugEnabled() )
1375 {
1376 log.debug( "IOException: " + e.getMessage() );
1377 }
1378 }
1379
1380 return javaOpts;
1381 }
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393 private static class PathTokenizer
1394 {
1395
1396
1397
1398 private StringTokenizer tokenizer;
1399
1400
1401
1402
1403
1404 private String lookahead = null;
1405
1406
1407
1408
1409
1410
1411 private boolean onNetWare = Os.isFamily( "netware" );
1412
1413
1414
1415
1416
1417 private boolean dosStyleFilesystem;
1418
1419
1420
1421
1422
1423
1424 public PathTokenizer( String path )
1425 {
1426 if ( onNetWare )
1427 {
1428
1429
1430 tokenizer = new StringTokenizer( path, ":;", true );
1431 }
1432 else
1433 {
1434
1435
1436 tokenizer = new StringTokenizer( path, ":;", false );
1437 }
1438 dosStyleFilesystem = File.pathSeparatorChar == ';';
1439 }
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449 public boolean hasMoreTokens()
1450 {
1451 if ( lookahead != null )
1452 {
1453 return true;
1454 }
1455
1456 return tokenizer.hasMoreTokens();
1457 }
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467 public String nextToken()
1468 throws NoSuchElementException
1469 {
1470 String token = null;
1471 if ( lookahead != null )
1472 {
1473 token = lookahead;
1474 lookahead = null;
1475 }
1476 else
1477 {
1478 token = tokenizer.nextToken().trim();
1479 }
1480
1481 if ( !onNetWare )
1482 {
1483 if ( token.length() == 1 && Character.isLetter( token.charAt( 0 ) ) && dosStyleFilesystem
1484 && tokenizer.hasMoreTokens() )
1485 {
1486
1487
1488 String nextToken = tokenizer.nextToken().trim();
1489 if ( nextToken.startsWith( "\\" ) || nextToken.startsWith( "/" ) )
1490 {
1491
1492
1493
1494 token += ":" + nextToken;
1495 }
1496 else
1497 {
1498
1499 lookahead = nextToken;
1500 }
1501 }
1502 }
1503 else
1504 {
1505
1506
1507 if ( token.equals( File.pathSeparator ) || token.equals( ":" ) )
1508 {
1509
1510 token = tokenizer.nextToken().trim();
1511 }
1512
1513 if ( tokenizer.hasMoreTokens() )
1514 {
1515
1516 String nextToken = tokenizer.nextToken().trim();
1517
1518
1519 if ( !nextToken.equals( File.pathSeparator ) )
1520 {
1521 if ( nextToken.equals( ":" ) )
1522 {
1523 if ( !token.startsWith( "/" ) && !token.startsWith( "\\" ) && !token.startsWith( "." )
1524 && !token.startsWith( ".." ) )
1525 {
1526
1527 String oneMore = tokenizer.nextToken().trim();
1528 if ( !oneMore.equals( File.pathSeparator ) )
1529 {
1530 token += ":" + oneMore;
1531 }
1532 else
1533 {
1534 token += ":";
1535 lookahead = oneMore;
1536 }
1537 }
1538
1539
1540 }
1541 else
1542 {
1543
1544 lookahead = nextToken;
1545 }
1546 }
1547 }
1548 }
1549 return token;
1550 }
1551 }
1552
1553 static List<String> toList( String src )
1554 {
1555 return toList( src, null, null );
1556 }
1557
1558 static List<String> toList( String src, String elementPrefix, String elementSuffix )
1559 {
1560 if ( StringUtils.isEmpty( src ) )
1561 {
1562 return null;
1563 }
1564
1565 List<String> result = new ArrayList<String>();
1566
1567 StringTokenizer st = new StringTokenizer( src, "[,:;]" );
1568 StringBuilder sb = new StringBuilder( 256 );
1569 while ( st.hasMoreTokens() )
1570 {
1571 sb.setLength( 0 );
1572 if ( StringUtils.isNotEmpty( elementPrefix ) )
1573 {
1574 sb.append( elementPrefix );
1575 }
1576
1577 sb.append( st.nextToken() );
1578
1579 if ( StringUtils.isNotEmpty( elementSuffix ) )
1580 {
1581 sb.append( elementSuffix );
1582 }
1583
1584 result.add( sb.toString() );
1585 }
1586
1587 return result;
1588 }
1589
1590 static <T> List<T> toList( T[] multiple )
1591 {
1592 return toList( null, multiple );
1593 }
1594
1595 static <T> List<T> toList( T single, T[] multiple )
1596 {
1597 if ( single == null && ( multiple == null || multiple.length < 1 ) )
1598 {
1599 return null;
1600 }
1601
1602 List<T> result = new ArrayList<T>();
1603 if ( single != null )
1604 {
1605 result.add( single );
1606 }
1607
1608 if ( multiple != null && multiple.length > 0 )
1609 {
1610 result.addAll( Arrays.asList( multiple ) );
1611 }
1612
1613 return result;
1614 }
1615
1616
1617 public static String toRelative( File basedir, String absolutePath )
1618 {
1619 String relative;
1620
1621 absolutePath = absolutePath.replace( '\\', '/' );
1622 String basedirPath = basedir.getAbsolutePath().replace( '\\', '/' );
1623
1624 if ( absolutePath.startsWith( basedirPath ) )
1625 {
1626 relative = absolutePath.substring( basedirPath.length() );
1627 if ( relative.startsWith( "/" ) )
1628 {
1629 relative = relative.substring( 1 );
1630 }
1631 if ( relative.length() <= 0 )
1632 {
1633 relative = ".";
1634 }
1635 }
1636 else
1637 {
1638 relative = absolutePath;
1639 }
1640
1641 return relative;
1642 }
1643
1644
1645
1646
1647 public static boolean isNotEmpty( final Collection<?> collection )
1648 {
1649 return collection != null && !collection.isEmpty();
1650 }
1651
1652
1653
1654
1655 public static boolean isEmpty( final Collection<?> collection )
1656 {
1657 return collection == null || collection.isEmpty();
1658 }
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677 protected static boolean isValidPackageList( URL url, Settings settings, boolean validateContent )
1678 throws IOException
1679 {
1680 if ( url == null )
1681 {
1682 throw new IllegalArgumentException( "The url is null" );
1683 }
1684
1685 BufferedReader reader = null;
1686 GetMethod httpMethod = null;
1687
1688 try
1689 {
1690 if ( "file".equals( url.getProtocol() ) )
1691 {
1692
1693 reader = new BufferedReader( new InputStreamReader( url.openStream() ) );
1694 }
1695 else
1696 {
1697
1698 HttpClient httpClient = createHttpClient( settings, url );
1699
1700 httpMethod = new GetMethod( url.toString() );
1701 int status;
1702 try
1703 {
1704 status = httpClient.executeMethod( httpMethod );
1705 }
1706 catch ( SocketTimeoutException e )
1707 {
1708
1709 status = httpClient.executeMethod( httpMethod );
1710 }
1711
1712 if ( status != HttpStatus.SC_OK )
1713 {
1714 throw new FileNotFoundException(
1715 "Unexpected HTTP status code " + status + " getting resource " + url.toExternalForm() + "." );
1716
1717 }
1718
1719
1720 reader = new BufferedReader( new InputStreamReader( httpMethod.getResponseBodyAsStream() ) );
1721 }
1722
1723 if ( validateContent )
1724 {
1725 String line;
1726 while ( ( line = reader.readLine() ) != null )
1727 {
1728 if ( !isValidPackageName( line ) )
1729 {
1730 return false;
1731 }
1732 }
1733 }
1734
1735 return true;
1736 }
1737 finally
1738 {
1739 IOUtil.close( reader );
1740
1741 if ( httpMethod != null )
1742 {
1743 httpMethod.releaseConnection();
1744 }
1745 }
1746 }
1747
1748 private static boolean isValidPackageName( String str )
1749 {
1750 if ( StringUtils.isEmpty( str ) )
1751 {
1752 return false;
1753 }
1754
1755 int idx;
1756 while ( ( idx = str.indexOf( '.' ) ) != -1 )
1757 {
1758 if ( !isValidClassName( str.substring( 0, idx ) ) )
1759 {
1760 return false;
1761 }
1762
1763 str = str.substring( idx + 1 );
1764 }
1765
1766 return isValidClassName( str );
1767 }
1768
1769 private static boolean isValidClassName( String str )
1770 {
1771 if ( StringUtils.isEmpty( str ) || !Character.isJavaIdentifierStart( str.charAt( 0 ) ) )
1772 {
1773 return false;
1774 }
1775
1776 for ( int i = str.length() - 1; i > 0; i-- )
1777 {
1778 if ( !Character.isJavaIdentifierPart( str.charAt( i ) ) )
1779 {
1780 return false;
1781 }
1782 }
1783
1784 return true;
1785 }
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798 private static HttpClient createHttpClient( Settings settings, URL url )
1799 {
1800 HttpClient httpClient = new HttpClient( new MultiThreadedHttpConnectionManager() );
1801 httpClient.getHttpConnectionManager().getParams().setConnectionTimeout( DEFAULT_TIMEOUT );
1802 httpClient.getHttpConnectionManager().getParams().setSoTimeout( DEFAULT_TIMEOUT );
1803 httpClient.getParams().setBooleanParameter( HttpClientParams.ALLOW_CIRCULAR_REDIRECTS, true );
1804
1805
1806 httpClient.getParams().setParameter( HttpMethodParams.USER_AGENT,
1807 "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" );
1808
1809 if ( settings != null && settings.getActiveProxy() != null )
1810 {
1811 Proxy activeProxy = settings.getActiveProxy();
1812
1813 ProxyInfo proxyInfo = new ProxyInfo();
1814 proxyInfo.setNonProxyHosts( activeProxy.getNonProxyHosts() );
1815
1816 if ( StringUtils.isNotEmpty( activeProxy.getHost() )
1817 && ( url == null || !ProxyUtils.validateNonProxyHosts( proxyInfo, url.getHost() ) ) )
1818 {
1819 httpClient.getHostConfiguration().setProxy( activeProxy.getHost(), activeProxy.getPort() );
1820
1821 if ( StringUtils.isNotEmpty( activeProxy.getUsername() ) && activeProxy.getPassword() != null )
1822 {
1823 Credentials credentials =
1824 new UsernamePasswordCredentials( activeProxy.getUsername(), activeProxy.getPassword() );
1825
1826 httpClient.getState().setProxyCredentials( AuthScope.ANY, credentials );
1827 }
1828 }
1829 }
1830
1831 return httpClient;
1832 }
1833
1834 static boolean equalsIgnoreCase( String value, String... strings )
1835 {
1836 for ( String s : strings )
1837 {
1838 if ( s.equalsIgnoreCase( value ) )
1839 {
1840 return true;
1841 }
1842 }
1843 return false;
1844 }
1845
1846 static boolean equals( String value, String... strings )
1847 {
1848 for ( String s : strings )
1849 {
1850 if ( s.equals( value ) )
1851 {
1852 return true;
1853 }
1854 }
1855 return false;
1856 }
1857 }