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