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
1665
1666
1667 protected boolean isAggregator() {
1668 return false;
1669 }
1670
1671
1672
1673
1674
1675
1676 protected boolean isTest() {
1677 return false;
1678 }
1679
1680
1681
1682
1683 protected String getOutputDirectory() {
1684 return outputDirectory.getAbsoluteFile().toString();
1685 }
1686
1687 protected MavenProject getProject() {
1688 return project;
1689 }
1690
1691
1692
1693
1694
1695
1696 protected List<File> getProjectBuildOutputDirs(MavenProject p) {
1697 if (StringUtils.isEmpty(p.getBuild().getOutputDirectory())) {
1698 return Collections.emptyList();
1699 }
1700
1701 return Collections.singletonList(new File(p.getBuild().getOutputDirectory()));
1702 }
1703
1704
1705
1706
1707
1708 protected File getClassesFile(MavenProject project) {
1709 if (!isAggregator() && isTest()) {
1710 return null;
1711 }
1712
1713 if (project.getArtifact() != null && project.getArtifact().getFile() != null) {
1714 File artifactFile = project.getArtifact().getFile();
1715 if (artifactFile.isDirectory() || artifactFile.getName().endsWith(".jar")) {
1716 return artifactFile;
1717 }
1718 } else if (project.getExecutionProject() != null
1719 && project.getExecutionProject().getArtifact() != null
1720 && project.getExecutionProject().getArtifact().getFile() != null) {
1721 File artifactFile = project.getExecutionProject().getArtifact().getFile();
1722 if (artifactFile.isDirectory() || artifactFile.getName().endsWith(".jar")) {
1723 return artifactFile;
1724 }
1725 }
1726
1727 if (project.getBuild().getOutputDirectory() != null) {
1728 return new File(project.getBuild().getOutputDirectory());
1729 } else {
1730 return null;
1731 }
1732 }
1733
1734
1735
1736
1737
1738 protected List<String> getProjectSourceRoots(MavenProject p) {
1739 if ("pom".equals(p.getPackaging().toLowerCase())) {
1740 return Collections.emptyList();
1741 }
1742
1743 return p.getCompileSourceRoots() == null
1744 ? Collections.<String>emptyList()
1745 : new LinkedList<>(p.getCompileSourceRoots());
1746 }
1747
1748
1749
1750
1751
1752 protected List<String> getExecutionProjectSourceRoots(MavenProject p) {
1753 if ("pom".equals(p.getExecutionProject().getPackaging().toLowerCase())) {
1754 return Collections.emptyList();
1755 }
1756
1757 return p.getExecutionProject().getCompileSourceRoots() == null
1758 ? Collections.<String>emptyList()
1759 : new LinkedList<>(p.getExecutionProject().getCompileSourceRoots());
1760 }
1761
1762
1763
1764
1765 protected File getJavadocDirectory() {
1766 return javadocDirectory;
1767 }
1768
1769
1770
1771
1772 protected String getDoclint() {
1773 return doclint;
1774 }
1775
1776
1777
1778
1779 protected String getDoctitle() {
1780 return doctitle;
1781 }
1782
1783
1784
1785
1786 protected File getOverview() {
1787 return overview;
1788 }
1789
1790
1791
1792
1793 protected String getWindowtitle() {
1794 return windowtitle;
1795 }
1796
1797
1798
1799
1800 private String getCharset() {
1801 return (charset == null || charset.isEmpty()) ? getDocencoding() : charset;
1802 }
1803
1804
1805
1806
1807 private String getDocencoding() {
1808 return (docencoding == null || docencoding.isEmpty()) ? ReaderFactory.UTF_8 : docencoding;
1809 }
1810
1811
1812
1813
1814 private String getEncoding() {
1815 return (encoding == null || encoding.isEmpty()) ? ReaderFactory.FILE_ENCODING : encoding;
1816 }
1817
1818 @Override
1819 public void execute() throws MojoExecutionException, MojoFailureException {
1820 verifyRemovedParameter("aggregator");
1821 verifyRemovedParameter("proxyHost");
1822 verifyRemovedParameter("proxyPort");
1823 verifyReplacedParameter("additionalparam", "additionalOptions");
1824
1825 doExecute();
1826 }
1827
1828 abstract void doExecute() throws MojoExecutionException, MojoFailureException;
1829
1830 protected final void verifyRemovedParameter(String paramName) {
1831 Xpp3Dom configDom = mojoExecution.getConfiguration();
1832 if (configDom != null) {
1833 if (configDom.getChild(paramName) != null) {
1834 throw new IllegalArgumentException(
1835 "parameter '" + paramName + "' has been removed from the plugin, please verify documentation.");
1836 }
1837 }
1838 }
1839
1840 private void verifyReplacedParameter(String oldParamName, String newParamNew) {
1841 Xpp3Dom configDom = mojoExecution.getConfiguration();
1842 if (configDom != null) {
1843 if (configDom.getChild(oldParamName) != null) {
1844 throw new IllegalArgumentException("parameter '" + oldParamName + "' has been replaced with "
1845 + newParamNew + ", please verify documentation.");
1846 }
1847 }
1848 }
1849
1850
1851
1852
1853
1854
1855
1856
1857 protected void executeReport(Locale unusedLocale) throws MavenReportException {
1858 if (skip) {
1859 getLog().info("Skipping javadoc generation");
1860 return;
1861 }
1862
1863 if (getLog().isDebugEnabled()) {
1864 this.debug = true;
1865 }
1866
1867
1868
1869 try {
1870 buildJavadocOptions();
1871 } catch (IOException e) {
1872 throw new MavenReportException("Failed to generate javadoc options file: " + e.getMessage(), e);
1873 }
1874
1875 Collection<JavadocModule> sourcePaths = getSourcePaths();
1876
1877 Collection<Path> collectedSourcePaths =
1878 sourcePaths.stream().flatMap(e -> e.getSourcePaths().stream()).collect(Collectors.toList());
1879
1880 Map<Path, Collection<String>> files = getFiles(collectedSourcePaths);
1881 if (!canGenerateReport(files)) {
1882 return;
1883 }
1884
1885
1886
1887
1888
1889 String jExecutable;
1890 try {
1891 jExecutable = getJavadocExecutable();
1892 } catch (IOException e) {
1893 throw new MavenReportException("Unable to find javadoc command: " + e.getMessage(), e);
1894 }
1895 setFJavadocVersion(new File(jExecutable));
1896
1897 Collection<String> packageNames;
1898 if (javadocRuntimeVersion.isAtLeast("9")) {
1899 packageNames = getPackageNamesRespectingJavaModules(sourcePaths);
1900 } else {
1901 packageNames = getPackageNames(files);
1902 }
1903
1904
1905
1906
1907
1908 File javadocOutputDirectory = new File(getOutputDirectory());
1909 if (javadocOutputDirectory.exists() && !javadocOutputDirectory.isDirectory()) {
1910 throw new MavenReportException("IOException: " + getOutputDirectory() + " is not a directory.");
1911 }
1912 if (javadocOutputDirectory.exists() && !javadocOutputDirectory.canWrite()) {
1913 throw new MavenReportException("IOException: " + getOutputDirectory() + " is not writable.");
1914 }
1915 javadocOutputDirectory.mkdirs();
1916
1917
1918
1919
1920
1921 copyAllResources(javadocOutputDirectory);
1922
1923
1924
1925
1926
1927 Commandline cmd = new Commandline();
1928 cmd.getShell().setQuotedArgumentsEnabled(false);
1929 cmd.setWorkingDirectory(javadocOutputDirectory.getAbsolutePath());
1930 cmd.setExecutable(jExecutable);
1931
1932
1933
1934
1935
1936 addMemoryArg(cmd, "-Xmx", this.maxmemory);
1937 addMemoryArg(cmd, "-Xms", this.minmemory);
1938 addProxyArg(cmd);
1939
1940 if (additionalJOption != null && !additionalJOption.isEmpty()) {
1941 cmd.createArg().setValue(additionalJOption);
1942 }
1943
1944 if (additionalJOptions != null && additionalJOptions.length != 0) {
1945 for (String jo : additionalJOptions) {
1946 cmd.createArg().setValue(jo);
1947 }
1948 }
1949
1950
1951
1952
1953 List<String> standardDocletArguments = new ArrayList<>();
1954
1955 Set<OfflineLink> offlineLinks;
1956 if ((doclet == null || doclet.isEmpty()) || useStandardDocletOptions) {
1957 offlineLinks = getLinkofflines();
1958 addStandardDocletOptions(javadocOutputDirectory, standardDocletArguments, offlineLinks);
1959 } else {
1960 offlineLinks = Collections.emptySet();
1961 }
1962
1963
1964
1965
1966 List<String> javadocArguments = new ArrayList<>();
1967
1968 addJavadocOptions(javadocOutputDirectory, javadocArguments, sourcePaths, offlineLinks);
1969
1970
1971
1972
1973
1974 List<String> arguments = new ArrayList<>(javadocArguments.size() + standardDocletArguments.size());
1975 arguments.addAll(javadocArguments);
1976 arguments.addAll(standardDocletArguments);
1977
1978 if (arguments.size() > 0) {
1979 addCommandLineOptions(cmd, arguments, javadocOutputDirectory);
1980 }
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990 boolean includesExcludesActive = (sourceFileIncludes != null && !sourceFileIncludes.isEmpty())
1991 || (sourceFileExcludes != null && !sourceFileExcludes.isEmpty());
1992 if (includesExcludesActive && !(subpackages == null || subpackages.isEmpty())) {
1993 getLog().warn("sourceFileIncludes and sourceFileExcludes have no effect when subpackages are specified!");
1994 includesExcludesActive = false;
1995 }
1996 if (!packageNames.isEmpty() && !includesExcludesActive) {
1997 addCommandLinePackages(cmd, javadocOutputDirectory, packageNames);
1998
1999
2000
2001
2002
2003 List<String> specialFiles = getSpecialFiles(files);
2004
2005 if (!specialFiles.isEmpty()) {
2006 addCommandLineArgFile(cmd, javadocOutputDirectory, specialFiles);
2007 }
2008 } else {
2009
2010
2011
2012
2013 List<String> allFiles = new ArrayList<>();
2014 for (Map.Entry<Path, Collection<String>> filesEntry : files.entrySet()) {
2015 for (String file : filesEntry.getValue()) {
2016 allFiles.add(filesEntry.getKey().resolve(file).toString());
2017 }
2018 }
2019
2020 if (!files.isEmpty()) {
2021 addCommandLineArgFile(cmd, javadocOutputDirectory, allFiles);
2022 }
2023 }
2024
2025
2026
2027
2028
2029 executeJavadocCommandLine(cmd, javadocOutputDirectory);
2030
2031
2032
2033
2034 if (!debug) {
2035 for (int i = 0; i < cmd.getArguments().length; i++) {
2036 String arg = cmd.getArguments()[i].trim();
2037
2038 if (!arg.startsWith("@")) {
2039 continue;
2040 }
2041
2042 File argFile = new File(javadocOutputDirectory, arg.substring(1));
2043 if (argFile.exists()) {
2044 argFile.delete();
2045 }
2046 }
2047
2048 File scriptFile = new File(javadocOutputDirectory, DEBUG_JAVADOC_SCRIPT_NAME);
2049 if (scriptFile.exists()) {
2050 scriptFile.delete();
2051 }
2052 }
2053 if (applyJavadocSecurityFix) {
2054
2055 try {
2056 final int patched = fixFrameInjectionBug(javadocOutputDirectory, getDocencoding());
2057 if (patched > 0) {
2058 getLog().info(String.format(
2059 "Fixed Javadoc frame injection vulnerability (CVE-2013-1571) in %d files.", patched));
2060 }
2061 } catch (IOException e) {
2062 throw new MavenReportException("Failed to patch javadocs vulnerability: " + e.getMessage(), e);
2063 }
2064 } else {
2065 getLog().info("applying javadoc security fix has been disabled");
2066 }
2067 }
2068
2069
2070
2071
2072
2073
2074
2075
2076 protected Map<Path, Collection<String>> getFiles(Collection<Path> sourcePaths) throws MavenReportException {
2077 Map<Path, Collection<String>> mappedFiles = new LinkedHashMap<>(sourcePaths.size());
2078 if (subpackages == null || subpackages.isEmpty()) {
2079 Collection<String> excludedPackages = getExcludedPackages();
2080
2081 final boolean autoExclude;
2082 if (release != null) {
2083 autoExclude = JavaVersion.parse(release).isBefore("9");
2084 } else if (source != null) {
2085 autoExclude = JavaVersion.parse(source).isBefore("9");
2086 } else {
2087
2088
2089 autoExclude = legacyMode;
2090 }
2091
2092 for (Path sourcePath : sourcePaths) {
2093 File sourceDirectory = sourcePath.toFile();
2094 List<String> files = new ArrayList<>(JavadocUtil.getFilesFromSource(
2095 sourceDirectory, sourceFileIncludes, sourceFileExcludes, excludedPackages));
2096
2097 if (autoExclude && files.remove("module-info.java")) {
2098 getLog().debug("Auto exclude module-info.java due to source value");
2099 }
2100 mappedFiles.put(sourcePath, files);
2101 }
2102 }
2103
2104 return mappedFiles;
2105 }
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115 protected Collection<JavadocModule> getSourcePaths() throws MavenReportException {
2116 Collection<JavadocModule> mappedSourcePaths = new ArrayList<>();
2117
2118 if (sourcepath == null || sourcepath.isEmpty()) {
2119 if (!"pom".equals(project.getPackaging())) {
2120 Set<Path> sourcePaths =
2121 new LinkedHashSet<>(JavadocUtil.pruneDirs(project, getProjectSourceRoots(project)));
2122
2123 if (project.getExecutionProject() != null) {
2124 sourcePaths.addAll(JavadocUtil.pruneDirs(project, getExecutionProjectSourceRoots(project)));
2125 }
2126
2127
2128
2129
2130
2131
2132 if (getJavadocDirectory() != null) {
2133 File javadocDir = getJavadocDirectory();
2134 if (javadocDir.exists() && javadocDir.isDirectory()) {
2135 Collection<Path> l = JavadocUtil.pruneDirs(
2136 project,
2137 Collections.singletonList(getJavadocDirectory().getAbsolutePath()));
2138 sourcePaths.addAll(l);
2139 }
2140 }
2141 if (!sourcePaths.isEmpty()) {
2142 mappedSourcePaths.add(buildJavadocModule(project, sourcePaths));
2143 }
2144 }
2145
2146 if (isAggregator()) {
2147 for (MavenProject subProject : getAggregatedProjects()) {
2148 if (subProject != project) {
2149 Collection<Path> additionalSourcePaths = new ArrayList<>();
2150
2151 List<String> sourceRoots = getProjectSourceRoots(subProject);
2152
2153 if (subProject.getExecutionProject() != null) {
2154 sourceRoots.addAll(getExecutionProjectSourceRoots(subProject));
2155 }
2156
2157 ArtifactHandler artifactHandler =
2158 subProject.getArtifact().getArtifactHandler();
2159 if ("java".equals(artifactHandler.getLanguage())) {
2160 additionalSourcePaths.addAll(JavadocUtil.pruneDirs(subProject, sourceRoots));
2161 }
2162
2163 if (getJavadocDirectory() != null) {
2164 String javadocDirRelative = PathUtils.toRelative(
2165 project.getBasedir(), getJavadocDirectory().getAbsolutePath());
2166 File javadocDir = new File(subProject.getBasedir(), javadocDirRelative);
2167 if (javadocDir.exists() && javadocDir.isDirectory()) {
2168 Collection<Path> l = JavadocUtil.pruneDirs(
2169 subProject, Collections.singletonList(javadocDir.getAbsolutePath()));
2170 additionalSourcePaths.addAll(l);
2171 }
2172 }
2173
2174 if (!additionalSourcePaths.isEmpty()) {
2175 mappedSourcePaths.add(buildJavadocModule(subProject, additionalSourcePaths));
2176 }
2177 }
2178 }
2179 }
2180
2181 if (includeDependencySources) {
2182 mappedSourcePaths.addAll(getDependencySourcePaths());
2183 }
2184 } else {
2185 Collection<Path> sourcePaths =
2186 JavadocUtil.pruneDirs(project, new ArrayList<>(Arrays.asList(JavadocUtil.splitPath(sourcepath))));
2187 if (getJavadocDirectory() != null) {
2188 Collection<Path> l = JavadocUtil.pruneDirs(
2189 project, Collections.singletonList(getJavadocDirectory().getAbsolutePath()));
2190 sourcePaths.addAll(l);
2191 }
2192
2193 if (!sourcePaths.isEmpty()) {
2194 mappedSourcePaths.add(new JavadocModule(
2195 ArtifactUtils.key(project.getGroupId(), project.getArtifactId(), project.getVersion()),
2196 getClassesFile(project),
2197 sourcePaths));
2198 }
2199 }
2200
2201 return mappedSourcePaths;
2202 }
2203
2204 private JavadocModule buildJavadocModule(MavenProject project, Collection<Path> sourcePaths) {
2205 File classessFile = getClassesFile(project);
2206 ResolvePathResult resolvePathResult = getResolvePathResult(classessFile);
2207 if (resolvePathResult == null) {
2208 return new JavadocModule(
2209 ArtifactUtils.key(project.getGroupId(), project.getArtifactId(), project.getVersion()),
2210 classessFile,
2211 sourcePaths);
2212 } else {
2213 return new JavadocModule(
2214 ArtifactUtils.key(project.getGroupId(), project.getArtifactId(), project.getVersion()),
2215 classessFile,
2216 sourcePaths,
2217 resolvePathResult.getModuleDescriptor(),
2218 resolvePathResult.getModuleNameSource());
2219 }
2220 }
2221
2222
2223
2224
2225
2226
2227
2228 private Set<MavenProject> modulesForAggregatedProject(
2229 MavenProject aggregatedProject, Map<Path, MavenProject> reactorProjectsMap) {
2230
2231
2232
2233
2234
2235 if (aggregatedProject.getModules().isEmpty()) {
2236 return Collections.singleton(aggregatedProject);
2237 }
2238
2239 Path basePath = aggregatedProject.getBasedir().toPath();
2240 List<Path> modulePaths = new LinkedList<>();
2241 for (String module : aggregatedProject.getModules()) {
2242 modulePaths.add(basePath.resolve(module).normalize());
2243 }
2244
2245 Set<MavenProject> aggregatedModules = new LinkedHashSet<>();
2246
2247 for (Path modulePath : modulePaths) {
2248 MavenProject module = reactorProjectsMap.remove(modulePath);
2249 if (module != null) {
2250 aggregatedModules.addAll(modulesForAggregatedProject(module, reactorProjectsMap));
2251 }
2252 }
2253
2254 return aggregatedModules;
2255 }
2256
2257
2258
2259
2260
2261
2262
2263 protected SourceResolverConfig configureDependencySourceResolution(final SourceResolverConfig config) {
2264 return config.withCompileSources();
2265 }
2266
2267
2268
2269
2270
2271
2272
2273 protected final Collection<JavadocModule> getDependencySourcePaths() throws MavenReportException {
2274 try {
2275 if (sourceDependencyCacheDir.exists()) {
2276 FileUtils.forceDelete(sourceDependencyCacheDir);
2277 sourceDependencyCacheDir.mkdirs();
2278 }
2279 } catch (IOException e) {
2280 throw new MavenReportException(
2281 "Failed to delete cache directory: " + sourceDependencyCacheDir + "\nReason: " + e.getMessage(), e);
2282 }
2283
2284 final SourceResolverConfig config = getDependencySourceResolverConfig();
2285
2286 try {
2287 return resourceResolver.resolveDependencySourcePaths(config);
2288 } catch (org.apache.maven.artifact.resolver.ArtifactResolutionException
2289 | org.apache.maven.artifact.resolver.ArtifactNotFoundException e) {
2290 throw new MavenReportException(
2291 "Failed to resolve one or more javadoc source/resource artifacts:\n\n" + e.getMessage(), e);
2292 }
2293 }
2294
2295
2296
2297
2298
2299
2300
2301 private TransformableFilter createDependencyArtifactFilter() {
2302 Set<Artifact> dependencyArtifacts = project.getDependencyArtifacts();
2303
2304 List<String> artifactPatterns = new ArrayList<>(dependencyArtifacts.size());
2305 for (Artifact artifact : dependencyArtifacts) {
2306 artifactPatterns.add(artifact.getGroupId() + ":" + artifact.getArtifactId());
2307 }
2308
2309 return new PatternInclusionsFilter(artifactPatterns);
2310 }
2311
2312
2313
2314
2315
2316
2317
2318 private SourceResolverConfig getDependencySourceResolverConfig() {
2319 final List<TransformableFilter> andFilters = new ArrayList<>();
2320
2321 final List<String> dependencyIncludes = dependencySourceIncludes;
2322 final List<String> dependencyExcludes = dependencySourceExcludes;
2323
2324 if (!includeTransitiveDependencySources || isNotEmpty(dependencyIncludes) || isNotEmpty(dependencyExcludes)) {
2325 if (!includeTransitiveDependencySources) {
2326 andFilters.add(createDependencyArtifactFilter());
2327 }
2328
2329 if (isNotEmpty(dependencyIncludes)) {
2330 andFilters.add(new PatternInclusionsFilter(dependencyIncludes));
2331 }
2332
2333 if (isNotEmpty(dependencyExcludes)) {
2334 andFilters.add(new PatternExclusionsFilter(dependencyExcludes));
2335 }
2336 }
2337
2338 return configureDependencySourceResolution(
2339 new SourceResolverConfig(project, getProjectBuildingRequest(project), sourceDependencyCacheDir)
2340 .withReactorProjects(this.reactorProjects))
2341 .withFilter(new AndFilter(andFilters));
2342 }
2343
2344 private ProjectBuildingRequest getProjectBuildingRequest(MavenProject currentProject) {
2345 return new DefaultProjectBuildingRequest(session.getProjectBuildingRequest())
2346 .setRemoteRepositories(currentProject.getRemoteArtifactRepositories());
2347 }
2348
2349
2350
2351
2352
2353
2354
2355
2356 protected boolean canGenerateReport(Map<Path, Collection<String>> files) {
2357 for (Collection<String> filesValues : files.values()) {
2358 if (!filesValues.isEmpty()) {
2359 return true;
2360 }
2361 }
2362
2363 return !(subpackages == null || subpackages.isEmpty());
2364 }
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378 private String getExcludedPackages(Collection<Path> sourcePaths) throws MavenReportException {
2379 List<String> excludedNames = null;
2380
2381 if ((sourcepath != null && !sourcepath.isEmpty()) && (subpackages != null && !subpackages.isEmpty())) {
2382 Collection<String> excludedPackages = getExcludedPackages();
2383
2384 excludedNames = JavadocUtil.getExcludedPackages(sourcePaths, excludedPackages);
2385 }
2386
2387 String excludeArg = "";
2388 if ((subpackages != null && !subpackages.isEmpty()) && excludedNames != null) {
2389
2390 excludeArg = StringUtils.join(excludedNames.iterator(), ":");
2391 }
2392
2393 return excludeArg;
2394 }
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404 private String getSourcePath(Collection<Path> sourcePaths) {
2405 String sourcePath = null;
2406
2407 if ((subpackages == null || subpackages.isEmpty()) || (sourcepath != null && !sourcepath.isEmpty())) {
2408 sourcePath = StringUtils.join(sourcePaths.iterator(), File.pathSeparator);
2409 }
2410
2411 return sourcePath;
2412 }
2413
2414
2415
2416
2417
2418
2419
2420
2421 private Collection<String> getExcludedPackages() throws MavenReportException {
2422 Set<String> excluded = new LinkedHashSet<>();
2423
2424 if (includeDependencySources) {
2425 try {
2426 resolveDependencyBundles();
2427 } catch (IOException e) {
2428 throw new MavenReportException(
2429 "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e);
2430 }
2431
2432 if (isNotEmpty(dependencyJavadocBundles)) {
2433 for (JavadocBundle bundle : dependencyJavadocBundles) {
2434 JavadocOptions options = bundle.getOptions();
2435 if (options != null && isNotEmpty(options.getExcludePackageNames())) {
2436 excluded.addAll(options.getExcludePackageNames());
2437 }
2438 }
2439 }
2440 }
2441
2442
2443 if (excludePackageNames != null && !excludePackageNames.isEmpty()) {
2444 List<String> packageNames = Arrays.asList(excludePackageNames.split("[,:;]"));
2445 excluded.addAll(trimValues(packageNames));
2446 }
2447
2448 return excluded;
2449 }
2450
2451 private static List<String> trimValues(List<String> items) {
2452 List<String> result = new ArrayList<>(items.size());
2453 for (String item : items) {
2454 String trimmed = item.trim();
2455 if (trimmed == null || trimmed.isEmpty()) {
2456 continue;
2457 }
2458 result.add(trimmed);
2459 }
2460 return result;
2461 }
2462
2463 private List<org.eclipse.aether.graph.Dependency> toResolverDependencies(List<Dependency> dependencies) {
2464 if (dependencies == null) {
2465 return null;
2466 }
2467 ArtifactTypeRegistry registry = RepositoryUtils.newArtifactTypeRegistry(artifactHandlerManager);
2468 return dependencies.stream()
2469 .map(d -> RepositoryUtils.toDependency(d, registry))
2470 .collect(Collectors.toList());
2471 }
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483 private Collection<File> getPathElements() throws MavenReportException {
2484 Set<File> classpathElements = new LinkedHashSet<>();
2485 Map<String, Artifact> compileArtifactMap = new LinkedHashMap<>();
2486
2487 if (isTest()) {
2488 classpathElements.addAll(getProjectBuildOutputDirs(project));
2489 }
2490
2491 populateCompileArtifactMap(compileArtifactMap, project.getArtifacts());
2492
2493 if (isAggregator()) {
2494 Collection<MavenProject> aggregatorProjects = getAggregatedProjects();
2495
2496 List<String> reactorArtifacts = new ArrayList<>();
2497 for (MavenProject p : aggregatorProjects) {
2498 reactorArtifacts.add(p.getGroupId() + ':' + p.getArtifactId());
2499 }
2500
2501 DependencyFilter dependencyFilter = new AndDependencyFilter(
2502 new PatternExclusionsDependencyFilter(reactorArtifacts), getDependencyScopeFilter());
2503
2504 for (MavenProject subProject : aggregatorProjects) {
2505 if (subProject != project) {
2506 File projectArtifactFile = getClassesFile(subProject);
2507 if (projectArtifactFile != null) {
2508 classpathElements.add(projectArtifactFile);
2509 } else {
2510 classpathElements.addAll(getProjectBuildOutputDirs(subProject));
2511 }
2512
2513 try {
2514 StringBuilder sb = new StringBuilder();
2515
2516 sb.append("Compiled artifacts for ");
2517 sb.append(subProject.getGroupId()).append(":");
2518 sb.append(subProject.getArtifactId()).append(":");
2519 sb.append(subProject.getVersion()).append('\n');
2520
2521 List<Dependency> managedDependencies = null;
2522 if (subProject.getDependencyManagement() != null) {
2523 managedDependencies =
2524 subProject.getDependencyManagement().getDependencies();
2525 }
2526
2527 CollectRequest collRequest = new CollectRequest(
2528 toResolverDependencies(subProject.getDependencies()),
2529 toResolverDependencies(managedDependencies),
2530 subProject.getRemoteProjectRepositories());
2531 DependencyRequest depRequest = new DependencyRequest(collRequest, dependencyFilter);
2532 for (ArtifactResult artifactResult : repoSystem
2533 .resolveDependencies(repoSession, depRequest)
2534 .getArtifactResults()) {
2535 List<Artifact> artifacts =
2536 Collections.singletonList(RepositoryUtils.toArtifact(artifactResult.getArtifact()));
2537 populateCompileArtifactMap(compileArtifactMap, artifacts);
2538
2539 sb.append(artifactResult.getArtifact().getFile()).append('\n');
2540 }
2541
2542 if (getLog().isDebugEnabled()) {
2543 getLog().debug(sb.toString());
2544 }
2545
2546 } catch (DependencyResolutionException e) {
2547 throw new MavenReportException(e.getMessage(), e);
2548 }
2549 }
2550 }
2551 }
2552
2553 for (Artifact a : compileArtifactMap.values()) {
2554 classpathElements.add(a.getFile());
2555 }
2556
2557 if (additionalDependencies != null) {
2558 for (Dependency dependency : additionalDependencies) {
2559 Artifact artifact = resolveDependency(dependency);
2560 getLog().debug("add additional artifact with path " + artifact.getFile());
2561 classpathElements.add(artifact.getFile());
2562 }
2563 }
2564
2565 return classpathElements;
2566 }
2567
2568 protected ScopeDependencyFilter getDependencyScopeFilter() {
2569 return new ScopeDependencyFilter(
2570 Arrays.asList(Artifact.SCOPE_COMPILE, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_SYSTEM), null);
2571 }
2572
2573
2574
2575
2576
2577
2578 public Artifact resolveDependency(Dependency dependency) throws MavenReportException {
2579 ArtifactTypeRegistry registry = RepositoryUtils.newArtifactTypeRegistry(artifactHandlerManager);
2580 ArtifactRequest req = new ArtifactRequest(
2581 RepositoryUtils.toDependency(dependency, registry).getArtifact(),
2582 project.getRemoteProjectRepositories(),
2583 null);
2584 try {
2585 ArtifactResult resolutionResult = repoSystem.resolveArtifact(repoSession, req);
2586 return RepositoryUtils.toArtifact(resolutionResult.getArtifact());
2587 } catch (ArtifactResolutionException e) {
2588 throw new MavenReportException("artifact resolver problem - " + e.getMessage(), e);
2589 }
2590 }
2591
2592
2593
2594 protected final Toolchain getToolchain() {
2595 Toolchain tc = null;
2596
2597 if (jdkToolchain != null) {
2598
2599 try {
2600 Method getToolchainsMethod = toolchainManager
2601 .getClass()
2602 .getMethod("getToolchains", MavenSession.class, String.class, Map.class);
2603
2604 @SuppressWarnings("unchecked")
2605 List<Toolchain> tcs =
2606 (List<Toolchain>) getToolchainsMethod.invoke(toolchainManager, session, "jdk", jdkToolchain);
2607
2608 if (tcs != null && tcs.size() > 0) {
2609 tc = tcs.get(0);
2610 }
2611 } catch (SecurityException | ReflectiveOperationException e) {
2612
2613 }
2614 }
2615
2616 if (tc == null) {
2617 tc = toolchainManager.getToolchainFromBuildContext("jdk", session);
2618 }
2619
2620 return tc;
2621 }
2622
2623
2624
2625
2626
2627
2628
2629
2630 private void populateCompileArtifactMap(Map<String, Artifact> compileArtifactMap, Collection<Artifact> artifactList)
2631 throws MavenReportException {
2632 if (artifactList == null) {
2633 return;
2634 }
2635
2636 for (Artifact newArtifact : artifactList) {
2637 File file = newArtifact.getFile();
2638
2639 if (file == null) {
2640 throw new MavenReportException(
2641 "Error in plugin descriptor - " + "dependency was not resolved for artifact: "
2642 + newArtifact.getGroupId() + ":" + newArtifact.getArtifactId() + ":"
2643 + newArtifact.getVersion());
2644 }
2645
2646 if (compileArtifactMap.get(newArtifact.getDependencyConflictId()) != null) {
2647 Artifact oldArtifact = compileArtifactMap.get(newArtifact.getDependencyConflictId());
2648
2649 ArtifactVersion oldVersion = new DefaultArtifactVersion(oldArtifact.getVersion());
2650 ArtifactVersion newVersion = new DefaultArtifactVersion(newArtifact.getVersion());
2651 if (newVersion.compareTo(oldVersion) > 0) {
2652 compileArtifactMap.put(newArtifact.getDependencyConflictId(), newArtifact);
2653 }
2654 } else {
2655 compileArtifactMap.put(newArtifact.getDependencyConflictId(), newArtifact);
2656 }
2657 }
2658 }
2659
2660
2661
2662
2663
2664
2665
2666 private String getBottomText() {
2667 final String inceptionYear = project.getInceptionYear();
2668
2669
2670 final LocalDate localDate = MavenArchiver.parseBuildOutputTimestamp(outputTimestamp)
2671 .map(instant -> instant.atZone(ZoneOffset.UTC).toLocalDate())
2672 .orElseGet(LocalDate::now);
2673
2674 final String currentYear = Integer.toString(localDate.getYear());
2675
2676 String theBottom = StringUtils.replace(this.bottom, "{currentYear}", currentYear);
2677
2678 if ((inceptionYear == null) || inceptionYear.equals(currentYear)) {
2679 theBottom = StringUtils.replace(theBottom, "{inceptionYear}–", "");
2680 } else {
2681 theBottom = StringUtils.replace(theBottom, "{inceptionYear}", inceptionYear);
2682 }
2683
2684 if (project.getOrganization() == null) {
2685 theBottom = StringUtils.replace(theBottom, " {organizationName}", "");
2686 } else {
2687 if (StringUtils.isNotEmpty(project.getOrganization().getName())) {
2688 if (StringUtils.isNotEmpty(project.getOrganization().getUrl())) {
2689 theBottom = StringUtils.replace(
2690 theBottom,
2691 "{organizationName}",
2692 "<a href=\"" + project.getOrganization().getUrl() + "\">"
2693 + project.getOrganization().getName() + "</a>");
2694 } else {
2695 theBottom = StringUtils.replace(
2696 theBottom,
2697 "{organizationName}",
2698 project.getOrganization().getName());
2699 }
2700 } else {
2701 theBottom = StringUtils.replace(theBottom, " {organizationName}", "");
2702 }
2703 }
2704
2705 return theBottom;
2706 }
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723 private Optional<File> getStylesheetFile(final File javadocOutputDirectory) {
2724 if (stylesheetfile == null || stylesheetfile.isEmpty()) {
2725 if ("java".equalsIgnoreCase(stylesheet)) {
2726
2727 return Optional.empty();
2728 }
2729
2730 getLog().warn("Parameter 'stylesheet' is no longer evaluated, rather use 'addStylesheets'"
2731 + " to customize the CSS!");
2732 return Optional.empty();
2733 }
2734
2735 if (new File(stylesheetfile).exists()) {
2736 return Optional.of(new File(stylesheetfile));
2737 }
2738
2739 return getResource(new File(javadocOutputDirectory, DEFAULT_CSS_NAME), stylesheetfile);
2740 }
2741
2742 private void addAddStyleSheets(List<String> arguments) throws MavenReportException {
2743 if (addStylesheets == null) {
2744 return;
2745 }
2746
2747 for (String addStylesheet : addStylesheets) {
2748 Optional<File> styleSheet = getAddStylesheet(getJavadocDirectory(), addStylesheet);
2749
2750 if (styleSheet.isPresent()) {
2751 addArgIfNotEmpty(
2752 arguments,
2753 "--add-stylesheet",
2754 JavadocUtil.quotedPathArgument(styleSheet.get().getAbsolutePath()),
2755 JavaVersion.parse("10"));
2756 }
2757 }
2758 }
2759
2760 private Optional<File> getAddStylesheet(final File javadocOutputDirectory, final String stylesheet)
2761 throws MavenReportException {
2762 if (stylesheet == null || stylesheet.isEmpty()) {
2763 return Optional.empty();
2764 }
2765
2766 File addstylesheetfile = new File(getJavadocDirectory(), stylesheet);
2767 if (addstylesheetfile.exists()) {
2768 Optional<File> stylesheetfile = getStylesheetFile(javadocOutputDirectory);
2769 if (stylesheetfile.isPresent()) {
2770 if (stylesheetfile.get().getName().equals(addstylesheetfile.getName())) {
2771 throw new MavenReportException("additional stylesheet must have a different name "
2772 + "than stylesheetfile: " + stylesheetfile.get().getName());
2773 }
2774 }
2775
2776 return Optional.of(addstylesheetfile);
2777 }
2778
2779 throw new MavenReportException(
2780 "additional stylesheet file does not exist: " + addstylesheetfile.getAbsolutePath());
2781 }
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795 private Optional<File> getHelpFile(final File javadocOutputDirectory) {
2796 if (helpfile == null || helpfile.isEmpty()) {
2797 return Optional.empty();
2798 }
2799
2800 if (new File(helpfile).exists()) {
2801 return Optional.of(new File(helpfile));
2802 }
2803
2804 return getResource(new File(javadocOutputDirectory, "help-doc.html"), helpfile);
2805 }
2806
2807
2808
2809
2810
2811
2812
2813
2814 private String getAccessLevel() {
2815 String accessLevel;
2816 if ("public".equalsIgnoreCase(show)
2817 || "protected".equalsIgnoreCase(show)
2818 || "package".equalsIgnoreCase(show)
2819 || "private".equalsIgnoreCase(show)) {
2820 accessLevel = "-" + show;
2821 } else {
2822 if (getLog().isErrorEnabled()) {
2823 getLog().error("Unrecognized access level to show '" + show + "'. Defaulting to protected.");
2824 }
2825 accessLevel = "-protected";
2826 }
2827
2828 return accessLevel;
2829 }
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839 private String getBootclassPath() throws MavenReportException {
2840 Set<BootclasspathArtifact> bootclasspathArtifacts = collectBootClasspathArtifacts();
2841
2842 List<String> bootclassPath = new ArrayList<>();
2843 for (BootclasspathArtifact aBootclasspathArtifact : bootclasspathArtifacts) {
2844 if ((StringUtils.isNotEmpty(aBootclasspathArtifact.getGroupId()))
2845 && (StringUtils.isNotEmpty(aBootclasspathArtifact.getArtifactId()))
2846 && (StringUtils.isNotEmpty(aBootclasspathArtifact.getVersion()))) {
2847 bootclassPath.addAll(getArtifactsAbsolutePath(aBootclasspathArtifact));
2848 }
2849 }
2850
2851 bootclassPath = JavadocUtil.pruneFiles(bootclassPath);
2852
2853 StringBuilder path = new StringBuilder();
2854 path.append(StringUtils.join(bootclassPath.iterator(), File.pathSeparator));
2855
2856 if (bootclasspath != null && !bootclasspath.isEmpty()) {
2857 path.append(JavadocUtil.unifyPathSeparator(bootclasspath));
2858 }
2859
2860 return path.toString();
2861 }
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875 private String getDocletPath() throws MavenReportException {
2876 Set<DocletArtifact> docletArtifacts = collectDocletArtifacts();
2877 List<String> pathParts = new ArrayList<>();
2878
2879 for (DocletArtifact docletArtifact : docletArtifacts) {
2880 if (!isDocletArtifactEmpty(docletArtifact)) {
2881 pathParts.addAll(getArtifactsAbsolutePath(docletArtifact));
2882 }
2883 }
2884
2885 if (!(docletPath == null || docletPath.isEmpty())) {
2886 pathParts.add(JavadocUtil.unifyPathSeparator(docletPath));
2887 }
2888
2889 String path = StringUtils.join(pathParts.iterator(), File.pathSeparator);
2890
2891 if ((path == null || path.isEmpty()) && getLog().isWarnEnabled()) {
2892 getLog().warn("No docletpath option was found. Please review <docletpath/> or <docletArtifact/>"
2893 + " or <doclets/>.");
2894 }
2895
2896 return path;
2897 }
2898
2899
2900
2901
2902
2903
2904
2905
2906 private boolean isDocletArtifactEmpty(DocletArtifact aDocletArtifact) {
2907 if (aDocletArtifact == null) {
2908 return true;
2909 }
2910
2911 return StringUtils.isEmpty(aDocletArtifact.getGroupId())
2912 && StringUtils.isEmpty(aDocletArtifact.getArtifactId())
2913 && StringUtils.isEmpty(aDocletArtifact.getVersion());
2914 }
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924 private String getTagletPath() throws MavenReportException {
2925 Set<TagletArtifact> tArtifacts = collectTagletArtifacts();
2926 Collection<String> pathParts = new ArrayList<>();
2927
2928 for (TagletArtifact tagletArtifact : tArtifacts) {
2929 if ((tagletArtifact != null)
2930 && (StringUtils.isNotEmpty(tagletArtifact.getGroupId()))
2931 && (StringUtils.isNotEmpty(tagletArtifact.getArtifactId()))
2932 && (StringUtils.isNotEmpty(tagletArtifact.getVersion()))) {
2933 pathParts.addAll(getArtifactsAbsolutePath(tagletArtifact));
2934 }
2935 }
2936
2937 Set<Taglet> taglets = collectTaglets();
2938 for (Taglet taglet : taglets) {
2939 if (taglet == null) {
2940 continue;
2941 }
2942
2943 if ((taglet.getTagletArtifact() != null)
2944 && (StringUtils.isNotEmpty(taglet.getTagletArtifact().getGroupId()))
2945 && (StringUtils.isNotEmpty(taglet.getTagletArtifact().getArtifactId()))
2946 && (StringUtils.isNotEmpty(taglet.getTagletArtifact().getVersion()))) {
2947 pathParts.addAll(JavadocUtil.pruneFiles(getArtifactsAbsolutePath(taglet.getTagletArtifact())));
2948 } else if (StringUtils.isNotEmpty(taglet.getTagletpath())) {
2949 for (Path dir : JavadocUtil.pruneDirs(project, Collections.singletonList(taglet.getTagletpath()))) {
2950 pathParts.add(dir.toString());
2951 }
2952 }
2953 }
2954
2955 StringBuilder path = new StringBuilder();
2956 path.append(StringUtils.join(pathParts.iterator(), File.pathSeparator));
2957
2958 if (tagletpath != null && !tagletpath.isEmpty()) {
2959 path.append(JavadocUtil.unifyPathSeparator(tagletpath));
2960 }
2961
2962 return path.toString();
2963 }
2964
2965 private Set<String> collectLinks() throws MavenReportException {
2966 Set<String> links = new LinkedHashSet<>();
2967
2968 if (includeDependencySources) {
2969 try {
2970 resolveDependencyBundles();
2971 } catch (IOException e) {
2972 throw new MavenReportException(
2973 "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e);
2974 }
2975
2976 if (isNotEmpty(dependencyJavadocBundles)) {
2977 for (JavadocBundle bundle : dependencyJavadocBundles) {
2978 JavadocOptions options = bundle.getOptions();
2979 if (options != null && isNotEmpty(options.getLinks())) {
2980 links.addAll(options.getLinks());
2981 }
2982 }
2983 }
2984 }
2985
2986 if (isNotEmpty(this.links)) {
2987 links.addAll(this.links);
2988 }
2989
2990 links.addAll(getDependenciesLinks());
2991
2992 return followLinks(links);
2993 }
2994
2995 private Set<Group> collectGroups() throws MavenReportException {
2996 Set<Group> groups = new LinkedHashSet<>();
2997
2998 if (includeDependencySources) {
2999 try {
3000 resolveDependencyBundles();
3001 } catch (IOException e) {
3002 throw new MavenReportException(
3003 "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e);
3004 }
3005
3006 if (isNotEmpty(dependencyJavadocBundles)) {
3007 for (JavadocBundle bundle : dependencyJavadocBundles) {
3008 JavadocOptions options = bundle.getOptions();
3009 if (options != null && isNotEmpty(options.getGroups())) {
3010 groups.addAll(options.getGroups());
3011 }
3012 }
3013 }
3014 }
3015
3016 if (this.groups != null && this.groups.length > 0) {
3017 groups.addAll(Arrays.asList(this.groups));
3018 }
3019
3020 return groups;
3021 }
3022
3023 private Set<ResourcesArtifact> collectResourcesArtifacts() throws MavenReportException {
3024 Set<ResourcesArtifact> result = new LinkedHashSet<>();
3025
3026 if (includeDependencySources) {
3027 try {
3028 resolveDependencyBundles();
3029 } catch (IOException e) {
3030 throw new MavenReportException(
3031 "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e);
3032 }
3033
3034 if (isNotEmpty(dependencyJavadocBundles)) {
3035 for (JavadocBundle bundle : dependencyJavadocBundles) {
3036 JavadocOptions options = bundle.getOptions();
3037 if (options != null && isNotEmpty(options.getResourcesArtifacts())) {
3038 result.addAll(options.getResourcesArtifacts());
3039 }
3040 }
3041 }
3042 }
3043
3044 if (this.resourcesArtifacts != null && this.resourcesArtifacts.length > 0) {
3045 result.addAll(Arrays.asList(this.resourcesArtifacts));
3046 }
3047
3048 return result;
3049 }
3050
3051 private Set<BootclasspathArtifact> collectBootClasspathArtifacts() throws MavenReportException {
3052 Set<BootclasspathArtifact> result = new LinkedHashSet<>();
3053
3054 if (includeDependencySources) {
3055 try {
3056 resolveDependencyBundles();
3057 } catch (IOException e) {
3058 throw new MavenReportException(
3059 "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e);
3060 }
3061
3062 if (isNotEmpty(dependencyJavadocBundles)) {
3063 for (JavadocBundle bundle : dependencyJavadocBundles) {
3064 JavadocOptions options = bundle.getOptions();
3065 if (options != null && isNotEmpty(options.getBootclasspathArtifacts())) {
3066 result.addAll(options.getBootclasspathArtifacts());
3067 }
3068 }
3069 }
3070 }
3071
3072 if (this.bootclasspathArtifacts != null && this.bootclasspathArtifacts.length > 0) {
3073 result.addAll(Arrays.asList(this.bootclasspathArtifacts));
3074 }
3075
3076 return result;
3077 }
3078
3079 private Set<OfflineLink> collectOfflineLinks() throws MavenReportException {
3080 Set<OfflineLink> result = new LinkedHashSet<>();
3081
3082 OfflineLink javaApiLink = getDefaultJavadocApiLink();
3083 if (javaApiLink != null) {
3084 result.add(javaApiLink);
3085 }
3086
3087 if (includeDependencySources) {
3088 try {
3089 resolveDependencyBundles();
3090 } catch (IOException e) {
3091 throw new MavenReportException(
3092 "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e);
3093 }
3094
3095 if (isNotEmpty(dependencyJavadocBundles)) {
3096 for (JavadocBundle bundle : dependencyJavadocBundles) {
3097 JavadocOptions options = bundle.getOptions();
3098 if (options != null && isNotEmpty(options.getOfflineLinks())) {
3099 result.addAll(options.getOfflineLinks());
3100 }
3101 }
3102 }
3103 }
3104
3105 if (this.offlineLinks != null && this.offlineLinks.length > 0) {
3106 result.addAll(Arrays.asList(this.offlineLinks));
3107 }
3108
3109 return result;
3110 }
3111
3112 private Set<Tag> collectTags() throws MavenReportException {
3113 Set<Tag> tags = new LinkedHashSet<>();
3114
3115 if (includeDependencySources) {
3116 try {
3117 resolveDependencyBundles();
3118 } catch (IOException e) {
3119 throw new MavenReportException(
3120 "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e);
3121 }
3122
3123 if (isNotEmpty(dependencyJavadocBundles)) {
3124 for (JavadocBundle bundle : dependencyJavadocBundles) {
3125 JavadocOptions options = bundle.getOptions();
3126 if (options != null && isNotEmpty(options.getTags())) {
3127 tags.addAll(options.getTags());
3128 }
3129 }
3130 }
3131 }
3132
3133 if (this.tags != null && this.tags.length > 0) {
3134 tags.addAll(Arrays.asList(this.tags));
3135 }
3136
3137 return tags;
3138 }
3139
3140 private Set<TagletArtifact> collectTagletArtifacts() throws MavenReportException {
3141 Set<TagletArtifact> tArtifacts = new LinkedHashSet<>();
3142
3143 if (includeDependencySources) {
3144 try {
3145 resolveDependencyBundles();
3146 } catch (IOException e) {
3147 throw new MavenReportException(
3148 "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e);
3149 }
3150
3151 if (isNotEmpty(dependencyJavadocBundles)) {
3152 for (JavadocBundle bundle : dependencyJavadocBundles) {
3153 JavadocOptions options = bundle.getOptions();
3154 if (options != null && isNotEmpty(options.getTagletArtifacts())) {
3155 tArtifacts.addAll(options.getTagletArtifacts());
3156 }
3157 }
3158 }
3159 }
3160
3161 if (tagletArtifact != null) {
3162 tArtifacts.add(tagletArtifact);
3163 }
3164
3165 if (tagletArtifacts != null && tagletArtifacts.length > 0) {
3166 tArtifacts.addAll(Arrays.asList(tagletArtifacts));
3167 }
3168
3169 return tArtifacts;
3170 }
3171
3172 private Set<DocletArtifact> collectDocletArtifacts() throws MavenReportException {
3173 Set<DocletArtifact> dArtifacts = new LinkedHashSet<>();
3174
3175 if (includeDependencySources) {
3176 try {
3177 resolveDependencyBundles();
3178 } catch (IOException e) {
3179 throw new MavenReportException(
3180 "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e);
3181 }
3182
3183 if (isNotEmpty(dependencyJavadocBundles)) {
3184 for (JavadocBundle bundle : dependencyJavadocBundles) {
3185 JavadocOptions options = bundle.getOptions();
3186 if (options != null && isNotEmpty(options.getDocletArtifacts())) {
3187 dArtifacts.addAll(options.getDocletArtifacts());
3188 }
3189 }
3190 }
3191 }
3192
3193 if (docletArtifact != null) {
3194 dArtifacts.add(docletArtifact);
3195 }
3196
3197 if (docletArtifacts != null && docletArtifacts.length > 0) {
3198 dArtifacts.addAll(Arrays.asList(docletArtifacts));
3199 }
3200
3201 return dArtifacts;
3202 }
3203
3204 private Set<Taglet> collectTaglets() throws MavenReportException {
3205 Set<Taglet> result = new LinkedHashSet<>();
3206
3207 if (includeDependencySources) {
3208 try {
3209 resolveDependencyBundles();
3210 } catch (IOException e) {
3211 throw new MavenReportException(
3212 "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e);
3213 }
3214
3215 if (isNotEmpty(dependencyJavadocBundles)) {
3216 for (JavadocBundle bundle : dependencyJavadocBundles) {
3217 JavadocOptions options = bundle.getOptions();
3218 if (options != null && isNotEmpty(options.getTaglets())) {
3219 result.addAll(options.getTaglets());
3220 }
3221 }
3222 }
3223 }
3224
3225 if (taglets != null && taglets.length > 0) {
3226 result.addAll(Arrays.asList(taglets));
3227 }
3228
3229 return result;
3230 }
3231
3232
3233
3234
3235
3236
3237
3238
3239 private List<String> getArtifactsAbsolutePath(JavadocPathArtifact javadocArtifact) throws MavenReportException {
3240 if ((StringUtils.isEmpty(javadocArtifact.getGroupId()))
3241 && (StringUtils.isEmpty(javadocArtifact.getArtifactId()))
3242 && (StringUtils.isEmpty(javadocArtifact.getVersion()))) {
3243 return Collections.emptyList();
3244 }
3245
3246 List<String> path = new ArrayList<>();
3247
3248 try {
3249 Artifact artifact = createAndResolveArtifact(javadocArtifact);
3250 path.add(artifact.getFile().getAbsolutePath());
3251
3252 DependencyFilter filter = new ScopeDependencyFilter(
3253 Arrays.asList(Artifact.SCOPE_COMPILE, Artifact.SCOPE_PROVIDED), Collections.emptySet());
3254 DependencyRequest req = new DependencyRequest(
3255 new CollectRequest(
3256 new org.eclipse.aether.graph.Dependency(RepositoryUtils.toArtifact(artifact), null),
3257 RepositoryUtils.toRepos(project.getRemoteArtifactRepositories())),
3258 filter);
3259 Iterable<ArtifactResult> deps =
3260 repoSystem.resolveDependencies(repoSession, req).getArtifactResults();
3261 for (ArtifactResult a : deps) {
3262 path.add(a.getArtifact().getFile().getAbsolutePath());
3263 }
3264
3265 return path;
3266 } catch (ArtifactResolutionException e) {
3267 throw new MavenReportException("Unable to resolve artifact:" + javadocArtifact, e);
3268 } catch (DependencyResolutionException e) {
3269 throw new MavenReportException("Unable to resolve dependencies for:" + javadocArtifact, e);
3270 }
3271 }
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281 private Artifact createAndResolveArtifact(JavadocPathArtifact javadocArtifact)
3282 throws org.eclipse.aether.resolution.ArtifactResolutionException {
3283 org.eclipse.aether.artifact.Artifact artifact = new DefaultArtifact(
3284 javadocArtifact.getGroupId(),
3285 javadocArtifact.getArtifactId(),
3286 javadocArtifact.getClassifier(),
3287 "jar",
3288 javadocArtifact.getVersion());
3289 ArtifactRequest req = new ArtifactRequest(artifact, project.getRemoteProjectRepositories(), null);
3290 return RepositoryUtils.toArtifact(
3291 repoSystem.resolveArtifact(repoSession, req).getArtifact());
3292 }
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302 private void addMemoryArg(Commandline cmd, String arg, String memory) {
3303 if (memory != null && !memory.isEmpty()) {
3304 try {
3305 cmd.createArg().setValue("-J" + arg + JavadocUtil.parseJavadocMemory(memory));
3306 } catch (IllegalArgumentException e) {
3307 if (getLog().isErrorEnabled()) {
3308 getLog().error("Malformed memory pattern for '" + arg + memory + "'. Ignore this option.");
3309 }
3310 }
3311 }
3312 }
3313
3314
3315
3316
3317
3318
3319 private void addProxyArg(Commandline cmd) {
3320 if (settings == null || settings.getProxies().isEmpty()) {
3321 return;
3322 }
3323
3324 Map<String, Proxy> activeProxies = new HashMap<>();
3325
3326 for (Proxy proxy : settings.getProxies()) {
3327 if (proxy.isActive()) {
3328 String protocol = proxy.getProtocol();
3329
3330 if (!activeProxies.containsKey(protocol)) {
3331 activeProxies.put(protocol, proxy);
3332 }
3333 }
3334 }
3335
3336 if (activeProxies.containsKey("https")) {
3337 Proxy httpsProxy = activeProxies.get("https");
3338 if (StringUtils.isNotEmpty(httpsProxy.getHost())) {
3339 cmd.createArg().setValue("-J-Dhttps.proxyHost=" + httpsProxy.getHost());
3340 cmd.createArg().setValue("-J-Dhttps.proxyPort=" + httpsProxy.getPort());
3341
3342 if (StringUtils.isNotEmpty(httpsProxy.getNonProxyHosts())
3343 && (!activeProxies.containsKey("http")
3344 || StringUtils.isEmpty(activeProxies.get("http").getNonProxyHosts()))) {
3345 cmd.createArg()
3346 .setValue("-J-Dhttp.nonProxyHosts=\""
3347 + httpsProxy.getNonProxyHosts().replace("|", "^|") + "\"");
3348 }
3349 }
3350 }
3351
3352 if (activeProxies.containsKey("http")) {
3353 Proxy httpProxy = activeProxies.get("http");
3354 if (StringUtils.isNotEmpty(httpProxy.getHost())) {
3355 cmd.createArg().setValue("-J-Dhttp.proxyHost=" + httpProxy.getHost());
3356 cmd.createArg().setValue("-J-Dhttp.proxyPort=" + httpProxy.getPort());
3357
3358 if (!activeProxies.containsKey("https")) {
3359 cmd.createArg().setValue("-J-Dhttps.proxyHost=" + httpProxy.getHost());
3360 cmd.createArg().setValue("-J-Dhttps.proxyPort=" + httpProxy.getPort());
3361 }
3362
3363 if (StringUtils.isNotEmpty(httpProxy.getNonProxyHosts())) {
3364 cmd.createArg()
3365 .setValue("-J-Dhttp.nonProxyHosts=\""
3366 + httpProxy.getNonProxyHosts().replace("|", "^|") + "\"");
3367 }
3368 }
3369 }
3370
3371
3372 }
3373
3374
3375
3376
3377
3378
3379
3380
3381 private String getJavadocExecutable() throws IOException {
3382 Toolchain tc = getToolchain();
3383
3384 if (tc != null) {
3385 getLog().info("Toolchain in maven-javadoc-plugin: " + tc);
3386 if (javadocExecutable != null) {
3387 getLog().warn("Toolchains are ignored, 'javadocExecutable' parameter is set to " + javadocExecutable);
3388 } else {
3389 javadocExecutable = tc.findTool("javadoc");
3390 }
3391 }
3392
3393 String javadocCommand = "javadoc" + (SystemUtils.IS_OS_WINDOWS ? ".exe" : "");
3394
3395 File javadocExe;
3396
3397
3398
3399
3400 if (javadocExecutable != null && !javadocExecutable.isEmpty()) {
3401 javadocExe = new File(javadocExecutable);
3402
3403 if (javadocExe.isDirectory()) {
3404 javadocExe = new File(javadocExe, javadocCommand);
3405 }
3406
3407 if (SystemUtils.IS_OS_WINDOWS && javadocExe.getName().indexOf('.') < 0) {
3408 javadocExe = new File(javadocExe.getPath() + ".exe");
3409 }
3410
3411 if (!javadocExe.isFile()) {
3412 throw new IOException("The javadoc executable '" + javadocExe
3413 + "' doesn't exist or is not a file. Verify the <javadocExecutable/> parameter.");
3414 }
3415
3416 return javadocExe.getAbsolutePath();
3417 }
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453 if (SystemUtils.IS_OS_AIX) {
3454 javadocExe =
3455 new File(SystemUtils.getJavaHome() + File.separator + ".." + File.separator + "sh", javadocCommand);
3456 }
3457
3458
3459 else if (SystemUtils.IS_OS_MAC_OSX && !JavaVersion.JAVA_SPECIFICATION_VERSION.isAtLeast("1.7"))
3460
3461 {
3462 javadocExe = new File(SystemUtils.getJavaHome() + File.separator + "bin", javadocCommand);
3463 } else if (isJavaVersionAtLeast(org.apache.commons.lang3.JavaVersion.JAVA_9)) {
3464 javadocExe = new File(SystemUtils.getJavaHome() + File.separator + "bin", javadocCommand);
3465 } else {
3466
3467 javadocExe = new File(
3468 SystemUtils.getJavaHome() + File.separator + ".." + File.separator + "bin", javadocCommand);
3469 }
3470
3471
3472
3473
3474 if (!javadocExe.exists() || !javadocExe.isFile()) {
3475 Properties env = CommandLineUtils.getSystemEnvVars();
3476 String javaHome = env.getProperty("JAVA_HOME");
3477 if (javaHome == null || javaHome.isEmpty()) {
3478 throw new IOException("The environment variable JAVA_HOME is not correctly set.");
3479 }
3480 if ((!new File(javaHome).getCanonicalFile().exists())
3481 || (new File(javaHome).getCanonicalFile().isFile())) {
3482 throw new IOException("The environment variable JAVA_HOME=" + javaHome
3483 + " doesn't exist or is not a valid directory.");
3484 }
3485
3486 javadocExe = new File(javaHome + File.separator + "bin", javadocCommand);
3487 }
3488
3489 if (!javadocExe.getCanonicalFile().exists()
3490 || !javadocExe.getCanonicalFile().isFile()) {
3491 throw new IOException("The javadoc executable '" + javadocExe
3492 + "' doesn't exist or is not a file. Verify the JAVA_HOME environment variable.");
3493 }
3494
3495 return javadocExe.getAbsolutePath();
3496 }
3497
3498
3499
3500
3501
3502
3503
3504
3505 private void setFJavadocVersion(File jExecutable) throws MavenReportException {
3506 JavaVersion jVersion;
3507 try {
3508 jVersion = JavadocUtil.getJavadocVersion(jExecutable);
3509 } catch (IOException | CommandLineException | IllegalArgumentException e) {
3510 if (getLog().isWarnEnabled()) {
3511 getLog().warn("Unable to find the javadoc version: " + e.getMessage());
3512 getLog().warn("Using the Java version instead of, i.e. " + JAVA_VERSION);
3513 }
3514 jVersion = JAVA_VERSION;
3515 }
3516
3517 if (javadocVersion != null && !javadocVersion.isEmpty()) {
3518 try {
3519 javadocRuntimeVersion = JavaVersion.parse(javadocVersion);
3520 } catch (NumberFormatException e) {
3521 throw new MavenReportException("Unable to parse javadoc version: " + e.getMessage(), e);
3522 }
3523
3524 if (javadocRuntimeVersion.compareTo(jVersion) != 0 && getLog().isWarnEnabled()) {
3525 getLog().warn("Are you sure about the <javadocVersion/> parameter? It seems to be " + jVersion);
3526 }
3527 } else {
3528 javadocRuntimeVersion = jVersion;
3529 }
3530 }
3531
3532
3533
3534
3535
3536
3537
3538
3539 private boolean isJavaDocVersionAtLeast(JavaVersion requiredVersion) {
3540 return JAVA_VERSION.compareTo(requiredVersion) >= 0;
3541 }
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551 private void addArgIf(List<String> arguments, boolean b, String value) {
3552 if (b) {
3553 arguments.add(value);
3554 }
3555 }
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568 private void addArgIf(List<String> arguments, boolean b, String value, JavaVersion requiredJavaVersion) {
3569 if (b) {
3570 if (isJavaDocVersionAtLeast(requiredJavaVersion)) {
3571 addArgIf(arguments, true, value);
3572 } else {
3573 if (getLog().isWarnEnabled()) {
3574 getLog().warn(value + " option is not supported on Java version < " + requiredJavaVersion
3575 + ". Ignore this option.");
3576 }
3577 }
3578 }
3579 }
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592 private void addArgIfNotEmpty(List<String> arguments, String key, String value) {
3593 addArgIfNotEmpty(arguments, key, value, false);
3594 }
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611 private void addArgIfNotEmpty(
3612 List<String> arguments,
3613 String key,
3614 String value,
3615 boolean repeatKey,
3616 boolean splitValue,
3617 JavaVersion requiredJavaVersion) {
3618 if (value != null && !value.isEmpty()) {
3619 if (isJavaDocVersionAtLeast(requiredJavaVersion)) {
3620 addArgIfNotEmpty(arguments, key, value, repeatKey, splitValue);
3621 } else {
3622 if (getLog().isWarnEnabled()) {
3623 getLog().warn(key + " option is not supported on Java version < " + requiredJavaVersion
3624 + ". Ignore this option.");
3625 }
3626 }
3627 }
3628 }
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642 private void addArgIfNotEmpty(
3643 List<String> arguments, String key, String value, boolean repeatKey, boolean splitValue) {
3644 if (value != null && !value.isEmpty()) {
3645 if (key != null && !key.isEmpty()) {
3646 arguments.add(key);
3647 }
3648
3649 if (splitValue) {
3650 StringTokenizer token = new StringTokenizer(value, ",");
3651 while (token.hasMoreTokens()) {
3652 String current = token.nextToken().trim();
3653
3654 if (current != null && !current.isEmpty()) {
3655 arguments.add(current);
3656
3657 if (token.hasMoreTokens() && repeatKey) {
3658 arguments.add(key);
3659 }
3660 }
3661 }
3662 } else {
3663 arguments.add(value);
3664 }
3665 }
3666 }
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679 private void addArgIfNotEmpty(List<String> arguments, String key, String value, boolean repeatKey) {
3680 addArgIfNotEmpty(arguments, key, value, repeatKey, true);
3681 }
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693 private void addArgIfNotEmpty(List<String> arguments, String key, String value, JavaVersion requiredJavaVersion) {
3694 addArgIfNotEmpty(arguments, key, value, requiredJavaVersion, false);
3695 }
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709 private void addArgIfNotEmpty(
3710 List<String> arguments, String key, String value, JavaVersion requiredJavaVersion, boolean repeatKey) {
3711 if (value != null && !value.isEmpty()) {
3712 if (isJavaDocVersionAtLeast(requiredJavaVersion)) {
3713 addArgIfNotEmpty(arguments, key, value, repeatKey);
3714 } else {
3715 if (getLog().isWarnEnabled()) {
3716 getLog().warn(key + " option is not supported on Java version < " + requiredJavaVersion);
3717 }
3718 }
3719 }
3720 }
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735 private void addLinkofflineArguments(List<String> arguments, Set<OfflineLink> offlineLinksList)
3736 throws MavenReportException {
3737 for (OfflineLink offlineLink : offlineLinksList) {
3738 String url = offlineLink.getUrl();
3739 if (url == null || url.isEmpty()) {
3740 continue;
3741 }
3742 url = cleanUrl(url);
3743
3744 String location = offlineLink.getLocation();
3745 if (location == null || location.isEmpty()) {
3746 continue;
3747 }
3748 if (isValidJavadocLink(location, false)) {
3749 addArgIfNotEmpty(
3750 arguments,
3751 "-linkoffline",
3752 JavadocUtil.quotedPathArgument(url) + " " + JavadocUtil.quotedPathArgument(location),
3753 true);
3754 }
3755 }
3756 }
3757
3758 private Set<OfflineLink> getLinkofflines() throws MavenReportException {
3759 Set<OfflineLink> offlineLinksList = collectOfflineLinks();
3760
3761 offlineLinksList.addAll(getModulesLinks());
3762
3763 return offlineLinksList;
3764 }
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785 private void addLinkArguments(List<String> arguments) throws MavenReportException {
3786 Set<String> links = collectLinks();
3787
3788 for (String link : links) {
3789 if (link == null || link.isEmpty()) {
3790 continue;
3791 }
3792
3793 if ((settings.isOffline() || offline) && !link.startsWith("file:")) {
3794 continue;
3795 }
3796
3797 while (link.endsWith("/")) {
3798 link = link.substring(0, link.lastIndexOf("/"));
3799 }
3800
3801 addArgIfNotEmpty(arguments, "-link", JavadocUtil.quotedPathArgument(link), true, false);
3802 }
3803 }
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814 private void copyAllResources(File javadocOutputDirectory) throws MavenReportException {
3815
3816
3817
3818
3819
3820 if (docfilessubdirs) {
3821
3822
3823
3824
3825 try {
3826 copyJavadocResources(javadocOutputDirectory);
3827 } catch (IOException e) {
3828 throw new MavenReportException("Unable to copy javadoc resources: " + e.getMessage(), e);
3829 }
3830 }
3831
3832
3833
3834
3835
3836 copyAdditionalJavadocResources(javadocOutputDirectory);
3837 }
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849 private void copyJavadocResources(File anOutputDirectory) throws IOException {
3850 if (anOutputDirectory == null || !anOutputDirectory.exists()) {
3851 throw new IOException("The outputDirectory " + anOutputDirectory + " doesn't exists.");
3852 }
3853
3854 if (includeDependencySources) {
3855 resolveDependencyBundles();
3856 if (isNotEmpty(dependencyJavadocBundles)) {
3857 for (JavadocBundle bundle : dependencyJavadocBundles) {
3858 File dir = bundle.getResourcesDirectory();
3859 JavadocOptions options = bundle.getOptions();
3860 if (dir != null && dir.isDirectory()) {
3861 JavadocUtil.copyJavadocResources(
3862 anOutputDirectory, dir, options == null ? null : options.getExcludedDocfilesSubdirs());
3863 }
3864 }
3865 }
3866 }
3867
3868 if (getJavadocDirectory() != null) {
3869 JavadocUtil.copyJavadocResources(anOutputDirectory, getJavadocDirectory(), excludedocfilessubdir);
3870 }
3871
3872 if (isAggregator()) {
3873 for (MavenProject subProject : getAggregatedProjects()) {
3874 if (subProject != project && getJavadocDirectory() != null) {
3875 String javadocDirRelative = PathUtils.toRelative(
3876 project.getBasedir(), getJavadocDirectory().getAbsolutePath());
3877 File javadocDir = new File(subProject.getBasedir(), javadocDirRelative);
3878 JavadocUtil.copyJavadocResources(anOutputDirectory, javadocDir, excludedocfilessubdir);
3879 }
3880 }
3881 }
3882 }
3883
3884 private synchronized void resolveDependencyBundles() throws IOException {
3885 if (dependencyJavadocBundles == null) {
3886 dependencyJavadocBundles =
3887 resourceResolver.resolveDependencyJavadocBundles(getDependencySourceResolverConfig());
3888 if (dependencyJavadocBundles == null) {
3889 dependencyJavadocBundles = new ArrayList<>();
3890 }
3891 }
3892 }
3893
3894
3895
3896
3897
3898
3899
3900
3901 private void copyAdditionalJavadocResources(File anOutputDirectory) throws MavenReportException {
3902 Set<ResourcesArtifact> resourcesArtifacts = collectResourcesArtifacts();
3903 if (isEmpty(resourcesArtifacts)) {
3904 return;
3905 }
3906
3907 UnArchiver unArchiver;
3908 try {
3909 unArchiver = archiverManager.getUnArchiver("jar");
3910 } catch (NoSuchArchiverException e) {
3911 throw new MavenReportException(
3912 "Unable to extract resources artifact. " + "No archiver for 'jar' available.", e);
3913 }
3914
3915 for (ResourcesArtifact item : resourcesArtifacts) {
3916 Artifact artifact;
3917 try {
3918 artifact = createAndResolveArtifact(item);
3919 } catch (ArtifactResolutionException e) {
3920 throw new MavenReportException("Unable to resolve artifact:" + item, e);
3921 }
3922
3923 unArchiver.setSourceFile(artifact.getFile());
3924 unArchiver.setDestDirectory(anOutputDirectory);
3925
3926 IncludeExcludeFileSelector[] selectors =
3927 new IncludeExcludeFileSelector[] {new IncludeExcludeFileSelector()};
3928 selectors[0].setExcludes(new String[] {"META-INF/**"});
3929 unArchiver.setFileSelectors(selectors);
3930
3931 getLog().info("Extracting contents of resources artifact: " + artifact.getArtifactId());
3932 try {
3933 unArchiver.extract();
3934 } catch (ArchiverException e) {
3935 throw new MavenReportException(
3936 "Extraction of resources failed. Artifact that failed was: " + artifact.getArtifactId(), e);
3937 }
3938 }
3939 }
3940
3941
3942
3943
3944
3945 private List<String> getPackageNames(Map<Path, Collection<String>> sourcePaths) {
3946 List<String> returnList = new ArrayList<>();
3947
3948 if (!(sourcepath == null || sourcepath.isEmpty())) {
3949 return returnList;
3950 }
3951
3952 for (Entry<Path, Collection<String>> currentPathEntry : sourcePaths.entrySet()) {
3953 for (String currentFile : currentPathEntry.getValue()) {
3954
3955
3956
3957
3958 if (currentFile.contains("doc-files")) {
3959 continue;
3960 }
3961
3962 int lastIndexOfSeparator = currentFile.lastIndexOf("/");
3963 if (lastIndexOfSeparator != -1) {
3964 String packagename =
3965 currentFile.substring(0, lastIndexOfSeparator).replace('/', '.');
3966
3967 if (!returnList.contains(packagename)) {
3968 returnList.add(packagename);
3969 }
3970 }
3971 }
3972 }
3973
3974 return returnList;
3975 }
3976
3977
3978
3979
3980
3981
3982
3983
3984 private Collection<String> getPackageNamesRespectingJavaModules(Collection<JavadocModule> javadocModules)
3985 throws MavenReportException {
3986 if (!(sourcepath == null || sourcepath.isEmpty())) {
3987 return Collections.emptyList();
3988 }
3989
3990 Set<String> returnList = new LinkedHashSet<>();
3991 for (JavadocModule javadocModule : javadocModules) {
3992 Collection<Path> artifactSourcePaths = javadocModule.getSourcePaths();
3993 Set<String> exportedPackages = new HashSet<>();
3994 boolean exportAllPackages;
3995 ResolvePathResult resolvedPath = getResolvePathResult(javadocModule.getArtifactFile());
3996 if (resolvedPath != null && resolvedPath.getModuleNameSource() == ModuleNameSource.MODULEDESCRIPTOR) {
3997 Set<JavaModuleDescriptor.JavaExports> exports =
3998 resolvedPath.getModuleDescriptor().exports();
3999 if (exports.isEmpty()) {
4000 continue;
4001 }
4002 for (JavaModuleDescriptor.JavaExports export : exports) {
4003 exportedPackages.add(export.source());
4004 }
4005 exportAllPackages = false;
4006 } else {
4007 exportAllPackages = true;
4008 }
4009
4010 for (Map.Entry<Path, Collection<String>> currentPathEntry :
4011 getFiles(artifactSourcePaths).entrySet()) {
4012 for (String currentFile : currentPathEntry.getValue()) {
4013
4014
4015
4016
4017 if (currentFile.contains("doc-files")) {
4018 continue;
4019 }
4020
4021 int lastIndexOfSeparator = currentFile.lastIndexOf('/');
4022 if (lastIndexOfSeparator != -1) {
4023 String packagename =
4024 currentFile.substring(0, lastIndexOfSeparator).replace('/', '.');
4025
4026 if (exportAllPackages || exportedPackages.contains(packagename)) {
4027 returnList.add(packagename);
4028 }
4029 }
4030 }
4031 }
4032 }
4033
4034 return returnList;
4035 }
4036
4037
4038
4039
4040
4041 private List<String> getFilesWithUnnamedPackages(Map<Path, Collection<String>> sourcePaths) {
4042 List<String> returnList = new ArrayList<>();
4043
4044 if (!(sourcepath == null || sourcepath.isEmpty())) {
4045 return returnList;
4046 }
4047
4048 for (Entry<Path, Collection<String>> currentPathEntry : sourcePaths.entrySet()) {
4049 Path currentSourcePath = currentPathEntry.getKey();
4050
4051 for (String currentFile : currentPathEntry.getValue()) {
4052
4053
4054
4055
4056 if (currentFile.contains("doc-files")) {
4057 continue;
4058 }
4059
4060 if (currentFile.indexOf('/') == -1) {
4061 returnList.add(currentSourcePath
4062 .resolve(currentFile)
4063 .toAbsolutePath()
4064 .toString());
4065 }
4066 }
4067 }
4068
4069 return returnList;
4070 }
4071
4072
4073
4074
4075
4076
4077 private List<String> getSpecialFiles(Map<Path, Collection<String>> sourcePaths) {
4078 if (!(sourcepath == null || sourcepath.isEmpty())) {
4079 return new ArrayList<>();
4080 }
4081
4082 boolean containsModuleDescriptor = false;
4083 for (Collection<String> sourcepathFiles : sourcePaths.values()) {
4084 containsModuleDescriptor = sourcepathFiles.contains("module-info.java");
4085 if (containsModuleDescriptor) {
4086 break;
4087 }
4088 }
4089
4090 if (containsModuleDescriptor) {
4091 return getModuleSourcePathFiles(sourcePaths);
4092 } else {
4093 return getFilesWithUnnamedPackages(sourcePaths);
4094 }
4095 }
4096
4097 private List<String> getModuleSourcePathFiles(Map<Path, Collection<String>> sourcePaths) {
4098 List<String> returnList = new ArrayList<>();
4099
4100 for (Entry<Path, Collection<String>> currentPathEntry : sourcePaths.entrySet()) {
4101 Path currentSourcePath = currentPathEntry.getKey();
4102 if (currentPathEntry.getValue().contains("module-info.java")) {
4103 returnList.add(currentSourcePath
4104 .resolve("module-info.java")
4105 .toAbsolutePath()
4106 .toString());
4107 } else {
4108 for (String currentFile : currentPathEntry.getValue()) {
4109
4110
4111
4112
4113 if (currentFile.contains("doc-files")) {
4114 continue;
4115 }
4116
4117 returnList.add(currentSourcePath
4118 .resolve(currentFile)
4119 .toAbsolutePath()
4120 .toString());
4121 }
4122 }
4123 }
4124 return returnList;
4125 }
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139 private void addCommandLineOptions(Commandline cmd, List<String> arguments, File javadocOutputDirectory)
4140 throws MavenReportException {
4141 File optionsFile = new File(javadocOutputDirectory, OPTIONS_FILE_NAME);
4142
4143 StringBuilder options = new StringBuilder();
4144 options.append(StringUtils.join(arguments.iterator(), SystemUtils.LINE_SEPARATOR));
4145
4146 Charset outputFileEncoding;
4147 if (JAVA_VERSION.isAtLeast("9") && JAVA_VERSION.isBefore("12")) {
4148 outputFileEncoding = StandardCharsets.UTF_8;
4149 } else {
4150 outputFileEncoding = Charset.defaultCharset();
4151 }
4152 try {
4153 Files.write(optionsFile.toPath(), Collections.singleton(options), outputFileEncoding);
4154 } catch (IOException e) {
4155 throw new MavenReportException(
4156 "Unable to write '" + optionsFile.getName() + "' temporary file for command execution", e);
4157 }
4158
4159 cmd.createArg().setValue("@" + OPTIONS_FILE_NAME);
4160 }
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180 private void addCommandLineArgFile(Commandline cmd, File javadocOutputDirectory, List<String> files)
4181 throws MavenReportException {
4182 File argfileFile;
4183 if (JAVA_VERSION.compareTo(SINCE_JAVADOC_1_4) >= 0) {
4184 argfileFile = new File(javadocOutputDirectory, ARGFILE_FILE_NAME);
4185 cmd.createArg().setValue("@" + ARGFILE_FILE_NAME);
4186 } else {
4187 argfileFile = new File(javadocOutputDirectory, FILES_FILE_NAME);
4188 cmd.createArg().setValue("@" + FILES_FILE_NAME);
4189 }
4190
4191 List<String> quotedFiles = new ArrayList<>(files.size());
4192 for (String file : files) {
4193 quotedFiles.add(JavadocUtil.quotedPathArgument(file));
4194 }
4195
4196 Charset cs;
4197 if (JavaVersion.JAVA_SPECIFICATION_VERSION.isAtLeast("9")
4198 && JavaVersion.JAVA_SPECIFICATION_VERSION.isBefore("12")) {
4199 cs = StandardCharsets.UTF_8;
4200 } else {
4201 cs = Charset.defaultCharset();
4202 }
4203
4204 try {
4205 Files.write(argfileFile.toPath(), quotedFiles, cs);
4206 } catch (IOException e) {
4207 throw new MavenReportException(
4208 "Unable to write '" + argfileFile.getName() + "' temporary file for command execution", e);
4209 }
4210 }
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224 private void addCommandLinePackages(Commandline cmd, File javadocOutputDirectory, Collection<String> packageNames)
4225 throws MavenReportException {
4226 File packagesFile = new File(javadocOutputDirectory, PACKAGES_FILE_NAME);
4227
4228 try {
4229 FileUtils.fileWrite(
4230 packagesFile.getAbsolutePath(),
4231 null ,
4232 StringUtils.join(packageNames.iterator(), SystemUtils.LINE_SEPARATOR));
4233 } catch (IOException e) {
4234 throw new MavenReportException(
4235 "Unable to write '" + packagesFile.getName() + "' temporary file for command execution", e);
4236 }
4237
4238 cmd.createArg().setValue("@" + PACKAGES_FILE_NAME);
4239 }
4240
4241
4242
4243
4244
4245
4246 private void validateJavadocOptions() throws MavenReportException {
4247
4248 if (StringUtils.isNotEmpty(getEncoding()) && !JavadocUtil.validateEncoding(getEncoding())) {
4249 throw new MavenReportException("Unsupported option <encoding/> '" + getEncoding() + "'");
4250 }
4251
4252
4253 if (this.locale != null && !this.locale.isEmpty()) {
4254 StringTokenizer tokenizer = new StringTokenizer(this.locale, "_");
4255 final int maxTokens = 3;
4256 if (tokenizer.countTokens() > maxTokens) {
4257 throw new MavenReportException(
4258 "Unsupported option <locale/> '" + this.locale + "', should be language_country_variant.");
4259 }
4260
4261 Locale localeObject = null;
4262 if (tokenizer.hasMoreTokens()) {
4263 String language = tokenizer.nextToken().toLowerCase(Locale.ENGLISH);
4264 if (!Arrays.asList(Locale.getISOLanguages()).contains(language)) {
4265 throw new MavenReportException(
4266 "Unsupported language '" + language + "' in option <locale/> '" + this.locale + "'");
4267 }
4268 localeObject = new Locale(language);
4269
4270 if (tokenizer.hasMoreTokens()) {
4271 String country = tokenizer.nextToken().toUpperCase(Locale.ENGLISH);
4272 if (!Arrays.asList(Locale.getISOCountries()).contains(country)) {
4273 throw new MavenReportException(
4274 "Unsupported country '" + country + "' in option <locale/> '" + this.locale + "'");
4275 }
4276 localeObject = new Locale(language, country);
4277
4278 if (tokenizer.hasMoreTokens()) {
4279 String variant = tokenizer.nextToken();
4280 localeObject = new Locale(language, country, variant);
4281 }
4282 }
4283 }
4284
4285 if (localeObject == null) {
4286 throw new MavenReportException(
4287 "Unsupported option <locale/> '" + this.locale + "', should be language_country_variant.");
4288 }
4289
4290 this.locale = localeObject.toString();
4291 final List<Locale> availableLocalesList = Arrays.asList(Locale.getAvailableLocales());
4292 if (StringUtils.isNotEmpty(localeObject.getVariant()) && !availableLocalesList.contains(localeObject)) {
4293 StringBuilder sb = new StringBuilder();
4294 sb.append("Unsupported option <locale/> with variant '").append(this.locale);
4295 sb.append("'");
4296
4297 localeObject = new Locale(localeObject.getLanguage(), localeObject.getCountry());
4298 this.locale = localeObject.toString();
4299
4300 sb.append(", trying to use <locale/> without variant, i.e. '")
4301 .append(this.locale)
4302 .append("'");
4303 if (getLog().isWarnEnabled()) {
4304 getLog().warn(sb.toString());
4305 }
4306 }
4307
4308 if (!availableLocalesList.contains(localeObject)) {
4309 throw new MavenReportException("Unsupported option <locale/> '" + this.locale + "'");
4310 }
4311 }
4312 }
4313
4314
4315
4316
4317
4318
4319
4320
4321 private void validateStandardDocletOptions() throws MavenReportException {
4322
4323 if (StringUtils.isNotEmpty(getDocencoding()) && !JavadocUtil.validateEncoding(getDocencoding())) {
4324 throw new MavenReportException("Unsupported option <docencoding/> '" + getDocencoding() + "'");
4325 }
4326
4327
4328 if (StringUtils.isNotEmpty(getCharset()) && !JavadocUtil.validateEncoding(getCharset())) {
4329 throw new MavenReportException("Unsupported option <charset/> '" + getCharset() + "'");
4330 }
4331
4332
4333 if ((helpfile != null && !helpfile.isEmpty()) && nohelp) {
4334 throw new MavenReportException("Option <nohelp/> conflicts with <helpfile/>");
4335 }
4336
4337
4338 if (getOverview() != null && getOverview().exists() && nooverview) {
4339 throw new MavenReportException("Option <nooverview/> conflicts with <overview/>");
4340 }
4341
4342
4343 if (splitindex && noindex) {
4344 throw new MavenReportException("Option <noindex/> conflicts with <splitindex/>");
4345 }
4346
4347
4348 if ((stylesheet != null && !stylesheet.isEmpty())
4349 && !(stylesheet.equalsIgnoreCase("maven") || stylesheet.equalsIgnoreCase("java"))) {
4350 throw new MavenReportException("Option <stylesheet/> supports only \"maven\" or \"java\" value.");
4351 }
4352 }
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366 private void addJavadocOptions(
4367 File javadocOutputDirectory,
4368 List<String> arguments,
4369 Collection<JavadocModule> allSourcePaths,
4370 Set<OfflineLink> offlineLinks)
4371 throws MavenReportException {
4372 Collection<Path> sourcePaths = allSourcePaths.stream()
4373 .flatMap(e -> e.getSourcePaths().stream())
4374 .collect(Collectors.toList());
4375
4376 validateJavadocOptions();
4377
4378
4379 addArgIfNotEmpty(arguments, "-locale", JavadocUtil.quotedArgument(this.locale));
4380
4381
4382
4383 if (old && isJavaDocVersionAtLeast(SINCE_JAVADOC_1_4)) {
4384 if (getLog().isWarnEnabled()) {
4385 getLog().warn("Javadoc 1.4+ doesn't support the -1.1 switch anymore. Ignore this option.");
4386 }
4387 } else {
4388 addArgIf(arguments, old, "-1.1");
4389 }
4390
4391 addArgIfNotEmpty(arguments, "-bootclasspath", JavadocUtil.quotedPathArgument(getBootclassPath()));
4392
4393 if (isJavaDocVersionAtLeast(SINCE_JAVADOC_1_5)) {
4394 addArgIf(arguments, breakiterator, "-breakiterator", SINCE_JAVADOC_1_5);
4395 }
4396
4397 List<MavenProject> aggregatedProjects = reactorProjects;
4398 Map<String, MavenProject> reactorKeys = new HashMap<>(aggregatedProjects.size());
4399 for (MavenProject reactorProject : aggregatedProjects) {
4400 reactorKeys.put(
4401 ArtifactUtils.key(
4402 reactorProject.getGroupId(), reactorProject.getArtifactId(), reactorProject.getVersion()),
4403 reactorProject);
4404 }
4405
4406 Map<String, JavaModuleDescriptor> allModuleDescriptors = new HashMap<>();
4407
4408
4409 boolean supportModulePath = !legacyMode;
4410
4411 if (supportModulePath) {
4412 supportModulePath &= javadocRuntimeVersion.isAtLeast("9");
4413 if (release != null) {
4414 supportModulePath &= JavaVersion.parse(release).isAtLeast("9");
4415 } else if (source != null) {
4416 supportModulePath &= JavaVersion.parse(source).isAtLeast("9");
4417 }
4418 }
4419
4420 if (supportModulePath) {
4421 for (JavadocModule entry : allSourcePaths) {
4422 if (entry.getModuleNameSource() == null || entry.getModuleNameSource() == ModuleNameSource.FILENAME) {
4423 Path moduleDescriptor = findMainDescriptor(entry.getSourcePaths());
4424
4425 if (moduleDescriptor != null) {
4426 try {
4427 allModuleDescriptors.put(
4428 entry.getGav(),
4429 locationManager
4430 .parseModuleDescriptor(moduleDescriptor)
4431 .getModuleDescriptor());
4432 } catch (IOException e) {
4433 throw new MavenReportException(e.getMessage(), e);
4434 }
4435 }
4436 } else {
4437 allModuleDescriptors.put(entry.getGav(), entry.getModuleDescriptor());
4438 }
4439 }
4440 }
4441
4442 Collection<String> additionalModules = new ArrayList<>();
4443
4444 ResolvePathResult mainResolvePathResult = null;
4445
4446 Map<String, Collection<Path>> patchModules = new HashMap<>();
4447
4448 Path moduleSourceDir = null;
4449 if (supportModulePath && !allModuleDescriptors.isEmpty()) {
4450 Collection<String> unnamedProjects = new ArrayList<>();
4451 for (JavadocModule javadocModule : allSourcePaths) {
4452 MavenProject aggregatedProject = reactorKeys.get(javadocModule.getGav());
4453 if (aggregatedProject != null && !"pom".equals(aggregatedProject.getPackaging())) {
4454 ResolvePathResult result = null;
4455
4456
4457 File artifactFile = getClassesFile(aggregatedProject);
4458 if (artifactFile != null) {
4459 ResolvePathRequest<File> request = ResolvePathRequest.ofFile(artifactFile);
4460 try {
4461 result = locationManager.resolvePath(request);
4462 } catch (RuntimeException e) {
4463
4464 if (!"java.lang.module.FindException"
4465 .equals(e.getClass().getName())) {
4466 throw e;
4467 }
4468 } catch (IOException e) {
4469 throw new MavenReportException(e.getMessage(), e);
4470 }
4471 } else {
4472 Path moduleDescriptor = findMainDescriptor(javadocModule.getSourcePaths());
4473
4474 if (moduleDescriptor != null) {
4475 try {
4476 result = locationManager.parseModuleDescriptor(moduleDescriptor);
4477 } catch (IOException e) {
4478 throw new MavenReportException(e.getMessage(), e);
4479 }
4480 }
4481 }
4482
4483 if (result != null && result.getModuleDescriptor() != null) {
4484 moduleSourceDir = javadocOutputDirectory.toPath().resolve("src");
4485 try {
4486 moduleSourceDir = Files.createDirectories(moduleSourceDir);
4487
4488 additionalModules.add(result.getModuleDescriptor().name());
4489
4490 patchModules.put(result.getModuleDescriptor().name(), javadocModule.getSourcePaths());
4491
4492 Path modulePath = moduleSourceDir.resolve(
4493 result.getModuleDescriptor().name());
4494 if (!Files.isDirectory(modulePath)) {
4495 Files.createDirectory(modulePath);
4496 }
4497 } catch (IOException e) {
4498 throw new MavenReportException(e.getMessage(), e);
4499 }
4500 } else {
4501 unnamedProjects.add(javadocModule.getGav());
4502 }
4503
4504 if (aggregatedProject.equals(getProject())) {
4505 mainResolvePathResult = result;
4506 }
4507 } else {
4508
4509 getLog().error("no reactor project: " + javadocModule.getGav());
4510 }
4511 }
4512
4513 if (!unnamedProjects.isEmpty()) {
4514 getLog().error("Creating an aggregated report for both named and unnamed modules is not possible.");
4515 getLog().error("Ensure that every module has a module descriptor or is a jar with a MANIFEST.MF "
4516 + "containing an Automatic-Module-Name.");
4517 getLog().error("Fix the following projects:");
4518 for (String unnamedProject : unnamedProjects) {
4519 getLog().error(" - " + unnamedProject);
4520 }
4521 throw new MavenReportException("Aggregator report contains named and unnamed modules");
4522 }
4523
4524 if (mainResolvePathResult != null
4525 && ModuleNameSource.MANIFEST.equals(mainResolvePathResult.getModuleNameSource())) {
4526 arguments.add("--add-modules");
4527 arguments.add("ALL-MODULE-PATH");
4528 }
4529 }
4530
4531
4532 boolean moduleDescriptorSource = false;
4533 for (Path sourcepath : sourcePaths) {
4534 if (Files.isRegularFile(sourcepath.resolve("module-info.java"))) {
4535 moduleDescriptorSource = true;
4536 break;
4537 }
4538 }
4539
4540 final ModuleNameSource mainModuleNameSource;
4541 if (mainResolvePathResult != null) {
4542 mainModuleNameSource = mainResolvePathResult.getModuleNameSource();
4543 } else {
4544 mainModuleNameSource = null;
4545 }
4546
4547 if (supportModulePath
4548 && (isAggregator()
4549 || ModuleNameSource.MODULEDESCRIPTOR.equals(mainModuleNameSource)
4550 || ModuleNameSource.MANIFEST.equals(mainModuleNameSource))) {
4551 List<File> pathElements = new ArrayList<>(getPathElements());
4552 File artifactFile = getClassesFile(project);
4553 if (artifactFile != null) {
4554 pathElements.add(0, artifactFile);
4555 }
4556
4557 ResolvePathsRequest<File> request = ResolvePathsRequest.ofFiles(pathElements);
4558
4559 String mainModuleName = null;
4560 if (mainResolvePathResult != null) {
4561 request.setModuleDescriptor(mainResolvePathResult.getModuleDescriptor());
4562 mainModuleName = mainResolvePathResult.getModuleDescriptor().name();
4563 }
4564
4565 request.setAdditionalModules(additionalModules);
4566 request.setIncludeStatic(isAggregator());
4567
4568 try {
4569 ResolvePathsResult<File> result = locationManager.resolvePaths(request);
4570
4571 Set<File> modulePathElements =
4572 new HashSet<>(result.getModulepathElements().keySet());
4573
4574 Collection<File> classPathElements =
4575 new ArrayList<>(result.getClasspathElements().size());
4576
4577 for (File file : result.getClasspathElements()) {
4578 if (file.isDirectory() && new File(file, "module-info.class").exists()) {
4579 modulePathElements.add(file);
4580 } else if (ModuleNameSource.MANIFEST.equals(mainModuleNameSource)) {
4581 ModuleNameSource depModuleNameSource = locationManager
4582 .resolvePath(ResolvePathRequest.ofFile(file))
4583 .getModuleNameSource();
4584 if (ModuleNameSource.MODULEDESCRIPTOR.equals(depModuleNameSource)) {
4585 modulePathElements.add(file);
4586 } else {
4587 patchModules.get(mainModuleName).add(file.toPath());
4588 }
4589 } else {
4590 classPathElements.add(file);
4591 }
4592 }
4593
4594
4595 for (Entry<File, Exception> pathExceptionEntry :
4596 result.getPathExceptions().entrySet()) {
4597 Exception exception = pathExceptionEntry.getValue();
4598
4599 if ("java.lang.module.FindException"
4600 .equals(exception.getClass().getName())) {
4601 File jarPath = pathExceptionEntry.getKey();
4602 classPathElements.add(jarPath);
4603 }
4604 }
4605
4606 String classpath = StringUtils.join(classPathElements.iterator(), File.pathSeparator);
4607 addArgIfNotEmpty(arguments, "--class-path", JavadocUtil.quotedPathArgument(classpath), false, false);
4608
4609 String modulepath = StringUtils.join(modulePathElements.iterator(), File.pathSeparator);
4610 addArgIfNotEmpty(arguments, "--module-path", JavadocUtil.quotedPathArgument(modulepath), false, false);
4611 } catch (IOException e) {
4612 throw new MavenReportException(e.getMessage(), e);
4613 }
4614 } else if (supportModulePath && moduleDescriptorSource && !isTest()) {
4615 String modulepath = StringUtils.join(getPathElements().iterator(), File.pathSeparator);
4616 addArgIfNotEmpty(arguments, "--module-path", JavadocUtil.quotedPathArgument(modulepath), false, false);
4617 } else {
4618 String classpath = StringUtils.join(getPathElements().iterator(), File.pathSeparator);
4619 addArgIfNotEmpty(arguments, "-classpath", JavadocUtil.quotedPathArgument(classpath), false, false);
4620 }
4621
4622 for (Entry<String, Collection<Path>> entry : patchModules.entrySet()) {
4623 if (!entry.getValue().isEmpty()) {
4624 addArgIfNotEmpty(
4625 arguments,
4626 "--patch-module",
4627 entry.getKey() + '=' + JavadocUtil.quotedPathArgument(getSourcePath(entry.getValue())),
4628 false,
4629 false);
4630 }
4631 }
4632
4633 if (doclet != null && !doclet.isEmpty()) {
4634 addArgIfNotEmpty(arguments, "-doclet", JavadocUtil.quotedArgument(doclet));
4635 addArgIfNotEmpty(arguments, "-docletpath", JavadocUtil.quotedPathArgument(getDocletPath()));
4636 }
4637
4638 if (encoding == null || encoding.isEmpty()) {
4639 getLog().warn("Source files encoding has not been set, using platform encoding "
4640 + ReaderFactory.FILE_ENCODING + ", i.e. build is platform dependent!");
4641 }
4642 addArgIfNotEmpty(arguments, "-encoding", JavadocUtil.quotedArgument(getEncoding()));
4643
4644 addArgIfNotEmpty(
4645 arguments, "-extdirs", JavadocUtil.quotedPathArgument(JavadocUtil.unifyPathSeparator(extdirs)));
4646
4647 if ((getOverview() != null) && (getOverview().exists())) {
4648 addArgIfNotEmpty(
4649 arguments,
4650 "-overview",
4651 JavadocUtil.quotedPathArgument(getOverview().getAbsolutePath()));
4652 }
4653
4654 arguments.add(getAccessLevel());
4655
4656 if (isJavaDocVersionAtLeast(SINCE_JAVADOC_1_5)) {
4657 addArgIf(arguments, quiet, "-quiet", SINCE_JAVADOC_1_5);
4658 }
4659
4660 if (release != null) {
4661 arguments.add("--release");
4662 arguments.add(release);
4663 } else {
4664 addArgIfNotEmpty(arguments, "-source", JavadocUtil.quotedArgument(source), SINCE_JAVADOC_1_4);
4665 }
4666
4667 if ((sourcepath == null || sourcepath.isEmpty()) && (subpackages != null && !subpackages.isEmpty())) {
4668 sourcepath = StringUtils.join(sourcePaths.iterator(), File.pathSeparator);
4669 }
4670
4671 if (moduleSourceDir == null) {
4672 addArgIfNotEmpty(
4673 arguments, "-sourcepath", JavadocUtil.quotedPathArgument(getSourcePath(sourcePaths)), false, false);
4674 } else if (mainResolvePathResult == null
4675 || ModuleNameSource.MODULEDESCRIPTOR.equals(mainResolvePathResult.getModuleNameSource())) {
4676 addArgIfNotEmpty(
4677 arguments, "--module-source-path", JavadocUtil.quotedPathArgument(moduleSourceDir.toString()));
4678 }
4679
4680 if ((sourcepath != null && !sourcepath.isEmpty()) && isJavaDocVersionAtLeast(SINCE_JAVADOC_1_5)) {
4681 addArgIfNotEmpty(arguments, "-subpackages", subpackages, SINCE_JAVADOC_1_5);
4682 }
4683
4684
4685 addArgIfNotEmpty(arguments, "-exclude", getExcludedPackages(sourcePaths), SINCE_JAVADOC_1_4);
4686
4687 addArgIf(arguments, verbose, "-verbose");
4688
4689 if (additionalOptions != null && additionalOptions.length > 0) {
4690 for (String additionalOption : additionalOptions) {
4691 arguments.add(additionalOption.replaceAll("(?<!\\\\)\\\\(?!\\\\|:)", "\\\\"));
4692 }
4693 }
4694 }
4695
4696 private ResolvePathResult getResolvePathResult(File artifactFile) {
4697 if (artifactFile == null) {
4698 return null;
4699 }
4700
4701 ResolvePathResult resolvePathResult = null;
4702 ResolvePathRequest<File> resolvePathRequest = ResolvePathRequest.ofFile(artifactFile);
4703 try {
4704 resolvePathResult = locationManager.resolvePath(resolvePathRequest);
4705
4706
4707 if (resolvePathResult.getModuleDescriptor() == null) {
4708 return null;
4709 }
4710 } catch (IOException | RuntimeException e) {
4711 if (getLog().isDebugEnabled()) {
4712 Throwable cause = e;
4713 while (cause.getCause() != null) {
4714 cause = cause.getCause();
4715 }
4716
4717 getLog().debug("resolve path for: " + artifactFile + " cause error: " + cause);
4718 }
4719 }
4720 return resolvePathResult;
4721 }
4722
4723 private Path findMainDescriptor(Collection<Path> roots) throws MavenReportException {
4724 for (Map.Entry<Path, Collection<String>> entry : getFiles(roots).entrySet()) {
4725 if (entry.getValue().contains("module-info.java")) {
4726 return entry.getKey().resolve("module-info.java");
4727 }
4728 }
4729 return null;
4730 }
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744 private void addStandardDocletOptions(
4745 File javadocOutputDirectory, List<String> arguments, Set<OfflineLink> offlineLinks)
4746 throws MavenReportException {
4747 validateStandardDocletOptions();
4748
4749
4750
4751 addArgIf(arguments, author, "-author");
4752
4753 addArgIfNotEmpty(arguments, "-bottom", JavadocUtil.quotedArgument(getBottomText()), false, false);
4754
4755 if (!isJavaDocVersionAtLeast(SINCE_JAVADOC_1_5)) {
4756 addArgIf(arguments, breakiterator, "-breakiterator", SINCE_JAVADOC_1_4);
4757 }
4758
4759 addArgIfNotEmpty(arguments, "-charset", JavadocUtil.quotedArgument(getCharset()));
4760
4761 addArgIfNotEmpty(arguments, "-d", JavadocUtil.quotedPathArgument(javadocOutputDirectory.toString()));
4762
4763 addArgIfNotEmpty(arguments, "-docencoding", JavadocUtil.quotedArgument(getDocencoding()));
4764
4765 addArgIf(arguments, docfilessubdirs, "-docfilessubdirs", SINCE_JAVADOC_1_4);
4766
4767 addArgIf(arguments, (doclint != null && !doclint.isEmpty()), "-Xdoclint:" + getDoclint(), SINCE_JAVADOC_1_8);
4768
4769 addArgIfNotEmpty(arguments, "-doctitle", JavadocUtil.quotedArgument(getDoctitle()), false, false);
4770
4771 if (docfilessubdirs) {
4772 addArgIfNotEmpty(
4773 arguments,
4774 "-excludedocfilessubdir",
4775 JavadocUtil.quotedPathArgument(excludedocfilessubdir),
4776 SINCE_JAVADOC_1_4);
4777 }
4778
4779 addArgIfNotEmpty(arguments, "-footer", JavadocUtil.quotedArgument(footer), false, false);
4780
4781 addGroups(arguments);
4782
4783 addArgIfNotEmpty(arguments, "-header", JavadocUtil.quotedArgument(header), false, false);
4784
4785 Optional<File> helpFile = getHelpFile(javadocOutputDirectory);
4786 if (helpFile.isPresent()) {
4787 addArgIfNotEmpty(
4788 arguments,
4789 "-helpfile",
4790 JavadocUtil.quotedPathArgument(helpFile.get().getAbsolutePath()));
4791 }
4792
4793 addArgIf(arguments, keywords, "-keywords", SINCE_JAVADOC_1_4_2);
4794
4795 addLinkArguments(arguments);
4796
4797 addLinkofflineArguments(arguments, offlineLinks);
4798
4799 addArgIf(arguments, linksource, "-linksource", SINCE_JAVADOC_1_4);
4800
4801 if (sourcetab > 0) {
4802 if (javadocRuntimeVersion == SINCE_JAVADOC_1_4_2) {
4803 addArgIfNotEmpty(arguments, "-linksourcetab", String.valueOf(sourcetab));
4804 }
4805 addArgIfNotEmpty(arguments, "-sourcetab", String.valueOf(sourcetab), SINCE_JAVADOC_1_5);
4806 }
4807
4808 addArgIf(arguments, nocomment, "-nocomment", SINCE_JAVADOC_1_4);
4809
4810 addArgIf(arguments, nodeprecated, "-nodeprecated");
4811
4812 addArgIf(arguments, nodeprecatedlist, "-nodeprecatedlist");
4813
4814 addArgIf(arguments, nohelp, "-nohelp");
4815
4816 addArgIf(arguments, noindex, "-noindex");
4817
4818 addArgIf(arguments, nonavbar, "-nonavbar");
4819
4820 addArgIf(arguments, nooverview, "-nooverview");
4821
4822 addArgIfNotEmpty(arguments, "-noqualifier", JavadocUtil.quotedArgument(noqualifier), SINCE_JAVADOC_1_4);
4823
4824 addArgIf(arguments, nosince, "-nosince");
4825
4826 if (!notimestamp
4827 && MavenArchiver.parseBuildOutputTimestamp(outputTimestamp).isPresent()) {
4828
4829 notimestamp = true;
4830 }
4831
4832 addArgIf(arguments, notimestamp, "-notimestamp", SINCE_JAVADOC_1_5);
4833
4834 addArgIf(arguments, notree, "-notree");
4835
4836 addArgIfNotEmpty(arguments, "-packagesheader", JavadocUtil.quotedArgument(packagesheader), SINCE_JAVADOC_1_4_2);
4837
4838 if (!isJavaDocVersionAtLeast(SINCE_JAVADOC_1_5))
4839 {
4840 addArgIf(arguments, quiet, "-quiet", SINCE_JAVADOC_1_4);
4841 }
4842
4843 addArgIf(arguments, serialwarn, "-serialwarn");
4844
4845 addArgIf(arguments, splitindex, "-splitindex");
4846
4847 Optional<File> stylesheetfile = getStylesheetFile(javadocOutputDirectory);
4848
4849 if (stylesheetfile.isPresent()) {
4850 addArgIfNotEmpty(
4851 arguments,
4852 "-stylesheetfile",
4853 JavadocUtil.quotedPathArgument(stylesheetfile.get().getAbsolutePath()));
4854 }
4855
4856 addAddStyleSheets(arguments);
4857
4858 if ((sourcepath != null && !sourcepath.isEmpty()) && !isJavaDocVersionAtLeast(SINCE_JAVADOC_1_5)) {
4859 addArgIfNotEmpty(arguments, "-subpackages", subpackages, SINCE_JAVADOC_1_4);
4860 }
4861
4862 addArgIfNotEmpty(arguments, "-taglet", JavadocUtil.quotedArgument(taglet), SINCE_JAVADOC_1_4);
4863 addTaglets(arguments);
4864 addTagletsFromTagletArtifacts(arguments);
4865 addArgIfNotEmpty(arguments, "-tagletpath", JavadocUtil.quotedPathArgument(getTagletPath()), SINCE_JAVADOC_1_4);
4866
4867 addTags(arguments);
4868
4869 addArgIfNotEmpty(arguments, "-top", JavadocUtil.quotedArgument(top), false, false, SINCE_JAVADOC_1_6);
4870
4871 addArgIf(arguments, use, "-use");
4872
4873 addArgIf(arguments, version, "-version");
4874
4875 addArgIfNotEmpty(arguments, "-windowtitle", JavadocUtil.quotedArgument(getWindowtitle()), false, false);
4876 }
4877
4878
4879
4880
4881
4882
4883
4884 private void addGroups(List<String> arguments) throws MavenReportException {
4885 Set<Group> groups = collectGroups();
4886 if (isEmpty(groups)) {
4887 return;
4888 }
4889
4890 for (Group group : groups) {
4891 if (group == null || StringUtils.isEmpty(group.getTitle()) || StringUtils.isEmpty(group.getPackages())) {
4892 if (getLog().isWarnEnabled()) {
4893 getLog().warn("A group option is empty. Ignore this option.");
4894 }
4895 } else {
4896 String groupTitle = StringUtils.replace(group.getTitle(), ",", ",");
4897 addArgIfNotEmpty(
4898 arguments,
4899 "-group",
4900 JavadocUtil.quotedArgument(groupTitle) + " " + JavadocUtil.quotedArgument(group.getPackages()),
4901 true);
4902 }
4903 }
4904 }
4905
4906
4907
4908
4909
4910
4911
4912 private void addTags(List<String> arguments) throws MavenReportException {
4913 final String lineSeparator;
4914 if (javadocRuntimeVersion.isBefore("9")) {
4915 lineSeparator = " ";
4916 } else {
4917 lineSeparator = " \\\\" + SystemUtils.LINE_SEPARATOR;
4918 }
4919
4920 for (Tag tag : collectTags()) {
4921 if (StringUtils.isEmpty(tag.getName())) {
4922 if (getLog().isWarnEnabled()) {
4923 getLog().warn("A tag name is empty. Ignore this option.");
4924 }
4925 } else {
4926 String value = "\"" + tag.getName();
4927 if (StringUtils.isNotEmpty(tag.getPlacement())) {
4928 value += ":" + tag.getPlacement().replaceAll("\\R", lineSeparator);
4929 if (StringUtils.isNotEmpty(tag.getHead())) {
4930 value += ":" + tag.getHead().replaceAll("\\R", lineSeparator);
4931 }
4932 }
4933 value += "\"";
4934 addArgIfNotEmpty(arguments, "-tag", value, SINCE_JAVADOC_1_4);
4935 }
4936 }
4937 }
4938
4939
4940
4941
4942
4943
4944 private void addTaglets(List<String> arguments) {
4945 if (taglets == null) {
4946 return;
4947 }
4948
4949 for (Taglet taglet1 : taglets) {
4950 if ((taglet1 == null) || (StringUtils.isEmpty(taglet1.getTagletClass()))) {
4951 if (getLog().isWarnEnabled()) {
4952 getLog().warn("A taglet option is empty. Ignore this option.");
4953 }
4954 } else {
4955 addArgIfNotEmpty(
4956 arguments, "-taglet", JavadocUtil.quotedArgument(taglet1.getTagletClass()), SINCE_JAVADOC_1_4);
4957 }
4958 }
4959 }
4960
4961
4962
4963
4964
4965
4966
4967
4968 private void addTagletsFromTagletArtifacts(List<String> arguments) throws MavenReportException {
4969 Set<TagletArtifact> tArtifacts = new LinkedHashSet<>();
4970 if (tagletArtifacts != null && tagletArtifacts.length > 0) {
4971 tArtifacts.addAll(Arrays.asList(tagletArtifacts));
4972 }
4973
4974 if (includeDependencySources) {
4975 try {
4976 resolveDependencyBundles();
4977 } catch (IOException e) {
4978 throw new MavenReportException(
4979 "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e);
4980 }
4981
4982 if (isNotEmpty(dependencyJavadocBundles)) {
4983 for (JavadocBundle bundle : dependencyJavadocBundles) {
4984 JavadocOptions options = bundle.getOptions();
4985 if (options != null && isNotEmpty(options.getTagletArtifacts())) {
4986 tArtifacts.addAll(options.getTagletArtifacts());
4987 }
4988 }
4989 }
4990 }
4991
4992 if (isEmpty(tArtifacts)) {
4993 return;
4994 }
4995
4996 List<String> tagletsPath = new ArrayList<>();
4997
4998 for (TagletArtifact aTagletArtifact : tArtifacts) {
4999 if ((StringUtils.isNotEmpty(aTagletArtifact.getGroupId()))
5000 && (StringUtils.isNotEmpty(aTagletArtifact.getArtifactId()))
5001 && (StringUtils.isNotEmpty(aTagletArtifact.getVersion()))) {
5002 Artifact artifact;
5003 try {
5004 artifact = createAndResolveArtifact(aTagletArtifact);
5005 } catch (ArtifactResolutionException e) {
5006 throw new MavenReportException("Unable to resolve artifact:" + aTagletArtifact, e);
5007 }
5008
5009 tagletsPath.add(artifact.getFile().getAbsolutePath());
5010 }
5011 }
5012
5013 tagletsPath = JavadocUtil.pruneFiles(tagletsPath);
5014
5015 for (String tagletJar : tagletsPath) {
5016 if (!tagletJar.toLowerCase(Locale.ENGLISH).endsWith(".jar")) {
5017 continue;
5018 }
5019
5020 List<String> tagletClasses;
5021 try {
5022 tagletClasses = JavadocUtil.getTagletClassNames(new File(tagletJar));
5023 } catch (IOException e) {
5024 if (getLog().isWarnEnabled()) {
5025 getLog().warn("Unable to auto-detect Taglet class names from '" + tagletJar
5026 + "'. Try to specify them with <taglets/>.");
5027 }
5028 if (getLog().isDebugEnabled()) {
5029 getLog().debug("IOException: " + e.getMessage(), e);
5030 }
5031 continue;
5032 } catch (ClassNotFoundException e) {
5033 if (getLog().isWarnEnabled()) {
5034 getLog().warn("Unable to auto-detect Taglet class names from '" + tagletJar
5035 + "'. Try to specify them with <taglets/>.");
5036 }
5037 if (getLog().isDebugEnabled()) {
5038 getLog().debug("ClassNotFoundException: " + e.getMessage(), e);
5039 }
5040 continue;
5041 } catch (NoClassDefFoundError e) {
5042 if (getLog().isWarnEnabled()) {
5043 getLog().warn("Unable to auto-detect Taglet class names from '" + tagletJar
5044 + "'. Try to specify them with <taglets/>.");
5045 }
5046 if (getLog().isDebugEnabled()) {
5047 getLog().debug("NoClassDefFoundError: " + e.getMessage(), e);
5048 }
5049 continue;
5050 }
5051
5052 if (tagletClasses != null && !tagletClasses.isEmpty()) {
5053 for (String tagletClass : tagletClasses) {
5054 addArgIfNotEmpty(arguments, "-taglet", JavadocUtil.quotedArgument(tagletClass), SINCE_JAVADOC_1_4);
5055 }
5056 }
5057 }
5058 }
5059
5060
5061
5062
5063
5064
5065
5066
5067 private void executeJavadocCommandLine(Commandline cmd, File javadocOutputDirectory) throws MavenReportException {
5068 if (staleDataPath != null) {
5069 if (!isUpToDate(cmd)) {
5070 doExecuteJavadocCommandLine(cmd, javadocOutputDirectory);
5071 StaleHelper.writeStaleData(cmd, staleDataPath.toPath());
5072 }
5073 } else {
5074 doExecuteJavadocCommandLine(cmd, javadocOutputDirectory);
5075 }
5076 }
5077
5078
5079
5080
5081
5082
5083
5084
5085 private boolean isUpToDate(Commandline cmd) throws MavenReportException {
5086 try {
5087 List<String> curdata = StaleHelper.getStaleData(cmd);
5088 Path cacheData = staleDataPath.toPath();
5089 List<String> prvdata;
5090 if (Files.isRegularFile(cacheData)) {
5091 prvdata = Files.lines(cacheData, StandardCharsets.UTF_8).collect(Collectors.toList());
5092 } else {
5093 prvdata = null;
5094 }
5095 if (curdata.equals(prvdata)) {
5096 getLog().info("Skipping javadoc generation, everything is up to date.");
5097 return true;
5098 } else {
5099 if (prvdata == null) {
5100 getLog().info("No previous run data found, generating javadoc.");
5101 } else {
5102 getLog().info("Configuration changed, re-generating javadoc.");
5103 if (getLog().isDebugEnabled()) {
5104 List<String> newStrings = new ArrayList<>(curdata);
5105 List<String> remStrings = new ArrayList<>(prvdata);
5106 newStrings.removeAll(prvdata);
5107 remStrings.removeAll(curdata);
5108 if (!remStrings.isEmpty()) {
5109 getLog().debug(" Removed: " + String.join(", ", remStrings));
5110 }
5111 if (!newStrings.isEmpty()) {
5112 getLog().debug(" Added: " + String.join(", ", newStrings));
5113 }
5114 }
5115 }
5116 }
5117 } catch (IOException e) {
5118 throw new MavenReportException("Error checking uptodate status", e);
5119 }
5120 return false;
5121 }
5122
5123
5124
5125
5126
5127
5128
5129
5130 private void doExecuteJavadocCommandLine(Commandline cmd, File javadocOutputDirectory) throws MavenReportException {
5131 if (getLog().isDebugEnabled()) {
5132
5133 getLog().debug(CommandLineUtils.toString(cmd.getCommandline()).replaceAll("'", ""));
5134 }
5135
5136 String cmdLine = null;
5137 if (debug) {
5138 cmdLine = CommandLineUtils.toString(cmd.getCommandline()).replaceAll("'", "");
5139
5140 writeDebugJavadocScript(cmdLine, javadocOutputDirectory);
5141 }
5142
5143 CommandLineUtils.StringStreamConsumer err = new JavadocUtil.JavadocOutputStreamConsumer();
5144 CommandLineUtils.StringStreamConsumer out = new JavadocUtil.JavadocOutputStreamConsumer();
5145 try {
5146 int exitCode = CommandLineUtils.executeCommandLine(cmd, out, err);
5147
5148 String output = StringUtils.isEmpty(out.getOutput())
5149 ? null
5150 : '\n' + out.getOutput().trim();
5151
5152 if (exitCode != 0) {
5153 if (cmdLine == null) {
5154 cmdLine = CommandLineUtils.toString(cmd.getCommandline()).replaceAll("'", "");
5155 }
5156 writeDebugJavadocScript(cmdLine, javadocOutputDirectory);
5157
5158 if ((output != null && !output.isEmpty())
5159 && StringUtils.isEmpty(err.getOutput())
5160 && isJavadocVMInitError(output)) {
5161 throw new MavenReportException(output + '\n' + '\n' + JavadocUtil.ERROR_INIT_VM + '\n'
5162 + "Or, try to reduce the Java heap size for the Javadoc goal using "
5163 + "-Dminmemory=<size> and -Dmaxmemory=<size>." + '\n' + '\n' + "Command line was: "
5164 + cmdLine
5165 + '\n' + '\n' + "Refer to the generated Javadoc files in '" + javadocOutputDirectory
5166 + "' dir.\n");
5167 }
5168
5169 if (output != null && !output.isEmpty()) {
5170 getLog().info(output);
5171 }
5172
5173 StringBuilder msg = new StringBuilder("\nExit code: ");
5174 msg.append(exitCode);
5175 if (StringUtils.isNotEmpty(err.getOutput())) {
5176
5177 List<String> nonInfoLines = new ArrayList<>();
5178 for (String str : err.getOutput().split("\\R")) {
5179 if (isInformationalOutput(str)) {
5180 getLog().debug(str);
5181 } else {
5182 nonInfoLines.add(str);
5183 }
5184 }
5185 if (!nonInfoLines.isEmpty()) {
5186 msg.append('\n');
5187 msg.append(String.join("\n", nonInfoLines));
5188 }
5189 }
5190 msg.append('\n');
5191 msg.append("Command line was: ").append(cmdLine).append('\n').append('\n');
5192
5193 msg.append("Refer to the generated Javadoc files in '")
5194 .append(javadocOutputDirectory)
5195 .append("' dir.\n");
5196
5197 throw new MavenReportException(msg.toString());
5198 }
5199
5200 if (output != null && !output.isEmpty()) {
5201 getLog().info(output);
5202 }
5203 } catch (CommandLineException e) {
5204 throw new MavenReportException("Unable to execute javadoc command: " + e.getMessage(), e);
5205 }
5206
5207
5208
5209
5210
5211 if (containsWarnings(err.getOutput())) {
5212 if (getLog().isWarnEnabled()) {
5213 getLog().warn("Javadoc Warnings");
5214
5215 StringTokenizer token = new StringTokenizer(err.getOutput(), "\n");
5216 while (token.hasMoreTokens()) {
5217 String current = token.nextToken().trim();
5218
5219
5220 if (isInformationalOutput(current)) {
5221 getLog().debug(current);
5222 } else {
5223 getLog().warn(current);
5224 }
5225 }
5226 }
5227
5228 if (failOnWarnings) {
5229 throw new MavenReportException("Project contains Javadoc Warnings");
5230 }
5231 }
5232 }
5233
5234 private boolean containsWarnings(String output) {
5235
5236 if (this.javadocRuntimeVersion.isBefore("17")) {
5237 return output != null && !output.isEmpty();
5238 } else {
5239 return Arrays.stream(output.split("\\R"))
5240 .reduce((first, second) -> second)
5241 .filter(line -> line.matches("\\d+ warnings?"))
5242 .isPresent();
5243 }
5244 }
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258 private boolean isInformationalOutput(String str) {
5259 return str == null
5260 || str.trim().isEmpty()
5261 || str.startsWith("Loading source files for package ")
5262 || str.startsWith("Loading source file ")
5263 || str.startsWith("Generating ")
5264 || str.startsWith("Constructing Javadoc information")
5265 || str.startsWith("Building index for ")
5266 || str.startsWith("Building tree for ")
5267 || str.startsWith("Standard Doclet version ");
5268 }
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279 private int fixFrameInjectionBug(File javadocOutputDirectory, String outputEncoding) throws IOException {
5280 final String fixData;
5281
5282 try (InputStream in = this.getClass().getResourceAsStream("frame-injection-fix.txt")) {
5283 if (in == null) {
5284 throw new FileNotFoundException("Missing resource 'frame-injection-fix.txt' in classpath.");
5285 }
5286 fixData = org.codehaus.plexus.util.StringUtils.unifyLineSeparators(IOUtil.toString(in, "US-ASCII"))
5287 .trim();
5288 }
5289
5290 final DirectoryScanner ds = new DirectoryScanner();
5291 ds.setBasedir(javadocOutputDirectory);
5292 ds.setCaseSensitive(false);
5293 ds.setIncludes(new String[] {"**/index.html", "**/index.htm", "**/toc.html", "**/toc.htm"});
5294 ds.addDefaultExcludes();
5295 ds.scan();
5296 int patched = 0;
5297 for (String f : ds.getIncludedFiles()) {
5298 final File file = new File(javadocOutputDirectory, f);
5299
5300
5301 final String fileContents = FileUtils.fileRead(file, outputEncoding);
5302
5303 if (!StringUtils.contains(fileContents, "function validURL(url) {")) {
5304
5305 final String patchedFileContents =
5306 StringUtils.replaceOnce(fileContents, "function loadFrames() {", fixData);
5307 if (!patchedFileContents.equals(fileContents)) {
5308 FileUtils.fileWrite(file, outputEncoding, patchedFileContents);
5309 patched++;
5310 }
5311 }
5312 }
5313 return patched;
5314 }
5315
5316
5317
5318
5319
5320
5321
5322
5323 private Optional<File> getResource(File outputFile, String inputResourceName) {
5324 if (inputResourceName.startsWith("/")) {
5325 inputResourceName = inputResourceName.replaceFirst("//*", "");
5326 }
5327
5328 List<String> classPath = new ArrayList<>();
5329 classPath.add(project.getBuild().getSourceDirectory());
5330
5331 URL resourceURL = getResource(classPath, inputResourceName);
5332 if (resourceURL != null) {
5333 getLog().debug(inputResourceName + " found in the main src directory of the project.");
5334 return Optional.of(FileUtils.toFile(resourceURL));
5335 }
5336
5337 classPath.clear();
5338 List<Resource> resources = project.getBuild().getResources();
5339 for (Resource resource : resources) {
5340 classPath.add(resource.getDirectory());
5341 }
5342 resourceURL = getResource(classPath, inputResourceName);
5343 if (resourceURL != null) {
5344 getLog().debug(inputResourceName + " found in the main resources directories of the project.");
5345 return Optional.of(FileUtils.toFile(resourceURL));
5346 }
5347
5348 if (javadocDirectory.exists()) {
5349 classPath.clear();
5350 classPath.add(javadocDirectory.getAbsolutePath());
5351 resourceURL = getResource(classPath, inputResourceName);
5352 if (resourceURL != null) {
5353 getLog().debug(inputResourceName + " found in the main javadoc directory of the project.");
5354 return Optional.of(FileUtils.toFile(resourceURL));
5355 }
5356 }
5357
5358 classPath.clear();
5359 final String pluginId = "org.apache.maven.plugins:maven-javadoc-plugin";
5360 Plugin javadocPlugin = getPlugin(project, pluginId);
5361 if (javadocPlugin != null && javadocPlugin.getDependencies() != null) {
5362 List<Dependency> dependencies = javadocPlugin.getDependencies();
5363 for (Dependency dependency : dependencies) {
5364 ResourcesArtifact resourceArtifact = new ResourcesArtifact();
5365 resourceArtifact.setGroupId(dependency.getGroupId());
5366 resourceArtifact.setArtifactId(dependency.getArtifactId());
5367 resourceArtifact.setVersion(dependency.getVersion());
5368 resourceArtifact.setClassifier(dependency.getClassifier());
5369 Artifact artifact = null;
5370 try {
5371 artifact = createAndResolveArtifact(resourceArtifact);
5372 } catch (Exception e) {
5373 logError("Unable to retrieve the dependency: " + dependency + ". Ignored.", e);
5374 }
5375
5376 if (artifact != null && artifact.getFile().exists()) {
5377 classPath.add(artifact.getFile().getAbsolutePath());
5378 }
5379 }
5380 resourceURL = getResource(classPath, inputResourceName);
5381 if (resourceURL != null) {
5382 getLog().debug(inputResourceName + " found in javadoc plugin dependencies.");
5383 try {
5384 JavadocUtil.copyResource(resourceURL, outputFile);
5385
5386 return Optional.of(outputFile);
5387 } catch (IOException e) {
5388 logError("IOException: " + e.getMessage(), e);
5389 }
5390 }
5391 }
5392
5393 getLog().warn("Unable to find the resource '" + inputResourceName + "'. Using default Javadoc resources.");
5394
5395 return Optional.empty();
5396 }
5397
5398
5399
5400
5401
5402
5403
5404
5405 private URL getResource(final List<String> classPath, final String resource) {
5406 List<URL> urls = new ArrayList<>(classPath.size());
5407 for (String filename : classPath) {
5408 try {
5409 urls.add(new File(filename).toURI().toURL());
5410 } catch (MalformedURLException e) {
5411 getLog().error("MalformedURLException: " + e.getMessage());
5412 }
5413 }
5414
5415 URLClassLoader javadocClassLoader = new URLClassLoader(urls.toArray(new URL[urls.size()]), null);
5416 try {
5417 return javadocClassLoader.getResource(resource);
5418 } finally {
5419 try {
5420 javadocClassLoader.close();
5421 } catch (IOException ex) {
5422
5423 }
5424 }
5425 }
5426
5427
5428
5429
5430
5431
5432 private String getFullJavadocGoal() {
5433 String javadocPluginVersion = null;
5434 String resource = "META-INF/maven/org.apache.maven.plugins/maven-javadoc-plugin/pom.properties";
5435 try (InputStream resourceAsStream =
5436 AbstractJavadocMojo.class.getClassLoader().getResourceAsStream(resource)) {
5437 if (resourceAsStream != null) {
5438 Properties properties = new Properties();
5439 properties.load(resourceAsStream);
5440 if (StringUtils.isNotEmpty(properties.getProperty("version"))) {
5441 javadocPluginVersion = properties.getProperty("version");
5442 }
5443 }
5444 } catch (IOException e) {
5445
5446 }
5447
5448 StringBuilder sb = new StringBuilder();
5449
5450 sb.append("org.apache.maven.plugins:maven-javadoc-plugin:");
5451 if (javadocPluginVersion != null && !javadocPluginVersion.isEmpty()) {
5452 sb.append(javadocPluginVersion).append(":");
5453 }
5454
5455 if (this instanceof TestJavadocReport) {
5456 sb.append("test-javadoc");
5457 } else {
5458 sb.append("javadoc");
5459 }
5460
5461 return sb.toString();
5462 }
5463
5464
5465
5466
5467
5468
5469
5470
5471
5472
5473
5474 private List<OfflineLink> getModulesLinks() throws MavenReportException {
5475 List<MavenProject> aggregatedProjects = reactorProjects;
5476 if (!detectOfflineLinks || isAggregator() || aggregatedProjects.isEmpty()) {
5477 return Collections.emptyList();
5478 }
5479
5480 getLog().debug("Trying to add links for modules...");
5481
5482 Set<String> dependencyArtifactIds = new HashSet<>();
5483 final Set<Artifact> dependencyArtifacts = project.getDependencyArtifacts();
5484 for (Artifact artifact : dependencyArtifacts) {
5485 dependencyArtifactIds.add(artifact.getId());
5486 }
5487
5488 List<OfflineLink> modulesLinks = new ArrayList<>();
5489 String javadocDirRelative = PathUtils.toRelative(project.getBasedir(), getOutputDirectory());
5490 for (MavenProject p : aggregatedProjects) {
5491 if (!dependencyArtifactIds.contains(p.getArtifact().getId()) || (p.getUrl() == null)) {
5492 continue;
5493 }
5494
5495 File location = new File(p.getBasedir(), javadocDirRelative);
5496
5497 if (!location.exists()) {
5498 if (getLog().isDebugEnabled()) {
5499 getLog().debug("Javadoc directory not found: " + location);
5500 }
5501
5502 String javadocGoal = getFullJavadocGoal();
5503 getLog().info("The goal '" + javadocGoal + "' has not been previously called for the module: '"
5504 + p.getId() + "'. Trying to invoke it...");
5505
5506 File invokerDir = new File(project.getBuild().getDirectory(), "invoker");
5507 invokerDir.mkdirs();
5508 File invokerLogFile = FileUtils.createTempFile("maven-javadoc-plugin", ".txt", invokerDir);
5509 try {
5510 JavadocUtil.invokeMaven(
5511 getLog(),
5512 session.getRepositorySession().getLocalRepository().getBasedir(),
5513 p.getFile(),
5514 Collections.singletonList(javadocGoal),
5515 null,
5516 invokerLogFile,
5517 session.getRequest().getGlobalSettingsFile());
5518 } catch (MavenInvocationException e) {
5519 logError("MavenInvocationException: " + e.getMessage(), e);
5520
5521 String invokerLogContent = JavadocUtil.readFile(invokerLogFile, null );
5522
5523
5524
5525
5526 if (invokerLogContent != null && invokerLogContent.contains(JavadocUtil.ERROR_INIT_VM)) {
5527 throw new MavenReportException(e.getMessage(), e);
5528 }
5529 } finally {
5530
5531 if (!location.exists()) {
5532 getLog().warn("Creating fake javadoc directory to prevent repeated invocations: " + location);
5533 location.mkdirs();
5534 }
5535 }
5536 }
5537
5538 if (location.exists()) {
5539 String url = getJavadocLink(p);
5540
5541 OfflineLink ol = new OfflineLink();
5542 ol.setUrl(url);
5543 ol.setLocation(location.getAbsolutePath());
5544
5545 if (getLog().isDebugEnabled()) {
5546 getLog().debug("Added Javadoc offline link: " + url + " for the module: " + p.getId());
5547 }
5548
5549 modulesLinks.add(ol);
5550 }
5551 }
5552
5553 return modulesLinks;
5554 }
5555
5556
5557
5558
5559
5560
5561
5562
5563
5564
5565 private List<String> getDependenciesLinks() {
5566 if (!detectLinks) {
5567 return Collections.emptyList();
5568 }
5569
5570 getLog().debug("Trying to add links for dependencies...");
5571
5572 List<String> dependenciesLinks = new ArrayList<>();
5573
5574 final Set<Artifact> dependencies = project.getDependencyArtifacts();
5575 for (Artifact artifact : dependencies) {
5576 if (artifact.getFile() == null || !artifact.getFile().exists()) {
5577 continue;
5578 }
5579
5580 Optional<DependencyLink> depLink = this.dependencyLinks.stream()
5581 .filter(d -> matches(d, artifact))
5582 .findAny();
5583
5584 final String url;
5585 final boolean detected;
5586 if (depLink.isPresent()) {
5587 url = depLink.get().getUrl();
5588 detected = false;
5589 } else {
5590 try {
5591 MavenProject artifactProject = mavenProjectBuilder
5592 .build(artifact, getProjectBuildingRequest(project))
5593 .getProject();
5594
5595 url = getJavadocLink(artifactProject);
5596 detected = true;
5597 } catch (ProjectBuildingException e) {
5598 logError("ProjectBuildingException for " + artifact.toString() + ": " + e.getMessage(), e);
5599 continue;
5600 }
5601 }
5602
5603 if (url != null && isValidJavadocLink(url, detected)) {
5604 getLog().debug("Added Javadoc link: " + url + " for " + artifact.getId());
5605
5606 dependenciesLinks.add(url);
5607 }
5608 }
5609
5610 return dependenciesLinks;
5611 }
5612
5613 private boolean matches(DependencyLink d, Artifact artifact) {
5614 if (d.getGroupId() != null && !d.getGroupId().equals(artifact.getGroupId())) {
5615 return false;
5616 }
5617 if (d.getArtifactId() != null && !d.getArtifactId().equals(artifact.getArtifactId())) {
5618 return false;
5619 }
5620 if (d.getClassifier() != null && !d.getClassifier().equals(artifact.getClassifier())) {
5621 return false;
5622 }
5623 return true;
5624 }
5625
5626
5627
5628
5629
5630
5631
5632
5633
5634
5635 protected final OfflineLink getDefaultJavadocApiLink() {
5636 if (!detectJavaApiLink) {
5637 return null;
5638 }
5639
5640 final JavaVersion javaApiversion;
5641 if (release != null) {
5642 javaApiversion = JavaVersion.parse(release);
5643 } else if (source != null && !source.isEmpty()) {
5644 javaApiversion = JavaVersion.parse(source);
5645 } else {
5646 final String pluginId = "org.apache.maven.plugins:maven-compiler-plugin";
5647 String sourceConfigured = getPluginParameter(project, pluginId, "source");
5648 if (sourceConfigured != null) {
5649 javaApiversion = JavaVersion.parse(sourceConfigured);
5650 } else {
5651 getLog().debug("No maven-compiler-plugin defined in ${build.plugins} or in "
5652 + "${project.build.pluginManagement} for the " + project.getId()
5653 + ". Added Javadoc API link according the javadoc executable version i.e.: "
5654 + javadocRuntimeVersion);
5655
5656 javaApiversion = javadocRuntimeVersion;
5657 }
5658 }
5659
5660 final String javaApiKey;
5661 if (javaApiversion.asMajor().isAtLeast("9")) {
5662 javaApiKey = "api_" + javaApiversion.asMajor();
5663 } else {
5664 javaApiKey = "api_1." + javaApiversion.asMajor().toString().charAt(0);
5665 }
5666
5667 final String javaApiLink;
5668 if (javaApiLinks != null && javaApiLinks.containsKey(javaApiKey)) {
5669 javaApiLink = javaApiLinks.getProperty(javaApiKey);
5670 } else if (javaApiversion.isAtLeast("16")) {
5671 javaApiLink = null;
5672 } else if (javaApiversion.isAtLeast("11")) {
5673 javaApiLink =
5674 String.format("https://docs.oracle.com/en/java/javase/%s/docs/api/", javaApiversion.getValue(1));
5675 } else if (javaApiversion.asMajor().isAtLeast("6")) {
5676 javaApiLink = String.format(
5677 "https://docs.oracle.com/javase/%s/docs/api/",
5678 javaApiversion.asMajor().getValue(1));
5679 } else if (javaApiversion.isAtLeast("1.5")) {
5680 javaApiLink = "https://docs.oracle.com/javase/1.5.0/docs/api/";
5681 } else {
5682 javaApiLink = null;
5683 }
5684
5685 if (getLog().isDebugEnabled()) {
5686 if (javaApiLink != null) {
5687 getLog().debug("Found Java API link: " + javaApiLink);
5688 } else {
5689 getLog().debug("No Java API link found.");
5690 }
5691 }
5692
5693 if (javaApiLink == null) {
5694 return null;
5695 }
5696
5697 final Path javaApiListFile;
5698 final String resourceName;
5699 if (javaApiversion.isAtLeast("10")) {
5700 javaApiListFile = getJavadocOptionsFile().getParentFile().toPath().resolve("element-list");
5701 resourceName = "java-api-element-list-" + javaApiversion.toString().substring(0, 2);
5702 } else if (javaApiversion.asMajor().isAtLeast("9")) {
5703 javaApiListFile = getJavadocOptionsFile().getParentFile().toPath().resolve("package-list");
5704 resourceName = "java-api-package-list-9";
5705 } else {
5706 javaApiListFile = getJavadocOptionsFile().getParentFile().toPath().resolve("package-list");
5707 resourceName = "java-api-package-list-1."
5708 + javaApiversion.asMajor().toString().charAt(0);
5709 }
5710
5711 OfflineLink link = new OfflineLink();
5712 link.setLocation(javaApiListFile.getParent().toAbsolutePath().toString());
5713 link.setUrl(javaApiLink);
5714
5715 InputStream in = this.getClass().getResourceAsStream(resourceName);
5716 if (in != null) {
5717 try (InputStream closableIS = in) {
5718
5719 Files.copy(closableIS, javaApiListFile, StandardCopyOption.REPLACE_EXISTING);
5720 } catch (IOException ioe) {
5721 logError("Can't get " + resourceName + ": " + ioe.getMessage(), ioe);
5722 return null;
5723 }
5724 }
5725
5726 return link;
5727 }
5728
5729
5730
5731
5732
5733
5734
5735
5736 private Set<String> followLinks(Set<String> links) {
5737 Set<String> redirectLinks = new LinkedHashSet<>(links.size());
5738 for (String link : links) {
5739 try {
5740 redirectLinks.add(JavadocUtil.getRedirectUrl(new URI(link).toURL(), settings)
5741 .toString());
5742 } catch (IOException e) {
5743
5744 getLog().debug("Could not follow " + link + ". Reason: " + e.getMessage());
5745
5746
5747
5748
5749 redirectLinks.add(link);
5750 } catch (URISyntaxException | IllegalArgumentException e) {
5751
5752 getLog().debug("Could not follow " + link + ". Reason: " + e.getMessage());
5753 }
5754 }
5755 return redirectLinks;
5756 }
5757
5758
5759
5760
5761
5762
5763
5764
5765
5766
5767 protected boolean isValidJavadocLink(String link, boolean detecting) {
5768 try {
5769 final URI packageListUri;
5770 final URI elementListUri;
5771
5772 if (link.trim().toLowerCase(Locale.ENGLISH).startsWith("http:")
5773 || link.trim().toLowerCase(Locale.ENGLISH).startsWith("https:")
5774 || link.trim().toLowerCase(Locale.ENGLISH).startsWith("ftp:")
5775 || link.trim().toLowerCase(Locale.ENGLISH).startsWith("file:")) {
5776 packageListUri = new URI(link + '/' + PACKAGE_LIST);
5777 elementListUri = new URI(link + '/' + ELEMENT_LIST);
5778 } else {
5779
5780 File dir = new File(link);
5781 if (!dir.isAbsolute()) {
5782 dir = new File(getOutputDirectory(), link);
5783 }
5784 if (!dir.isDirectory()) {
5785 if (detecting) {
5786 getLog().warn("The given File link: " + dir + " is not a dir.");
5787 } else {
5788 getLog().error("The given File link: " + dir + " is not a dir.");
5789 }
5790 }
5791 packageListUri = new File(dir, PACKAGE_LIST).toURI();
5792 elementListUri = new File(dir, ELEMENT_LIST).toURI();
5793 }
5794
5795 try {
5796 if (JavadocUtil.isValidElementList(elementListUri.toURL(), settings, validateLinks)) {
5797 return true;
5798 }
5799 } catch (IOException e) {
5800 }
5801
5802 if (JavadocUtil.isValidPackageList(packageListUri.toURL(), settings, validateLinks)) {
5803 return true;
5804 }
5805
5806 if (getLog().isErrorEnabled()) {
5807 if (detecting) {
5808 getLog().warn("Invalid links: " + link + " with /" + PACKAGE_LIST + " or / " + ELEMENT_LIST
5809 + ". Ignored it.");
5810 } else {
5811 getLog().error("Invalid links: " + link + " with /" + PACKAGE_LIST + " or / " + ELEMENT_LIST
5812 + ". Ignored it.");
5813 }
5814 }
5815
5816 return false;
5817 } catch (URISyntaxException e) {
5818 if (getLog().isErrorEnabled()) {
5819 if (detecting) {
5820 getLog().warn("Malformed link: " + e.getInput() + ". Ignored it.");
5821 } else {
5822 getLog().error("Malformed link: " + e.getInput() + ". Ignored it.");
5823 }
5824 }
5825 return false;
5826 } catch (IOException e) {
5827 if (getLog().isErrorEnabled()) {
5828 if (detecting) {
5829 getLog().warn("Error fetching link: " + link + ". Ignored it.");
5830 } else {
5831 getLog().error("Error fetching link: " + link + ". Ignored it.");
5832 }
5833 }
5834 return false;
5835 }
5836 }
5837
5838
5839
5840
5841
5842
5843
5844
5845
5846 private void writeDebugJavadocScript(String cmdLine, File javadocOutputDirectory) {
5847 File commandLineFile = new File(javadocOutputDirectory, DEBUG_JAVADOC_SCRIPT_NAME);
5848 commandLineFile.getParentFile().mkdirs();
5849
5850 try {
5851 FileUtils.fileWrite(commandLineFile.getAbsolutePath(), null , cmdLine);
5852
5853 if (!SystemUtils.IS_OS_WINDOWS) {
5854 Runtime.getRuntime().exec(new String[] {"chmod", "a+x", commandLineFile.getAbsolutePath()});
5855 }
5856 } catch (IOException e) {
5857 logError("Unable to write '" + commandLineFile.getName() + "' debug script file", e);
5858 }
5859 }
5860
5861
5862
5863
5864
5865
5866
5867
5868
5869 private boolean isJavadocVMInitError(String output) {
5870
5871
5872
5873
5874 return !(output.contains("Javadoc") || output.contains("javadoc"));
5875 }
5876
5877
5878
5879
5880
5881
5882
5883
5884
5885
5886
5887 private static String getJavadocLink(MavenProject p) {
5888 if (p.getUrl() == null) {
5889 return null;
5890 }
5891
5892 String url = cleanUrl(p.getUrl());
5893 String destDir = "apidocs";
5894
5895 final String pluginId = "org.apache.maven.plugins:maven-javadoc-plugin";
5896 String destDirConfigured = getPluginParameter(p, pluginId, "destDir");
5897 if (destDirConfigured != null) {
5898 destDir = destDirConfigured;
5899 }
5900
5901 return url + "/" + destDir;
5902 }
5903
5904
5905
5906
5907
5908
5909 private static String cleanUrl(String url) {
5910 if (url == null) {
5911 return "";
5912 }
5913
5914 url = url.trim();
5915 while (url.endsWith("/")) {
5916 url = url.substring(0, url.lastIndexOf("/"));
5917 }
5918
5919 return url;
5920 }
5921
5922
5923
5924
5925
5926
5927
5928
5929
5930 private static Plugin getPlugin(MavenProject p, String pluginId) {
5931 if ((p.getBuild() == null) || (p.getBuild().getPluginsAsMap() == null)) {
5932 return null;
5933 }
5934
5935 Plugin plugin = p.getBuild().getPluginsAsMap().get(pluginId);
5936
5937 if ((plugin == null)
5938 && (p.getBuild().getPluginManagement() != null)
5939 && (p.getBuild().getPluginManagement().getPluginsAsMap() != null)) {
5940 plugin = p.getBuild().getPluginManagement().getPluginsAsMap().get(pluginId);
5941 }
5942
5943 return plugin;
5944 }
5945
5946
5947
5948
5949
5950
5951
5952
5953
5954 private static String getPluginParameter(MavenProject p, String pluginId, String param) {
5955
5956 Plugin plugin = getPlugin(p, pluginId);
5957 if (plugin != null) {
5958 Xpp3Dom xpp3Dom = (Xpp3Dom) plugin.getConfiguration();
5959 if (xpp3Dom != null
5960 && xpp3Dom.getChild(param) != null
5961 && StringUtils.isNotEmpty(xpp3Dom.getChild(param).getValue())) {
5962 return xpp3Dom.getChild(param).getValue();
5963 }
5964 }
5965
5966 return null;
5967 }
5968
5969
5970
5971
5972
5973
5974
5975
5976 protected final File getJavadocOptionsFile() {
5977 if (javadocOptionsDir != null && !javadocOptionsDir.exists()) {
5978 javadocOptionsDir.mkdirs();
5979 }
5980
5981 return new File(javadocOptionsDir, "javadoc-options-" + getAttachmentClassifier() + ".xml");
5982 }
5983
5984
5985
5986
5987
5988
5989
5990
5991
5992
5993 protected final JavadocOptions buildJavadocOptions() throws IOException {
5994 JavadocOptions options = new JavadocOptions();
5995
5996 options.setBootclasspathArtifacts(toList(bootclasspathArtifacts));
5997 options.setDocfilesSubdirsUsed(docfilessubdirs);
5998 options.setDocletArtifacts(toList(docletArtifact, docletArtifacts));
5999 options.setExcludedDocfilesSubdirs(excludedocfilessubdir);
6000 options.setExcludePackageNames(toList(excludePackageNames));
6001 options.setGroups(toList(groups));
6002 options.setLinks(links);
6003 options.setOfflineLinks(toList(offlineLinks));
6004 options.setResourcesArtifacts(toList(resourcesArtifacts));
6005 options.setTagletArtifacts(toList(tagletArtifact, tagletArtifacts));
6006 options.setTaglets(toList(taglets));
6007 options.setTags(toList(tags));
6008
6009 if (getProject() != null && getJavadocDirectory() != null) {
6010 options.setJavadocResourcesDirectory(
6011 toRelative(getProject().getBasedir(), getJavadocDirectory().getAbsolutePath()));
6012 }
6013
6014 File optionsFile = getJavadocOptionsFile();
6015
6016 try (Writer writer = WriterFactory.newXmlWriter(optionsFile)) {
6017 new JavadocOptionsXpp3Writer().write(writer, options);
6018 }
6019
6020 return options;
6021 }
6022
6023
6024
6025
6026
6027
6028 protected String getAttachmentClassifier() {
6029 return JAVADOC_RESOURCES_ATTACHMENT_CLASSIFIER;
6030 }
6031
6032
6033
6034
6035
6036
6037
6038 protected void logError(String message, Throwable t) {
6039 if (getLog().isDebugEnabled()) {
6040 getLog().error(message, t);
6041 } else {
6042 getLog().error(message);
6043 }
6044 }
6045
6046 protected List<MavenProject> getReactorProjects() {
6047 return reactorProjects;
6048 }
6049
6050
6051
6052
6053
6054
6055 protected void failOnError(String prefix, Exception e) throws MojoExecutionException {
6056 if (failOnError) {
6057 if (e instanceof RuntimeException) {
6058 throw (RuntimeException) e;
6059 }
6060 throw new MojoExecutionException(prefix + ": " + e.getMessage(), e);
6061 }
6062
6063 getLog().error(prefix + ": " + e.getMessage(), e);
6064 }
6065
6066
6067
6068
6069 private List<MavenProject> getAggregatedProjects() {
6070 if (this.reactorProjects == null) {
6071 return Collections.emptyList();
6072 }
6073 Map<Path, MavenProject> reactorProjectsMap = new HashMap<>();
6074 for (MavenProject reactorProject : this.reactorProjects) {
6075 if (!isSkippedJavadoc(reactorProject)
6076 &&
6077 !isSkippedModule(reactorProject)) {
6078 reactorProjectsMap.put(reactorProject.getBasedir().toPath(), reactorProject);
6079 }
6080 }
6081
6082 return new ArrayList<>(modulesForAggregatedProject(project, reactorProjectsMap));
6083 }
6084
6085
6086
6087
6088
6089 protected boolean isSkippedModule(MavenProject mavenProject) {
6090 if (this.skippedModules == null || this.skippedModules.isEmpty()) {
6091 return false;
6092 }
6093 List<String> modulesToSkip = Arrays.asList(StringUtils.split(this.skippedModules, ','));
6094 return modulesToSkip.contains(mavenProject.getArtifactId());
6095 }
6096
6097
6098
6099
6100
6101 protected boolean isSkippedJavadoc(MavenProject mavenProject) {
6102 String property = mavenProject.getProperties().getProperty("maven.javadoc.skip");
6103 if (property != null) {
6104 boolean skip = BooleanUtils.toBoolean(property);
6105 getLog().debug("isSkippedJavadoc " + mavenProject + " " + skip);
6106 return skip;
6107 }
6108 final String pluginId = "org.apache.maven.plugins:maven-javadoc-plugin";
6109 property = getPluginParameter(mavenProject, pluginId, "skip");
6110 if (property != null) {
6111 boolean skip = BooleanUtils.toBoolean(property);
6112 getLog().debug("isSkippedJavadoc " + mavenProject + " " + skip);
6113 return skip;
6114 }
6115 if (mavenProject.getParent() != null) {
6116 return isSkippedJavadoc(mavenProject.getParent());
6117 }
6118 getLog().debug("isSkippedJavadoc " + mavenProject + " " + false);
6119 return false;
6120 }
6121 }