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