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