Author: hboutemy Date: Mon Feb 5 22:42:48 2018 New Revision: 1823259 URL: http://svn.apache.org/viewvc?rev=1823259&view=rev Log: Filled in guide-java-report-plugin-development.apt #11 https://github.com/apache/maven-site/pull/11 Submitted by: Bertrand Martin https://github.com/bertysentry
Modified: maven/site/trunk/content/apt/guides/plugin/guide-java-report-plugin-development.apt Modified: maven/site/trunk/content/apt/guides/plugin/guide-java-report-plugin-development.apt URL: http://svn.apache.org/viewvc/maven/site/trunk/content/apt/guides/plugin/guide-java-report-plugin-development.apt?rev=1823259&r1=1823258&r2=1823259&view=diff ============================================================================== --- maven/site/trunk/content/apt/guides/plugin/guide-java-report-plugin-development.apt (original) +++ maven/site/trunk/content/apt/guides/plugin/guide-java-report-plugin-development.apt Mon Feb 5 22:42:48 2018 @@ -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/}<<<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/}<<<maven-site-plugin>>>}} or site pdf documents generated by {{{/plugins/maven-pdf-plugin/}<<<maven-pdf-site>>>}}. - Any Mojo becomes a <report> 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 <report plugin> is a <Maven plugin> 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 <<<target/generated-site/>>>)... + A plugin is actually not a <report plugin> in itself. But one (or several) of its goals or <Mojos> may be + specialized to be invoked by {{{/plugins/maven-site-plugin/}<<<maven-site-plugin>>>}}, typically during the + <<<site>>> build life cycle. + + A Maven plugin can therefore implement <regular> goals and <report> goals. The below details how to write a <Mojo> + that will get invoked as a <report> by {{{/plugins/maven-site-plugin/}<<<maven-site-plugin>>>}}. + +* How It Works + + [[1]] + A regular Maven project usually invokes a <reporting goal> of a plugin by declaring such plugin in the + {{{/plugins/maven-site-plugin/examples/configuring-reports.html}<<<<reporting\>>>>}} section of its <<<pom.xml>>> as in the example below: + ++--- +<project> + ... + <reporting> + <plugins> + <plugin> + <groupId>com.mycompany.maven</groupId> + <artifactId>simple-maven-plugin</artifactId> + <version>1.0-SNAPSHOT</version> + </plugin> + </plugins> + </reporting> + ... ++--- + + [[2]] + When {{{/plugins/maven-site-plugin/}<<<maven-site-plugin>>>}} is invoked (for example with the <<<mvn site>>> command), + the specified plugins are loaded and the <executeReport()> method of each class that extends + {{{/shared/maven-reporting-impl/apidocs/org/apache/maven/reporting/AbstractMavenReport.html}<AbstractMavenReport>}} + is executed. + + [[3]] + The <executeReport()> 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 <Mojo> + + Each goal or <Mojo> is implemented with a separate Java class. For a <Mojo> to become a <report Mojo>, it needs + to extend the {{{/shared/maven-reporting-impl/apidocs/org/apache/maven/reporting/AbstractMavenReport.html}<org.apache.maven.reporting.AbstractMavenReport>}} + class (instead of <org.apache.maven.plugin.AbstractMojo> for a regular <Mojo>). + + The class will also need to implement the following methods: + + * <<<public String getOutputName()>>>: returns the name of page that will be produced + + * <<<public String getName(Locale locale)>>>: returns the display name of the report + + * <<<public String getDescription(Locale locale)>>>: returns the description of the report + + * <<<protected void executeReport(Locale locale) throws MavenReportException>>>: produces the actual report + + [] + + To build a Maven plugin that includes <report Mojos>, the <<<pom.xml>>> of your project will need declare the project + as a regular plugin, and include specific dependencies required by the report <Mojos>: + + * {{{https://mvnrepository.com/artifact/org.apache.maven.reporting/maven-reporting-impl}<<<org.apache.maven.reporting:maven-reporting-impl:3.0.0>>>}} + + * {{{https://mvnrepository.com/artifact/org.apache.maven.reporting/maven-reporting-api}<<<org.apache.maven.reporting:maven-reporting-api:3.0>>>}} + + [] + +* A (Very) Simple Report + + Let's write a very simple <report Mojo> in a very simple Maven plugin: + + * Plugin's name: <<Simple Plugin>> + + * Plugin's artifact coordinates: <<<com.mycompany.maven:simple-maven-plugin:1.0-SNAPSHOT>>> + + * One goal: <<simple>> + + * One result: <<<simple-report.html>>> + + [] + + 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 + ++--- +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <groupId>com.mycompany.maven</groupId> + <artifactId>simple-maven-plugin</artifactId> + <version>1.0-SNAPSHOT</version> + <packaging>maven-plugin</packaging> + + <name>Simple Plugin</name> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencies> + <!-- reporting API --> + <dependency> + <groupId>org.apache.maven.reporting</groupId> + <artifactId>maven-reporting-impl</artifactId> + <version>3.0.0</version> + </dependency> + <dependency> + <groupId>org.apache.maven.reporting</groupId> + <artifactId>maven-reporting-api</artifactId> + <version>3.0</version> + </dependency> + + <!-- plugin API and plugin-tools --> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-plugin-api</artifactId> + <version>3.5.2</version> + </dependency> + <dependency> + <groupId>org.apache.maven.plugin-tools</groupId> + <artifactId>maven-plugin-annotations</artifactId> + <version>3.5</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.apache.maven.shared</groupId> + <artifactId>maven-shared-utils</artifactId> + <version>3.2.0</version> + </dependency> + + </dependencies> + + + <build> + <plugins> + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.7.0</version> + </plugin> + <plugin> + <artifactId>maven-install-plugin</artifactId> + <version>2.5.2</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-plugin-plugin</artifactId> + <version>3.5</version> + <configuration> + <goalPrefix>simple</goalPrefix> + </configuration> + <executions> + <execution> + <id>default-descriptor</id> + <phase>process-classes</phase> + </execution> + <execution> + <id>generated-helpmojo</id> + <goals> + <goal>helpmojo</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> ++--- + +** ./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. + * + * <p> + * 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=<goal-name> 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 <report Mojo> of our plugin in another Maven project, we just need to declare the plugin in the + {{{/plugins/maven-site-plugin/examples/configuring-reports.html}<<<<reporting\>>>>}} section of its <<<pom.xml>>> as in the example below: + ++--- +<project> +... +<reporting> + <plugins> + <plugin> + <groupId>com.mycompany.maven</groupId> + <artifactId>simple-maven-plugin</artifactId> + <version>1.0-SNAPSHOT</version> + </plugin> + </plugins> +</reporting> +... ++--- + + Note: When no specific report is specified, all of the <Mojos> 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 <executeReport()> 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}<Sink>}} 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 <sink.body()> (opening) and <sink.body_()> (closing). + + * <sink.head()> and <sink.head_()> + + * <sink.paragraph()> and <sink.paragraph_()> + + * <sink.section1()> and <sink.section1_()> + + * <sink.bold()> and <sink.bold_()> + + * etc. + + [] + + <<Do not forget to close elements!>> + + At the very least, a document should include the following: + + * Head and title (<sink.head()> and <sink.title()>) + + * Body (<sink.body()>) + + * Section 1 with title (<sink.section1()> and <sink.sectionTitle1()>) + + [] + + The {{{/doxia/doxia/doxia-sink-api/apidocs/org/apache/maven/doxia/sink/Sink.html}<Sink>}} object + allows you to add raw text with the <rawText()> 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/}<<<maven-pdf-site>>>}}). + + The Doxia Sink API allows you to specify {{{/doxia/doxia/doxia-sink-api/apidocs/org/apache/maven/doxia/sink/SinkEventAttributes.html}<SinkEventAttributes>}} + 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 <Sink> 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}<SinkFactory>}} object + that you can easily obtain with the + {{{/shared/maven-reporting-impl/apidocs/org/apache/maven/reporting/AbstractMavenReport.html#getSinkFactory()}<getSinkFactory()>}} + method of your + {{{/shared/maven-reporting-impl/apidocs/org/apache/maven/reporting/AbstractMavenReport.html}<AbstractMavenReport>}} 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 <<<other-report.html>>> HTML file along with <<<simple-report.html>>>. + + Note: Despite the fact that you will be creating additional HTML files, the Velocity variable <<<$currentFileName>>> + passed to the <<<site.vm>>> script of the Maven Skin will keep the name of the original report (i.e. the result of + your <getOutputName()> method). {{{/doxia/doxia-sitetools/doxia-site-renderer/}More information about the Velocity + variables}}. * Resources