1 package org.apache.maven.plugin.jxr;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.net.URL;
25 import java.nio.file.Path;
26 import java.nio.file.Paths;
27 import java.util.ArrayList;
28 import java.util.Calendar;
29 import java.util.Collections;
30 import java.util.List;
31 import java.util.Locale;
32 import java.util.ResourceBundle;
33
34 import org.apache.maven.execution.MavenSession;
35 import org.apache.maven.jxr.JXR;
36 import org.apache.maven.jxr.JavaCodeTransform;
37 import org.apache.maven.jxr.JxrException;
38 import org.apache.maven.jxr.pacman.FileManager;
39 import org.apache.maven.jxr.pacman.PackageManager;
40 import org.apache.maven.model.ReportPlugin;
41 import org.apache.maven.plugins.annotations.Parameter;
42 import org.apache.maven.project.MavenProject;
43 import org.apache.maven.reporting.AbstractMavenReport;
44 import org.apache.maven.reporting.MavenReportException;
45 import org.codehaus.plexus.languages.java.version.JavaVersion;
46 import org.codehaus.plexus.util.FileUtils;
47 import org.codehaus.plexus.util.StringUtils;
48
49
50
51
52
53
54
55
56
57 public abstract class AbstractJxrReport
58 extends AbstractMavenReport
59 {
60
61 @Parameter( defaultValue = "${session}", readonly = true, required = true )
62 private MavenSession session;
63
64
65
66
67 @Parameter( defaultValue = "${project.name} ${project.version} Reference" )
68 private String windowTitle;
69
70
71
72
73 @Parameter( defaultValue = "${project.name} ${project.version} Reference" )
74 private String docTitle;
75
76
77
78
79
80 @Parameter( property = "bottom", defaultValue = "Copyright © {inceptionYear}–{currentYear} {organizationName}. All rights reserved." )
81 private String bottom;
82
83
84
85
86
87
88
89 @Parameter
90 private String templateDir;
91
92
93
94
95
96 @Parameter
97 private String stylesheet;
98
99
100
101
102
103
104 @Parameter
105 private ArrayList<String> excludes;
106
107
108
109
110
111
112 @Parameter
113 private ArrayList<String> includes;
114
115
116
117
118 @Parameter( defaultValue = "${reactorProjects}", readonly = true )
119 protected List<MavenProject> reactorProjects;
120
121
122
123
124
125
126 @Parameter( property = "maven.jxr.skip", defaultValue = "false" )
127 protected boolean skip;
128
129
130
131
132
133 @Parameter( defaultValue = "true" )
134 private boolean linkJavadoc;
135
136
137
138
139
140
141 @Parameter( property = "javadocVersion" )
142 private String javadocVersion;
143
144
145
146
147 private JavaVersion javadocTemplatesVersion;
148
149
150
151
152
153
154
155 protected List<String> pruneSourceDirs( List<String> sourceDirs )
156 {
157 List<String> pruned = new ArrayList<>( sourceDirs.size() );
158 for ( String dir : sourceDirs )
159 {
160 if ( !pruned.contains( dir ) && hasSources( new File( dir ) ) )
161 {
162 pruned.add( dir );
163 }
164 }
165 return pruned;
166 }
167
168
169
170
171 protected void init()
172 {
173
174
175 if ( project.getModel().getReporting() != null )
176 {
177 for ( ReportPlugin reportPlugin : Collections.unmodifiableList(
178 project.getModel().getReporting().getPlugins() ) )
179 {
180 if ( "maven-javadoc-plugin".equals( reportPlugin.getArtifactId() ) )
181 {
182 break;
183 }
184 }
185 }
186 }
187
188
189
190
191
192
193
194 private boolean hasSources( File dir )
195 {
196 if ( dir.exists() && dir.isDirectory() )
197 {
198 for ( File currentFile : dir.listFiles() )
199 {
200 if ( currentFile.isFile() )
201 {
202 if ( currentFile.getName().endsWith( ".java" ) )
203 {
204 return true;
205 }
206 }
207 else
208 {
209 if ( Character.isJavaIdentifierStart( currentFile.getName().charAt( 0 ) )
210 && hasSources( currentFile ) )
211 {
212 return true;
213 }
214 }
215 }
216 }
217 return false;
218 }
219
220
221
222
223
224
225
226
227
228
229
230 private void createXref( Locale locale, String destinationDirectory, List<String> sourceDirs )
231 throws IOException, JxrException
232 {
233 FileManager fileManager = new FileManager();
234 PackageManager packageManager = new PackageManager( fileManager );
235 JavaCodeTransform codeTransform = new JavaCodeTransform( packageManager, fileManager );
236
237 JXR jxr = new JXR( packageManager, codeTransform );
238 jxr.setDest( Paths.get( destinationDirectory ) );
239 jxr.setInputEncoding( getInputEncoding() );
240 jxr.setLocale( locale );
241 jxr.setOutputEncoding( getOutputEncoding() );
242 jxr.setRevision( "HEAD" );
243 jxr.setJavadocLinkDir( getJavadocLocation() );
244
245 if ( excludes != null && !excludes.isEmpty() )
246 {
247 jxr.setExcludes( excludes.toArray( new String[0] ) );
248 }
249 if ( includes != null && !includes.isEmpty() )
250 {
251 jxr.setIncludes( includes.toArray( new String[0] ) );
252 }
253
254
255 ClassLoader savedTccl = Thread.currentThread().getContextClassLoader();
256 try
257 {
258 Thread.currentThread().setContextClassLoader( getClass().getClassLoader() );
259 jxr.xref( sourceDirs, getTemplateDir(), windowTitle, docTitle, getBottomText() );
260 }
261 finally
262 {
263 Thread.currentThread().setContextClassLoader( savedTccl );
264 }
265
266
267 copyRequiredResources( destinationDirectory );
268 }
269
270
271
272
273 private String getBottomText()
274 {
275 int currentYear = Calendar.getInstance().get( Calendar.YEAR );
276 String year = String.valueOf( currentYear );
277
278 String inceptionYear = project.getInceptionYear();
279
280 String theBottom = StringUtils.replace( this.bottom, "{currentYear}", year );
281
282 if ( inceptionYear != null )
283 {
284 if ( inceptionYear.equals( year ) )
285 {
286 theBottom = StringUtils.replace( theBottom, "{inceptionYear}–", "" );
287 }
288 else
289 {
290 theBottom = StringUtils.replace( theBottom, "{inceptionYear}", inceptionYear );
291 }
292 }
293 else
294 {
295 theBottom = StringUtils.replace( theBottom, "{inceptionYear}–", "" );
296 }
297
298 if ( project.getOrganization() == null )
299 {
300 theBottom = StringUtils.replace( theBottom, " {organizationName}", "" );
301 }
302 else
303 {
304 if ( StringUtils.isNotEmpty( project.getOrganization().getName() ) )
305 {
306 if ( StringUtils.isNotEmpty( project.getOrganization().getUrl() ) )
307 {
308
309 theBottom =
310 StringUtils.replace( theBottom, "{organizationName}", "<a href=\""
311 + project.getOrganization().getUrl() + "\">" + project.getOrganization().getName() + "</a>" );
312
313 }
314 else
315 {
316 theBottom =
317 StringUtils.replace( theBottom, "{organizationName}", project.getOrganization().getName() );
318 }
319 }
320 else
321 {
322 theBottom = StringUtils.replace( theBottom, " {organizationName}", "" );
323 }
324 }
325
326 return theBottom;
327 }
328
329
330
331
332
333
334 private void copyRequiredResources( String dir )
335 {
336 if ( StringUtils.isNotEmpty( stylesheet ) )
337 {
338 File stylesheetFile = new File( stylesheet );
339 File destStylesheetFile = new File( dir, "stylesheet.css" );
340
341 try
342 {
343 if ( stylesheetFile.isAbsolute() )
344 {
345 FileUtils.copyFile( stylesheetFile, destStylesheetFile );
346 }
347 else
348 {
349 URL stylesheetUrl = this.getClass().getClassLoader().getResource( stylesheet );
350 FileUtils.copyURLToFile( stylesheetUrl, destStylesheetFile );
351 }
352 }
353 catch ( IOException e )
354 {
355 getLog().warn( "An error occured while copying the stylesheet to the target directory", e );
356 }
357 }
358 else
359 {
360 if ( javadocTemplatesVersion.isAtLeast( "1.8" ) )
361 {
362 copyResources( dir, "jdk8/", "stylesheet.css" );
363 }
364 else if ( javadocTemplatesVersion.isAtLeast( "1.7" ) )
365 {
366 String[] jdk7Resources =
367 {
368 "stylesheet.css",
369 "resources/background.gif",
370 "resources/tab.gif",
371 "resources/titlebar.gif",
372 "resources/titlebar_end.gif"
373 };
374 copyResources( dir, "jdk7/", jdk7Resources );
375 }
376 else if ( javadocTemplatesVersion.isAtLeast( "1.6" ) )
377 {
378 copyResources( dir, "jdk6/", "stylesheet.css" );
379 }
380 else if ( javadocTemplatesVersion.isAtLeast( "1.4" ) )
381 {
382 copyResources( dir, "jdk4/", "stylesheet.css" );
383 }
384 else
385 {
386
387 copyResources( dir, "", "stylesheet.css" );
388 }
389 }
390 }
391
392
393
394
395
396
397
398
399 private void copyResources( String dir, String sourceFolder, String... files )
400 {
401 try
402 {
403 for ( String file : files )
404 {
405 URL resourceUrl = this.getClass().getClassLoader().getResource( sourceFolder + file );
406 File destResourceFile = new File( dir, file );
407 FileUtils.copyURLToFile( resourceUrl, destResourceFile );
408 }
409 }
410 catch ( IOException e )
411 {
412 getLog().warn( "An error occured while copying the resource to the target directory", e );
413 }
414 }
415
416 @Override
417 protected MavenProject getProject()
418 {
419 return project;
420 }
421
422 protected MavenSession getSession()
423 {
424 return session;
425 }
426
427
428
429
430
431
432
433 protected ResourceBundle getBundle( Locale locale )
434 {
435 return ResourceBundle.getBundle( "jxr-report", locale, this.getClass().getClassLoader() );
436 }
437
438
439
440
441
442 protected boolean canGenerateReport( List<String> sourceDirs )
443 {
444 boolean canGenerate = !sourceDirs.isEmpty();
445
446 if ( isAggregate() && !project.isExecutionRoot() )
447 {
448 canGenerate = false;
449 }
450 return canGenerate;
451 }
452
453 @Override
454 protected void executeReport( Locale locale )
455 throws MavenReportException
456 {
457 if ( skip )
458 {
459 getLog().info( "Skipping JXR." );
460 return;
461 }
462 List<String> sourceDirs = constructSourceDirs();
463 if ( canGenerateReport( sourceDirs ) )
464 {
465
466 init();
467
468
469 setJavadocTemplatesVersion();
470
471 try
472 {
473 createXref( locale, getDestinationDirectory(), sourceDirs );
474 }
475 catch ( JxrException | IOException e )
476 {
477 throw new MavenReportException( "Error while generating the HTML source code of the project.", e );
478 }
479 }
480 }
481
482
483
484
485
486
487
488 private String getTemplateDir()
489 {
490
491 if ( StringUtils.isEmpty( templateDir ) )
492 {
493 if ( javadocTemplatesVersion.isAtLeast( "1.8" ) )
494 {
495 return "templates/jdk8";
496 }
497 else if ( javadocTemplatesVersion.isAtLeast( "1.7" ) )
498 {
499 return "templates/jdk7";
500 }
501 else if ( javadocTemplatesVersion.isAtLeast( "1.4" ) )
502 {
503 return "templates/jdk4";
504 }
505 else
506 {
507 getLog().warn( "Unsupported javadocVersion: " + javadocTemplatesVersion + ". Fallback to original" );
508 return "templates";
509 }
510 }
511
512 return templateDir;
513 }
514
515
516
517
518 private void setJavadocTemplatesVersion()
519 {
520 JavaVersion javaVersion = JavaVersion.JAVA_SPECIFICATION_VERSION;
521
522 if ( StringUtils.isNotEmpty( javadocVersion ) )
523 {
524 javadocTemplatesVersion = JavaVersion.parse( javadocVersion );
525 }
526 else
527 {
528 javadocTemplatesVersion = javaVersion;
529 }
530 }
531
532
533
534
535
536
537 protected List<String> constructSourceDirs()
538 {
539 List<String> sourceDirs = new ArrayList<>( getSourceRoots() );
540 if ( isAggregate() )
541 {
542 for ( MavenProject project : reactorProjects )
543 {
544 if ( "java".equals( project.getArtifact().getArtifactHandler().getLanguage() ) )
545 {
546 sourceDirs.addAll( getSourceRoots( project ) );
547 }
548 }
549 }
550
551 sourceDirs = pruneSourceDirs( sourceDirs );
552 return sourceDirs;
553 }
554
555 @Override
556 public boolean canGenerateReport()
557 {
558 return canGenerateReport( constructSourceDirs() );
559 }
560
561 @Override
562 public boolean isExternalReport()
563 {
564 return true;
565 }
566
567
568
569
570 private Path getJavadocLocation()
571 throws IOException
572 {
573 Path location = null;
574 if ( linkJavadoc )
575 {
576
577
578 if ( getJavadocDir().exists() )
579 {
580
581 location = getJavadocDir().toPath().toAbsolutePath();
582 }
583 else
584 {
585
586
587
588 String stagingDirectory = System.getProperty( "stagingDirectory" );
589
590 if ( StringUtils.isNotEmpty( stagingDirectory ) )
591 {
592 String javadocDestDir = getJavadocDir().getName();
593 boolean javadocAggregate = JxrReportUtil.isJavadocAggregated( project );
594 String structureProject = JxrReportUtil.getStructure( project, false );
595
596 if ( isAggregate() && javadocAggregate )
597 {
598 location = Paths.get( stagingDirectory, structureProject, javadocDestDir );
599 }
600 if ( !isAggregate() && javadocAggregate )
601 {
602 location = Paths.get( stagingDirectory, javadocDestDir );
603
604 String hierarchy = project.getName();
605
606 MavenProject parent = project.getParent();
607 while ( parent != null )
608 {
609 hierarchy = parent.getName();
610 parent = parent.getParent();
611 }
612 location = Paths.get( stagingDirectory, hierarchy, javadocDestDir );
613 }
614 if ( isAggregate() && !javadocAggregate )
615 {
616 getLog().warn( "The JXR plugin is configured to build an aggregated report at the root, "
617 + "not the Javadoc plugin." );
618 }
619 if ( !isAggregate() && !javadocAggregate )
620 {
621 location = Paths.get( stagingDirectory, structureProject, javadocDestDir );
622 }
623 }
624 else
625 {
626 location = getJavadocDir().toPath();
627 }
628 }
629
630 if ( location == null )
631 {
632 getLog().warn( "Unable to locate Javadoc to link to - DISABLED" );
633 }
634 }
635
636 return location;
637 }
638
639
640
641
642
643
644 protected abstract String getDestinationDirectory();
645
646
647
648
649
650
651 protected abstract List<String> getSourceRoots();
652
653
654
655
656
657
658
659
660 protected abstract List<String> getSourceRoots( MavenProject project );
661
662
663
664
665
666
667 protected abstract File getJavadocDir();
668
669
670
671
672
673
674 protected boolean isAggregate()
675 {
676 return false;
677 }
678 }