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