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