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