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