From 65d4566f5e917417b8df5ad2ec8567b36441b311 Mon Sep 17 00:00:00 2001 From: Bertrand Martin Date: Sun, 21 Jan 2018 23:28:59 +0100 Subject: [PATCH] Filled in guide-java-report-plugin-development.apt --- .../guide-java-report-plugin-development.apt | 487 +++++++++++++++++- 1 file changed, 481 insertions(+), 6 deletions(-) diff --git a/content/apt/guides/plugin/guide-java-report-plugin-development.apt b/content/apt/guides/plugin/guide-java-report-plugin-development.apt index e8134830da..2108ed7164 100644 --- a/content/apt/guides/plugin/guide-java-report-plugin-development.apt +++ b/content/apt/guides/plugin/guide-java-report-plugin-development.apt @@ -2,8 +2,9 @@ Guide to Developing Java Report Plugins ------ Hervé Boutemy + Bertrand Martin ------ - 2017-11-16 + 2018-01-21 ------ ~~ Licensed to the Apache Software Foundation (ASF) under one @@ -28,14 +29,488 @@ Introduction - This guide is intended to assist users in developing Java reporting plugins for - Maven that will contribute to sites generated by {{{/plugins/maven-site-plugin/}<<>>}} + This guide is intended to assist users in developing reporting plugins for + Maven in Java that will contribute to sites generated by {{{/plugins/maven-site-plugin/}<<>>}} or site pdf documents generated by {{{/plugins/maven-pdf-plugin/}<<>>}}. - Any Mojo becomes a Mojo when it implements {{{/shared/maven-reporting-api/}Maven Reporting API}}. Then a plugin - may have some reporting goals and some build (non-reporting) goals. + First and foremost, a is a and it is strongly advised to first read the + {{{./guide-java-plugin-development.html}Guide to Developing Java Plugins}} to properly understand + its core mechanisms. - Work In Progress (external reports, Doxia Sink API vs generated markup in <<>>)... + A plugin is actually not a in itself. But one (or several) of its goals or may be + specialized to be invoked by {{{/plugins/maven-site-plugin/}<<>>}}, typically during the + <<>> build life cycle. + + A Maven plugin can therefore implement goals and goals. The below details how to write a + that will get invoked as a by {{{/plugins/maven-site-plugin/}<<>>}}. + +* How It Works + + [[1]] + A regular Maven project usually invokes a of a plugin by declaring such plugin in the + {{{/plugins/maven-site-plugin/examples/configuring-reports.html}<<<>>>}} section of its <<>> as in the example below: + ++--- + + ... + + + + com.mycompany.maven + simple-maven-plugin + 1.0-SNAPSHOT + + + + ... ++--- + + [[2]] + When {{{/plugins/maven-site-plugin/}<<>>}} is invoked (for example with the <<>> command), + the specified plugins are loaded and the method of each class that extends + {{{/shared/maven-reporting-impl/apidocs/org/apache/maven/reporting/AbstractMavenReport.html}}} + is executed. + + [[3]] + The method generates a document through Maven's {{{/doxia/doxia/doxia-sink-api/}Doxia Sink API}}. + This document is comprised of basic elements like title, headings, text, links, tables, etc. + This is where you will put the logic of your report, assembling elements, based on the content of the Maven project. + + [[4]] + These document elements are passed to Doxia to generate an HTML document, which itself gets wrapped into a {{{/skins}Maven Skin}}, + as specified in the projects {{{/guides/mini/guide-site.html}<<<./src/site/site.xml>>>}}. + + [[5]] + The result produces an HTML file in the <<<./target/site>>> directory of your project. + + [] + + {{{/doxia/doxia-sitetools/doxia-site-renderer/}More details about Doxia Site Renderer}} + +* Basic Requirements of a Report + + Each goal or is implemented with a separate Java class. For a to become a , it needs + to extend the {{{/shared/maven-reporting-impl/apidocs/org/apache/maven/reporting/AbstractMavenReport.html}}} + class (instead of for a regular ). + + The class will also need to implement the following methods: + + * <<>>: returns the name of page that will be produced + + * <<>>: returns the display name of the report + + * <<>>: returns the description of the report + + * <<>>: produces the actual report + + [] + + To build a Maven plugin that includes , the <<>> of your project will need declare the project + as a regular plugin, and include specific dependencies required by the report : + + * {{{https://mvnrepository.com/artifact/org.apache.maven.reporting/maven-reporting-impl}<<>>}} + + * {{{https://mvnrepository.com/artifact/org.apache.maven.reporting/maven-reporting-api}<<>>}} + + [] + +* A (Very) Simple Report + + Let's write a very simple in a very simple Maven plugin: + + * Plugin's name: <> + + * Plugin's artifact coordinates: <<>> + + * One goal: <> + + * One result: <<>> + + [] + + Our Maven plugin project has 2 files only: + + * <<<./pom.xml>>> + + * <<<./src/main/java/com/mycompany/maven/SimpleReport.java>>> + + [] + + The below examples can be copied and pasted as a template. + +** ./pom.xml + ++--- + + + 4.0.0 + + com.mycompany.maven + simple-maven-plugin + 1.0-SNAPSHOT + maven-plugin + + Simple Plugin + + + UTF-8 + + + + + + org.apache.maven.reporting + maven-reporting-impl + 3.0.0 + + + org.apache.maven.reporting + maven-reporting-api + 3.0 + + + + + org.apache.maven + maven-plugin-api + 3.5.2 + + + org.apache.maven.plugin-tools + maven-plugin-annotations + 3.5 + provided + + + org.apache.maven.shared + maven-shared-utils + 3.2.0 + + + + + + + + + maven-compiler-plugin + 3.7.0 + + + maven-install-plugin + 2.5.2 + + + org.apache.maven.plugins + maven-plugin-plugin + 3.5 + + simple + + + + default-descriptor + process-classes + + + generated-helpmojo + + helpmojo + + + + + + + + ++--- + +** ./src/main/java/com/mycompany/maven/SimpleReport.java + ++--- +package com.mycompany.maven; + +import java.util.Locale; + +import org.apache.maven.doxia.sink.Sink; +import org.apache.maven.plugin.logging.Log; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; +import org.apache.maven.project.MavenProject; +import org.apache.maven.reporting.AbstractMavenReport; +import org.apache.maven.reporting.MavenReportException; + +/** + * Builds an simple report page as an example. + * + *

+ * This example show how easy it is to build your own reporting plugin + * (or, for that matter, your own reporting Mojo) + * + */ +@Mojo( + name = "simple", + aggregator = false, + executionStrategy = "always", + defaultPhase = LifecyclePhase.SITE, + requiresDependencyResolution = ResolutionScope.RUNTIME, + requiresDirectInvocation = false, + requiresOnline = false, + requiresProject = true, + threadSafe = true + ) +public class SimpleReport extends AbstractMavenReport { + + public String getOutputName() { + // This report will generate simple-report.html when invoked in a project with `mvn site` + return "simple-report"; + } + + public String getName(Locale locale) { + // Name of the report when listed in the project-reports.html page of a project + return "Simple Report"; + } + + public String getDescription(Locale locale) { + // Description of the report when listed in the project-reports.html page of a project + return "This simple report is a very simple report that does nothing but " + + "shows off Maven's wonderful reporting capabilities."; + } + + /** + * Practical reference to the Maven project + */ + @Parameter(defaultValue = "${project}", readonly = true) + private MavenProject project; + + @Override + protected void executeReport(Locale locale) throws MavenReportException { + + // Get the logger + Log logger = getLog(); + + // Some info + logger.info("Generating " + getOutputName() + ".html" + + " for " + project.getName() + " " + project.getVersion()); + + // Get the Maven Doxia Sink, which will be used to generate the + // various elements of the document + Sink mainSink = getSink(); + if (mainSink == null) { + throw new MavenReportException("Could not get the Doxia sink"); + } + + // Page title + mainSink.head(); + mainSink.title(); + mainSink.text("Simple Report for " + project.getName() + " " + project.getVersion()); + mainSink.title_(); + mainSink.head_(); + + mainSink.body(); + + // Heading 1 + mainSink.section1(); + mainSink.sectionTitle1(); + mainSink.text("Simple Report for " + project.getName() + " " + project.getVersion()); + mainSink.sectionTitle1_(); + + // Content + mainSink.paragraph(); + mainSink.text("This page provides simple information, like its location: "); + mainSink.text(project.getBasedir().getAbsolutePath()); + mainSink.paragraph_(); + + // Close + mainSink.section1_(); + mainSink.body_(); + + } + +} ++--- + +** Building the Simple Plugin + + Building the plugin is done by executing the below command in the root directory of the plugin project: + ++--- +$ mvn clean install ++--- + + This command will: + + * erase the content of the <<<./target>>> directory + + * compile your code + + * produces the plugin JAR artifact (<<<./target/simple-maven-plugin-1.0-SNAPSHOT.jar>>>) + + * copy the artifact to your local repository so that it can be "consumed" by other projects (which + is the purpose of a plugin, right?). + + [] + + To make sure everything went well and is properly declared, you can now execute the below command + in any other Maven project directory: + ++--- +$ mvn com.mycompany.maven:simple-maven-plugin:1.0-SNAPSHOT:help + +[INFO] --- simple-maven-plugin:1.0-SNAPSHOT:help (default-cli) @ hardware-connectors --- +[INFO] Simple Plugin 1.0-SNAPSHOT + + +This plugin has 2 goals: + +simple:help + Display help information on simple-maven-plugin. + Call mvn simple:help -Ddetail=true -Dgoal= to display parameter + details. + +simple:simple + Builds an simple report page as an example. + This example show how easy it is to build your own reporting plugin (or, for + that matter, your own reporting Mojo) + + +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ ++--- + +** Invoking the Simple Plugin + + To invoke the of our plugin in another Maven project, we just need to declare the plugin in the + {{{/plugins/maven-site-plugin/examples/configuring-reports.html}<<<>>>}} section of its <<>> as in the example below: + ++--- + +... + + + + com.mycompany.maven + simple-maven-plugin + 1.0-SNAPSHOT + + + +... ++--- + + Note: When no specific report is specified, all of the in the plugin, that are declared as "reporting" will be executed. + {{{/plugins/maven-site-plugin/examples/configuring-reports.html}More information about configuring reports}}. + + +* More Information + +** The Doxia Sink API + + In your method, you will leverage the {{{/doxia/doxia/doxia-sink-api/}Doxia Sink API}} + to add elements to the report document. + + You will use the {{{https://maven.apache.org/doxia/doxia/doxia-sink-api/apidocs/org/apache/maven/doxia/sink/Sink.html}}} object associated to the report: + ++--- +Sink sink = getSink(); ++--- + + This object allows you to append new elements to the report document (initially empty). Unlike some DOM manipulation APIs, + you cannot insert elements in already existing elements, or remove elements. + + The elements that you append to the document will look familiar if you have basic knowledge of HTML. Most of the elements + have opening and closing tags, like (opening) and (closing). + + * and + + * and + + * and + + * and + + * etc. + + [] + + <> + + At the very least, a document should include the following: + + * Head and title ( and ) + + * Body () + + * Section 1 with title ( and ) + + [] + + The {{{/doxia/doxia/doxia-sink-api/apidocs/org/apache/maven/doxia/sink/Sink.html}}} object + allows you to add raw text with the method. More precisely, it allows you to add raw HTML code into the + document for full flexibility. However, you should limit the usage of this method as you may add elements that are not supported + by non-HTML renderers (like {{{/plugins/maven-pdf-plugin/}<<>>}}). + + The Doxia Sink API allows you to specify {{{/doxia/doxia/doxia-sink-api/apidocs/org/apache/maven/doxia/sink/SinkEventAttributes.html}}} + to each element, i.e. HTML properties, notably the class and the ID of an object, which allows for easy customization + with an appropriate CSS (either provided by the specified Maven Skin, or by the project itself). + +** Creating more than one document + + You may need to create not just one HTML file, but several of them (like Javadoc produces one HTML file for + each Java class). To do so, you will need to get a new for each HTML file you need to produce. + This is achieved by using the + {{{/doxia/doxia/doxia-sink-api/apidocs/org/apache/maven/doxia/sink/SinkFactory.html}}} object + that you can easily obtain with the + {{{/shared/maven-reporting-impl/apidocs/org/apache/maven/reporting/AbstractMavenReport.html#getSinkFactory()}}} + method of your + {{{/shared/maven-reporting-impl/apidocs/org/apache/maven/reporting/AbstractMavenReport.html}}} instance, + as in the example below. + ++--- +public class SimpleReport extends AbstractMavenReport { + + ... + + /** + * Where the HTML pages of the report will be created. + */ + @Parameter( defaultValue = "${project.reporting.outputDirectory}", property = "outputDirectory", required = true ) + private File outputDirectory; + + ... + + @Override + protected void executeReport(Locale locale) throws MavenReportException { + + ... + + // Create a new sink + String pageFilename = "other-report.html"; + Sink otherSink; + try { + otherSink = getSinkFactory().createSink(outputDirectory, pageFilename); + } catch (IOException e) { + throw new MavenReportException("Could not create sink for " + pageFilename + " in " + outputDirectory.getAbsolutePath(), e); + } + + // Create the "other" report + otherSink.head(); + otherSink.title(); + otherSink.text("The Other Report"); + ... ++--- + + The above example will create a <<>> HTML file along with <<>>. + + Note: Despite the fact that you will be creating additional HTML files, the Velocity variable <<<$currentFileName>>> + passed to the <<>> script of the Maven Skin will keep the name of the original report (i.e. the result of + your method). {{{/doxia/doxia-sitetools/doxia-site-renderer/}More information about the Velocity + variables}}. * Resources