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