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