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