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