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 static org.codehaus.plexus.util.IOUtil.close;
23 import static org.apache.maven.plugin.javadoc.JavadocUtil.toList;
24 import static org.apache.maven.plugin.javadoc.JavadocUtil.toRelative;
25 import static org.apache.maven.plugin.javadoc.JavadocUtil.isNotEmpty;
26 import static org.apache.maven.plugin.javadoc.JavadocUtil.isEmpty;
27
28 import java.io.File;
29 import java.io.FileOutputStream;
30 import java.io.FileWriter;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.io.OutputStream;
34 import java.net.MalformedURLException;
35 import java.net.URI;
36 import java.net.URISyntaxException;
37 import java.net.URL;
38 import java.net.URLClassLoader;
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.Calendar;
42 import java.util.Collection;
43 import java.util.Collections;
44 import java.util.HashMap;
45 import java.util.HashSet;
46 import java.util.LinkedHashSet;
47 import java.util.LinkedList;
48 import java.util.List;
49 import java.util.Locale;
50 import java.util.Map;
51 import java.util.Properties;
52 import java.util.Set;
53 import java.util.StringTokenizer;
54
55 import org.apache.commons.lang.ClassUtils;
56 import org.apache.commons.lang.SystemUtils;
57 import org.apache.maven.artifact.Artifact;
58 import org.apache.maven.artifact.factory.ArtifactFactory;
59 import org.apache.maven.artifact.handler.ArtifactHandler;
60 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
61 import org.apache.maven.artifact.repository.ArtifactRepository;
62 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
63 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
64 import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
65 import org.apache.maven.artifact.resolver.ArtifactResolver;
66 import org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException;
67 import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
68 import org.apache.maven.artifact.versioning.ArtifactVersion;
69 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
70 import org.apache.maven.execution.MavenSession;
71 import org.apache.maven.model.Dependency;
72 import org.apache.maven.model.Plugin;
73 import org.apache.maven.model.Resource;
74 import org.apache.maven.plugin.AbstractMojo;
75 import org.apache.maven.plugin.MojoExecutionException;
76 import org.apache.maven.plugin.javadoc.options.BootclasspathArtifact;
77 import org.apache.maven.plugin.javadoc.options.DocletArtifact;
78 import org.apache.maven.plugin.javadoc.options.Group;
79 import org.apache.maven.plugin.javadoc.options.JavadocOptions;
80 import org.apache.maven.plugin.javadoc.options.JavadocPathArtifact;
81 import org.apache.maven.plugin.javadoc.options.OfflineLink;
82 import org.apache.maven.plugin.javadoc.options.ResourcesArtifact;
83 import org.apache.maven.plugin.javadoc.options.Tag;
84 import org.apache.maven.plugin.javadoc.options.Taglet;
85 import org.apache.maven.plugin.javadoc.options.TagletArtifact;
86 import org.apache.maven.plugin.javadoc.options.io.xpp3.JavadocOptionsXpp3Writer;
87 import org.apache.maven.plugin.javadoc.resolver.JavadocBundle;
88 import org.apache.maven.plugin.javadoc.resolver.ResourceResolver;
89 import org.apache.maven.plugin.javadoc.resolver.SourceResolverConfig;
90 import org.apache.maven.project.MavenProject;
91 import org.apache.maven.project.MavenProjectBuilder;
92 import org.apache.maven.project.ProjectBuildingException;
93 import org.apache.maven.project.artifact.InvalidDependencyVersionException;
94 import org.apache.maven.reporting.MavenReportException;
95 import org.apache.maven.settings.Proxy;
96 import org.apache.maven.settings.Settings;
97 import org.apache.maven.shared.artifact.filter.PatternExcludesArtifactFilter;
98 import org.apache.maven.shared.artifact.filter.PatternIncludesArtifactFilter;
99 import org.apache.maven.shared.invoker.MavenInvocationException;
100 import org.apache.maven.toolchain.Toolchain;
101 import org.apache.maven.toolchain.ToolchainManager;
102 import org.apache.maven.wagon.PathUtils;
103 import org.codehaus.plexus.archiver.ArchiverException;
104 import org.codehaus.plexus.archiver.UnArchiver;
105 import org.codehaus.plexus.archiver.manager.ArchiverManager;
106 import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
107 import org.codehaus.plexus.components.io.fileselectors.IncludeExcludeFileSelector;
108 import org.codehaus.plexus.util.FileUtils;
109 import org.codehaus.plexus.util.IOUtil;
110 import org.codehaus.plexus.util.ReaderFactory;
111 import org.codehaus.plexus.util.StringUtils;
112 import org.codehaus.plexus.util.cli.CommandLineException;
113 import org.codehaus.plexus.util.cli.CommandLineUtils;
114 import org.codehaus.plexus.util.cli.Commandline;
115 import org.codehaus.plexus.util.xml.Xpp3Dom;
116
117
118
119
120
121
122
123
124
125
126
127
128 public abstract class AbstractJavadocMojo
129 extends AbstractMojo
130 {
131
132
133
134
135
136
137
138 public static final String JAVADOC_RESOURCES_ATTACHMENT_CLASSIFIER = "javadoc-resources";
139
140
141
142
143
144
145
146
147 public static final String TEST_JAVADOC_RESOURCES_ATTACHMENT_CLASSIFIER = "test-javadoc-resources";
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175 public static final Properties DEFAULT_JAVA_API_LINKS = new Properties();
176
177
178 protected static final String DEBUG_JAVADOC_SCRIPT_NAME =
179 "javadoc." + ( SystemUtils.IS_OS_WINDOWS ? "bat" : "sh" );
180
181
182
183 protected static final String OPTIONS_FILE_NAME = "options";
184
185
186
187 protected static final String PACKAGES_FILE_NAME = "packages";
188
189
190
191 protected static final String ARGFILE_FILE_NAME = "argfile";
192
193
194
195 protected static final String FILES_FILE_NAME = "files";
196
197
198 private static final String RESOURCE_DIR = ClassUtils.getPackageName( JavadocReport.class ).replace( '.', '/' );
199
200
201 private static final String DEFAULT_CSS_NAME = "stylesheet.css";
202
203
204 private static final String RESOURCE_CSS_DIR = RESOURCE_DIR + "/css";
205
206
207
208
209
210
211
212 private static final float SINCE_JAVADOC_1_4 = 1.4f;
213
214
215
216
217
218
219
220 private static final float SINCE_JAVADOC_1_4_2 = 1.42f;
221
222
223
224
225
226
227
228 private static final float SINCE_JAVADOC_1_5 = 1.5f;
229
230
231
232
233
234
235
236 private static final float SINCE_JAVADOC_1_6 = 1.6f;
237
238
239
240
241
242
243
244
245
246
247
248 private ArchiverManager archiverManager;
249
250
251
252
253
254
255 private ArtifactFactory factory;
256
257
258
259
260
261
262
263 private ArtifactMetadataSource artifactMetadataSource;
264
265
266
267
268
269
270 private ArtifactResolver resolver;
271
272
273
274
275
276
277
278 private MavenProjectBuilder mavenProjectBuilder;
279
280
281 private ToolchainManager toolchainManager;
282
283
284
285
286
287
288
289
290
291
292
293
294
295 private MavenSession session;
296
297
298
299
300
301
302
303
304
305 private Settings settings;
306
307
308
309
310
311
312
313
314 protected MavenProject project;
315
316
317
318
319
320
321
322
323 private boolean isOffline;
324
325
326
327
328
329
330
331
332
333
334
335
336 private File javadocDirectory;
337
338
339
340
341
342
343
344 private String additionalparam;
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361 private String additionalJOption;
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384 private ResourcesArtifact[] resourcesArtifacts;
385
386
387
388
389
390
391 private ArtifactRepository localRepository;
392
393
394
395
396
397
398 private List<ArtifactRepository> remoteRepositories;
399
400
401
402
403
404
405
406 private List<MavenProject> reactorProjects;
407
408
409
410
411
412
413
414 protected boolean aggregate;
415
416
417
418
419
420
421
422
423
424 private boolean debug;
425
426
427
428
429
430
431
432
433 private String javadocExecutable;
434
435
436
437
438
439
440
441 private String javadocVersion;
442
443
444
445
446 private float fJavadocVersion = 0.0f;
447
448
449
450
451
452
453
454 protected boolean skip;
455
456
457
458
459
460
461
462 protected boolean failOnError;
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483 protected boolean useStandardDocletOptions;
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503 private boolean detectLinks;
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522 private boolean detectOfflineLinks;
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542 private boolean detectJavaApiLink;
543
544
545
546
547
548
549
550
551
552
553
554
555
556 private Properties javaApiLinks;
557
558
559
560
561
562
563
564
565 private boolean validateLinks;
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581 private String bootclasspath;
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605 private BootclasspathArtifact[] bootclasspathArtifacts;
606
607
608
609
610
611
612
613
614
615
616
617 private boolean breakiterator;
618
619
620
621
622
623
624
625
626 private String doclet;
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648 private DocletArtifact docletArtifact;
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 private DocletArtifact[] docletArtifacts;
674
675
676
677
678
679
680
681
682
683
684 private String docletPath;
685
686
687
688
689
690
691
692
693
694
695
696
697
698 private String encoding;
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716 private String excludePackageNames;
717
718
719
720
721
722
723
724
725
726 private String extdirs;
727
728
729
730
731
732
733
734
735 private String locale;
736
737
738
739
740
741
742
743
744
745
746 private String maxmemory;
747
748
749
750
751
752
753
754
755
756
757 private String minmemory;
758
759
760
761
762
763
764
765
766
767
768 private boolean old;
769
770
771
772
773
774
775
776
777
778
779
780
781 private File overview;
782
783
784
785
786
787
788
789
790
791
792 private String proxyHost;
793
794
795
796
797
798
799
800
801
802
803 private int proxyPort;
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819 private boolean quiet;
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838 private String show;
839
840
841
842
843
844
845
846
847
848
849 private String source;
850
851
852
853
854
855
856
857
858
859 private String sourcepath;
860
861
862
863
864
865
866
867
868
869
870
871 private String subpackages;
872
873
874
875
876
877
878
879
880
881 private boolean verbose;
882
883
884
885
886
887
888
889
890
891
892
893
894
895 private boolean author;
896
897
898
899
900
901
902
903
904
905
906
907
908 private String bottom;
909
910
911
912
913
914
915
916
917
918
919 private String charset;
920
921
922
923
924
925
926
927
928
929 private String docencoding;
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948 private boolean docfilessubdirs;
949
950
951
952
953
954
955
956
957
958 private String doctitle;
959
960
961
962
963
964
965
966
967
968
969
970
971
972 private String excludedocfilessubdir;
973
974
975
976
977
978
979
980
981 private String footer;
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017 private Group[] groups;
1018
1019
1020
1021
1022
1023
1024
1025
1026 private String header;
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072 private String helpfile;
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089 private boolean keywords;
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115 protected ArrayList<String> links;
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128 private boolean linksource;
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140 private boolean nocomment;
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150 private boolean nodeprecated;
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162 private boolean nodeprecatedlist;
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174 private boolean nohelp;
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186 private boolean noindex;
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196 private boolean nonavbar;
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209 private boolean nooverview;
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225 private String noqualifier;
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235 private boolean nosince;
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249 private boolean notimestamp;
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259 private boolean notree;
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285 private OfflineLink[] offlineLinks;
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296 protected File outputDirectory;
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307 private String packagesheader;
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317 private boolean serialwarn;
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334 private int sourcetab;
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347 private boolean splitindex;
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358 private String stylesheet;
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402 private String stylesheetfile;
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413 private String taglet;
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444 private TagletArtifact tagletArtifact;
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472 private TagletArtifact[] tagletArtifacts;
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484 private String tagletpath;
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514 private Taglet[] taglets;
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549 private Tag[] tags;
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561 private String top;
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571 private boolean use;
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581 private boolean version;
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591 private String windowtitle;
1592
1593
1594
1595
1596
1597
1598
1599
1600 private boolean includeDependencySources;
1601
1602
1603
1604
1605
1606
1607
1608
1609 private File sourceDependencyCacheDir;
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619 private boolean includeTransitiveDependencySources;
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629 private List<String> dependencySourceIncludes;
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639 private List<String> dependencySourceExcludes;
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649 private File javadocOptionsDir;
1650
1651
1652
1653
1654
1655
1656
1657 private transient List<JavadocBundle> dependencyJavadocBundles;
1658
1659
1660
1661
1662
1663 static
1664 {
1665 DEFAULT_JAVA_API_LINKS.put( "api_1.3", "http://download.oracle.com/javase/1.3/docs/api/" );
1666 DEFAULT_JAVA_API_LINKS.put( "api_1.4", "http://download.oracle.com/javase/1.4.2/docs/api/" );
1667 DEFAULT_JAVA_API_LINKS.put( "api_1.5", "http://download.oracle.com/javase/1.5.0/docs/api/" );
1668 DEFAULT_JAVA_API_LINKS.put( "api_1.6", "http://download.oracle.com/javase/6/docs/api/" );
1669 }
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682 protected boolean isAggregator()
1683 {
1684 return false;
1685 }
1686
1687
1688
1689
1690 protected String getOutputDirectory()
1691 {
1692 return outputDirectory.getAbsoluteFile().toString();
1693 }
1694
1695 protected MavenProject getProject()
1696 {
1697 return project;
1698 }
1699
1700
1701
1702
1703
1704
1705 protected List<String> getProjectBuildOutputDirs( MavenProject p )
1706 {
1707 if ( StringUtils.isEmpty( p.getBuild().getOutputDirectory() ) )
1708 {
1709 return Collections.emptyList();
1710 }
1711
1712 return Collections.singletonList( p.getBuild().getOutputDirectory() );
1713 }
1714
1715
1716
1717
1718
1719 protected List<String> getProjectSourceRoots( MavenProject p )
1720 {
1721 if ( "pom".equals( p.getPackaging().toLowerCase() ) )
1722 {
1723 return Collections.emptyList();
1724 }
1725
1726 return ( p.getCompileSourceRoots() == null ? Collections.EMPTY_LIST
1727 : new LinkedList( p.getCompileSourceRoots() ) );
1728 }
1729
1730
1731
1732
1733
1734 protected List<String> getExecutionProjectSourceRoots( MavenProject p )
1735 {
1736 if ( "pom".equals( p.getExecutionProject().getPackaging().toLowerCase() ) )
1737 {
1738 return Collections.emptyList();
1739 }
1740
1741 return ( p.getExecutionProject().getCompileSourceRoots() == null ? Collections.<String>emptyList()
1742 : new LinkedList<String>( p.getExecutionProject().getCompileSourceRoots() ) );
1743 }
1744
1745
1746
1747
1748
1749 protected List<Artifact> getProjectArtifacts( MavenProject p )
1750 {
1751 return ( p.getCompileArtifacts() == null ? Collections.<Artifact>emptyList()
1752 : new LinkedList<Artifact>( p.getCompileArtifacts() ) );
1753 }
1754
1755
1756
1757
1758 protected File getJavadocDirectory()
1759 {
1760 return javadocDirectory;
1761 }
1762
1763
1764
1765
1766 protected String getDoctitle()
1767 {
1768 return doctitle;
1769 }
1770
1771
1772
1773
1774 protected File getOverview()
1775 {
1776 return overview;
1777 }
1778
1779
1780
1781
1782 protected String getWindowtitle()
1783 {
1784 return windowtitle;
1785 }
1786
1787
1788
1789
1790 private String getCharset()
1791 {
1792 return ( StringUtils.isEmpty( charset ) ) ? getDocencoding() : charset;
1793 }
1794
1795
1796
1797
1798 private String getDocencoding()
1799 {
1800 return ( StringUtils.isEmpty( docencoding ) ) ? ReaderFactory.UTF_8 : docencoding;
1801 }
1802
1803
1804
1805
1806 private String getEncoding()
1807 {
1808 return ( StringUtils.isEmpty( encoding ) ) ? ReaderFactory.FILE_ENCODING : encoding;
1809 }
1810
1811
1812
1813
1814
1815
1816
1817
1818 protected void executeReport( Locale unusedLocale )
1819 throws MavenReportException
1820 {
1821 if ( skip )
1822 {
1823 getLog().info( "Skipping javadoc generation" );
1824 return;
1825 }
1826
1827 if ( isAggregator() && !project.isExecutionRoot() )
1828 {
1829 return;
1830 }
1831
1832 if ( getLog().isDebugEnabled() )
1833 {
1834 this.debug = true;
1835 }
1836
1837
1838
1839 try
1840 {
1841 buildJavadocOptions();
1842 }
1843 catch ( IOException e )
1844 {
1845 throw new MavenReportException( "Failed to generate javadoc options file: " + e.getMessage(), e );
1846 }
1847
1848 List<String> sourcePaths = getSourcePaths();
1849 List<String> files = getFiles( sourcePaths );
1850 if ( !canGenerateReport( files ) )
1851 {
1852 return;
1853 }
1854
1855 List<String> packageNames = getPackageNames( sourcePaths, files );
1856 List<String> filesWithUnnamedPackages = getFilesWithUnnamedPackages( sourcePaths, files );
1857
1858
1859
1860
1861
1862 String jExecutable;
1863 try
1864 {
1865 jExecutable = getJavadocExecutable();
1866 }
1867 catch ( IOException e )
1868 {
1869 throw new MavenReportException( "Unable to find javadoc command: " + e.getMessage(), e );
1870 }
1871 setFJavadocVersion( new File( jExecutable ) );
1872
1873
1874
1875
1876
1877 File javadocOutputDirectory = new File( getOutputDirectory() );
1878 if ( javadocOutputDirectory.exists() && !javadocOutputDirectory.isDirectory() )
1879 {
1880 throw new MavenReportException( "IOException: " + getOutputDirectory() + " is not a directory." );
1881 }
1882 if ( javadocOutputDirectory.exists() && !javadocOutputDirectory.canWrite() )
1883 {
1884 throw new MavenReportException( "IOException: " + getOutputDirectory() + " is not writable." );
1885 }
1886 javadocOutputDirectory.mkdirs();
1887
1888
1889
1890
1891
1892 copyAllResources( javadocOutputDirectory );
1893
1894
1895
1896
1897
1898 Commandline cmd = new Commandline();
1899 cmd.getShell().setQuotedArgumentsEnabled( false );
1900 cmd.setWorkingDirectory( javadocOutputDirectory.getAbsolutePath() );
1901 cmd.setExecutable( jExecutable );
1902
1903
1904
1905
1906
1907 addMemoryArg( cmd, "-Xmx", this.maxmemory );
1908 addMemoryArg( cmd, "-Xms", this.minmemory );
1909 addProxyArg( cmd );
1910
1911 if ( StringUtils.isNotEmpty( additionalJOption ) )
1912 {
1913 cmd.createArg().setValue( additionalJOption );
1914 }
1915
1916 List<String> arguments = new ArrayList<String>();
1917
1918
1919
1920
1921
1922 addJavadocOptions( arguments, sourcePaths );
1923
1924
1925
1926
1927
1928 if ( StringUtils.isEmpty( doclet ) || useStandardDocletOptions )
1929 {
1930 addStandardDocletOptions( javadocOutputDirectory, arguments );
1931 }
1932
1933
1934
1935
1936
1937 if ( arguments.size() > 0 )
1938 {
1939 addCommandLineOptions( cmd, arguments, javadocOutputDirectory );
1940 }
1941
1942
1943
1944
1945
1946 if ( !packageNames.isEmpty() )
1947 {
1948 addCommandLinePackages( cmd, javadocOutputDirectory, packageNames );
1949
1950
1951
1952
1953
1954 if ( !filesWithUnnamedPackages.isEmpty() )
1955 {
1956 addCommandLineArgFile( cmd, javadocOutputDirectory, filesWithUnnamedPackages );
1957 }
1958 }
1959 else
1960 {
1961
1962
1963
1964
1965 if ( !files.isEmpty() )
1966 {
1967 addCommandLineArgFile( cmd, javadocOutputDirectory, files );
1968 }
1969 }
1970
1971
1972
1973
1974
1975 executeJavadocCommandLine( cmd, javadocOutputDirectory );
1976
1977
1978 if ( !debug )
1979 {
1980 for ( int i = 0; i < cmd.getArguments().length; i++)
1981 {
1982 String arg = cmd.getArguments()[i].trim();
1983
1984 if ( !arg.startsWith( "@" ))
1985 {
1986 continue;
1987 }
1988
1989 File argFile = new File( javadocOutputDirectory, arg.substring( 1 ) );
1990 if ( argFile.exists() )
1991 {
1992 argFile.deleteOnExit();
1993 }
1994 }
1995
1996 File scriptFile = new File( javadocOutputDirectory, DEBUG_JAVADOC_SCRIPT_NAME );
1997 if ( scriptFile.exists() )
1998 {
1999 scriptFile.deleteOnExit();
2000 }
2001 }
2002 }
2003
2004
2005
2006
2007
2008
2009
2010
2011 protected List<String> getFiles( List<String> sourcePaths )
2012 throws MavenReportException
2013 {
2014 List<String> files = new ArrayList<String>();
2015 if ( StringUtils.isEmpty( subpackages ) )
2016 {
2017 String[] excludedPackages = getExcludedPackages();
2018
2019 for ( String sourcePath : sourcePaths )
2020 {
2021 File sourceDirectory = new File( sourcePath );
2022 JavadocUtil.addFilesFromSource( files, sourceDirectory, excludedPackages );
2023 }
2024 }
2025
2026 return files;
2027 }
2028
2029
2030
2031
2032
2033
2034
2035
2036 protected List<String> getSourcePaths()
2037 throws MavenReportException
2038 {
2039 List<String> sourcePaths;
2040
2041 if ( StringUtils.isEmpty( sourcepath ) )
2042 {
2043 sourcePaths = new ArrayList<String>( JavadocUtil.pruneDirs( project, getProjectSourceRoots( project ) ) );
2044
2045 if ( project.getExecutionProject() != null )
2046 {
2047 sourcePaths.addAll( JavadocUtil.pruneDirs( project, getExecutionProjectSourceRoots( project ) ) );
2048 }
2049
2050
2051
2052
2053
2054
2055 if ( getJavadocDirectory() != null )
2056 {
2057 File javadocDir = getJavadocDirectory();
2058 if ( javadocDir.exists() && javadocDir.isDirectory() )
2059 {
2060 List<String> l =
2061 JavadocUtil.pruneDirs( project,
2062 Collections.singletonList( getJavadocDirectory().getAbsolutePath() ) );
2063 sourcePaths.addAll( l );
2064 }
2065 }
2066
2067 if ( includeDependencySources )
2068 {
2069 sourcePaths.addAll( getDependencySourcePaths() );
2070 }
2071
2072 if ( isAggregator() && project.isExecutionRoot() )
2073 {
2074 for ( MavenProject subProject : reactorProjects )
2075 {
2076 if ( subProject != project )
2077 {
2078 List<String> sourceRoots = getProjectSourceRoots( subProject );
2079
2080 if ( subProject.getExecutionProject() != null )
2081 {
2082 sourceRoots.addAll( getExecutionProjectSourceRoots( subProject ) );
2083 }
2084
2085 ArtifactHandler artifactHandler = subProject.getArtifact().getArtifactHandler();
2086 if ( "java".equals( artifactHandler.getLanguage() ) )
2087 {
2088 sourcePaths.addAll( JavadocUtil.pruneDirs( subProject, sourceRoots ) );
2089 }
2090
2091 String javadocDirRelative =
2092 PathUtils.toRelative( project.getBasedir(), getJavadocDirectory().getAbsolutePath() );
2093 File javadocDir = new File( subProject.getBasedir(), javadocDirRelative );
2094 if ( javadocDir.exists() && javadocDir.isDirectory() )
2095 {
2096 List<String> l =
2097 JavadocUtil.pruneDirs( subProject,
2098 Collections.singletonList( javadocDir.getAbsolutePath() ) );
2099 sourcePaths.addAll( l );
2100 }
2101 }
2102 }
2103 }
2104 }
2105 else
2106 {
2107 sourcePaths = new ArrayList<String>( Arrays.asList( JavadocUtil.splitPath( sourcepath ) ) );
2108 sourcePaths = JavadocUtil.pruneDirs( project, sourcePaths );
2109 if ( getJavadocDirectory() != null )
2110 {
2111 List<String> l =
2112 JavadocUtil.pruneDirs( project,
2113 Collections.singletonList( getJavadocDirectory().getAbsolutePath() ) );
2114 sourcePaths.addAll( l );
2115 }
2116 }
2117
2118 sourcePaths = JavadocUtil.pruneDirs( project, sourcePaths );
2119
2120 return sourcePaths;
2121 }
2122
2123
2124
2125
2126
2127 protected SourceResolverConfig configureDependencySourceResolution( final SourceResolverConfig config )
2128 {
2129 return config.withCompileSources();
2130 }
2131
2132
2133
2134
2135
2136 protected final List<String> getDependencySourcePaths()
2137 throws MavenReportException
2138 {
2139 try
2140 {
2141 if ( sourceDependencyCacheDir.exists() )
2142 {
2143 FileUtils.forceDelete( sourceDependencyCacheDir );
2144 sourceDependencyCacheDir.mkdirs();
2145 }
2146 }
2147 catch ( IOException e )
2148 {
2149 throw new MavenReportException( "Failed to delete cache directory: " + sourceDependencyCacheDir + "\nReason: " + e.getMessage(), e );
2150 }
2151
2152 final SourceResolverConfig config = getDependencySourceResolverConfig();
2153
2154 final AndArtifactFilter andFilter = new AndArtifactFilter();
2155
2156 final List<String> dependencyIncludes = dependencySourceIncludes;
2157 final List<String> dependencyExcludes = dependencySourceExcludes;
2158
2159 if ( isNotEmpty( dependencyIncludes ) || isNotEmpty( dependencyExcludes ) )
2160 {
2161 if ( isNotEmpty( dependencyIncludes ) )
2162 {
2163 andFilter.add( new PatternIncludesArtifactFilter( dependencyIncludes,
2164 !includeTransitiveDependencySources ) );
2165 }
2166
2167 if ( isNotEmpty( dependencyExcludes ) )
2168 {
2169 andFilter.add( new PatternExcludesArtifactFilter( dependencyExcludes,
2170 !includeTransitiveDependencySources ) );
2171 }
2172
2173 config.withFilter( andFilter );
2174 }
2175
2176 try
2177 {
2178 return ResourceResolver.resolveDependencySourcePaths( config );
2179 }
2180 catch ( final ArtifactResolutionException e )
2181 {
2182 throw new MavenReportException( "Failed to resolve one or more javadoc source/resource artifacts:\n\n"
2183 + e.getMessage(), e );
2184 }
2185 catch ( final ArtifactNotFoundException e )
2186 {
2187 throw new MavenReportException( "Failed to resolve one or more javadoc source/resource artifacts:\n\n"
2188 + e.getMessage(), e );
2189 }
2190 }
2191
2192
2193
2194
2195
2196
2197
2198 private SourceResolverConfig getDependencySourceResolverConfig()
2199 {
2200 return configureDependencySourceResolution( new SourceResolverConfig( getLog(), project, localRepository,
2201 sourceDependencyCacheDir, resolver,
2202 factory, artifactMetadataSource,
2203 archiverManager ).withReactorProjects( reactorProjects ) );
2204 }
2205
2206
2207
2208
2209
2210
2211
2212
2213 protected boolean canGenerateReport( List<String> files )
2214 {
2215 boolean canGenerate = true;
2216
2217 if ( files.isEmpty() && StringUtils.isEmpty( subpackages ) )
2218 {
2219 canGenerate = false;
2220 }
2221
2222 return canGenerate;
2223 }
2224
2225
2226
2227
2228
2229
2230 protected List<Artifact> getCompileArtifacts( ArtifactResolutionResult result )
2231 {
2232 return JavadocUtil.getCompileArtifacts( result.getArtifacts(), false );
2233 }
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247 private String getExcludedPackages( List<String> sourcePaths )
2248 throws MavenReportException
2249 {
2250 List<String> excludedNames = null;
2251
2252 if ( StringUtils.isNotEmpty( sourcepath ) && StringUtils.isNotEmpty( subpackages ) )
2253 {
2254 String[] excludedPackages = getExcludedPackages();
2255 String[] subpackagesList = subpackages.split( "[:]" );
2256
2257 excludedNames = JavadocUtil.getExcludedNames( sourcePaths, subpackagesList, excludedPackages );
2258 }
2259
2260 String excludeArg = "";
2261 if ( StringUtils.isNotEmpty( subpackages ) && excludedNames != null )
2262 {
2263
2264 excludeArg = StringUtils.join( excludedNames.iterator(), ":" );
2265 }
2266
2267 return excludeArg;
2268 }
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278 private String getSourcePath( List<String> sourcePaths )
2279 {
2280 String sourcePath = null;
2281
2282 if ( StringUtils.isEmpty( subpackages ) || StringUtils.isNotEmpty( sourcepath ) )
2283 {
2284 sourcePath = StringUtils.join( sourcePaths.iterator(), File.pathSeparator );
2285 }
2286
2287 return sourcePath;
2288 }
2289
2290
2291
2292
2293
2294
2295
2296
2297 private String[] getExcludedPackages()
2298 throws MavenReportException
2299 {
2300 Set<String> excluded = new LinkedHashSet<String>();
2301
2302 if ( includeDependencySources )
2303 {
2304 try
2305 {
2306 resolveDependencyBundles();
2307 }
2308 catch ( IOException e )
2309 {
2310 throw new MavenReportException( "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
2311 }
2312
2313 if ( isNotEmpty( dependencyJavadocBundles ) )
2314 {
2315 for ( JavadocBundle bundle : dependencyJavadocBundles )
2316 {
2317 JavadocOptions options = bundle.getOptions();
2318 if ( options != null && isNotEmpty( options.getExcludePackageNames() ) )
2319 {
2320 excluded.addAll( options.getExcludePackageNames() );
2321 }
2322 }
2323 }
2324 }
2325
2326
2327 if ( StringUtils.isNotEmpty( excludePackageNames ) )
2328 {
2329 excluded.addAll( Arrays.asList( excludePackageNames.split( "[,:;]" ) ) );
2330 }
2331
2332 String[] result = new String[excluded.size()];
2333 if ( isNotEmpty( excluded ) )
2334 {
2335 int idx = 0;
2336 for ( String exclude : excluded )
2337 {
2338 result[idx] = exclude.replace( '.', File.separatorChar );
2339 idx++;
2340 }
2341 }
2342
2343 return result;
2344 }
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355 private String getClasspath()
2356 throws MavenReportException
2357 {
2358 List<String> classpathElements = new ArrayList<String>();
2359 Map<String, Artifact> compileArtifactMap = new HashMap<String, Artifact>();
2360
2361 classpathElements.addAll( getProjectBuildOutputDirs( project ) );
2362
2363 populateCompileArtifactMap( compileArtifactMap, getProjectArtifacts( project ) );
2364
2365 if ( isAggregator() && project.isExecutionRoot() )
2366 {
2367 try
2368 {
2369 for ( MavenProject subProject : reactorProjects )
2370 {
2371 if ( subProject != project )
2372 {
2373 classpathElements.addAll( getProjectBuildOutputDirs( subProject ) );
2374
2375 Set<Artifact> dependencyArtifacts = subProject.createArtifacts( factory, null, null );
2376 if ( !dependencyArtifacts.isEmpty() )
2377 {
2378 ArtifactResolutionResult result = null;
2379 try
2380 {
2381 result =
2382 resolver.resolveTransitively( dependencyArtifacts, subProject.getArtifact(),
2383 subProject.getManagedVersionMap(),
2384 localRepository,
2385 subProject.getRemoteArtifactRepositories(),
2386 artifactMetadataSource );
2387 }
2388 catch ( MultipleArtifactsNotFoundException e )
2389 {
2390 if ( checkMissingArtifactsInReactor( dependencyArtifacts, e.getMissingArtifacts() ) )
2391 {
2392 getLog().warn( "IGNORED to add some artifacts in the classpath. See above." );
2393 }
2394 else
2395 {
2396
2397 throw new MavenReportException( e.getMessage(), e );
2398 }
2399 }
2400 catch ( ArtifactNotFoundException e )
2401 {
2402 throw new MavenReportException( e.getMessage(), e );
2403 }
2404 catch ( ArtifactResolutionException e )
2405 {
2406 throw new MavenReportException( e.getMessage(), e );
2407 }
2408
2409 if ( result == null )
2410 {
2411 continue;
2412 }
2413
2414 populateCompileArtifactMap( compileArtifactMap, getCompileArtifacts( result ) );
2415
2416 if ( getLog().isDebugEnabled() )
2417 {
2418 StringBuffer sb = new StringBuffer();
2419
2420 sb.append( "Compiled artifacts for " );
2421 sb.append( subProject.getGroupId() ).append( ":" );
2422 sb.append( subProject.getArtifactId() ).append( ":" );
2423 sb.append( subProject.getVersion() ).append( '\n' );
2424 for ( String key : compileArtifactMap.keySet() )
2425 {
2426 Artifact a = compileArtifactMap.get( key );
2427 sb.append( a.getFile() ).append( '\n' );
2428 }
2429
2430 getLog().debug( sb.toString() );
2431 }
2432 }
2433 }
2434 }
2435 }
2436 catch ( InvalidDependencyVersionException e )
2437 {
2438 throw new MavenReportException( e.getMessage(), e );
2439 }
2440 }
2441
2442 for ( Artifact a : compileArtifactMap.values() )
2443 {
2444 classpathElements.add( a.getFile().toString() );
2445 }
2446
2447 return StringUtils.join( classpathElements.iterator(), File.pathSeparator );
2448 }
2449
2450
2451
2452
2453
2454
2455
2456 private Toolchain getToolchain()
2457 {
2458 Toolchain tc = null;
2459 if ( toolchainManager != null )
2460 {
2461 tc = toolchainManager.getToolchainFromBuildContext( "jdk", session );
2462 }
2463
2464 return tc;
2465 }
2466
2467
2468
2469
2470
2471
2472
2473
2474 private void populateCompileArtifactMap( Map<String, Artifact> compileArtifactMap, Collection<Artifact> artifactList )
2475 throws MavenReportException
2476 {
2477 if ( artifactList == null )
2478 {
2479 return;
2480 }
2481
2482 for ( Artifact newArtifact : artifactList )
2483 {
2484 File file = newArtifact.getFile();
2485
2486 if ( file == null )
2487 {
2488 throw new MavenReportException( "Error in plugin descriptor - "
2489 + "dependency was not resolved for artifact: " + newArtifact.getGroupId() + ":"
2490 + newArtifact.getArtifactId() + ":" + newArtifact.getVersion() );
2491 }
2492
2493 if ( compileArtifactMap.get( newArtifact.getDependencyConflictId() ) != null )
2494 {
2495 Artifact oldArtifact = compileArtifactMap.get( newArtifact.getDependencyConflictId() );
2496
2497 ArtifactVersion oldVersion = new DefaultArtifactVersion( oldArtifact.getVersion() );
2498 ArtifactVersion newVersion = new DefaultArtifactVersion( newArtifact.getVersion() );
2499 if ( newVersion.compareTo( oldVersion ) > 0 )
2500 {
2501 compileArtifactMap.put( newArtifact.getDependencyConflictId(), newArtifact );
2502 }
2503 }
2504 else
2505 {
2506 compileArtifactMap.put( newArtifact.getDependencyConflictId(), newArtifact );
2507 }
2508 }
2509 }
2510
2511
2512
2513
2514
2515
2516
2517 private String getBottomText()
2518 {
2519 int actualYear = Calendar.getInstance().get( Calendar.YEAR );
2520 String year = String.valueOf( actualYear );
2521
2522 String inceptionYear = project.getInceptionYear();
2523
2524 String theBottom = StringUtils.replace( this.bottom, "{currentYear}", year );
2525
2526 if ( inceptionYear != null )
2527 {
2528 if ( inceptionYear.equals( year ) )
2529 {
2530 theBottom = StringUtils.replace( theBottom, "{inceptionYear}-", "" );
2531 }
2532 else
2533 {
2534 theBottom = StringUtils.replace( theBottom, "{inceptionYear}", inceptionYear );
2535 }
2536 }
2537 else
2538 {
2539 theBottom = StringUtils.replace( theBottom, "{inceptionYear}-", "" );
2540 }
2541
2542 if ( project.getOrganization() == null )
2543 {
2544 theBottom = StringUtils.replace( theBottom, " {organizationName}", "" );
2545 }
2546 else
2547 {
2548 if ( StringUtils.isNotEmpty( project.getOrganization().getName() ) )
2549 {
2550 if ( StringUtils.isNotEmpty( project.getOrganization().getUrl() ) )
2551 {
2552 theBottom =
2553 StringUtils.replace( theBottom, "{organizationName}", "<a href=\""
2554 + project.getOrganization().getUrl() + "\">" + project.getOrganization().getName()
2555 + "</a>" );
2556 }
2557 else
2558 {
2559 theBottom =
2560 StringUtils.replace( theBottom, "{organizationName}", project.getOrganization().getName() );
2561 }
2562 }
2563 else
2564 {
2565 theBottom = StringUtils.replace( theBottom, " {organizationName}", "" );
2566 }
2567 }
2568
2569 return theBottom;
2570 }
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587 private String getStylesheetFile( final File javadocOutputDirectory )
2588 {
2589 if ( StringUtils.isEmpty( stylesheetfile ) )
2590 {
2591 if ( "java".equalsIgnoreCase( stylesheet ) )
2592 {
2593
2594 return null;
2595 }
2596
2597
2598 return new File( javadocOutputDirectory, DEFAULT_CSS_NAME ).getAbsolutePath();
2599 }
2600
2601 if ( new File( stylesheetfile ).exists() )
2602 {
2603 return new File( stylesheetfile ).getAbsolutePath();
2604 }
2605
2606 return getResource( new File( javadocOutputDirectory, DEFAULT_CSS_NAME ), stylesheetfile );
2607 }
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621 private String getHelpFile( final File javadocOutputDirectory )
2622 {
2623 if ( StringUtils.isEmpty( helpfile ) )
2624 {
2625 return null;
2626 }
2627
2628 if ( new File( helpfile ).exists() )
2629 {
2630 return new File( helpfile ).getAbsolutePath();
2631 }
2632
2633 return getResource( new File( javadocOutputDirectory, "help-doc.html" ), helpfile );
2634 }
2635
2636
2637
2638
2639
2640
2641
2642
2643 private String getAccessLevel()
2644 {
2645 String accessLevel;
2646 if ( "public".equalsIgnoreCase( show ) || "protected".equalsIgnoreCase( show )
2647 || "package".equalsIgnoreCase( show ) || "private".equalsIgnoreCase( show ) )
2648 {
2649 accessLevel = "-" + show;
2650 }
2651 else
2652 {
2653 if ( getLog().isErrorEnabled() )
2654 {
2655 getLog().error( "Unrecognized access level to show '" + show + "'. Defaulting to protected." );
2656 }
2657 accessLevel = "-protected";
2658 }
2659
2660 return accessLevel;
2661 }
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671 private String getBootclassPath()
2672 throws MavenReportException
2673 {
2674 Set<BootclasspathArtifact> bootclasspathArtifacts = collectBootClasspathArtifacts();
2675
2676 List<String> bootclassPath = new ArrayList<String>();
2677 for ( BootclasspathArtifact aBootclasspathArtifact : bootclasspathArtifacts )
2678 {
2679 if ( ( StringUtils.isNotEmpty( aBootclasspathArtifact.getGroupId() ) )
2680 && ( StringUtils.isNotEmpty( aBootclasspathArtifact.getArtifactId() ) )
2681 && ( StringUtils.isNotEmpty( aBootclasspathArtifact.getVersion() ) ) )
2682 {
2683 bootclassPath.addAll( getArtifactsAbsolutePath( aBootclasspathArtifact ) );
2684 }
2685 }
2686
2687 bootclassPath = JavadocUtil.pruneFiles( bootclassPath );
2688
2689 StringBuffer path = new StringBuffer();
2690 path.append( StringUtils.join( bootclassPath.iterator(), File.pathSeparator ) );
2691
2692 if ( StringUtils.isNotEmpty( bootclasspath ) )
2693 {
2694 path.append( JavadocUtil.unifyPathSeparator( bootclasspath ) );
2695 }
2696
2697 return path.toString();
2698 }
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712 private String getDocletPath()
2713 throws MavenReportException
2714 {
2715 Set<DocletArtifact> docletArtifacts = collectDocletArtifacts();
2716 List<String> pathParts = new ArrayList<String>();
2717
2718 for ( DocletArtifact docletArtifact : docletArtifacts )
2719 {
2720 if ( !isDocletArtifactEmpty( docletArtifact ) )
2721 {
2722 pathParts.addAll( getArtifactsAbsolutePath( docletArtifact ) );
2723 }
2724 }
2725
2726 StringBuffer path = new StringBuffer();
2727 path.append( StringUtils.join( pathParts.iterator(), File.pathSeparator ) );
2728
2729 if ( !StringUtils.isEmpty( docletPath ) )
2730 {
2731 path.append( JavadocUtil.unifyPathSeparator( docletPath ) );
2732 }
2733
2734 if ( StringUtils.isEmpty( path.toString() ) && getLog().isWarnEnabled() )
2735 {
2736 getLog().warn(
2737 "No docletpath option was found. Please review <docletpath/> or <docletArtifact/>"
2738 + " or <doclets/>." );
2739 }
2740
2741 return path.toString();
2742 }
2743
2744
2745
2746
2747
2748
2749
2750
2751 private boolean isDocletArtifactEmpty( DocletArtifact aDocletArtifact )
2752 {
2753 if ( aDocletArtifact == null )
2754 {
2755 return true;
2756 }
2757
2758 return StringUtils.isEmpty( aDocletArtifact.getGroupId() )
2759 && StringUtils.isEmpty( aDocletArtifact.getArtifactId() )
2760 && StringUtils.isEmpty( aDocletArtifact.getVersion() );
2761 }
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771 private String getTagletPath()
2772 throws MavenReportException
2773 {
2774 Set<TagletArtifact> tArtifacts = collectTagletArtifacts();
2775 List<String> pathParts = new ArrayList<String>();
2776
2777 for ( TagletArtifact tagletArtifact : tArtifacts )
2778 {
2779 if ( ( tagletArtifact != null ) && ( StringUtils.isNotEmpty( tagletArtifact.getGroupId() ) )
2780 && ( StringUtils.isNotEmpty( tagletArtifact.getArtifactId() ) )
2781 && ( StringUtils.isNotEmpty( tagletArtifact.getVersion() ) ) )
2782 {
2783 pathParts.addAll( getArtifactsAbsolutePath( tagletArtifact ) );
2784 }
2785 }
2786
2787
2788 Set<Taglet> taglets = collectTaglets();
2789 for ( Taglet taglet : taglets )
2790 {
2791 if ( taglet == null )
2792 {
2793 continue;
2794 }
2795
2796 if ( ( taglet.getTagletArtifact() != null )
2797 && ( StringUtils.isNotEmpty( taglet.getTagletArtifact().getGroupId() ) )
2798 && ( StringUtils.isNotEmpty( taglet.getTagletArtifact().getArtifactId() ) )
2799 && ( StringUtils.isNotEmpty( taglet.getTagletArtifact().getVersion() ) ) )
2800 {
2801 pathParts.addAll( getArtifactsAbsolutePath( taglet.getTagletArtifact() ) );
2802
2803 pathParts = JavadocUtil.pruneFiles( pathParts );
2804 }
2805 else if ( StringUtils.isNotEmpty( taglet.getTagletpath() ) )
2806 {
2807 pathParts.add( taglet.getTagletpath() );
2808
2809 pathParts = JavadocUtil.pruneDirs( project, pathParts );
2810 }
2811 }
2812
2813 StringBuffer path = new StringBuffer();
2814 path.append( StringUtils.join( pathParts.iterator(), File.pathSeparator ) );
2815
2816 if ( StringUtils.isNotEmpty( tagletpath ) )
2817 {
2818 path.append( JavadocUtil.unifyPathSeparator( tagletpath ) );
2819 }
2820
2821 return path.toString();
2822 }
2823
2824 private Set<String> collectLinks()
2825 throws MavenReportException
2826 {
2827 Set<String> links = new LinkedHashSet<String>();
2828
2829 if ( includeDependencySources )
2830 {
2831 try
2832 {
2833 resolveDependencyBundles();
2834 }
2835 catch ( IOException e )
2836 {
2837 throw new MavenReportException( "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
2838 }
2839
2840 if ( isNotEmpty( dependencyJavadocBundles ) )
2841 {
2842 for ( JavadocBundle bundle : dependencyJavadocBundles )
2843 {
2844 JavadocOptions options = bundle.getOptions();
2845 if ( options != null && isNotEmpty( options.getLinks() ) )
2846 {
2847 links.addAll( options.getLinks() );
2848 }
2849 }
2850 }
2851 }
2852
2853 if ( isNotEmpty( this.links ) )
2854 {
2855 links.addAll( this.links );
2856 }
2857
2858 links.addAll( getDependenciesLinks() );
2859
2860 return links;
2861 }
2862
2863 private Set<Group> collectGroups()
2864 throws MavenReportException
2865 {
2866 Set<Group> groups = new LinkedHashSet<Group>();
2867
2868 if ( includeDependencySources )
2869 {
2870 try
2871 {
2872 resolveDependencyBundles();
2873 }
2874 catch ( IOException e )
2875 {
2876 throw new MavenReportException( "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
2877 }
2878
2879 if ( isNotEmpty( dependencyJavadocBundles ) )
2880 {
2881 for ( JavadocBundle bundle : dependencyJavadocBundles )
2882 {
2883 JavadocOptions options = bundle.getOptions();
2884 if ( options != null && isNotEmpty( options.getGroups() ) )
2885 {
2886 groups.addAll( options.getGroups() );
2887 }
2888 }
2889 }
2890 }
2891
2892 if ( this.groups != null && this.groups.length > 0 )
2893 {
2894 groups.addAll( Arrays.asList( this.groups ) );
2895 }
2896
2897 return groups;
2898 }
2899
2900 private Set<ResourcesArtifact> collectResourcesArtifacts()
2901 throws MavenReportException
2902 {
2903 Set<ResourcesArtifact> result = new LinkedHashSet<ResourcesArtifact>();
2904
2905 if ( includeDependencySources )
2906 {
2907 try
2908 {
2909 resolveDependencyBundles();
2910 }
2911 catch ( IOException e )
2912 {
2913 throw new MavenReportException( "Failed to resolve javadoc bundles from dependencies: "
2914 + e.getMessage(), e );
2915 }
2916
2917 if ( isNotEmpty( dependencyJavadocBundles ) )
2918 {
2919 for ( JavadocBundle bundle : dependencyJavadocBundles )
2920 {
2921 JavadocOptions options = bundle.getOptions();
2922 if ( options != null && isNotEmpty( options.getResourcesArtifacts() ) )
2923 {
2924 result.addAll( options.getResourcesArtifacts() );
2925 }
2926 }
2927 }
2928 }
2929
2930 if ( this.resourcesArtifacts != null && this.resourcesArtifacts.length > 0 )
2931 {
2932 result.addAll( Arrays.asList( this.resourcesArtifacts ) );
2933 }
2934
2935 return result;
2936 }
2937
2938 private Set<BootclasspathArtifact> collectBootClasspathArtifacts()
2939 throws MavenReportException
2940 {
2941 Set<BootclasspathArtifact> result = new LinkedHashSet<BootclasspathArtifact>();
2942
2943 if ( includeDependencySources )
2944 {
2945 try
2946 {
2947 resolveDependencyBundles();
2948 }
2949 catch ( IOException e )
2950 {
2951 throw new MavenReportException( "Failed to resolve javadoc bundles from dependencies: "
2952 + e.getMessage(), e );
2953 }
2954
2955 if ( isNotEmpty( dependencyJavadocBundles ) )
2956 {
2957 for ( JavadocBundle bundle : dependencyJavadocBundles )
2958 {
2959 JavadocOptions options = bundle.getOptions();
2960 if ( options != null && isNotEmpty( options.getBootclasspathArtifacts() ) )
2961 {
2962 result.addAll( options.getBootclasspathArtifacts() );
2963 }
2964 }
2965 }
2966 }
2967
2968 if ( this.bootclasspathArtifacts != null && this.bootclasspathArtifacts.length > 0 )
2969 {
2970 result.addAll( Arrays.asList( this.bootclasspathArtifacts ) );
2971 }
2972
2973 return result;
2974 }
2975
2976 private Set<OfflineLink> collectOfflineLinks()
2977 throws MavenReportException
2978 {
2979 Set<OfflineLink> result = new LinkedHashSet<OfflineLink>();
2980
2981 OfflineLink javaApiLink = getDefaultJavadocApiLink();
2982 if ( javaApiLink != null )
2983 {
2984 result.add( javaApiLink );
2985 }
2986
2987 if ( includeDependencySources )
2988 {
2989 try
2990 {
2991 resolveDependencyBundles();
2992 }
2993 catch ( IOException e )
2994 {
2995 throw new MavenReportException( "Failed to resolve javadoc bundles from dependencies: "
2996 + e.getMessage(), e );
2997 }
2998
2999 if ( isNotEmpty( dependencyJavadocBundles ) )
3000 {
3001 for ( JavadocBundle bundle : dependencyJavadocBundles )
3002 {
3003 JavadocOptions options = bundle.getOptions();
3004 if ( options != null && isNotEmpty( options.getOfflineLinks() ) )
3005 {
3006 result.addAll( options.getOfflineLinks() );
3007 }
3008 }
3009 }
3010 }
3011
3012 if ( this.offlineLinks != null && this.offlineLinks.length > 0 )
3013 {
3014 result.addAll( Arrays.asList( this.offlineLinks ) );
3015 }
3016
3017 return result;
3018 }
3019
3020 private Set<Tag> collectTags()
3021 throws MavenReportException
3022 {
3023 Set<Tag> tags = new LinkedHashSet<Tag>();
3024
3025 if ( includeDependencySources )
3026 {
3027 try
3028 {
3029 resolveDependencyBundles();
3030 }
3031 catch ( IOException e )
3032 {
3033 throw new MavenReportException( "Failed to resolve javadoc bundles from dependencies: "
3034 + e.getMessage(), e );
3035 }
3036
3037 if ( isNotEmpty( dependencyJavadocBundles ) )
3038 {
3039 for ( JavadocBundle bundle : dependencyJavadocBundles )
3040 {
3041 JavadocOptions options = bundle.getOptions();
3042 if ( options != null && isNotEmpty( options.getTags() ) )
3043 {
3044 tags.addAll( options.getTags() );
3045 }
3046 }
3047 }
3048 }
3049
3050 if ( this.tags != null && this.tags.length > 0 )
3051 {
3052 tags.addAll( Arrays.asList( this.tags ) );
3053 }
3054
3055 return tags;
3056 }
3057
3058 private Set<TagletArtifact> collectTagletArtifacts()
3059 throws MavenReportException
3060 {
3061 Set<TagletArtifact> tArtifacts = new LinkedHashSet<TagletArtifact>();
3062
3063 if ( includeDependencySources )
3064 {
3065 try
3066 {
3067 resolveDependencyBundles();
3068 }
3069 catch ( IOException e )
3070 {
3071 throw new MavenReportException( "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
3072 }
3073
3074 if ( isNotEmpty( dependencyJavadocBundles ) )
3075 {
3076 for ( JavadocBundle bundle : dependencyJavadocBundles )
3077 {
3078 JavadocOptions options = bundle.getOptions();
3079 if ( options != null && isNotEmpty( options.getTagletArtifacts() ) )
3080 {
3081 tArtifacts.addAll( options.getTagletArtifacts() );
3082 }
3083 }
3084 }
3085 }
3086
3087 if ( tagletArtifact != null )
3088 {
3089 tArtifacts.add( tagletArtifact );
3090 }
3091
3092 if ( tagletArtifacts != null && tagletArtifacts.length > 0 )
3093 {
3094 tArtifacts.addAll( Arrays.asList( tagletArtifacts ) );
3095 }
3096
3097 return tArtifacts;
3098 }
3099
3100 private Set<DocletArtifact> collectDocletArtifacts()
3101 throws MavenReportException
3102 {
3103 Set<DocletArtifact> dArtifacts = new LinkedHashSet<DocletArtifact>();
3104
3105 if ( includeDependencySources )
3106 {
3107 try
3108 {
3109 resolveDependencyBundles();
3110 }
3111 catch ( IOException e )
3112 {
3113 throw new MavenReportException( "Failed to resolve javadoc bundles from dependencies: "
3114 + e.getMessage(), e );
3115 }
3116
3117 if ( isNotEmpty( dependencyJavadocBundles ) )
3118 {
3119 for ( JavadocBundle bundle : dependencyJavadocBundles )
3120 {
3121 JavadocOptions options = bundle.getOptions();
3122 if ( options != null && isNotEmpty( options.getDocletArtifacts() ) )
3123 {
3124 dArtifacts.addAll( options.getDocletArtifacts() );
3125 }
3126 }
3127 }
3128 }
3129
3130 if ( docletArtifact != null )
3131 {
3132 dArtifacts.add( docletArtifact );
3133 }
3134
3135 if ( docletArtifacts != null && docletArtifacts.length > 0 )
3136 {
3137 dArtifacts.addAll( Arrays.asList( docletArtifacts ) );
3138 }
3139
3140 return dArtifacts;
3141 }
3142
3143 private Set<Taglet> collectTaglets()
3144 throws MavenReportException
3145 {
3146 Set<Taglet> result = new LinkedHashSet<Taglet>();
3147
3148 if ( includeDependencySources )
3149 {
3150 try
3151 {
3152 resolveDependencyBundles();
3153 }
3154 catch ( IOException e )
3155 {
3156 throw new MavenReportException( "Failed to resolve javadoc bundles from dependencies: "
3157 + e.getMessage(), e );
3158 }
3159
3160 if ( isNotEmpty( dependencyJavadocBundles ) )
3161 {
3162 for ( JavadocBundle bundle : dependencyJavadocBundles )
3163 {
3164 JavadocOptions options = bundle.getOptions();
3165 if ( options != null && isNotEmpty( options.getTaglets() ) )
3166 {
3167 result.addAll( options.getTaglets() );
3168 }
3169 }
3170 }
3171 }
3172
3173 if ( taglets != null && taglets.length > 0 )
3174 {
3175 result.addAll( Arrays.asList( taglets ) );
3176 }
3177
3178 return result;
3179 }
3180
3181
3182
3183
3184
3185
3186
3187
3188 private List<String> getArtifactsAbsolutePath( JavadocPathArtifact javadocArtifact )
3189 throws MavenReportException
3190 {
3191 if ( ( StringUtils.isEmpty( javadocArtifact.getGroupId() ) )
3192 && ( StringUtils.isEmpty( javadocArtifact.getArtifactId() ) )
3193 && ( StringUtils.isEmpty( javadocArtifact.getVersion() ) ) )
3194 {
3195 return Collections.emptyList();
3196 }
3197
3198 List<String> path = new ArrayList<String>();
3199
3200 try
3201 {
3202 Artifact artifact = createAndResolveArtifact( javadocArtifact );
3203 path.add( artifact.getFile().getAbsolutePath() );
3204
3205
3206 MavenProject artifactProject =
3207 mavenProjectBuilder.buildFromRepository( artifact, remoteRepositories, localRepository );
3208 Set<Artifact> dependencyArtifacts = artifactProject.createArtifacts( factory, null, null );
3209 if ( !dependencyArtifacts.isEmpty() )
3210 {
3211 ArtifactResolutionResult result =
3212 resolver.resolveTransitively( dependencyArtifacts, artifactProject.getArtifact(),
3213 artifactProject.getRemoteArtifactRepositories(),
3214 localRepository, artifactMetadataSource );
3215 Set<Artifact> artifacts = result.getArtifacts();
3216
3217 Map<String, Artifact> compileArtifactMap = new HashMap<String, Artifact>();
3218 populateCompileArtifactMap( compileArtifactMap, artifacts );
3219
3220 for ( Artifact a : compileArtifactMap.values() )
3221 {
3222 path.add( a.getFile().getAbsolutePath() );
3223 }
3224 }
3225
3226 return path;
3227 }
3228 catch ( ArtifactResolutionException e )
3229 {
3230 throw new MavenReportException( "Unable to resolve artifact:" + javadocArtifact, e );
3231 }
3232 catch ( ArtifactNotFoundException e )
3233 {
3234 throw new MavenReportException( "Unable to find artifact:" + javadocArtifact, e );
3235 }
3236 catch ( ProjectBuildingException e )
3237 {
3238 throw new MavenReportException( "Unable to build the Maven project for the artifact:"
3239 + javadocArtifact, e );
3240 }
3241 catch ( InvalidDependencyVersionException e )
3242 {
3243 throw new MavenReportException( "Unable to resolve artifact:" + javadocArtifact, e );
3244 }
3245 }
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256 private Artifact createAndResolveArtifact( JavadocPathArtifact javadocArtifact )
3257 throws ArtifactResolutionException, ArtifactNotFoundException, ProjectBuildingException
3258 {
3259 Artifact artifact =
3260 factory.createProjectArtifact( javadocArtifact.getGroupId(), javadocArtifact.getArtifactId(),
3261 javadocArtifact.getVersion(), Artifact.SCOPE_COMPILE );
3262
3263 if ( artifact.getFile() == null )
3264 {
3265 MavenProject pluginProject =
3266 mavenProjectBuilder.buildFromRepository( artifact, remoteRepositories, localRepository );
3267 artifact = pluginProject.getArtifact();
3268
3269 resolver.resolve( artifact, remoteRepositories, localRepository );
3270 }
3271
3272 return artifact;
3273 }
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283 private void addMemoryArg( Commandline cmd, String arg, String memory )
3284 {
3285 if ( StringUtils.isNotEmpty( memory ) )
3286 {
3287 try
3288 {
3289 cmd.createArg().setValue( "-J" + arg + JavadocUtil.parseJavadocMemory( memory ) );
3290 }
3291 catch ( IllegalArgumentException e )
3292 {
3293 if ( getLog().isErrorEnabled() )
3294 {
3295 getLog().error( "Malformed memory pattern for '" + arg + memory + "'. Ignore this option." );
3296 }
3297 }
3298 }
3299 }
3300
3301
3302
3303
3304
3305
3306 private void addProxyArg( Commandline cmd )
3307 {
3308
3309 if ( StringUtils.isNotEmpty( proxyHost ) )
3310 {
3311 if ( getLog().isWarnEnabled() )
3312 {
3313 getLog().warn(
3314 "The Javadoc plugin parameter 'proxyHost' is deprecated since 2.4. "
3315 + "Please configure an active proxy in your settings.xml." );
3316 }
3317 cmd.createArg().setValue( "-J-DproxyHost=" + proxyHost );
3318
3319 if ( proxyPort > 0 )
3320 {
3321 if ( getLog().isWarnEnabled() )
3322 {
3323 getLog().warn(
3324 "The Javadoc plugin parameter 'proxyPort' is deprecated since 2.4. "
3325 + "Please configure an active proxy in your settings.xml." );
3326 }
3327 cmd.createArg().setValue( "-J-DproxyPort=" + proxyPort );
3328 }
3329 }
3330
3331 if ( settings == null || settings.getActiveProxy() == null )
3332 {
3333 return;
3334 }
3335
3336 Proxy activeProxy = settings.getActiveProxy();
3337 String protocol =
3338 StringUtils.isNotEmpty( activeProxy.getProtocol() ) ? activeProxy.getProtocol() + "." : "";
3339
3340 if ( StringUtils.isNotEmpty( activeProxy.getHost() ) )
3341 {
3342 cmd.createArg().setValue( "-J-D" + protocol + "proxySet=true" );
3343 cmd.createArg().setValue( "-J-D" + protocol + "proxyHost=" + activeProxy.getHost() );
3344
3345 if ( activeProxy.getPort() > 0 )
3346 {
3347 cmd.createArg().setValue( "-J-D" + protocol + "proxyPort=" + activeProxy.getPort() );
3348 }
3349
3350 if ( StringUtils.isNotEmpty( activeProxy.getNonProxyHosts() ) )
3351 {
3352 cmd.createArg().setValue(
3353 "-J-D" + protocol + "nonProxyHosts=\""
3354 + activeProxy.getNonProxyHosts() + "\"" );
3355 }
3356
3357 if ( StringUtils.isNotEmpty( activeProxy.getUsername() ) )
3358 {
3359 cmd.createArg().setValue( "-J-Dhttp.proxyUser=\"" + activeProxy.getUsername() + "\"" );
3360
3361 if ( StringUtils.isNotEmpty( activeProxy.getPassword() ) )
3362 {
3363 cmd.createArg().setValue( "-J-Dhttp.proxyPassword=\"" + activeProxy.getPassword() + "\"" );
3364 }
3365 }
3366 }
3367 }
3368
3369
3370
3371
3372
3373
3374
3375
3376 private String getJavadocExecutable()
3377 throws IOException
3378 {
3379 Toolchain tc = getToolchain();
3380
3381 if ( tc != null )
3382 {
3383 getLog().info( "Toolchain in javadoc-plugin: " + tc );
3384 if ( javadocExecutable != null )
3385 {
3386 getLog().warn(
3387 "Toolchains are ignored, 'javadocExecutable' parameter is set to "
3388 + javadocExecutable );
3389 }
3390 else
3391 {
3392 javadocExecutable = tc.findTool( "javadoc" );
3393 }
3394 }
3395
3396 String javadocCommand = "javadoc" + ( SystemUtils.IS_OS_WINDOWS ? ".exe" : "" );
3397
3398 File javadocExe;
3399
3400
3401
3402
3403 if ( StringUtils.isNotEmpty( javadocExecutable ) )
3404 {
3405 javadocExe = new File( javadocExecutable );
3406
3407 if ( javadocExe.isDirectory() )
3408 {
3409 javadocExe = new File( javadocExe, javadocCommand );
3410 }
3411
3412 if ( SystemUtils.IS_OS_WINDOWS && javadocExe.getName().indexOf( '.' ) < 0 )
3413 {
3414 javadocExe = new File( javadocExe.getPath() + ".exe" );
3415 }
3416
3417 if ( !javadocExe.isFile() )
3418 {
3419 throw new IOException( "The javadoc executable '" + javadocExe
3420 + "' doesn't exist or is not a file. Verify the <javadocExecutable/> parameter." );
3421 }
3422
3423 return javadocExe.getAbsolutePath();
3424 }
3425
3426
3427
3428
3429
3430
3431
3432 if ( SystemUtils.IS_OS_AIX )
3433 {
3434 javadocExe =
3435 new File( SystemUtils.getJavaHome() + File.separator + ".." + File.separator + "sh",
3436 javadocCommand );
3437 }
3438 else if ( SystemUtils.IS_OS_MAC_OSX )
3439 {
3440 javadocExe = new File( SystemUtils.getJavaHome() + File.separator + "bin", javadocCommand );
3441 }
3442 else
3443 {
3444 javadocExe =
3445 new File( SystemUtils.getJavaHome() + File.separator + ".." + File.separator + "bin",
3446 javadocCommand );
3447 }
3448
3449
3450
3451
3452 if ( !javadocExe.exists() || !javadocExe.isFile() )
3453 {
3454 Properties env = CommandLineUtils.getSystemEnvVars();
3455 String javaHome = env.getProperty( "JAVA_HOME" );
3456 if ( StringUtils.isEmpty( javaHome ) )
3457 {
3458 throw new IOException( "The environment variable JAVA_HOME is not correctly set." );
3459 }
3460 if ( ( !new File( javaHome ).exists() ) || ( !new File( javaHome ).isDirectory() ) )
3461 {
3462 throw new IOException( "The environment variable JAVA_HOME=" + javaHome
3463 + " doesn't exist or is not a valid directory." );
3464 }
3465
3466 javadocExe = new File( env.getProperty( "JAVA_HOME" ) + File.separator + "bin", javadocCommand );
3467 }
3468
3469 if ( !javadocExe.exists() || !javadocExe.isFile() )
3470 {
3471 throw new IOException( "The javadoc executable '" + javadocExe
3472 + "' doesn't exist or is not a file. Verify the JAVA_HOME environment variable." );
3473 }
3474
3475 return javadocExe.getAbsolutePath();
3476 }
3477
3478
3479
3480
3481
3482
3483
3484
3485 private void setFJavadocVersion( File jExecutable )
3486 throws MavenReportException
3487 {
3488 float jVersion;
3489 try
3490 {
3491 jVersion = JavadocUtil.getJavadocVersion( jExecutable );
3492 }
3493 catch ( IOException e )
3494 {
3495 if ( getLog().isWarnEnabled() )
3496 {
3497 getLog().warn( "Unable to find the javadoc version: " + e.getMessage() );
3498 getLog().warn( "Using the Java version instead of, i.e. " + SystemUtils.JAVA_VERSION_FLOAT );
3499 }
3500 jVersion = SystemUtils.JAVA_VERSION_FLOAT;
3501 }
3502 catch ( CommandLineException e )
3503 {
3504 if ( getLog().isWarnEnabled() )
3505 {
3506 getLog().warn( "Unable to find the javadoc version: " + e.getMessage() );
3507 getLog().warn( "Using the Java the version instead of, i.e. " + SystemUtils.JAVA_VERSION_FLOAT );
3508 }
3509 jVersion = SystemUtils.JAVA_VERSION_FLOAT;
3510 }
3511 catch ( IllegalArgumentException e )
3512 {
3513 if ( getLog().isWarnEnabled() )
3514 {
3515 getLog().warn( "Unable to find the javadoc version: " + e.getMessage() );
3516 getLog().warn( "Using the Java the version instead of, i.e. " + SystemUtils.JAVA_VERSION_FLOAT );
3517 }
3518 jVersion = SystemUtils.JAVA_VERSION_FLOAT;
3519 }
3520
3521 if ( StringUtils.isNotEmpty( javadocVersion ) )
3522 {
3523 try
3524 {
3525 fJavadocVersion = Float.parseFloat( javadocVersion );
3526 }
3527 catch ( NumberFormatException e )
3528 {
3529 throw new MavenReportException( "Unable to parse javadoc version: " + e.getMessage(), e );
3530 }
3531
3532 if ( fJavadocVersion != jVersion && getLog().isWarnEnabled() )
3533 {
3534 getLog().warn( "Are you sure about the <javadocVersion/> parameter? It seems to be " + jVersion );
3535 }
3536 }
3537 else
3538 {
3539 fJavadocVersion = jVersion;
3540 }
3541 }
3542
3543
3544
3545
3546
3547
3548
3549
3550 private boolean isJavaDocVersionAtLeast( float requiredVersion )
3551 {
3552 return fJavadocVersion >= requiredVersion;
3553 }
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563 private void addArgIf( List<String> arguments, boolean b, String value )
3564 {
3565 if ( b )
3566 {
3567 arguments.add( value );
3568 }
3569 }
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582 private void addArgIf( List<String> arguments, boolean b, String value, float requiredJavaVersion )
3583 {
3584 if ( b )
3585 {
3586 if ( isJavaDocVersionAtLeast( requiredJavaVersion ) )
3587 {
3588 addArgIf( arguments, b, value );
3589 }
3590 else
3591 {
3592 if ( getLog().isWarnEnabled() )
3593 {
3594 getLog().warn(
3595 value + " option is not supported on Java version < " + requiredJavaVersion
3596 + ". Ignore this option." );
3597 }
3598 }
3599 }
3600 }
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613 private void addArgIfNotEmpty( List<String> arguments, String key, String value )
3614 {
3615 addArgIfNotEmpty( arguments, key, value, false );
3616 }
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633 private void addArgIfNotEmpty( List<String> arguments, String key, String value, boolean repeatKey,
3634 boolean splitValue, float requiredJavaVersion )
3635 {
3636 if ( StringUtils.isNotEmpty( value ) )
3637 {
3638 if ( isJavaDocVersionAtLeast( requiredJavaVersion ) )
3639 {
3640 addArgIfNotEmpty( arguments, key, value, repeatKey, splitValue );
3641 }
3642 else
3643 {
3644 if ( getLog().isWarnEnabled() )
3645 {
3646 getLog().warn(
3647 key + " option is not supported on Java version < " + requiredJavaVersion
3648 + ". Ignore this option." );
3649 }
3650 }
3651 }
3652 }
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666 private void addArgIfNotEmpty( List<String> arguments, String key, String value, boolean repeatKey,
3667 boolean splitValue )
3668 {
3669 if ( StringUtils.isNotEmpty( value ) )
3670 {
3671 if ( StringUtils.isNotEmpty( key ) )
3672 {
3673 arguments.add( key );
3674 }
3675
3676 if ( splitValue )
3677 {
3678 StringTokenizer token = new StringTokenizer( value, "," );
3679 while ( token.hasMoreTokens() )
3680 {
3681 String current = token.nextToken().trim();
3682
3683 if ( StringUtils.isNotEmpty( current ) )
3684 {
3685 arguments.add( current );
3686
3687 if ( token.hasMoreTokens() && repeatKey )
3688 {
3689 arguments.add( key );
3690 }
3691 }
3692 }
3693 }
3694 else
3695 {
3696 arguments.add( value );
3697 }
3698 }
3699 }
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712 private void addArgIfNotEmpty( List<String> arguments, String key, String value, boolean repeatKey )
3713 {
3714 addArgIfNotEmpty( arguments, key, value, repeatKey, true );
3715 }
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727 private void addArgIfNotEmpty( List<String> arguments, String key, String value, float requiredJavaVersion )
3728 {
3729 addArgIfNotEmpty( arguments, key, value, requiredJavaVersion, false );
3730 }
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744 private void addArgIfNotEmpty( List<String> arguments, String key, String value, float requiredJavaVersion,
3745 boolean repeatKey )
3746 {
3747 if ( StringUtils.isNotEmpty( value ) )
3748 {
3749 if ( isJavaDocVersionAtLeast( requiredJavaVersion ) )
3750 {
3751 addArgIfNotEmpty( arguments, key, value, repeatKey );
3752 }
3753 else
3754 {
3755 if ( getLog().isWarnEnabled() )
3756 {
3757 getLog().warn( key + " option is not supported on Java version < " + requiredJavaVersion );
3758 }
3759 }
3760 }
3761 }
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776 private void addLinkofflineArguments( List<String> arguments )
3777 throws MavenReportException
3778 {
3779 Set<OfflineLink> offlineLinksList = collectOfflineLinks();
3780
3781 offlineLinksList.addAll( getModulesLinks() );
3782
3783 for ( OfflineLink offlineLink : offlineLinksList )
3784 {
3785 String url = offlineLink.getUrl();
3786 if ( StringUtils.isEmpty( url ) )
3787 {
3788 continue;
3789 }
3790 url = cleanUrl( url );
3791
3792 String location = offlineLink.getLocation();
3793 if ( StringUtils.isEmpty( location ) )
3794 {
3795 continue;
3796 }
3797 if ( isValidJavadocLink( location ) )
3798 {
3799 addArgIfNotEmpty( arguments, "-linkoffline", JavadocUtil.quotedPathArgument( url ) + " "
3800 + JavadocUtil.quotedPathArgument( location ), true );
3801 }
3802 }
3803 }
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824 private void addLinkArguments( List<String> arguments )
3825 throws MavenReportException
3826 {
3827 Set<String> links = collectLinks();
3828
3829 for ( String link : links )
3830 {
3831 if ( StringUtils.isEmpty( link ) )
3832 {
3833 continue;
3834 }
3835
3836 while ( link.endsWith( "/" ) )
3837 {
3838 link = link.substring( 0, link.lastIndexOf( "/" ) );
3839 }
3840
3841 addArgIfNotEmpty( arguments, "-link", JavadocUtil.quotedPathArgument( link ), true );
3842 }
3843 }
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854 private void copyAllResources( File javadocOutputDirectory )
3855 throws MavenReportException
3856 {
3857
3858
3859
3860
3861 try
3862 {
3863 copyDefaultStylesheet( javadocOutputDirectory );
3864 }
3865 catch ( IOException e )
3866 {
3867 throw new MavenReportException( "Unable to copy default stylesheet: " + e.getMessage(), e );
3868 }
3869
3870
3871
3872
3873
3874 if ( docfilessubdirs )
3875 {
3876
3877
3878
3879
3880 try
3881 {
3882 copyJavadocResources( javadocOutputDirectory );
3883 }
3884 catch ( IOException e )
3885 {
3886 throw new MavenReportException( "Unable to copy javadoc resources: " + e.getMessage(), e );
3887 }
3888 }
3889
3890
3891
3892
3893
3894 copyAdditionalJavadocResources( javadocOutputDirectory );
3895 }
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907 private void copyDefaultStylesheet( File anOutputDirectory )
3908 throws IOException
3909 {
3910 if ( StringUtils.isNotEmpty( stylesheetfile ) )
3911 {
3912 return;
3913 }
3914
3915 if ( !stylesheet.equalsIgnoreCase( "maven" ) )
3916 {
3917 return;
3918 }
3919
3920 URL url = getClass().getClassLoader().getResource( RESOURCE_CSS_DIR + "/" + DEFAULT_CSS_NAME );
3921 File outFile = new File( anOutputDirectory, DEFAULT_CSS_NAME );
3922 JavadocUtil.copyResource( url, outFile );
3923 }
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936 private void copyJavadocResources( File anOutputDirectory )
3937 throws IOException
3938 {
3939 if ( anOutputDirectory == null || !anOutputDirectory.exists() )
3940 {
3941 throw new IOException( "The outputDirectory " + anOutputDirectory + " doesn't exists." );
3942 }
3943
3944 if ( includeDependencySources )
3945 {
3946 resolveDependencyBundles();
3947 if ( isNotEmpty( dependencyJavadocBundles ) )
3948 {
3949 for ( JavadocBundle bundle : dependencyJavadocBundles )
3950 {
3951 File dir = bundle.getResourcesDirectory();
3952 JavadocOptions options = bundle.getOptions();
3953 if ( dir != null && dir.isDirectory() )
3954 {
3955 JavadocUtil.copyJavadocResources( anOutputDirectory, dir, options == null ? null
3956 : options.getExcludedDocfilesSubdirs() );
3957 }
3958 }
3959 }
3960 }
3961
3962 if ( getJavadocDirectory() != null )
3963 {
3964 JavadocUtil.copyJavadocResources( anOutputDirectory, getJavadocDirectory(), excludedocfilessubdir );
3965 }
3966
3967 if ( isAggregator() && project.isExecutionRoot() )
3968 {
3969 for ( MavenProject subProject : reactorProjects )
3970 {
3971 if ( subProject != project )
3972 {
3973 String javadocDirRelative =
3974 PathUtils.toRelative( project.getBasedir(), getJavadocDirectory().getAbsolutePath() );
3975 File javadocDir = new File( subProject.getBasedir(), javadocDirRelative );
3976 JavadocUtil.copyJavadocResources( anOutputDirectory, javadocDir, excludedocfilessubdir );
3977 }
3978 }
3979 }
3980 }
3981
3982 private synchronized void resolveDependencyBundles()
3983 throws IOException
3984 {
3985 if ( dependencyJavadocBundles == null )
3986 {
3987 dependencyJavadocBundles = ResourceResolver.resolveDependencyJavadocBundles( getDependencySourceResolverConfig() );
3988 if ( dependencyJavadocBundles == null )
3989 {
3990 dependencyJavadocBundles = new ArrayList<JavadocBundle>();
3991 }
3992 }
3993 }
3994
3995
3996
3997
3998
3999
4000
4001
4002 private void copyAdditionalJavadocResources( File anOutputDirectory )
4003 throws MavenReportException
4004 {
4005 Set<ResourcesArtifact> resourcesArtifacts = collectResourcesArtifacts();
4006 if ( isEmpty( resourcesArtifacts ) )
4007 {
4008 return;
4009 }
4010
4011 UnArchiver unArchiver;
4012 try
4013 {
4014 unArchiver = archiverManager.getUnArchiver( "jar" );
4015 }
4016 catch ( NoSuchArchiverException e )
4017 {
4018 throw new MavenReportException( "Unable to extract resources artifact. "
4019 + "No archiver for 'jar' available.", e );
4020 }
4021
4022 for ( ResourcesArtifact item : resourcesArtifacts )
4023 {
4024 Artifact artifact;
4025 try
4026 {
4027 artifact = createAndResolveArtifact( item );
4028 }
4029 catch ( ArtifactResolutionException e )
4030 {
4031 throw new MavenReportException( "Unable to resolve artifact:" + item, e );
4032 }
4033 catch ( ArtifactNotFoundException e )
4034 {
4035 throw new MavenReportException( "Unable to find artifact:" + item, e );
4036 }
4037 catch ( ProjectBuildingException e )
4038 {
4039 throw new MavenReportException( "Unable to build the Maven project for the artifact:" + item,
4040 e );
4041 }
4042
4043 unArchiver.setSourceFile( artifact.getFile() );
4044 unArchiver.setDestDirectory( anOutputDirectory );
4045
4046 IncludeExcludeFileSelector[] selectors =
4047 new IncludeExcludeFileSelector[] { new IncludeExcludeFileSelector() };
4048 selectors[0].setExcludes( new String[] { "META-INF/**" } );
4049 unArchiver.setFileSelectors( selectors );
4050
4051 getLog().info( "Extracting contents of resources artifact: " + artifact.getArtifactId() );
4052 try
4053 {
4054 unArchiver.extract();
4055 }
4056 catch ( ArchiverException e )
4057 {
4058 throw new MavenReportException( "Extraction of resources failed. Artifact that failed was: "
4059 + artifact.getArtifactId(), e );
4060 }
4061 }
4062 }
4063
4064
4065
4066
4067
4068
4069 private List<String> getPackageNames( List<String> sourcePaths, List<String> files )
4070 {
4071 return getPackageNamesOrFilesWithUnnamedPackages( sourcePaths, files, true );
4072 }
4073
4074
4075
4076
4077
4078
4079 private List<String> getFilesWithUnnamedPackages( List<String> sourcePaths, List<String> files )
4080 {
4081 return getPackageNamesOrFilesWithUnnamedPackages( sourcePaths, files, false );
4082 }
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092 private List<String> getPackageNamesOrFilesWithUnnamedPackages( List<String> sourcePaths, List<String> files,
4093 boolean onlyPackageName )
4094 {
4095 List<String> returnList = new ArrayList<String>();
4096
4097 if ( !StringUtils.isEmpty( sourcepath ) )
4098 {
4099 return returnList;
4100 }
4101
4102 for ( String currentFile : files )
4103 {
4104 currentFile = currentFile.replace( '\\', '/' );
4105
4106 for ( String currentSourcePath : sourcePaths )
4107 {
4108 currentSourcePath = currentSourcePath.replace( '\\', '/' );
4109
4110 if ( !currentSourcePath.endsWith( "/" ) )
4111 {
4112 currentSourcePath += "/";
4113 }
4114
4115 if ( currentFile.indexOf( currentSourcePath ) != -1 )
4116 {
4117 String packagename = currentFile.substring( currentSourcePath.length() + 1 );
4118
4119
4120
4121
4122
4123 if ( packagename.indexOf( "doc-files" ) != -1 )
4124 {
4125 continue;
4126 }
4127
4128 if ( onlyPackageName && packagename.lastIndexOf( "/" ) != -1 )
4129 {
4130 packagename = packagename.substring( 0, packagename.lastIndexOf( "/" ) );
4131 packagename = packagename.replace( '/', '.' );
4132
4133 if ( !returnList.contains( packagename ) )
4134 {
4135 returnList.add( packagename );
4136 }
4137 }
4138 if ( !onlyPackageName && packagename.lastIndexOf( "/" ) == -1 )
4139 {
4140 returnList.add( currentFile );
4141 }
4142 }
4143 }
4144 }
4145
4146 return returnList;
4147 }
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162 private void addCommandLineOptions( Commandline cmd, List<String> arguments, File javadocOutputDirectory )
4163 throws MavenReportException
4164 {
4165 File optionsFile = new File( javadocOutputDirectory, OPTIONS_FILE_NAME );
4166
4167 StringBuffer options = new StringBuffer();
4168 options.append( StringUtils.join( arguments.toArray( new String[0] ), SystemUtils.LINE_SEPARATOR ) );
4169
4170 try
4171 {
4172 FileUtils.fileWrite( optionsFile.getAbsolutePath(), options.toString() );
4173 }
4174 catch ( IOException e )
4175 {
4176 throw new MavenReportException( "Unable to write '" + optionsFile.getName()
4177 + "' temporary file for command execution", e );
4178 }
4179
4180 cmd.createArg().setValue( "@" + OPTIONS_FILE_NAME );
4181 }
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202 private void addCommandLineArgFile( Commandline cmd, File javadocOutputDirectory, List<String> files )
4203 throws MavenReportException
4204 {
4205 File argfileFile;
4206 if ( isJavaDocVersionAtLeast( SINCE_JAVADOC_1_4 ) )
4207 {
4208 argfileFile = new File( javadocOutputDirectory, ARGFILE_FILE_NAME );
4209 }
4210 else
4211 {
4212 argfileFile = new File( javadocOutputDirectory, FILES_FILE_NAME );
4213 }
4214
4215 try
4216 {
4217 FileUtils.fileWrite( argfileFile.getAbsolutePath(), StringUtils.join( files.iterator(),
4218 SystemUtils.LINE_SEPARATOR ) );
4219 }
4220 catch ( IOException e )
4221 {
4222 throw new MavenReportException( "Unable to write '" + argfileFile.getName()
4223 + "' temporary file for command execution", e );
4224 }
4225
4226 if ( isJavaDocVersionAtLeast( SINCE_JAVADOC_1_4 ) )
4227 {
4228 cmd.createArg().setValue( "@" + ARGFILE_FILE_NAME );
4229 }
4230 else
4231 {
4232 cmd.createArg().setValue( "@" + FILES_FILE_NAME );
4233 }
4234 }
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249 private void addCommandLinePackages( Commandline cmd, File javadocOutputDirectory, List<String> packageNames )
4250 throws MavenReportException
4251 {
4252 File packagesFile = new File( javadocOutputDirectory, PACKAGES_FILE_NAME );
4253
4254 try
4255 {
4256 FileUtils.fileWrite( packagesFile.getAbsolutePath(),
4257 StringUtils.join( packageNames.toArray( new String[0] ),
4258 SystemUtils.LINE_SEPARATOR ) );
4259 }
4260 catch ( IOException e )
4261 {
4262 throw new MavenReportException( "Unable to write '" + packagesFile.getName()
4263 + "' temporary file for command execution", e );
4264 }
4265
4266 cmd.createArg().setValue( "@" + PACKAGES_FILE_NAME );
4267 }
4268
4269
4270
4271
4272
4273
4274 private void validateJavadocOptions()
4275 throws MavenReportException
4276 {
4277
4278 if ( StringUtils.isNotEmpty( getEncoding() ) && !JavadocUtil.validateEncoding( getEncoding() ) )
4279 {
4280 throw new MavenReportException( "Unsupported option <encoding/> '" + getEncoding() + "'" );
4281 }
4282
4283
4284 if ( StringUtils.isNotEmpty( this.locale ) )
4285 {
4286 StringTokenizer tokenizer = new StringTokenizer( this.locale, "_" );
4287 final int maxTokens = 3;
4288 if ( tokenizer.countTokens() > maxTokens )
4289 {
4290 throw new MavenReportException( "Unsupported option <locale/> '" + this.locale
4291 + "', should be language_country_variant." );
4292 }
4293
4294 Locale localeObject = null;
4295 if ( tokenizer.hasMoreTokens() )
4296 {
4297 String language = tokenizer.nextToken().toLowerCase( Locale.ENGLISH );
4298 if ( !Arrays.asList( Locale.getISOLanguages() ).contains( language ) )
4299 {
4300 throw new MavenReportException( "Unsupported language '" + language
4301 + "' in option <locale/> '" + this.locale + "'" );
4302 }
4303 localeObject = new Locale( language );
4304
4305 if ( tokenizer.hasMoreTokens() )
4306 {
4307 String country = tokenizer.nextToken().toUpperCase( Locale.ENGLISH );
4308 if ( !Arrays.asList( Locale.getISOCountries() ).contains( country ) )
4309 {
4310 throw new MavenReportException( "Unsupported country '" + country
4311 + "' in option <locale/> '" + this.locale + "'" );
4312 }
4313 localeObject = new Locale( language, country );
4314
4315 if ( tokenizer.hasMoreTokens() )
4316 {
4317 String variant = tokenizer.nextToken();
4318 localeObject = new Locale( language, country, variant );
4319 }
4320 }
4321 }
4322
4323 if ( localeObject == null )
4324 {
4325 throw new MavenReportException( "Unsupported option <locale/> '" + this.locale
4326 + "', should be language_country_variant." );
4327 }
4328
4329 this.locale = localeObject.toString();
4330 final List<Locale> availableLocalesList = Arrays.asList( Locale.getAvailableLocales() );
4331 if ( StringUtils.isNotEmpty( localeObject.getVariant() )
4332 && !availableLocalesList.contains( localeObject ) )
4333 {
4334 StringBuffer sb = new StringBuffer();
4335 sb.append( "Unsupported option <locale/> with variant '" ).append( this.locale );
4336 sb.append( "'" );
4337
4338 localeObject = new Locale( localeObject.getLanguage(), localeObject.getCountry() );
4339 this.locale = localeObject.toString();
4340
4341 sb.append( ", trying to use <locale/> without variant, i.e. '" ).append( this.locale ).append( "'" );
4342 if ( getLog().isWarnEnabled() )
4343 {
4344 getLog().warn( sb.toString() );
4345 }
4346 }
4347
4348 if ( !availableLocalesList.contains( localeObject ) )
4349 {
4350 throw new MavenReportException( "Unsupported option <locale/> '" + this.locale + "'" );
4351 }
4352 }
4353 }
4354
4355
4356
4357
4358
4359
4360
4361
4362 private void validateStandardDocletOptions()
4363 throws MavenReportException
4364 {
4365
4366 if ( StringUtils.isNotEmpty( getDocencoding() ) && !JavadocUtil.validateEncoding( getDocencoding() ) )
4367 {
4368 throw new MavenReportException( "Unsupported option <docencoding/> '" + getDocencoding() + "'" );
4369 }
4370
4371
4372 if ( StringUtils.isNotEmpty( getCharset() ) && !JavadocUtil.validateEncoding( getCharset() ) )
4373 {
4374 throw new MavenReportException( "Unsupported option <charset/> '" + getCharset() + "'" );
4375 }
4376
4377
4378 if ( StringUtils.isNotEmpty( helpfile ) && nohelp )
4379 {
4380 throw new MavenReportException( "Option <nohelp/> conflicts with <helpfile/>" );
4381 }
4382
4383
4384 if ( ( getOverview() != null ) && nooverview )
4385 {
4386 throw new MavenReportException( "Option <nooverview/> conflicts with <overview/>" );
4387 }
4388
4389
4390 if ( splitindex && noindex )
4391 {
4392 throw new MavenReportException( "Option <noindex/> conflicts with <splitindex/>" );
4393 }
4394
4395
4396 if ( StringUtils.isNotEmpty( stylesheet )
4397 && !( stylesheet.equalsIgnoreCase( "maven" ) || stylesheet.equalsIgnoreCase( "java" ) ) )
4398 {
4399 throw new MavenReportException( "Option <stylesheet/> supports only \"maven\" or \"java\" value." );
4400 }
4401
4402
4403 if ( javaApiLinks == null || javaApiLinks.size() == 0 )
4404 {
4405 javaApiLinks = DEFAULT_JAVA_API_LINKS;
4406 }
4407 }
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419 private boolean checkMissingArtifactsInReactor( Collection<Artifact> dependencyArtifacts,
4420 Collection<Artifact> missing )
4421 {
4422 Set<MavenProject> foundInReactor = new HashSet<MavenProject>();
4423 for ( Artifact mArtifact : missing )
4424 {
4425 for ( MavenProject p : reactorProjects )
4426 {
4427 if ( p.getArtifactId().equals( mArtifact.getArtifactId() )
4428 && p.getGroupId().equals( mArtifact.getGroupId() )
4429 && p.getVersion().equals( mArtifact.getVersion() ) )
4430 {
4431 getLog().warn(
4432 "The dependency: ["
4433 + p.getId()
4434 + "] can't be resolved but has been found in the reactor (probably snapshots).\n"
4435 + "This dependency has been excluded from the Javadoc classpath. "
4436 + "You should rerun javadoc after executing mvn install." );
4437
4438
4439 foundInReactor.add( p );
4440 break;
4441 }
4442 }
4443 }
4444
4445
4446 return foundInReactor.size() == missing.size();
4447 }
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460 private void addJavadocOptions( List<String> arguments, List<String> sourcePaths )
4461 throws MavenReportException
4462 {
4463 validateJavadocOptions();
4464
4465
4466 addArgIfNotEmpty( arguments, "-locale", JavadocUtil.quotedArgument( this.locale ) );
4467
4468
4469
4470 if ( old && isJavaDocVersionAtLeast( SINCE_JAVADOC_1_4 ) )
4471 {
4472 if ( getLog().isWarnEnabled() )
4473 {
4474 getLog().warn( "Javadoc 1.4+ doesn't support the -1.1 switch anymore. Ignore this option." );
4475 }
4476 }
4477 else
4478 {
4479 addArgIf( arguments, old, "-1.1" );
4480 }
4481
4482 addArgIfNotEmpty( arguments, "-bootclasspath", JavadocUtil.quotedPathArgument( getBootclassPath() ) );
4483
4484 if ( isJavaDocVersionAtLeast( SINCE_JAVADOC_1_5 ) )
4485 {
4486 addArgIf( arguments, breakiterator, "-breakiterator", SINCE_JAVADOC_1_5 );
4487 }
4488
4489 addArgIfNotEmpty( arguments, "-classpath", JavadocUtil.quotedPathArgument( getClasspath() ) );
4490
4491 if ( StringUtils.isNotEmpty( doclet ) )
4492 {
4493 addArgIfNotEmpty( arguments, "-doclet", JavadocUtil.quotedArgument( doclet ) );
4494 addArgIfNotEmpty( arguments, "-docletpath", JavadocUtil.quotedPathArgument( getDocletPath() ) );
4495 }
4496
4497 if ( StringUtils.isEmpty( encoding ) )
4498 {
4499 getLog().warn(
4500 "Source files encoding has not been set, using platform encoding "
4501 + ReaderFactory.FILE_ENCODING + ", i.e. build is platform dependent!" );
4502 }
4503 addArgIfNotEmpty( arguments, "-encoding", JavadocUtil.quotedArgument( getEncoding() ) );
4504
4505 addArgIfNotEmpty( arguments, "-exclude", getExcludedPackages( sourcePaths ), SINCE_JAVADOC_1_4 );
4506
4507 addArgIfNotEmpty( arguments, "-extdirs", JavadocUtil.quotedPathArgument( JavadocUtil.unifyPathSeparator( extdirs ) ) );
4508
4509 if ( ( getOverview() != null ) && ( getOverview().exists() ) )
4510 {
4511 addArgIfNotEmpty( arguments, "-overview",
4512 JavadocUtil.quotedPathArgument( getOverview().getAbsolutePath() ) );
4513 }
4514
4515 arguments.add( getAccessLevel() );
4516
4517 if ( isJavaDocVersionAtLeast( SINCE_JAVADOC_1_5 ) )
4518 {
4519 addArgIf( arguments, quiet, "-quiet", SINCE_JAVADOC_1_5 );
4520 }
4521
4522 addArgIfNotEmpty( arguments, "-source", JavadocUtil.quotedArgument( source ), SINCE_JAVADOC_1_4 );
4523
4524 if ( ( StringUtils.isEmpty( sourcepath ) ) && ( StringUtils.isNotEmpty( subpackages ) ) )
4525 {
4526 sourcepath = StringUtils.join( sourcePaths.iterator(), File.pathSeparator );
4527 }
4528 addArgIfNotEmpty( arguments, "-sourcepath", JavadocUtil.quotedPathArgument( getSourcePath( sourcePaths ) ) );
4529
4530 if ( StringUtils.isNotEmpty( sourcepath ) && isJavaDocVersionAtLeast( SINCE_JAVADOC_1_5 ) )
4531 {
4532 addArgIfNotEmpty( arguments, "-subpackages", subpackages, SINCE_JAVADOC_1_5 );
4533 }
4534
4535 addArgIf( arguments, verbose, "-verbose" );
4536
4537 addArgIfNotEmpty( arguments, null, additionalparam );
4538 }
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552 private void addStandardDocletOptions( File javadocOutputDirectory, List<String> arguments )
4553 throws MavenReportException
4554 {
4555 validateStandardDocletOptions();
4556
4557
4558
4559 addArgIf( arguments, author, "-author" );
4560
4561 addArgIfNotEmpty( arguments, "-bottom", JavadocUtil.quotedArgument( getBottomText() ), false, false );
4562
4563 if ( !isJavaDocVersionAtLeast( SINCE_JAVADOC_1_5 ) )
4564 {
4565 addArgIf( arguments, breakiterator, "-breakiterator", SINCE_JAVADOC_1_4 );
4566 }
4567
4568 addArgIfNotEmpty( arguments, "-charset", JavadocUtil.quotedArgument( getCharset() ) );
4569
4570 addArgIfNotEmpty( arguments, "-d", JavadocUtil.quotedPathArgument( javadocOutputDirectory.toString() ) );
4571
4572 addArgIfNotEmpty( arguments, "-docencoding", JavadocUtil.quotedArgument( getDocencoding() ) );
4573
4574 addArgIf( arguments, docfilessubdirs, "-docfilessubdirs", SINCE_JAVADOC_1_4 );
4575
4576 addArgIfNotEmpty( arguments, "-doctitle", JavadocUtil.quotedArgument( getDoctitle() ), false, false );
4577
4578 if ( docfilessubdirs )
4579 {
4580 addArgIfNotEmpty( arguments, "-excludedocfilessubdir",
4581 JavadocUtil.quotedPathArgument( excludedocfilessubdir ), SINCE_JAVADOC_1_4 );
4582 }
4583
4584 addArgIfNotEmpty( arguments, "-footer", JavadocUtil.quotedArgument( footer ), false, false );
4585
4586 addGroups( arguments );
4587
4588 addArgIfNotEmpty( arguments, "-header", JavadocUtil.quotedArgument( header ), false, false );
4589
4590 addArgIfNotEmpty( arguments, "-helpfile",
4591 JavadocUtil.quotedPathArgument( getHelpFile( javadocOutputDirectory ) ) );
4592
4593 addArgIf( arguments, keywords, "-keywords", SINCE_JAVADOC_1_4_2 );
4594
4595 if ( !isOffline )
4596 {
4597 addLinkArguments( arguments );
4598 }
4599
4600 addLinkofflineArguments( arguments );
4601
4602 addArgIf( arguments, linksource, "-linksource", SINCE_JAVADOC_1_4 );
4603
4604 if ( sourcetab > 0 )
4605 {
4606 if ( fJavadocVersion == SINCE_JAVADOC_1_4_2 )
4607 {
4608 addArgIfNotEmpty( arguments, "-linksourcetab", String.valueOf( sourcetab ) );
4609 }
4610 addArgIfNotEmpty( arguments, "-sourcetab", String.valueOf( sourcetab ), SINCE_JAVADOC_1_5 );
4611 }
4612
4613 addArgIf( arguments, nocomment, "-nocomment", SINCE_JAVADOC_1_4 );
4614
4615 addArgIf( arguments, nodeprecated, "-nodeprecated" );
4616
4617 addArgIf( arguments, nodeprecatedlist, "-nodeprecatedlist" );
4618
4619 addArgIf( arguments, nohelp, "-nohelp" );
4620
4621 addArgIf( arguments, noindex, "-noindex" );
4622
4623 addArgIf( arguments, nonavbar, "-nonavbar" );
4624
4625 addArgIf( arguments, nooverview, "-nooverview" );
4626
4627 addArgIfNotEmpty( arguments, "-noqualifier", JavadocUtil.quotedArgument( noqualifier ), SINCE_JAVADOC_1_4 );
4628
4629 addArgIf( arguments, nosince, "-nosince" );
4630
4631 addArgIf( arguments, notimestamp, "-notimestamp", SINCE_JAVADOC_1_5 );
4632
4633 addArgIf( arguments, notree, "-notree" );
4634
4635 addArgIfNotEmpty( arguments, "-packagesheader", JavadocUtil.quotedArgument( packagesheader ),
4636 SINCE_JAVADOC_1_4_2 );
4637
4638 if ( !isJavaDocVersionAtLeast( SINCE_JAVADOC_1_5 ) )
4639 {
4640 addArgIf( arguments, quiet, "-quiet", SINCE_JAVADOC_1_4 );
4641 }
4642
4643 addArgIf( arguments, serialwarn, "-serialwarn" );
4644
4645 addArgIf( arguments, splitindex, "-splitindex" );
4646
4647 addArgIfNotEmpty( arguments, "-stylesheetfile",
4648 JavadocUtil.quotedPathArgument( getStylesheetFile( javadocOutputDirectory ) ) );
4649
4650 if ( StringUtils.isNotEmpty( sourcepath ) && !isJavaDocVersionAtLeast( SINCE_JAVADOC_1_5 ) )
4651 {
4652 addArgIfNotEmpty( arguments, "-subpackages", subpackages, SINCE_JAVADOC_1_4 );
4653 }
4654
4655 addArgIfNotEmpty( arguments, "-taglet", JavadocUtil.quotedArgument( taglet ), SINCE_JAVADOC_1_4 );
4656 addTaglets( arguments );
4657 addTagletsFromTagletArtifacts( arguments );
4658 addArgIfNotEmpty( arguments, "-tagletpath", JavadocUtil.quotedPathArgument( getTagletPath() ),
4659 SINCE_JAVADOC_1_4 );
4660
4661 addTags( arguments );
4662
4663 addArgIfNotEmpty( arguments, "-top", JavadocUtil.quotedArgument( top ), false, false, SINCE_JAVADOC_1_6 );
4664
4665 addArgIf( arguments, use, "-use" );
4666
4667 addArgIf( arguments, version, "-version" );
4668
4669 addArgIfNotEmpty( arguments, "-windowtitle", JavadocUtil.quotedArgument( getWindowtitle() ), false, false );
4670 }
4671
4672
4673
4674
4675
4676
4677
4678 private void addGroups( List<String> arguments )
4679 throws MavenReportException
4680 {
4681 Set<Group> groups = collectGroups();
4682 if ( isEmpty( groups ) )
4683 {
4684 return;
4685 }
4686
4687 for ( Group group : groups )
4688 {
4689 if ( group == null || StringUtils.isEmpty( group.getTitle() )
4690 || StringUtils.isEmpty( group.getPackages() ) )
4691 {
4692 if ( getLog().isWarnEnabled() )
4693 {
4694 getLog().warn( "A group option is empty. Ignore this option." );
4695 }
4696 }
4697 else
4698 {
4699 String groupTitle = StringUtils.replace( group.getTitle(), ",", "," );
4700 addArgIfNotEmpty( arguments, "-group", JavadocUtil.quotedArgument( groupTitle ) + " "
4701 + JavadocUtil.quotedArgument( group.getPackages() ), true );
4702 }
4703 }
4704 }
4705
4706
4707
4708
4709
4710
4711
4712 private void addTags( List<String> arguments )
4713 throws MavenReportException
4714 {
4715 Set<Tag> tags = collectTags();
4716
4717 if ( isEmpty( tags ) )
4718 {
4719 return;
4720 }
4721
4722 for ( Tag tag : tags )
4723 {
4724 if ( StringUtils.isEmpty( tag.getName() ) )
4725 {
4726 if ( getLog().isWarnEnabled() )
4727 {
4728 getLog().warn( "A tag name is empty. Ignore this option." );
4729 }
4730 }
4731 else
4732 {
4733 String value = "\"" + tag.getName();
4734 if ( StringUtils.isNotEmpty( tag.getPlacement() ) )
4735 {
4736 value += ":" + tag.getPlacement();
4737 if ( StringUtils.isNotEmpty( tag.getHead() ) )
4738 {
4739 value += ":" + tag.getHead();
4740 }
4741 }
4742 value += "\"";
4743 addArgIfNotEmpty( arguments, "-tag", value, SINCE_JAVADOC_1_4 );
4744 }
4745 }
4746 }
4747
4748
4749
4750
4751
4752
4753 private void addTaglets( List<String> arguments )
4754 {
4755 if ( taglets == null )
4756 {
4757 return;
4758 }
4759
4760 for ( int i = 0; i < taglets.length; i++ )
4761 {
4762 if ( ( taglets[i] == null ) || ( StringUtils.isEmpty( taglets[i].getTagletClass() ) ) )
4763 {
4764 if ( getLog().isWarnEnabled() )
4765 {
4766 getLog().warn( "A taglet option is empty. Ignore this option." );
4767 }
4768 }
4769 else
4770 {
4771 addArgIfNotEmpty( arguments, "-taglet", JavadocUtil.quotedArgument( taglets[i].getTagletClass() ),
4772 SINCE_JAVADOC_1_4 );
4773 }
4774 }
4775 }
4776
4777
4778
4779
4780
4781
4782
4783
4784 private void addTagletsFromTagletArtifacts( List<String> arguments )
4785 throws MavenReportException
4786 {
4787 Set<TagletArtifact> tArtifacts = new LinkedHashSet<TagletArtifact>();
4788 if ( tagletArtifacts != null && tagletArtifacts.length > 0 )
4789 {
4790 tArtifacts.addAll( Arrays.asList( tagletArtifacts ) );
4791 }
4792
4793 if ( includeDependencySources )
4794 {
4795 try
4796 {
4797 resolveDependencyBundles();
4798 }
4799 catch ( IOException e )
4800 {
4801 throw new MavenReportException( "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
4802 }
4803
4804 if ( isNotEmpty( dependencyJavadocBundles ) )
4805 {
4806 for ( JavadocBundle bundle : dependencyJavadocBundles )
4807 {
4808 JavadocOptions options = bundle.getOptions();
4809 if ( options != null && isNotEmpty( options.getTagletArtifacts() ) )
4810 {
4811 tArtifacts.addAll( options.getTagletArtifacts() );
4812 }
4813 }
4814 }
4815 }
4816
4817 if ( isEmpty( tArtifacts ) )
4818 {
4819 return;
4820 }
4821
4822 List<String> tagletsPath = new ArrayList<String>();
4823
4824 for ( TagletArtifact aTagletArtifact : tArtifacts )
4825 {
4826 if ( ( StringUtils.isNotEmpty( aTagletArtifact.getGroupId() ) )
4827 && ( StringUtils.isNotEmpty( aTagletArtifact.getArtifactId() ) )
4828 && ( StringUtils.isNotEmpty( aTagletArtifact.getVersion() ) ) )
4829 {
4830 Artifact artifact;
4831 try
4832 {
4833 artifact = createAndResolveArtifact( aTagletArtifact );
4834 }
4835 catch ( ArtifactResolutionException e )
4836 {
4837 throw new MavenReportException( "Unable to resolve artifact:" + aTagletArtifact, e );
4838 }
4839 catch ( ArtifactNotFoundException e )
4840 {
4841 throw new MavenReportException( "Unable to find artifact:" + aTagletArtifact, e );
4842 }
4843 catch ( ProjectBuildingException e )
4844 {
4845 throw new MavenReportException( "Unable to build the Maven project for the artifact:"
4846 + aTagletArtifact, e );
4847 }
4848
4849 tagletsPath.add( artifact.getFile().getAbsolutePath() );
4850 }
4851 }
4852
4853 tagletsPath = JavadocUtil.pruneFiles( tagletsPath );
4854
4855 for ( String tagletJar : tagletsPath )
4856 {
4857 if ( !tagletJar.toLowerCase( Locale.ENGLISH ).endsWith( ".jar" ) )
4858 {
4859 continue;
4860 }
4861
4862 List<String> tagletClasses;
4863 try
4864 {
4865 tagletClasses = JavadocUtil.getTagletClassNames( new File( tagletJar ) );
4866 }
4867 catch ( IOException e )
4868 {
4869 if ( getLog().isWarnEnabled() )
4870 {
4871 getLog().warn(
4872 "Unable to auto-detect Taglet class names from '" + tagletJar
4873 + "'. Try to specify them with <taglets/>." );
4874 }
4875 if ( getLog().isDebugEnabled() )
4876 {
4877 getLog().debug( "IOException: " + e.getMessage(), e );
4878 }
4879 continue;
4880 }
4881 catch ( ClassNotFoundException e )
4882 {
4883 if ( getLog().isWarnEnabled() )
4884 {
4885 getLog().warn(
4886 "Unable to auto-detect Taglet class names from '" + tagletJar
4887 + "'. Try to specify them with <taglets/>." );
4888 }
4889 if ( getLog().isDebugEnabled() )
4890 {
4891 getLog().debug( "ClassNotFoundException: " + e.getMessage(), e );
4892 }
4893 continue;
4894 }
4895 catch ( NoClassDefFoundError e )
4896 {
4897 if ( getLog().isWarnEnabled() )
4898 {
4899 getLog().warn(
4900 "Unable to auto-detect Taglet class names from '" + tagletJar
4901 + "'. Try to specify them with <taglets/>." );
4902 }
4903 if ( getLog().isDebugEnabled() )
4904 {
4905 getLog().debug( "NoClassDefFoundError: " + e.getMessage(), e );
4906 }
4907 continue;
4908 }
4909
4910 if ( tagletClasses != null && !tagletClasses.isEmpty() )
4911 {
4912 for ( String tagletClass : tagletClasses )
4913 {
4914 addArgIfNotEmpty( arguments, "-taglet", JavadocUtil.quotedArgument( tagletClass ),
4915 SINCE_JAVADOC_1_4 );
4916 }
4917 }
4918 }
4919 }
4920
4921
4922
4923
4924
4925
4926
4927
4928 private void executeJavadocCommandLine( Commandline cmd, File javadocOutputDirectory )
4929 throws MavenReportException
4930 {
4931 if ( getLog().isDebugEnabled() )
4932 {
4933
4934 getLog().debug( CommandLineUtils.toString( cmd.getCommandline() ).replaceAll( "'", "" ) );
4935 }
4936
4937 String cmdLine = null;
4938 if ( debug )
4939 {
4940 cmdLine = CommandLineUtils.toString( cmd.getCommandline() ).replaceAll( "'", "" );
4941 cmdLine = JavadocUtil.hideProxyPassword( cmdLine, settings );
4942
4943 writeDebugJavadocScript( cmdLine, javadocOutputDirectory );
4944 }
4945
4946 CommandLineUtils.StringStreamConsumer err = new CommandLineUtils.StringStreamConsumer();
4947 CommandLineUtils.StringStreamConsumer out = new CommandLineUtils.StringStreamConsumer();
4948 try
4949 {
4950 int exitCode = CommandLineUtils.executeCommandLine( cmd, out, err );
4951
4952 String output = ( StringUtils.isEmpty( out.getOutput() ) ? null : '\n' + out.getOutput().trim() );
4953
4954 if ( exitCode != 0 )
4955 {
4956 if ( cmdLine == null )
4957 {
4958 cmdLine = CommandLineUtils.toString( cmd.getCommandline() ).replaceAll( "'", "" );
4959 cmdLine = JavadocUtil.hideProxyPassword( cmdLine, settings );
4960 }
4961 writeDebugJavadocScript( cmdLine, javadocOutputDirectory );
4962
4963 if ( StringUtils.isNotEmpty( output ) && StringUtils.isEmpty( err.getOutput() )
4964 && isJavadocVMInitError( output ) )
4965 {
4966 StringBuffer msg = new StringBuffer();
4967 msg.append( output );
4968 msg.append( '\n' ).append( '\n' );
4969 msg.append( JavadocUtil.ERROR_INIT_VM ).append( '\n' );
4970 msg.append( "Or, try to reduce the Java heap size for the Javadoc goal using " );
4971 msg.append( "-Dminmemory=<size> and -Dmaxmemory=<size>." ).append( '\n' ).append( '\n' );
4972
4973 msg.append( "Command line was: " ).append( cmdLine ).append( '\n' ).append( '\n' );
4974 msg.append( "Refer to the generated Javadoc files in '" ).append( javadocOutputDirectory )
4975 .append( "' dir.\n" );
4976
4977 throw new MavenReportException( msg.toString() );
4978 }
4979
4980 if ( StringUtils.isNotEmpty( output ) )
4981 {
4982 getLog().info( output );
4983 }
4984
4985 StringBuffer msg = new StringBuffer( "\nExit code: " );
4986 msg.append( exitCode );
4987 if ( StringUtils.isNotEmpty( err.getOutput() ) )
4988 {
4989 msg.append( " - " ).append( err.getOutput() );
4990 }
4991 msg.append( '\n' );
4992 msg.append( "Command line was: " ).append( cmdLine ).append( '\n' ).append( '\n' );
4993
4994 msg.append( "Refer to the generated Javadoc files in '" ).append( javadocOutputDirectory )
4995 .append( "' dir.\n" );
4996
4997 throw new MavenReportException( msg.toString() );
4998 }
4999
5000 if ( StringUtils.isNotEmpty( output ) )
5001 {
5002 getLog().info( output );
5003 }
5004 }
5005 catch ( CommandLineException e )
5006 {
5007 throw new MavenReportException( "Unable to execute javadoc command: " + e.getMessage(), e );
5008 }
5009
5010
5011
5012
5013
5014 if ( StringUtils.isNotEmpty( err.getOutput() ) && getLog().isWarnEnabled() )
5015 {
5016 getLog().warn( "Javadoc Warnings" );
5017
5018 StringTokenizer token = new StringTokenizer( err.getOutput(), "\n" );
5019 while ( token.hasMoreTokens() )
5020 {
5021 String current = token.nextToken().trim();
5022
5023 getLog().warn( current );
5024 }
5025 }
5026 }
5027
5028
5029
5030
5031
5032
5033
5034
5035 private String getResource( File outputFile, String inputResourceName )
5036 {
5037 if ( inputResourceName.startsWith( "/" ) )
5038 {
5039 inputResourceName = inputResourceName.replaceFirst( "//*", "" );
5040 }
5041
5042 List<String> classPath = new ArrayList<String>();
5043 classPath.add( project.getBuild().getSourceDirectory() );
5044
5045 URL resourceURL = getResource( classPath, inputResourceName );
5046 if ( resourceURL != null )
5047 {
5048 getLog().debug( inputResourceName + " found in the main src directory of the project." );
5049 return FileUtils.toFile( resourceURL ).getAbsolutePath();
5050 }
5051
5052 classPath.clear();
5053 List<Resource> resources = project.getBuild().getResources();
5054 for ( Resource resource : resources )
5055 {
5056 classPath.add( resource.getDirectory() );
5057 }
5058 resourceURL = getResource( classPath, inputResourceName );
5059 if ( resourceURL != null )
5060 {
5061 getLog().debug( inputResourceName + " found in the main resources directories of the project." );
5062 return FileUtils.toFile( resourceURL ).getAbsolutePath();
5063 }
5064
5065 if ( javadocDirectory.exists() )
5066 {
5067 classPath.clear();
5068 classPath.add( javadocDirectory.getAbsolutePath() );
5069 resourceURL = getResource( classPath, inputResourceName );
5070 if ( resourceURL != null )
5071 {
5072 getLog().debug( inputResourceName + " found in the main javadoc directory of the project." );
5073 return FileUtils.toFile( resourceURL ).getAbsolutePath();
5074 }
5075 }
5076
5077 classPath.clear();
5078 final String pluginId = "org.apache.maven.plugins:maven-javadoc-plugin";
5079 Plugin javadocPlugin = getPlugin( project, pluginId );
5080 if ( javadocPlugin != null && javadocPlugin.getDependencies() != null )
5081 {
5082 List<Dependency> dependencies = javadocPlugin.getDependencies();
5083 for ( Dependency dependency : dependencies )
5084 {
5085 JavadocPathArtifact javadocPathArtifact = new JavadocPathArtifact();
5086 javadocPathArtifact.setGroupId( dependency.getGroupId() );
5087 javadocPathArtifact.setArtifactId( dependency.getArtifactId() );
5088 javadocPathArtifact.setVersion( dependency.getVersion() );
5089 Artifact artifact = null;
5090 try
5091 {
5092 artifact = createAndResolveArtifact( javadocPathArtifact );
5093 }
5094 catch ( Exception e )
5095 {
5096 logError( "Unable to retrieve the dependency: " + dependency + ". Ignored.", e );
5097 }
5098
5099 if ( artifact != null && artifact.getFile().exists() )
5100 {
5101 classPath.add( artifact.getFile().getAbsolutePath() );
5102 }
5103 }
5104 resourceURL = getResource( classPath, inputResourceName );
5105 if ( resourceURL != null )
5106 {
5107 getLog().debug( inputResourceName + " found in javadoc plugin dependencies." );
5108 try
5109 {
5110 JavadocUtil.copyResource( resourceURL, outputFile );
5111
5112 return outputFile.getAbsolutePath();
5113 }
5114 catch ( IOException e )
5115 {
5116 logError( "IOException: " + e.getMessage(), e );
5117 }
5118 }
5119 }
5120
5121 getLog()
5122 .warn( "Unable to find the resource '" + inputResourceName + "'. Using default Javadoc resources." );
5123
5124 return null;
5125 }
5126
5127
5128
5129
5130
5131
5132
5133
5134 private URL getResource( final List<String> classPath, final String resource )
5135 {
5136 List<URL> urls = new ArrayList<URL>( classPath.size() );
5137 for ( String filename : classPath )
5138 {
5139 try
5140 {
5141 urls.add( new File( filename ).toURL() );
5142 }
5143 catch ( MalformedURLException e )
5144 {
5145 getLog().error( "MalformedURLException: " + e.getMessage() );
5146 }
5147 }
5148
5149 ClassLoader javadocClassLoader = new URLClassLoader( (URL[]) urls.toArray( new URL[urls.size()] ), null );
5150
5151 return javadocClassLoader.getResource( resource );
5152 }
5153
5154
5155
5156
5157
5158
5159 private String getFullJavadocGoal()
5160 {
5161 String javadocPluginVersion = null;
5162 InputStream resourceAsStream = null;
5163 try
5164 {
5165 String resource =
5166 "META-INF/maven/org.apache.maven.plugins/maven-javadoc-plugin/pom.properties";
5167 resourceAsStream = AbstractJavadocMojo.class.getClassLoader().getResourceAsStream( resource );
5168
5169 if ( resourceAsStream != null )
5170 {
5171 Properties properties = new Properties();
5172 properties.load( resourceAsStream );
5173
5174 if ( StringUtils.isNotEmpty( properties.getProperty( "version" ) ) )
5175 {
5176 javadocPluginVersion = properties.getProperty( "version" );
5177 }
5178 }
5179 }
5180 catch ( IOException e )
5181 {
5182
5183 }
5184 finally
5185 {
5186 IOUtil.close( resourceAsStream );
5187 }
5188
5189 StringBuffer sb = new StringBuffer();
5190
5191 sb.append( "org.apache.maven.plugins:maven-javadoc-plugin:" );
5192 if ( StringUtils.isNotEmpty( javadocPluginVersion ) )
5193 {
5194 sb.append( javadocPluginVersion ).append( ":" );
5195 }
5196
5197 if ( this instanceof TestJavadocReport )
5198 {
5199 sb.append( "test-javadoc" );
5200 }
5201 else
5202 {
5203 sb.append( "javadoc" );
5204 }
5205
5206 return sb.toString();
5207 }
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219 private List<OfflineLink> getModulesLinks()
5220 throws MavenReportException
5221 {
5222 if ( !detectOfflineLinks || isAggregator() || reactorProjects == null )
5223 {
5224 return Collections.emptyList();
5225 }
5226
5227 getLog().debug( "Trying to add links for modules..." );
5228
5229 Set<String> dependencyArtifactIds = new HashSet<String>();
5230 final Set<Artifact> dependencyArtifacts = project.getDependencyArtifacts();
5231 for ( Artifact artifact : dependencyArtifacts )
5232 {
5233 dependencyArtifactIds.add( artifact.getId() );
5234 }
5235
5236 List<OfflineLink> modulesLinks = new ArrayList<OfflineLink>();
5237 String javadocDirRelative = PathUtils.toRelative( project.getBasedir(), getOutputDirectory() );
5238 for ( MavenProject p : reactorProjects )
5239 {
5240 if ( !dependencyArtifactIds.contains( p.getArtifact().getId() ) || ( p.getUrl() == null ) )
5241 {
5242 continue;
5243 }
5244
5245 File location = new File( p.getBasedir(), javadocDirRelative );
5246
5247 if ( !location.exists() )
5248 {
5249 if ( getLog().isDebugEnabled() )
5250 {
5251 getLog().debug( "Javadoc directory not found: " + location );
5252 }
5253
5254 String javadocGoal = getFullJavadocGoal();
5255 getLog().info( "The goal '" + javadocGoal + "' has not been previously called for the module: '"
5256 + p.getId() + "'. Trying to invoke it..." );
5257
5258 File invokerDir = new File( project.getBuild().getDirectory(), "invoker" );
5259 invokerDir.mkdirs();
5260 File invokerLogFile = FileUtils.createTempFile( "maven-javadoc-plugin", ".txt", invokerDir );
5261 try
5262 {
5263 JavadocUtil.invokeMaven( getLog(), new File( localRepository.getBasedir() ), p.getFile(),
5264 Collections.singletonList( javadocGoal ), null, invokerLogFile );
5265 }
5266 catch ( MavenInvocationException e )
5267 {
5268 logError( "MavenInvocationException: " + e.getMessage(), e );
5269
5270 String invokerLogContent = JavadocUtil.readFile( invokerLogFile, "UTF-8" );
5271
5272
5273
5274
5275 if ( invokerLogContent != null && invokerLogContent.contains( JavadocUtil.ERROR_INIT_VM ) )
5276 {
5277 throw new MavenReportException( e.getMessage(), e );
5278 }
5279 }
5280 finally
5281 {
5282
5283 if ( !location.exists() )
5284 {
5285 getLog().warn( "Creating fake javadoc directory to prevent repeated invocations: " + location );
5286 location.mkdirs();
5287 }
5288 }
5289 }
5290
5291 if ( location.exists() )
5292 {
5293 String url = getJavadocLink( p );
5294
5295 OfflineLink ol = new OfflineLink();
5296 ol.setUrl( url );
5297 ol.setLocation( location.getAbsolutePath() );
5298
5299 if ( getLog().isDebugEnabled() )
5300 {
5301 getLog().debug( "Added Javadoc offline link: " + url + " for the module: " + p.getId() );
5302 }
5303
5304 modulesLinks.add( ol );
5305 }
5306 }
5307
5308 return modulesLinks;
5309 }
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320 private List<String> getDependenciesLinks()
5321 {
5322 if ( !detectLinks )
5323 {
5324 return Collections.emptyList();
5325 }
5326
5327 getLog().debug( "Trying to add links for dependencies..." );
5328
5329 List<String> dependenciesLinks = new ArrayList<String>();
5330
5331 final Set<Artifact> dependencies = project.getDependencyArtifacts();
5332 for ( Artifact artifact : dependencies )
5333 {
5334 if ( artifact.getFile() == null || !artifact.getFile().exists() )
5335 {
5336 continue;
5337 }
5338
5339 try
5340 {
5341 MavenProject artifactProject =
5342 mavenProjectBuilder.buildFromRepository( artifact, remoteRepositories, localRepository );
5343
5344 if ( StringUtils.isNotEmpty( artifactProject.getUrl() ) )
5345 {
5346 String url = getJavadocLink( artifactProject );
5347
5348 if ( isValidJavadocLink( url ) )
5349 {
5350 getLog().debug( "Added Javadoc link: " + url + " for " + artifactProject.getId() );
5351
5352 dependenciesLinks.add( url );
5353 }
5354 }
5355 }
5356 catch ( ProjectBuildingException e )
5357 {
5358 logError( "ProjectBuildingException for " + artifact.toString() + ": " + e.getMessage(), e );
5359 }
5360 }
5361
5362 return dependenciesLinks;
5363 }
5364
5365
5366
5367
5368
5369
5370
5371
5372
5373
5374
5375
5376 private OfflineLink getDefaultJavadocApiLink()
5377 {
5378 if ( !detectJavaApiLink )
5379 {
5380 return null;
5381 }
5382
5383 final String pluginId = "org.apache.maven.plugins:maven-compiler-plugin";
5384 float sourceVersion = fJavadocVersion;
5385 String sourceConfigured = getPluginParameter( project, pluginId, "source" );
5386 if ( sourceConfigured != null )
5387 {
5388 try
5389 {
5390 sourceVersion = Float.parseFloat( sourceConfigured );
5391 }
5392 catch ( NumberFormatException e )
5393 {
5394 getLog().debug( "NumberFormatException for the source parameter in the maven-compiler-plugin. "
5395 + "Ignored it", e );
5396 }
5397 }
5398 else
5399 {
5400 getLog().debug( "No maven-compiler-plugin defined in ${build.plugins} or in "
5401 + "${project.build.pluginManagement} for the " + project.getId()
5402 + ". Added Javadoc API link according the javadoc executable version i.e.: "
5403 + fJavadocVersion );
5404 }
5405
5406 String apiVersion = null;
5407 if ( sourceVersion >= 1.3f && sourceVersion < 1.4f )
5408 {
5409 apiVersion = "1.3";
5410 }
5411 else if ( sourceVersion >= 1.4f && sourceVersion < 1.5f )
5412 {
5413 apiVersion = "1.4";
5414 }
5415 else if ( sourceVersion >= 1.5f && sourceVersion < 1.6f )
5416 {
5417 apiVersion = "1.5";
5418 }
5419 else if ( sourceVersion >= 1.6f )
5420 {
5421 apiVersion = "1.6";
5422 }
5423 String javaApiLink = javaApiLinks.getProperty( "api_" + apiVersion, null );
5424
5425 if ( getLog().isDebugEnabled() )
5426 {
5427 if ( StringUtils.isNotEmpty( javaApiLink ) )
5428 {
5429 getLog().debug( "Found Java API link: " + javaApiLink );
5430 }
5431 else
5432 {
5433 getLog().debug( "No Java API link found." );
5434 }
5435 }
5436
5437 if ( javaApiLink == null )
5438 {
5439 return null;
5440 }
5441
5442 File javaApiPackageListFile = new File( getJavadocOptionsFile().getParentFile(), "package-list" );
5443
5444 OfflineLink link = new OfflineLink();
5445 link.setLocation( javaApiPackageListFile.getParentFile().getAbsolutePath() );
5446 link.setUrl( javaApiLink );
5447
5448 InputStream in = this.getClass().getResourceAsStream( "java-api-package-list-" + apiVersion );
5449 OutputStream out = null;
5450 try
5451 {
5452 out = new FileOutputStream( javaApiPackageListFile );
5453 IOUtil.copy( in, out );
5454 }
5455 catch ( IOException ioe )
5456 {
5457 logError( "Can't get java-api-package-list-" + apiVersion + ": " + ioe.getMessage(), ioe );
5458 return null;
5459 }
5460 finally
5461 {
5462 IOUtil.close( in );
5463 IOUtil.close( out );
5464 }
5465
5466 return link;
5467 }
5468
5469
5470
5471
5472
5473
5474
5475
5476 private boolean isValidJavadocLink( String link )
5477 {
5478 try
5479 {
5480 URI linkUri;
5481 if ( link.trim().toLowerCase( Locale.ENGLISH ).startsWith( "http:" )
5482 || link.trim().toLowerCase( Locale.ENGLISH ).startsWith( "https:" )
5483 || link.trim().toLowerCase( Locale.ENGLISH ).startsWith( "ftp:" )
5484 || link.trim().toLowerCase( Locale.ENGLISH ).startsWith( "file:" ) )
5485 {
5486 linkUri = new URI( link + "/package-list" );
5487 }
5488 else
5489 {
5490
5491 File dir = new File( link );
5492 if ( !dir.isAbsolute() )
5493 {
5494 dir = new File( getOutputDirectory(), link );
5495 }
5496 if ( !dir.isDirectory() )
5497 {
5498 getLog().error( "The given File link: " + dir + " is not a dir." );
5499 }
5500 linkUri = new File( dir, "package-list" ).toURI();
5501 }
5502
5503 if ( !JavadocUtil.isValidPackageList( linkUri.toURL(), settings, validateLinks ) )
5504 {
5505 if ( getLog().isErrorEnabled() )
5506 {
5507 getLog().error( "Invalid link: " + link + "/package-list. Ignored it." );
5508 }
5509
5510 return false;
5511 }
5512
5513 return true;
5514 }
5515 catch ( URISyntaxException e )
5516 {
5517 if ( getLog().isErrorEnabled() )
5518 {
5519 getLog().error( "Malformed link: " + link + "/package-list. Ignored it." );
5520 }
5521 return false;
5522 }
5523 catch ( IOException e )
5524 {
5525 if ( getLog().isErrorEnabled() )
5526 {
5527 getLog().error( "Error fetching link: " + link + "/package-list. Ignored it." );
5528 }
5529 return false;
5530 }
5531 }
5532
5533
5534
5535
5536
5537
5538
5539
5540
5541 private void writeDebugJavadocScript( String cmdLine, File javadocOutputDirectory )
5542 {
5543 File commandLineFile = new File( javadocOutputDirectory, DEBUG_JAVADOC_SCRIPT_NAME );
5544 commandLineFile.getParentFile().mkdirs();
5545
5546 try
5547 {
5548 FileUtils.fileWrite( commandLineFile.getAbsolutePath(), "UTF-8", cmdLine );
5549
5550 if ( !SystemUtils.IS_OS_WINDOWS )
5551 {
5552 Runtime.getRuntime().exec( new String[] { "chmod", "a+x", commandLineFile.getAbsolutePath() } );
5553 }
5554 }
5555 catch ( IOException e )
5556 {
5557 logError( "Unable to write '" + commandLineFile.getName() + "' debug script file", e );
5558 }
5559 }
5560
5561
5562
5563
5564
5565
5566
5567
5568
5569 private boolean isJavadocVMInitError( String output )
5570 {
5571
5572
5573
5574
5575 return !( output.contains( "Javadoc" ) || output.contains( "javadoc" ) );
5576 }
5577
5578
5579
5580
5581
5582
5583
5584
5585
5586
5587
5588 private static String getJavadocLink( MavenProject p )
5589 {
5590 if ( p.getUrl() == null )
5591 {
5592 return null;
5593 }
5594
5595 String url = cleanUrl( p.getUrl() );
5596 String destDir = "apidocs";
5597
5598 final String pluginId = "org.apache.maven.plugins:maven-javadoc-plugin";
5599 String destDirConfigured = getPluginParameter( p, pluginId, "destDir" );
5600 if ( destDirConfigured != null )
5601 {
5602 destDir = destDirConfigured;
5603 }
5604
5605 return url + "/" + destDir;
5606 }
5607
5608
5609
5610
5611
5612
5613 private static String cleanUrl( String url )
5614 {
5615 if ( url == null )
5616 {
5617 return "";
5618 }
5619
5620 url = url.trim();
5621 while ( url.endsWith( "/" ) )
5622 {
5623 url = url.substring( 0, url.lastIndexOf( "/" ) );
5624 }
5625
5626 return url;
5627 }
5628
5629
5630
5631
5632
5633
5634
5635
5636
5637 private static Plugin getPlugin( MavenProject p, String pluginId )
5638 {
5639 if ( ( p.getBuild() == null) || ( p.getBuild().getPluginsAsMap() == null ) )
5640 {
5641 return null;
5642 }
5643
5644 Plugin plugin = (Plugin) p.getBuild().getPluginsAsMap().get( pluginId );
5645
5646 if ( ( plugin == null ) && ( p.getBuild().getPluginManagement() != null )
5647 && ( p.getBuild().getPluginManagement().getPluginsAsMap() != null ) )
5648 {
5649 plugin = (Plugin) p.getBuild().getPluginManagement().getPluginsAsMap().get( pluginId );
5650 }
5651
5652 return plugin;
5653 }
5654
5655
5656
5657
5658
5659
5660
5661
5662
5663 private static String getPluginParameter( MavenProject p, String pluginId, String param )
5664 {
5665
5666 Plugin plugin = getPlugin( p, pluginId );
5667 if ( plugin != null )
5668 {
5669 Xpp3Dom xpp3Dom = (Xpp3Dom) plugin.getConfiguration();
5670 if ( xpp3Dom != null && xpp3Dom.getChild( param ) != null
5671 && StringUtils.isNotEmpty( xpp3Dom.getChild( param ).getValue() ) )
5672 {
5673 return xpp3Dom.getChild( param ).getValue();
5674 }
5675 }
5676
5677 return null;
5678 }
5679
5680
5681
5682
5683
5684
5685
5686 protected final File getJavadocOptionsFile()
5687 {
5688 if ( javadocOptionsDir != null && !javadocOptionsDir.exists() )
5689 {
5690 javadocOptionsDir.mkdirs();
5691 }
5692
5693 return new File( javadocOptionsDir, "javadoc-options-" + getAttachmentClassifier() + ".xml" );
5694 }
5695
5696
5697
5698
5699
5700
5701
5702
5703 protected final JavadocOptions buildJavadocOptions()
5704 throws IOException
5705 {
5706 JavadocOptions options = new JavadocOptions();
5707
5708 options.setBootclasspathArtifacts( toList( bootclasspathArtifacts ) );
5709 options.setDocfilesSubdirsUsed( docfilessubdirs );
5710 options.setDocletArtifacts( toList( docletArtifact, docletArtifacts ) );
5711 options.setExcludedDocfilesSubdirs( excludedocfilessubdir );
5712 options.setExcludePackageNames( toList( excludePackageNames ) );
5713 options.setGroups( toList( groups ) );
5714 options.setLinks( links );
5715 options.setOfflineLinks( toList( offlineLinks ) );
5716 options.setResourcesArtifacts( toList( resourcesArtifacts ) );
5717 options.setTagletArtifacts( toList( tagletArtifact, tagletArtifacts ) );
5718 options.setTaglets( toList( taglets ) );
5719 options.setTags( toList( tags ) );
5720
5721 if ( getProject() != null && getJavadocDirectory() != null )
5722 {
5723 options.setJavadocResourcesDirectory( toRelative( getProject().getBasedir(), getJavadocDirectory().getAbsolutePath() ) );
5724 }
5725
5726 File optionsFile = getJavadocOptionsFile();
5727 FileWriter writer = null;
5728 try
5729 {
5730 writer = new FileWriter( optionsFile );
5731 new JavadocOptionsXpp3Writer().write( writer, options );
5732 }
5733 finally
5734 {
5735 close( writer );
5736 }
5737
5738 return options;
5739 }
5740
5741
5742
5743
5744
5745 protected String getAttachmentClassifier()
5746 {
5747 return JAVADOC_RESOURCES_ATTACHMENT_CLASSIFIER;
5748 }
5749
5750
5751
5752
5753
5754
5755
5756 protected void logError( String message, Throwable t )
5757 {
5758 if ( getLog().isDebugEnabled() )
5759 {
5760 getLog().error( message, t );
5761 }
5762 else
5763 {
5764 getLog().error( message );
5765 }
5766 }
5767
5768 protected void failOnError( String prefix, Exception e )
5769 throws MojoExecutionException
5770 {
5771 if ( failOnError )
5772 {
5773 if ( e instanceof RuntimeException )
5774 {
5775 throw (RuntimeException) e;
5776 }
5777 throw new MojoExecutionException( prefix + ": " + e.getMessage(), e );
5778 }
5779
5780 getLog().error( prefix + ": " + e.getMessage(), e );
5781 }
5782 }