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