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