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