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