Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package org.apache.maven.plugins.javadoc;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import static org.apache.maven.plugins.javadoc.JavadocUtil.isEmpty;
import static org.apache.maven.plugins.javadoc.JavadocUtil.isNotEmpty;
import static org.apache.maven.plugins.javadoc.JavadocUtil.toList;
import static org.apache.maven.plugins.javadoc.JavadocUtil.toRelative;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.JavaVersion;
import org.apache.commons.lang3.SystemUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.artifact.handler.ArtifactHandler;
import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.Resource;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.javadoc.options.BootclasspathArtifact;
import org.apache.maven.plugins.javadoc.options.DocletArtifact;
import org.apache.maven.plugins.javadoc.options.Group;
import org.apache.maven.plugins.javadoc.options.JavadocOptions;
import org.apache.maven.plugins.javadoc.options.JavadocPathArtifact;
import org.apache.maven.plugins.javadoc.options.OfflineLink;
import org.apache.maven.plugins.javadoc.options.ResourcesArtifact;
import org.apache.maven.plugins.javadoc.options.Tag;
import org.apache.maven.plugins.javadoc.options.Taglet;
import org.apache.maven.plugins.javadoc.options.TagletArtifact;
import org.apache.maven.plugins.javadoc.options.io.xpp3.JavadocOptionsXpp3Writer;
import org.apache.maven.plugins.javadoc.resolver.JavadocBundle;
import org.apache.maven.plugins.javadoc.resolver.ResourceResolver;
import org.apache.maven.plugins.javadoc.resolver.SourceResolverConfig;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuilder;
import org.apache.maven.project.ProjectBuildingException;
import org.apache.maven.project.ProjectBuildingRequest;
import org.apache.maven.reporting.MavenReportException;
import org.apache.maven.settings.Proxy;
import org.apache.maven.settings.Settings;
import org.apache.maven.shared.artifact.DefaultArtifactCoordinate;
import org.apache.maven.shared.artifact.filter.resolve.AndFilter;
import org.apache.maven.shared.artifact.filter.resolve.PatternExclusionsFilter;
import org.apache.maven.shared.artifact.filter.resolve.PatternInclusionsFilter;
import org.apache.maven.shared.artifact.filter.resolve.ScopeFilter;
import org.apache.maven.shared.artifact.filter.resolve.TransformableFilter;
import org.apache.maven.shared.artifact.resolve.ArtifactResolver;
import org.apache.maven.shared.artifact.resolve.ArtifactResolverException;
import org.apache.maven.shared.artifact.resolve.ArtifactResult;
import org.apache.maven.shared.dependencies.DefaultDependableCoordinate;
import org.apache.maven.shared.dependencies.resolve.DependencyResolver;
import org.apache.maven.shared.dependencies.resolve.DependencyResolverException;
import org.apache.maven.shared.invoker.MavenInvocationException;
import org.apache.maven.toolchain.Toolchain;
import org.apache.maven.toolchain.ToolchainManager;
import org.apache.maven.wagon.PathUtils;
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.archiver.UnArchiver;
import org.codehaus.plexus.archiver.manager.ArchiverManager;
import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
import org.codehaus.plexus.components.io.fileselectors.IncludeExcludeFileSelector;
import org.codehaus.plexus.languages.java.jpms.LocationManager;
import org.codehaus.plexus.languages.java.jpms.ResolvePathsRequest;
import org.codehaus.plexus.languages.java.jpms.ResolvePathsResult;
import org.codehaus.plexus.util.DirectoryScanner;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.WriterFactory;
import org.codehaus.plexus.util.cli.CommandLineException;
import org.codehaus.plexus.util.cli.CommandLineUtils;
import org.codehaus.plexus.util.cli.Commandline;
import org.codehaus.plexus.util.xml.Xpp3Dom;
/**
* Base class with majority of Javadoc functionalities.
*
* @author Brett Porter
* @author Vincent Siveton
* @version $Id: AbstractJavadocMojo.java 1801354 2017-07-09 08:49:46Z rfscholte $
* @see
* The Java API Documentation Generator, 7
* @since 2.0
*/
public abstract class AbstractJavadocMojo
extends AbstractMojo
{
/**
* Classifier used in the name of the javadoc-options XML file, and in the resources bundle
* artifact that gets attached to the project. This one is used for non-test javadocs.
*
* @see #TEST_JAVADOC_RESOURCES_ATTACHMENT_CLASSIFIER
* @since 2.7
*/
public static final String JAVADOC_RESOURCES_ATTACHMENT_CLASSIFIER = "javadoc-resources";
/**
* Classifier used in the name of the javadoc-options XML file, and in the resources bundle
* artifact that gets attached to the project. This one is used for test-javadocs.
*
* @see #JAVADOC_RESOURCES_ATTACHMENT_CLASSIFIER
* @since 2.7
*/
public static final String TEST_JAVADOC_RESOURCES_ATTACHMENT_CLASSIFIER = "test-javadoc-resources";
/**
* The default Javadoc API urls according the
* Sun API
* Specifications:
*
* See Jflag.
*
* See vmoptions.
*
* See Networking
* Properties.
*
* @since 2.3
*/
@Parameter( property = "additionalJOption" )
private String additionalJOption;
/**
* Set additional JVM options for the execution of the javadoc command via the '-J' option to javadoc.
* Example:
*
* @since 2.9
*/
@Parameter
private String[] additionalJOptions;
/**
* A list of artifacts containing resources which should be copied into the
* Javadoc output directory (like stylesheets, icons, etc.).
*
* Example:
*
*
* See Javadoc.
*
*
* @since 2.5
*/
@Parameter( property = "resourcesArtifacts" )
private ResourcesArtifact[] resourcesArtifacts;
/**
* The local repository where the artifacts are located.
*/
@Parameter( property = "localRepository" )
private ArtifactRepository localRepository;
/**
* The projects in the reactor for aggregation report.
*/
@Parameter( property = "reactorProjects", readonly = true )
private List reactorProjects;
/**
* Set this to true to debug the Javadoc plugin. With this, javadoc.bat(or.sh),
* options, @packages or argfile files are provided in the output directory.
*
*
* @since 2.1
*/
@Parameter( property = "debug", defaultValue = "false" )
private boolean debug;
/**
* Sets the absolute path of the Javadoc Tool executable to use. Since version 2.5, a mere directory specification
* is sufficient to have the plugin use "javadoc" or "javadoc.exe" respectively from this directory.
*
* @since 2.3
*/
@Parameter( property = "javadocExecutable" )
private String javadocExecutable;
/**
* Version of the Javadoc Tool executable to use, ex. "1.3", "1.5".
*
* @since 2.3
*/
@Parameter( property = "javadocVersion" )
private String javadocVersion;
/**
* Version of the Javadoc Tool executable to use.
*/
private JavadocVersion javadocRuntimeVersion;
/**
* Specifies whether the Javadoc generation should be skipped.
*
* @since 2.5
*/
@Parameter( property = "maven.javadoc.skip", defaultValue = "false" )
protected boolean skip;
/**
* Specifies if the build will fail if there are errors during javadoc execution or not.
*
* @since 2.5
*/
@Parameter( property = "maven.javadoc.failOnError", defaultValue = "true" )
protected boolean failOnError;
/**
* Specifies to use the
*
* options provided by the Standard Doclet for a custom doclet.
*
* Example:
*
*
* @since 2.5
*/
@Parameter( property = "useStandardDocletOptions", defaultValue = "true" )
protected boolean useStandardDocletOptions;
/**
* Detect the Javadoc links for all dependencies defined in the project. The detection is based on the default
* Maven conventions, i.e.: ${project.url}/apidocs.
*
* For instance, if the project has a dependency to
* Apache Commons Lang i.e.:
*
* The added Javadoc -link parameter will be http://commons.apache.org/lang/apidocs.
*
* @see #links
* @since 2.6
*/
@Parameter( property = "detectLinks", defaultValue = "false" )
private boolean detectLinks;
/**
* Detect the links for all modules defined in the project.
*
* If {@link #reactorProjects} is defined in a non-aggregator way, it generates default offline links
* between modules based on the defined project's urls. For instance, if a parent project has two projects
* module1 and module2, the -linkoffline will be:
*
* The added Javadoc -linkoffline parameter for module1 will be
* /absolute/path/to/module2/target/site/apidocs
*
* The added Javadoc -linkoffline parameter for module2 will be
* /absolute/path/to/module1/target/site/apidocs
*
* @see #offlineLinks
* @since 2.6
*/
@Parameter( property = "detectOfflineLinks", defaultValue = "true" )
private boolean detectOfflineLinks;
/**
* Detect the Java API link for the current build, i.e. http://docs.oracle.com/javase/1.4.2/docs/api/
* for Java source 1.4.
*
* By default, the goal detects the Javadoc API link depending the value of the source
* parameter in the org.apache.maven.plugins:maven-compiler-plugin
* (defined in ${project.build.plugins} or in ${project.build.pluginManagement}),
* or try to compute it from the {@link #javadocExecutable} version.
*
* See
* Javadoc
* for the default values.
*
*
* @see #links
* @see #javaApiLinks
* @see #DEFAULT_JAVA_API_LINKS
* @since 2.6
*/
@Parameter( property = "detectJavaApiLink", defaultValue = "true" )
private boolean detectJavaApiLink;
/**
* Use this parameter only if the Sun Javadoc API
* urls have been changed or to use custom urls for Javadoc API url.
*
* See
* Javadoc
* for the default values.
*
*
* @see #DEFAULT_JAVA_API_LINKS
* @since 2.6
*/
@Parameter( property = "javaApiLinks" )
private Properties javaApiLinks;
/**
* Flag controlling content validation of package-list resources. If set, the content of
* package-list resources will be validated.
*
* @since 2.8
*/
@Parameter( property = "validateLinks", defaultValue = "false" )
private boolean validateLinks;
// ----------------------------------------------------------------------
// Javadoc Options - all alphabetical
// ----------------------------------------------------------------------
/**
* Specifies the paths where the boot classes reside. The bootclasspath can contain multiple paths
* by separating them with a colon (:) or a semi-colon (;).
*
* See bootclasspath.
*
*
* @since 2.5
*/
@Parameter( property = "bootclasspath" )
private String bootclasspath;
/**
* Specifies the artifacts where the boot classes reside.
*
* See bootclasspath.
*
* Example:
*
*
* See Javadoc.
*
*
* @since 2.5
*/
@Parameter( property = "bootclasspathArtifacts" )
private BootclasspathArtifact[] bootclasspathArtifacts;
/**
* Uses the sentence break iterator to determine the end of the first sentence.
*
* See breakiterator.
*
* Since Java
* 1.4.
*
*/
@Parameter( property = "breakiterator", defaultValue = "false" )
private boolean breakiterator;
/**
* Specifies the class file that starts the doclet used in generating the documentation.
*
* See doclet.
*/
@Parameter( property = "doclet" )
private String doclet;
/**
* Specifies the artifact containing the doclet starting class file (specified with the -doclet
* option).
*
* See
* docletpath.
*
* Example:
*
*
* See Javadoc.
*
*
* @since 2.1
*/
@Parameter( property = "docletArtifacts" )
private DocletArtifact[] docletArtifacts;
/**
* Specifies the path to the doclet starting class file (specified with the -doclet option) and
* any jar files it depends on. The docletPath can contain multiple paths by separating them with
* a colon (:) or a semi-colon (;).
*
* See
* docletpath.
*/
@Parameter( property = "docletPath" )
private String docletPath;
/**
* Specifies the encoding name of the source files. If not specificed, the encoding value will be the value of the
* file.encoding system property.
*
* See encoding.
*
* Note: In 2.4, the default value was locked to ISO-8859-1 to ensure reproducing build, but
* this was reverted in 2.5.
*
*/
@Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}" )
private String encoding;
/**
* Unconditionally excludes the specified packages and their subpackages from the list formed by
* -subpackages. Multiple packages can be separated by commas (,), colons (:)
* or semicolons (;).
*
* Example:
*
*
* See exclude.
*
* Since Java
* 1.4.
*/
@Parameter( property = "excludePackageNames" )
private String excludePackageNames;
/**
* Specifies the directories where extension classes reside. Separate directories in extdirs with a
* colon (:) or a semi-colon (;).
*
* See extdirs.
*/
@Parameter( property = "extdirs" )
private String extdirs;
/**
* Specifies the locale that javadoc uses when generating documentation.
*
* See locale.
*/
@Parameter( property = "locale" )
private String locale;
/**
* Specifies the maximum Java heap size to be used when launching the Javadoc tool.
* JVMs refer to this property as the -Xmx parameter. Example: '512' or '512m'.
* The memory unit depends on the JVM used. The units supported could be: k, kb,
* m, mb, g, gb, t, tb.
* If no unit specified, the default unit is m.
*/
@Parameter( property = "maxmemory" )
private String maxmemory;
/**
* Specifies the minimum Java heap size to be used when launching the Javadoc tool.
* JVMs refer to this property as the -Xms parameter. Example: '512' or '512m'.
* The memory unit depends on the JVM used. The units supported could be: k, kb,
* m, mb, g, gb, t, tb.
* If no unit specified, the default unit is m.
*/
@Parameter( property = "minmemory" )
private String minmemory;
/**
* This option creates documentation with the appearance and functionality of documentation generated by
* Javadoc 1.1.
*
* See 1.1.
*
*/
@Parameter( property = "old", defaultValue = "false" )
private boolean old;
/**
* Specifies that javadoc should retrieve the text for the overview documentation from the "source" file
* specified by path/filename and place it on the Overview page (overview-summary.html).
*
* Note: could be in conflict with <nooverview/>.
*
* See overview.
*
*/
@Parameter( property = "overview", defaultValue = "${basedir}/src/main/javadoc/overview.html" )
private File overview;
/**
* Shuts off non-error and non-warning messages, leaving only the warnings and errors appear, making them
* easier to view.
*
* Note: was a standard doclet in Java 1.4.2 (refer to bug ID
* 4714350).
*
* See quiet.
*
* Since Java 5.0.
*
*/
@Parameter( property = "quiet", defaultValue = "false" )
private boolean quiet;
/**
* Specifies the access level for classes and members to show in the Javadocs.
* Possible values are:
*
* <groups>
* <group>
* <title>Core Packages</title>
* <!-- To includes java.lang, java.lang.ref,
* java.lang.reflect and only java.util
* (i.e. not java.util.jar) -->
* <packages>java.lang*:java.util</packages>
* </group>
* <group>
* <title>Extension Packages</title>
* <!-- To include javax.accessibility,
* javax.crypto, ... (among others) -->
* <packages>javax.*</packages>
* </group>
* </groups>
*
* Note: using java.lang.* for packages would omit the java.lang
* package but using java.lang* will include it.
*
* See group.
*
* See Javadoc.
*
*/
@Parameter( property = "groups" )
private Group[] groups;
/**
* Specifies the header text to be placed at the top of each output file.
*
* See header.
*/
@Parameter( property = "header" )
private String header;
/**
* Specifies the path of an alternate help file path\filename that the HELP link in the top and bottom
* navigation bars link to.
*
* Note: could be in conflict with <nohelp/>.
*
* The helpfile could be an absolute File path.
*
* Since 2.6, it could be also be a path from a resource in the current project source directories
* (i.e. src/main/java, src/main/resources or src/main/javadoc)
* or from a resource in the Javadoc plugin dependencies, for instance:
*
* will be used because http://docs.oracle.com/javase/1.4.2/docs/api/package-list exists.
*
if {@link #detectLinks} is defined, the links between the project dependencies are
* automatically added.
*
if {@link #detectJavaApiLink} is defined, a Java API link, based on the Java version of the
* project's sources, will be added automatically.
*
* See link.
*
* @see #detectLinks
* @see #detectJavaApiLink
*/
@Parameter( property = "links" )
protected ArrayList links;
/**
* Creates an HTML version of each source file (with line numbers) and adds links to them from the standard
* HTML documentation.
*
* See
* linksource.
*
* Since Java
* 1.4.
*
*/
@Parameter( property = "linksource", defaultValue = "false" )
private boolean linksource;
/**
* Suppress the entire comment body, including the main description and all tags, generating only declarations.
*
* See nocomment.
*
* Since Java
* 1.4.
*
*/
@Parameter( property = "nocomment", defaultValue = "false" )
private boolean nocomment;
/**
* Prevents the generation of any deprecated API at all in the documentation.
*
* See
* nodeprecated.
*
*/
@Parameter( property = "nodeprecated", defaultValue = "false" )
private boolean nodeprecated;
/**
* Prevents the generation of the file containing the list of deprecated APIs (deprecated-list.html) and the
* link in the navigation bar to that page.
*
* See
* nodeprecatedlist.
*
*/
@Parameter( property = "nodeprecatedlist", defaultValue = "false" )
private boolean nodeprecatedlist;
/**
* Omits the HELP link in the navigation bars at the top and bottom of each page of output.
*
* Note: could be in conflict with <helpfile/>.
*
* See nohelp.
*
*/
@Parameter( property = "nohelp", defaultValue = "false" )
private boolean nohelp;
/**
* Omits the index from the generated docs.
*
* Note: could be in conflict with <splitindex/>.
*
* See noindex.
*
*/
@Parameter( property = "noindex", defaultValue = "false" )
private boolean noindex;
/**
* Omits the navigation bar from the generated docs.
*
* See nonavbar.
*
*/
@Parameter( property = "nonavbar", defaultValue = "false" )
private boolean nonavbar;
/**
* Omits the entire overview page from the generated docs.
*
* Note: could be in conflict with <overview/>.
*
* Standard Doclet undocumented option.
*
*
* @since 2.4
*/
@Parameter( property = "nooverview", defaultValue = "false" )
private boolean nooverview;
/**
* Omits qualifying package name from ahead of class names in output.
* Example:
*
* <noqualifier>all</noqualifier>
* or
* <noqualifier>packagename1:packagename2</noqualifier>
*
* See
* noqualifier.
*
* Since Java
* 1.4.
*/
@Parameter( property = "noqualifier" )
private String noqualifier;
/**
* Omits from the generated docs the "Since" sections associated with the since tags.
*
* See nosince.
*
*/
@Parameter( property = "nosince", defaultValue = "false" )
private boolean nosince;
/**
* Suppresses the timestamp, which is hidden in an HTML comment in the generated HTML near the top of each page.
*
* See
* notimestamp.
*
* Since
*
* Java 5.0.
*
*
* @since 2.1
*/
@Parameter( property = "notimestamp", defaultValue = "false" )
private boolean notimestamp;
/**
* Omits the class/interface hierarchy pages from the generated docs.
*
* See notree.
*
*/
@Parameter( property = "notree", defaultValue = "false" )
private boolean notree;
/**
* This option is a variation of -link; they both create links to javadoc-generated documentation
* for external referenced classes.
*
* See
* linkoffline.
*
* Example:
*
*
* Note: if {@link #detectOfflineLinks} is defined, the offline links between the project modules are
* automatically added if the goal is calling in a non-aggregator way.
*
* See Javadoc.
*
*/
@Parameter( property = "offlineLinks" )
private OfflineLink[] offlineLinks;
/**
* Specifies the destination directory where javadoc saves the generated HTML files.
*
* See d.
*
*/
@Parameter( property = "destDir", alias = "destDir", defaultValue = "${project.build.directory}/apidocs",
required = true )
protected File outputDirectory;
/**
* Specify the text for upper left frame.
*
* Since
*
* Java 1.4.2.
*
* @since 2.1
*/
@Parameter( property = "packagesheader" )
private String packagesheader;
/**
* Generates compile-time warnings for missing serial tags.
*
* See serialwarn
*
*/
@Parameter( property = "serialwarn", defaultValue = "false" )
private boolean serialwarn;
/**
* Specify the number of spaces each tab takes up in the source. If no tab is used in source, the default
* space is used.
*
* Note: was linksourcetab in Java 1.4.2 (refer to bug ID
* 4788919).
*
* Since
*
* 1.4.2.
*
* Since Java 5.0.
*
* @since 2.1
*/
@Parameter( property = "sourcetab", alias = "linksourcetab" )
private int sourcetab;
/**
* Splits the index file into multiple files, alphabetically, one file per letter, plus a file for any index
* entries that start with non-alphabetical characters.
*
* Note: could be in conflict with <noindex/>.
*
* See
* splitindex.
*
*/
@Parameter( property = "splitindex", defaultValue = "false" )
private boolean splitindex;
/**
* Specifies whether the stylesheet to be used is the maven's javadoc stylesheet or
* java's default stylesheet when a stylesheetfile parameter is not specified.
*
* Possible values: maven or java.
*
*/
@Parameter( property = "stylesheet", defaultValue = "java" )
private String stylesheet;
/**
* Specifies the path of an alternate HTML stylesheet file.
*
* The stylesheetfile could be an absolute File path.
*
* Since 2.6, it could be also be a path from a resource in the current project source directories
* (i.e. src/main/java, src/main/resources or src/main/javadoc)
* or from a resource in the Javadoc plugin dependencies, for instance:
*
* Where path/to/your/resource/yourstylesheet.css is defined in the
* groupId:artifactId:version javadoc plugin dependency.
*
* See
* stylesheetfile.
*/
@Parameter( property = "stylesheetfile" )
private String stylesheetfile;
/**
* Specifies the class file that starts the taglet used in generating the documentation for that tag.
*
* See taglet.
*
* Since
* Java 1.4.
*/
@Parameter( property = "taglet" )
private String taglet;
/**
* Specifies the Taglet artifact containing the taglet class files (.class).
*
* See
* tagletpath.
*
* Example:
*
*
* See Javadoc.
*
*
* @since 2.1
*/
@Parameter( property = "tagletArtifact" )
private TagletArtifact tagletArtifact;
/**
* Specifies several Taglet artifacts containing the taglet class files (.class). These taglets class names will be
* auto-detect and so no need to specify them.
*
* See taglet.
*
* See
* tagletpath.
*
* Example:
*
* Note: the placement should be a combinaison of Xaoptcmf letters:
*
*
X (disable tag)
*
a (all)
*
o (overview)
*
p (packages)
*
t (types, that is classes and interfaces)
*
c (constructors)
*
m (methods)
*
f (fields)
*
* See Javadoc.
*
*/
@Parameter( property = "tags" )
private Tag[] tags;
/**
* Specifies the top text to be placed at the top of each output file.
*
* See 6227616.
*
* Since Java 6.0
*
* @since 2.4
*/
@Parameter( property = "top" )
private String top;
/**
* Includes one "Use" page for each documented class and package.
*
* See use.
*
*/
@Parameter( property = "use", defaultValue = "true" )
private boolean use;
/**
* Includes the version text in the generated docs.
*
* See version.
*
*/
@Parameter( property = "version", defaultValue = "true" )
private boolean version;
/**
* Specifies the title to be placed in the HTML title tag.
*
* See
* windowtitle.
*
*/
@Parameter( property = "windowtitle", defaultValue = "${project.name} ${project.version} API" )
private String windowtitle;
/**
* Whether dependency -sources jars should be resolved and included as source paths for javadoc generation.
* This is useful when creating javadocs for a distribution project.
*
* @since 2.7
*/
@Parameter( defaultValue = "false" )
private boolean includeDependencySources;
/**
* Directory where unpacked project sources / test-sources should be cached.
*
* @see #includeDependencySources
* @since 2.7
*/
@Parameter( defaultValue = "${project.build.directory}/distro-javadoc-sources" )
private File sourceDependencyCacheDir;
/**
* Whether to include transitive dependencies in the list of dependency -sources jars to include
* in this javadoc run.
*
* @see #includeDependencySources
* @since 2.7
*/
@Parameter( defaultValue = "false" )
private boolean includeTransitiveDependencySources;
/**
* List of included dependency-source patterns. Example: org.apache.maven:*
*
* @see #includeDependencySources
* @since 2.7
*/
@Parameter
private List dependencySourceIncludes;
/**
* List of excluded dependency-source patterns. Example: org.apache.maven.shared:*
*
* @see #includeDependencySources
* @since 2.7
*/
@Parameter
private List dependencySourceExcludes;
/**
* Directory into which assembled {@link JavadocOptions} instances will be written before they
* are added to javadoc resources bundles.
*
* @since 2.7
*/
@Parameter( defaultValue = "${project.build.directory}/javadoc-bundle-options", readonly = true )
private File javadocOptionsDir;
/**
* Transient variable to allow lazy-resolution of javadoc bundles from dependencies, so they can
* be used at various points in the javadoc generation process.
*
* @since 2.7
*/
private transient List dependencyJavadocBundles;
/**
* Capability to add additional dependencies to the javadoc classpath.
* Example:
*
*
* @since 2.8.1
*/
@Parameter
private List additionalDependencies;
/**
* Include filters on the source files. Default is **\/\*.java.
* These are ignored if you specify subpackages or subpackage excludes.
*/
@Parameter
private List sourceFileIncludes;
/**
* exclude filters on the source files.
* These are ignored if you specify subpackages or subpackage excludes.
*/
@Parameter
private List sourceFileExcludes;
/**
* To apply the security fix on generated javadoc see http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-1571
* @since 2.9.1
*/
@Parameter( defaultValue = "true", property = "maven.javadoc.applyJavadocSecurityFix" )
private boolean applyJavadocSecurityFix = true;
/**
*
* Specify the requirements for this jdk toolchain.
* This overrules the toolchain selected by the maven-toolchain-plugin.
*
* note: requires at least Maven 3.3.1
*
* @since 3.0.0
*/
@Parameter
private Map jdkToolchain;
// ----------------------------------------------------------------------
// static
// ----------------------------------------------------------------------
static
{
DEFAULT_JAVA_API_LINKS.put( "api_1.5", "https://docs.oracle.com/javase/1.5.0/docs/api/" );
DEFAULT_JAVA_API_LINKS.put( "api_1.6", "https://docs.oracle.com/javase/6/docs/api/" );
DEFAULT_JAVA_API_LINKS.put( "api_1.7", "https://docs.oracle.com/javase/7/docs/api/" );
DEFAULT_JAVA_API_LINKS.put( "api_1.8", "https://docs.oracle.com/javase/8/docs/api/" );
DEFAULT_JAVA_API_LINKS.put( "api_9", "https://docs.oracle.com/javase/9/docs/api/" );
}
// ----------------------------------------------------------------------
// protected methods
// ----------------------------------------------------------------------
/**
* Indicates whether this goal is flagged with @aggregator.
*
* @return true if the goal is designed as an aggregator, false otherwise.
* @see AggregatorJavadocReport
* @see AggregatorTestJavadocReport
*/
protected boolean isAggregator()
{
return false;
}
/**
* Indicates whether this goal generates documentation for the Java Test code.
*
* @return true if the goal generates Test Javadocs, false otherwise.
*/
protected boolean isTest()
{
return false;
}
/**
* @return the output directory
*/
protected String getOutputDirectory()
{
return outputDirectory.getAbsoluteFile().toString();
}
protected MavenProject getProject()
{
return project;
}
/**
* @param p not null maven project
* @return the list of directories where compiled classes are placed for the given project. These dirs are
* added in the javadoc classpath.
*/
protected List getProjectBuildOutputDirs( MavenProject p )
{
if ( StringUtils.isEmpty( p.getBuild().getOutputDirectory() ) )
{
return Collections.emptyList();
}
return Collections.singletonList( new File( p.getBuild().getOutputDirectory() ) );
}
/**
* @param p not null maven project
* @return the list of source paths for the given project
*/
protected List getProjectSourceRoots( MavenProject p )
{
if ( "pom".equals( p.getPackaging().toLowerCase() ) )
{
return Collections.emptyList();
}
return ( p.getCompileSourceRoots() == null
? Collections.emptyList()
: new LinkedList<>( p.getCompileSourceRoots() ) );
}
/**
* @param p not null maven project
* @return the list of source paths for the execution project of the given project
*/
protected List getExecutionProjectSourceRoots( MavenProject p )
{
if ( "pom".equals( p.getExecutionProject().getPackaging().toLowerCase() ) )
{
return Collections.emptyList();
}
return ( p.getExecutionProject().getCompileSourceRoots() == null
? Collections.emptyList()
: new LinkedList<>( p.getExecutionProject().getCompileSourceRoots() ) );
}
/**
* @return the current javadoc directory
*/
protected File getJavadocDirectory()
{
return javadocDirectory;
}
/**
* @return the doclint specific checks configuration
*/
protected String getDoclint()
{
return doclint;
}
/**
* @return the title to be placed near the top of the overview summary file
*/
protected String getDoctitle()
{
return doctitle;
}
/**
* @return the overview documentation file from the user parameter or from the javadocdirectory
*/
protected File getOverview()
{
return overview;
}
/**
* @return the title to be placed in the HTML title tag
*/
protected String getWindowtitle()
{
return windowtitle;
}
/**
* @return the charset attribute or the value of {@link #getDocencoding()} if null.
*/
private String getCharset()
{
return ( StringUtils.isEmpty( charset ) ) ? getDocencoding() : charset;
}
/**
* @return the docencoding attribute or UTF-8 if null.
*/
private String getDocencoding()
{
return ( StringUtils.isEmpty( docencoding ) ) ? ReaderFactory.UTF_8 : docencoding;
}
/**
* @return the encoding attribute or the value of file.encoding system property if null.
*/
private String getEncoding()
{
return ( StringUtils.isEmpty( encoding ) ) ? ReaderFactory.FILE_ENCODING : encoding;
}
@Override
public void execute()
throws MojoExecutionException, MojoFailureException
{
verifyRemovedParameter( "aggregator" );
verifyRemovedParameter( "proxyHost" );
verifyRemovedParameter( "proxyPort" );
verifyReplacedParameter( "additionalparam", "additionalOptions" );
doExecute();
}
abstract void doExecute() throws MojoExecutionException, MojoFailureException;
protected final void verifyRemovedParameter( String paramName )
{
Object pluginConfiguration = mojo.getConfiguration();
if ( pluginConfiguration instanceof Xpp3Dom )
{
Xpp3Dom configDom = (Xpp3Dom) pluginConfiguration;
if ( configDom.getChild( paramName ) != null )
{
throw new IllegalArgumentException( "parameter '" + paramName
+ "' has been removed from the plugin, please verify documentation." );
}
}
}
private void verifyReplacedParameter( String oldParamName, String newParamNew )
{
Object pluginConfiguration = mojo.getConfiguration();
if ( pluginConfiguration instanceof Xpp3Dom )
{
Xpp3Dom configDom = (Xpp3Dom) pluginConfiguration;
if ( configDom.getChild( oldParamName ) != null )
{
throw new IllegalArgumentException( "parameter '" + oldParamName
+ "' has been replaced with " + newParamNew + ", please verify documentation." );
}
}
}
/**
* The package documentation details the
* Javadoc Options used by this Plugin.
*
* @param unusedLocale the wanted locale (actually unused).
* @throws MavenReportException if any
*/
protected void executeReport( Locale unusedLocale )
throws MavenReportException
{
if ( skip )
{
getLog().info( "Skipping javadoc generation" );
return;
}
if ( isAggregator() && !project.isExecutionRoot() )
{
return;
}
if ( getLog().isDebugEnabled() )
{
this.debug = true;
}
// NOTE: Always generate this file, to allow javadocs from modules to be aggregated via
// useDependencySources in a distro module build.
try
{
buildJavadocOptions();
}
catch ( IOException e )
{
throw new MavenReportException( "Failed to generate javadoc options file: " + e.getMessage(), e );
}
Map> sourcePaths = getSourcePaths();
Collection collectedSourcePaths = collect( sourcePaths.values() );
List files = getFiles( collectedSourcePaths );
if ( !canGenerateReport( files ) )
{
return;
}
List packageNames = getPackageNames( collectedSourcePaths, files );
List filesWithUnnamedPackages = getFilesWithUnnamedPackages( collectedSourcePaths, files );
// ----------------------------------------------------------------------
// Find the javadoc executable and version
// ----------------------------------------------------------------------
String jExecutable;
try
{
jExecutable = getJavadocExecutable();
}
catch ( IOException e )
{
throw new MavenReportException( "Unable to find javadoc command: " + e.getMessage(), e );
}
setFJavadocVersion( new File( jExecutable ) );
// ----------------------------------------------------------------------
// Javadoc output directory as File
// ----------------------------------------------------------------------
File javadocOutputDirectory = new File( getOutputDirectory() );
if ( javadocOutputDirectory.exists() && !javadocOutputDirectory.isDirectory() )
{
throw new MavenReportException( "IOException: " + getOutputDirectory() + " is not a directory." );
}
if ( javadocOutputDirectory.exists() && !javadocOutputDirectory.canWrite() )
{
throw new MavenReportException( "IOException: " + getOutputDirectory() + " is not writable." );
}
javadocOutputDirectory.mkdirs();
// ----------------------------------------------------------------------
// Copy all resources
// ----------------------------------------------------------------------
copyAllResources( javadocOutputDirectory );
// ----------------------------------------------------------------------
// Create command line for Javadoc
// ----------------------------------------------------------------------
Commandline cmd = new Commandline();
cmd.getShell().setQuotedArgumentsEnabled( false ); // for Javadoc JVM args
cmd.setWorkingDirectory( javadocOutputDirectory.getAbsolutePath() );
cmd.setExecutable( jExecutable );
// ----------------------------------------------------------------------
// Wrap Javadoc JVM args
// ----------------------------------------------------------------------
addMemoryArg( cmd, "-Xmx", this.maxmemory );
addMemoryArg( cmd, "-Xms", this.minmemory );
addProxyArg( cmd );
if ( StringUtils.isNotEmpty( additionalJOption ) )
{
cmd.createArg().setValue( additionalJOption );
}
if ( additionalJOptions != null && additionalJOptions.length != 0 )
{
for ( String jo : additionalJOptions )
{
cmd.createArg().setValue( jo );
}
}
List arguments = new ArrayList<>();
// ----------------------------------------------------------------------
// Wrap Javadoc options
// ----------------------------------------------------------------------
addJavadocOptions( javadocOutputDirectory, arguments, sourcePaths );
// ----------------------------------------------------------------------
// Wrap Standard doclet Options
// ----------------------------------------------------------------------
if ( StringUtils.isEmpty( doclet ) || useStandardDocletOptions )
{
addStandardDocletOptions( javadocOutputDirectory, arguments );
}
// ----------------------------------------------------------------------
// Write options file and include it in the command line
// ----------------------------------------------------------------------
if ( arguments.size() > 0 )
{
addCommandLineOptions( cmd, arguments, javadocOutputDirectory );
}
// ----------------------------------------------------------------------
// Write packages file and include it in the command line
// ----------------------------------------------------------------------
// MJAVADOC-365 if includes/excludes are specified, these take precedence over the default
// package-based mode and force javadoc into file-based mode unless subpackages are
// specified. Subpackages take precedence over file-based include/excludes. Why? Because
// getFiles(...) returns an empty list when subpackages are specified.
boolean includesExcludesActive =
( sourceFileIncludes != null && !sourceFileIncludes.isEmpty() )
|| ( sourceFileExcludes != null && !sourceFileExcludes.isEmpty() );
if ( includesExcludesActive && !StringUtils.isEmpty( subpackages ) )
{
getLog().warn( "sourceFileIncludes and sourceFileExcludes have no effect when subpackages are specified!" );
includesExcludesActive = false;
}
if ( !packageNames.isEmpty() && !includesExcludesActive )
{
addCommandLinePackages( cmd, javadocOutputDirectory, packageNames );
// ----------------------------------------------------------------------
// Write argfile file and include it in the command line
// ----------------------------------------------------------------------
if ( !filesWithUnnamedPackages.isEmpty() )
{
addCommandLineArgFile( cmd, javadocOutputDirectory, filesWithUnnamedPackages );
}
}
else
{
// ----------------------------------------------------------------------
// Write argfile file and include it in the command line
// ----------------------------------------------------------------------
if ( !files.isEmpty() )
{
addCommandLineArgFile( cmd, javadocOutputDirectory, files );
}
}
// ----------------------------------------------------------------------
// Execute command line
// ----------------------------------------------------------------------
executeJavadocCommandLine( cmd, javadocOutputDirectory );
// delete generated javadoc files only if no error and no debug mode
// [MJAVADOC-336] Use File.delete() instead of File.deleteOnExit() to
// prevent these files from making their way into archives.
if ( !debug )
{
for ( int i = 0; i < cmd.getArguments().length; i++ )
{
String arg = cmd.getArguments()[i].trim();
if ( !arg.startsWith( "@" ) )
{
continue;
}
File argFile = new File( javadocOutputDirectory, arg.substring( 1 ) );
if ( argFile.exists() )
{
argFile.delete();
}
}
File scriptFile = new File( javadocOutputDirectory, DEBUG_JAVADOC_SCRIPT_NAME );
if ( scriptFile.exists() )
{
scriptFile.delete();
}
}
if ( applyJavadocSecurityFix )
{
// finally, patch the Javadoc vulnerability in older Javadoc tools (CVE-2013-1571):
try
{
final int patched = fixFrameInjectionBug( javadocOutputDirectory, getDocencoding() );
if ( patched > 0 )
{
getLog().info(
String.format( "Fixed Javadoc frame injection vulnerability (CVE-2013-1571) in %d files.",
patched ) );
}
}
catch ( IOException e )
{
throw new MavenReportException( "Failed to patch javadocs vulnerability: " + e.getMessage(), e );
}
}
else
{
getLog().info( "applying javadoc security fix has been disabled" );
}
}
protected final Collection collect( Collection> sourcePaths )
{
Collection collectedSourcePaths = new LinkedHashSet<>();
for ( Collection sp : sourcePaths )
{
collectedSourcePaths.addAll( sp );
}
return collectedSourcePaths;
}
/**
* Method to get the files on the specified source paths
*
* @param sourcePaths a Collection that contains the paths to the source files
* @return a List that contains the specific path for every source file
* @throws MavenReportException {@link MavenReportException}
*/
protected List getFiles( Collection sourcePaths )
throws MavenReportException
{
List files = new ArrayList<>();
if ( StringUtils.isEmpty( subpackages ) )
{
String[] excludedPackages = getExcludedPackages();
for ( String sourcePath : sourcePaths )
{
File sourceDirectory = new File( sourcePath );
JavadocUtil.addFilesFromSource( files, sourceDirectory, sourceFileIncludes, sourceFileExcludes,
excludedPackages );
}
}
return files;
}
/**
* Method to get the source paths. If no source path is specified in the parameter, the compile source roots
* of the project will be used.
*
* @return a Collection of the project absolute source paths as String
* @throws MavenReportException {@link MavenReportException}
* @see JavadocUtil#pruneDirs(MavenProject, List)
*/
protected Map> getSourcePaths()
throws MavenReportException
{
Map> mappedSourcePaths = new LinkedHashMap<>();
if ( StringUtils.isEmpty( sourcepath ) )
{
Set sourcePaths =
new LinkedHashSet<>( JavadocUtil.pruneDirs( project, getProjectSourceRoots( project ) ) );
if ( project.getExecutionProject() != null )
{
sourcePaths.addAll( JavadocUtil.pruneDirs( project, getExecutionProjectSourceRoots( project ) ) );
}
/*
* Should be after the source path (i.e. -sourcepath '.../src/main/java;.../src/main/javadoc') and
* *not* the opposite. If not, the javadoc tool always copies doc files, even if -docfilessubdirs is
* not setted.
*/
if ( getJavadocDirectory() != null )
{
File javadocDir = getJavadocDirectory();
if ( javadocDir.exists() && javadocDir.isDirectory() )
{
Collection l = JavadocUtil.pruneDirs( project, Collections.singletonList(
getJavadocDirectory().getAbsolutePath() ) );
sourcePaths.addAll( l );
}
}
mappedSourcePaths.put( ArtifactUtils.versionlessKey( project.getGroupId(), project.getArtifactId() ),
sourcePaths );
if ( includeDependencySources )
{
mappedSourcePaths.putAll( getDependencySourcePaths() );
}
if ( isAggregator() && project.isExecutionRoot() )
{
for ( MavenProject subProject : reactorProjects )
{
if ( subProject != project )
{
Collection additionalSourcePaths = new ArrayList<>();
List sourceRoots = getProjectSourceRoots( subProject );
if ( subProject.getExecutionProject() != null )
{
sourceRoots.addAll( getExecutionProjectSourceRoots( subProject ) );
}
ArtifactHandler artifactHandler = subProject.getArtifact().getArtifactHandler();
if ( "java".equals( artifactHandler.getLanguage() ) )
{
additionalSourcePaths.addAll( JavadocUtil.pruneDirs( subProject, sourceRoots ) );
}
if ( getJavadocDirectory() != null )
{
String javadocDirRelative =
PathUtils.toRelative( project.getBasedir(),
getJavadocDirectory().getAbsolutePath() );
File javadocDir = new File( subProject.getBasedir(), javadocDirRelative );
if ( javadocDir.exists() && javadocDir.isDirectory() )
{
Collection l = JavadocUtil.pruneDirs( subProject, Collections.singletonList(
javadocDir.getAbsolutePath() ) );
additionalSourcePaths.addAll( l );
}
}
mappedSourcePaths.put( ArtifactUtils.versionlessKey( subProject.getGroupId(),
subProject.getArtifactId() ),
additionalSourcePaths );
}
}
}
}
else
{
Collection sourcePaths = new ArrayList<>( Arrays.asList( JavadocUtil.splitPath( sourcepath ) ) );
sourcePaths = JavadocUtil.pruneDirs( project, sourcePaths );
if ( getJavadocDirectory() != null )
{
Collection l = JavadocUtil.pruneDirs( project, Collections.singletonList(
getJavadocDirectory().getAbsolutePath() ) );
sourcePaths.addAll( l );
}
mappedSourcePaths.put( ArtifactUtils.versionlessKey( project.getGroupId(), project.getArtifactId() ),
sourcePaths );
}
return mappedSourcePaths;
}
/**
* Override this method to customize the configuration for resolving dependency sources. The default
* behavior enables the resolution of -sources jar files.
* @param config {@linke SourceResolverConfig}
* @return {@link SourceResolverConfig}
*/
protected SourceResolverConfig configureDependencySourceResolution( final SourceResolverConfig config )
{
return config.withCompileSources();
}
/**
* Resolve dependency sources so they can be included directly in the javadoc process. To customize this,
* override {@link AbstractJavadocMojo#configureDependencySourceResolution(SourceResolverConfig)}.
* @return List of source paths.
* @throws MavenReportException {@link MavenReportException}
*/
protected final Map> getDependencySourcePaths()
throws MavenReportException
{
try
{
if ( sourceDependencyCacheDir.exists() )
{
FileUtils.forceDelete( sourceDependencyCacheDir );
sourceDependencyCacheDir.mkdirs();
}
}
catch ( IOException e )
{
throw new MavenReportException(
"Failed to delete cache directory: " + sourceDependencyCacheDir + "\nReason: " + e.getMessage(), e );
}
final SourceResolverConfig config = getDependencySourceResolverConfig();
final List andFilters = new ArrayList<>();
final List dependencyIncludes = dependencySourceIncludes;
final List dependencyExcludes = dependencySourceExcludes;
if ( !includeTransitiveDependencySources || isNotEmpty( dependencyIncludes ) || isNotEmpty(
dependencyExcludes ) )
{
if ( !includeTransitiveDependencySources )
{
andFilters.add( createDependencyArtifactFilter() );
}
if ( isNotEmpty( dependencyIncludes ) )
{
andFilters.add( new PatternInclusionsFilter( dependencyIncludes ) );
}
if ( isNotEmpty( dependencyExcludes ) )
{
andFilters.add( new PatternExclusionsFilter( dependencyExcludes ) );
}
config.withFilter( new AndFilter( andFilters ) );
}
try
{
return resourceResolver.resolveDependencySourcePaths( config );
}
catch ( final ArtifactResolutionException e )
{
throw new MavenReportException(
"Failed to resolve one or more javadoc source/resource artifacts:\n\n" + e.getMessage(), e );
}
catch ( final ArtifactNotFoundException e )
{
throw new MavenReportException(
"Failed to resolve one or more javadoc source/resource artifacts:\n\n" + e.getMessage(), e );
}
}
/**
* Returns a ArtifactFilter that only includes direct dependencies of this project
* (verified via groupId and artifactId).
*
* @return
*/
private TransformableFilter createDependencyArtifactFilter()
{
Set dependencyArtifacts = project.getDependencyArtifacts();
List artifactPatterns = new ArrayList<>( dependencyArtifacts.size() );
for ( Artifact artifact : dependencyArtifacts )
{
artifactPatterns.add( artifact.getGroupId() + ":" + artifact.getArtifactId() );
}
return new PatternInclusionsFilter( artifactPatterns );
}
/**
* Construct a SourceResolverConfig for resolving dependency sources and resources in a consistent
* way, so it can be reused for both source and resource resolution.
*
* @since 2.7
*/
private SourceResolverConfig getDependencySourceResolverConfig()
{
return configureDependencySourceResolution(
new SourceResolverConfig( project, session.getProjectBuildingRequest(),
sourceDependencyCacheDir ).withReactorProjects( reactorProjects ) );
}
/**
* Method that indicates whether the javadoc can be generated or not. If the project does not contain any source
* files and no subpackages are specified, the plugin will terminate.
*
* @param files the project files
* @return a boolean that indicates whether javadoc report can be generated or not
*/
protected boolean canGenerateReport( List files )
{
boolean canGenerate = true;
if ( files.isEmpty() && StringUtils.isEmpty( subpackages ) )
{
canGenerate = false;
}
return canGenerate;
}
// ----------------------------------------------------------------------
// private methods
// ----------------------------------------------------------------------
/**
* Method to get the excluded source files from the javadoc and create the argument string
* that will be included in the javadoc commandline execution.
*
* @param sourcePaths the collection of paths to the source files
* @return a String that contains the exclude argument that will be used by javadoc
* @throws MavenReportException
*/
private String getExcludedPackages( Collection sourcePaths )
throws MavenReportException
{
List excludedNames = null;
if ( StringUtils.isNotEmpty( sourcepath ) && StringUtils.isNotEmpty( subpackages ) )
{
String[] excludedPackages = getExcludedPackages();
String[] subpackagesList = subpackages.split( "[:]" );
excludedNames = JavadocUtil.getExcludedNames( sourcePaths, subpackagesList, excludedPackages );
}
String excludeArg = "";
if ( StringUtils.isNotEmpty( subpackages ) && excludedNames != null )
{
// add the excludedpackage names
excludeArg = StringUtils.join( excludedNames.iterator(), ":" );
}
return excludeArg;
}
/**
* Method to format the specified source paths that will be accepted by the javadoc tool.
*
* @param sourcePaths the list of paths to the source files that will be included in the javadoc.
* @return a String that contains the formatted source path argument, separated by the System pathSeparator
* string (colon (:) on Solaris or semi-colon (;) on Windows).
* @see File#pathSeparator
*/
private String getSourcePath( Collection sourcePaths )
{
String sourcePath = null;
if ( StringUtils.isEmpty( subpackages ) || StringUtils.isNotEmpty( sourcepath ) )
{
sourcePath = StringUtils.join( sourcePaths.iterator(), File.pathSeparator );
}
return sourcePath;
}
/**
* Method to get the packages specified in the excludePackageNames parameter. The packages are split
* with ',', ':', or ';' and then formatted.
*
* @return an array of String objects that contain the package names
* @throws MavenReportException
*/
private String[] getExcludedPackages()
throws MavenReportException
{
Set excluded = new LinkedHashSet<>();
if ( includeDependencySources )
{
try
{
resolveDependencyBundles();
}
catch ( IOException e )
{
throw new MavenReportException(
"Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
}
if ( isNotEmpty( dependencyJavadocBundles ) )
{
for ( JavadocBundle bundle : dependencyJavadocBundles )
{
JavadocOptions options = bundle.getOptions();
if ( options != null && isNotEmpty( options.getExcludePackageNames() ) )
{
excluded.addAll( options.getExcludePackageNames() );
}
}
}
}
// for the specified excludePackageNames
if ( StringUtils.isNotEmpty( excludePackageNames ) )
{
List packageNames = Arrays.asList( excludePackageNames.split( "[,:;]" ) );
excluded.addAll( trimValues( packageNames ) );
}
String[] result = new String[excluded.size()];
if ( isNotEmpty( excluded ) )
{
int idx = 0;
for ( String exclude : excluded )
{
result[idx] = exclude.replace( '.', File.separatorChar );
idx++;
}
}
return result;
}
private static List trimValues( List items )
{
List result = new ArrayList<>( items.size() );
for ( String item : items )
{
String trimmed = item.trim();
if ( StringUtils.isEmpty( trimmed ) )
{
continue;
}
result.add( trimmed );
}
return result;
}
/**
* Method that gets the classpath and modulepath elements that will be specified in the javadoc
* -classpath and --module-path parameter.
* Since we have all the sources of the current reactor, it is sufficient to consider the
* dependencies of the reactor modules, excluding the module artifacts which may not yet be available
* when the reactor project is built for the first time.
*
* @return all classpath elements
* @throws MavenReportException if any.
*/
private List getPathElements()
throws MavenReportException
{
List classpathElements = new ArrayList<>();
Map compileArtifactMap = new HashMap<>();
if ( isTest() )
{
classpathElements.addAll( getProjectBuildOutputDirs( project ) );
}
populateCompileArtifactMap( compileArtifactMap, project.getArtifacts() );
if ( isAggregator() && project.isExecutionRoot() )
{
List reactorArtifacts = new ArrayList<>();
for ( MavenProject p : reactorProjects )
{
reactorArtifacts.add( p.getGroupId() + ':' + p.getArtifactId() );
}
TransformableFilter dependencyFilter = new AndFilter( Arrays.asList(
new PatternExclusionsFilter( reactorArtifacts ),
getDependencyScopeFilter() ) );
for ( MavenProject subProject : reactorProjects )
{
if ( subProject != project )
{
classpathElements.addAll( getProjectBuildOutputDirs( subProject ) );
try
{
StringBuilder sb = new StringBuilder();
sb.append( "Compiled artifacts for " );
sb.append( subProject.getGroupId() ).append( ":" );
sb.append( subProject.getArtifactId() ).append( ":" );
sb.append( subProject.getVersion() ).append( '\n' );
ProjectBuildingRequest buildingRequest = session.getProjectBuildingRequest();
buildingRequest =
buildingRequest.setRemoteRepositories( subProject.getRemoteArtifactRepositories() );
for ( ArtifactResult artifactResult
: dependencyResolver.resolveDependencies( buildingRequest,
subProject.getDependencies(),
null,
dependencyFilter ) )
{
populateCompileArtifactMap( compileArtifactMap,
Collections.singletonList( artifactResult.getArtifact() ) );
sb.append( artifactResult.getArtifact().getFile() ).append( '\n' );
}
if ( getLog().isDebugEnabled() )
{
getLog().debug( sb.toString() );
}
}
catch ( DependencyResolverException e )
{
throw new MavenReportException( e.getMessage(), e );
}
}
}
}
for ( Artifact a : compileArtifactMap.values() )
{
classpathElements.add( a.getFile() );
}
if ( additionalDependencies != null )
{
for ( Dependency dependency : additionalDependencies )
{
Artifact artifact = resolveDependency( dependency );
getLog().debug( "add additional artifact with path " + artifact.getFile() );
classpathElements.add( artifact.getFile() );
}
}
return classpathElements;
}
protected ScopeFilter getDependencyScopeFilter()
{
return ScopeFilter.including( Artifact.SCOPE_COMPILE, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_SYSTEM );
}
/**
* @param dependency {@link Dependency}
* @return {@link Artifact}
* @throws MavenReportException
*/
public Artifact resolveDependency( Dependency dependency )
throws MavenReportException
{
DefaultArtifactCoordinate coordinate = new DefaultArtifactCoordinate();
coordinate.setGroupId( dependency.getGroupId() );
coordinate.setArtifactId( dependency.getArtifactId() );
coordinate.setVersion( dependency.getVersion() );
coordinate.setClassifier( dependency.getClassifier() );
coordinate.setExtension( artifactHandlerManager.getArtifactHandler( dependency.getType() ).getExtension() );
try
{
return artifactResolver.resolveArtifact( session.getProjectBuildingRequest(), coordinate ).getArtifact();
}
catch ( ArtifactResolverException e )
{
throw new MavenReportException( "artifact resolver problem - " + e.getMessage(), e );
}
}
//TODO remove the part with ToolchainManager lookup once we depend on
//3.0.9 (have it as prerequisite). Define as regular component field then.
protected final Toolchain getToolchain()
{
Toolchain tc = null;
if ( jdkToolchain != null )
{
// Maven 3.3.1 has plugin execution scoped Toolchain Support
try
{
Method getToolchainsMethod =
toolchainManager.getClass().getMethod( "getToolchains", MavenSession.class, String.class,
Map.class );
@SuppressWarnings( "unchecked" )
List tcs =
(List) getToolchainsMethod.invoke( toolchainManager, session, "jdk",
jdkToolchain );
if ( tcs != null && tcs.size() > 0 )
{
tc = tcs.get( 0 );
}
}
catch ( NoSuchMethodException e )
{
// ignore
}
catch ( SecurityException e )
{
// ignore
}
catch ( IllegalAccessException e )
{
// ignore
}
catch ( IllegalArgumentException e )
{
// ignore
}
catch ( InvocationTargetException e )
{
// ignore
}
}
if ( tc == null )
{
tc = toolchainManager.getToolchainFromBuildContext( "jdk", session );
}
return tc;
}
/**
* Method to put the artifacts in the hashmap.
*
* @param compileArtifactMap the hashmap that will contain the artifacts
* @param artifactList the list of artifacts that will be put in the map
* @throws MavenReportException if any
*/
private void populateCompileArtifactMap( Map compileArtifactMap,
Collection artifactList )
throws MavenReportException
{
if ( artifactList == null )
{
return;
}
for ( Artifact newArtifact : artifactList )
{
File file = newArtifact.getFile();
if ( file == null )
{
throw new MavenReportException(
"Error in plugin descriptor - " + "dependency was not resolved for artifact: "
+ newArtifact.getGroupId() + ":" + newArtifact.getArtifactId() + ":"
+ newArtifact.getVersion() );
}
if ( compileArtifactMap.get( newArtifact.getDependencyConflictId() ) != null )
{
Artifact oldArtifact = compileArtifactMap.get( newArtifact.getDependencyConflictId() );
ArtifactVersion oldVersion = new DefaultArtifactVersion( oldArtifact.getVersion() );
ArtifactVersion newVersion = new DefaultArtifactVersion( newArtifact.getVersion() );
if ( newVersion.compareTo( oldVersion ) > 0 )
{
compileArtifactMap.put( newArtifact.getDependencyConflictId(), newArtifact );
}
}
else
{
compileArtifactMap.put( newArtifact.getDependencyConflictId(), newArtifact );
}
}
}
/**
* Method that sets the bottom text that will be displayed on the bottom of the
* javadocs.
*
* @return a String that contains the text that will be displayed at the bottom of the javadoc
*/
private String getBottomText()
{
int currentYear = Calendar.getInstance().get( Calendar.YEAR );
String year = String.valueOf( currentYear );
String inceptionYear = project.getInceptionYear();
String theBottom = StringUtils.replace( this.bottom, "{currentYear}", year );
if ( inceptionYear != null )
{
if ( inceptionYear.equals( year ) )
{
theBottom = StringUtils.replace( theBottom, "{inceptionYear}–", "" );
}
else
{
theBottom = StringUtils.replace( theBottom, "{inceptionYear}", inceptionYear );
}
}
else
{
theBottom = StringUtils.replace( theBottom, "{inceptionYear}–", "" );
}
if ( project.getOrganization() == null )
{
theBottom = StringUtils.replace( theBottom, " {organizationName}", "" );
}
else
{
if ( StringUtils.isNotEmpty( project.getOrganization().getName() ) )
{
if ( StringUtils.isNotEmpty( project.getOrganization().getUrl() ) )
{
theBottom = StringUtils.replace( theBottom, "{organizationName}",
""
+ project.getOrganization().getName() + "" );
}
else
{
theBottom =
StringUtils.replace( theBottom, "{organizationName}", project.getOrganization().getName() );
}
}
else
{
theBottom = StringUtils.replace( theBottom, " {organizationName}", "" );
}
}
return theBottom;
}
/**
* Method to get the stylesheet path file to be used by the Javadoc Tool.
*
* If the {@link #stylesheetfile} is empty, return the file as String definded by {@link #stylesheet} value.
*
* If the {@link #stylesheetfile} is defined, return the file as String.
*
* Note: since 2.6, the {@link #stylesheetfile} could be a path from a resource in the project source
* directories (i.e. src/main/java, src/main/resources or src/main/javadoc)
* or from a resource in the Javadoc plugin dependencies.
*
* @param javadocOutputDirectory the output directory
* @return the stylesheet file absolute path as String.
* @see #getResource(List, String)
*/
private String getStylesheetFile( final File javadocOutputDirectory )
{
if ( StringUtils.isEmpty( stylesheetfile ) )
{
if ( "java".equalsIgnoreCase( stylesheet ) )
{
// use the default Javadoc tool stylesheet
return null;
}
// maven, see #copyDefaultStylesheet(File)
return new File( javadocOutputDirectory, DEFAULT_CSS_NAME ).getAbsolutePath();
}
if ( new File( stylesheetfile ).exists() )
{
return new File( stylesheetfile ).getAbsolutePath();
}
return getResource( new File( javadocOutputDirectory, DEFAULT_CSS_NAME ), stylesheetfile );
}
/**
* Method to get the help file to be used by the Javadoc Tool.
*
* Since 2.6, the {@link #helpfile} could be a path from a resource in the project source
* directories (i.e. src/main/java, src/main/resources or src/main/javadoc)
* or from a resource in the Javadoc plugin dependencies.
*
* @param javadocOutputDirectory the output directory.
* @return the help file absolute path as String.
* @see #getResource(File, String)
* @since 2.6
*/
private String getHelpFile( final File javadocOutputDirectory )
{
if ( StringUtils.isEmpty( helpfile ) )
{
return null;
}
if ( new File( helpfile ).exists() )
{
return new File( helpfile ).getAbsolutePath();
}
return getResource( new File( javadocOutputDirectory, "help-doc.html" ), helpfile );
}
/**
* Method to get the access level for the classes and members to be shown in the generated javadoc.
* If the specified access level is not public, protected, package or private, the access level
* is set to protected.
*
* @return the access level
*/
private String getAccessLevel()
{
String accessLevel;
if ( "public".equalsIgnoreCase( show ) || "protected".equalsIgnoreCase( show ) || "package".equalsIgnoreCase(
show ) || "private".equalsIgnoreCase( show ) )
{
accessLevel = "-" + show;
}
else
{
if ( getLog().isErrorEnabled() )
{
getLog().error( "Unrecognized access level to show '" + show + "'. Defaulting to protected." );
}
accessLevel = "-protected";
}
return accessLevel;
}
/**
* Method to get the path of the bootclass artifacts used in the -bootclasspath option.
*
* @return a string that contains bootclass path, separated by the System pathSeparator string
* (colon (:) on Solaris or semi-colon (;) on Windows).
* @throws MavenReportException if any
* @see File#pathSeparator
*/
private String getBootclassPath()
throws MavenReportException
{
Set bootclasspathArtifacts = collectBootClasspathArtifacts();
List bootclassPath = new ArrayList<>();
for ( BootclasspathArtifact aBootclasspathArtifact : bootclasspathArtifacts )
{
if ( ( StringUtils.isNotEmpty( aBootclasspathArtifact.getGroupId() ) ) && ( StringUtils.isNotEmpty(
aBootclasspathArtifact.getArtifactId() ) ) && ( StringUtils.isNotEmpty(
aBootclasspathArtifact.getVersion() ) ) )
{
bootclassPath.addAll( getArtifactsAbsolutePath( aBootclasspathArtifact ) );
}
}
bootclassPath = JavadocUtil.pruneFiles( bootclassPath );
StringBuilder path = new StringBuilder();
path.append( StringUtils.join( bootclassPath.iterator(), File.pathSeparator ) );
if ( StringUtils.isNotEmpty( bootclasspath ) )
{
path.append( JavadocUtil.unifyPathSeparator( bootclasspath ) );
}
return path.toString();
}
/**
* Method to get the path of the doclet artifacts used in the -docletpath option.
*
* Either docletArtifact or doclectArtifacts can be defined and used, not both, docletArtifact
* takes precedence over doclectArtifacts. docletPath is always appended to any result path
* definition.
*
* @return a string that contains doclet path, separated by the System pathSeparator string
* (colon (:) on Solaris or semi-colon (;) on Windows).
* @throws MavenReportException if any
* @see File#pathSeparator
*/
private String getDocletPath()
throws MavenReportException
{
Set docletArtifacts = collectDocletArtifacts();
List pathParts = new ArrayList<>();
for ( DocletArtifact docletArtifact : docletArtifacts )
{
if ( !isDocletArtifactEmpty( docletArtifact ) )
{
pathParts.addAll( getArtifactsAbsolutePath( docletArtifact ) );
}
}
if ( !StringUtils.isEmpty( docletPath ) )
{
pathParts.add( JavadocUtil.unifyPathSeparator( docletPath ) );
}
String path = StringUtils.join( pathParts.iterator(), File.pathSeparator );
if ( StringUtils.isEmpty( path ) && getLog().isWarnEnabled() )
{
getLog().warn( "No docletpath option was found. Please review or "
+ " or ." );
}
return path;
}
/**
* Verify if a doclet artifact is empty or not
*
* @param aDocletArtifact could be null
* @return true if aDocletArtifact or the groupId/artifactId/version of the doclet artifact is null,
* false otherwise.
*/
private boolean isDocletArtifactEmpty( DocletArtifact aDocletArtifact )
{
if ( aDocletArtifact == null )
{
return true;
}
return StringUtils.isEmpty( aDocletArtifact.getGroupId() ) && StringUtils.isEmpty(
aDocletArtifact.getArtifactId() ) && StringUtils.isEmpty( aDocletArtifact.getVersion() );
}
/**
* Method to get the path of the taglet artifacts used in the -tagletpath option.
*
* @return a string that contains taglet path, separated by the System pathSeparator string
* (colon (:) on Solaris or semi-colon (;) on Windows).
* @throws MavenReportException if any
* @see File#pathSeparator
*/
private String getTagletPath()
throws MavenReportException
{
Set tArtifacts = collectTagletArtifacts();
Collection pathParts = new ArrayList<>();
for ( TagletArtifact tagletArtifact : tArtifacts )
{
if ( ( tagletArtifact != null ) && ( StringUtils.isNotEmpty( tagletArtifact.getGroupId() ) )
&& ( StringUtils.isNotEmpty( tagletArtifact.getArtifactId() ) ) && ( StringUtils.isNotEmpty(
tagletArtifact.getVersion() ) ) )
{
pathParts.addAll( getArtifactsAbsolutePath( tagletArtifact ) );
}
}
Set taglets = collectTaglets();
for ( Taglet taglet : taglets )
{
if ( taglet == null )
{
continue;
}
if ( ( taglet.getTagletArtifact() != null ) && ( StringUtils.isNotEmpty(
taglet.getTagletArtifact().getGroupId() ) ) && ( StringUtils.isNotEmpty(
taglet.getTagletArtifact().getArtifactId() ) ) && ( StringUtils.isNotEmpty(
taglet.getTagletArtifact().getVersion() ) ) )
{
pathParts.addAll( getArtifactsAbsolutePath( taglet.getTagletArtifact() ) );
pathParts = JavadocUtil.pruneFiles( pathParts );
}
else if ( StringUtils.isNotEmpty( taglet.getTagletpath() ) )
{
pathParts.add( taglet.getTagletpath() );
pathParts = JavadocUtil.pruneDirs( project, pathParts );
}
}
StringBuilder path = new StringBuilder();
path.append( StringUtils.join( pathParts.iterator(), File.pathSeparator ) );
if ( StringUtils.isNotEmpty( tagletpath ) )
{
path.append( JavadocUtil.unifyPathSeparator( tagletpath ) );
}
return path.toString();
}
private Set collectLinks()
throws MavenReportException
{
Set links = new LinkedHashSet<>();
if ( includeDependencySources )
{
try
{
resolveDependencyBundles();
}
catch ( IOException e )
{
throw new MavenReportException(
"Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
}
if ( isNotEmpty( dependencyJavadocBundles ) )
{
for ( JavadocBundle bundle : dependencyJavadocBundles )
{
JavadocOptions options = bundle.getOptions();
if ( options != null && isNotEmpty( options.getLinks() ) )
{
links.addAll( options.getLinks() );
}
}
}
}
if ( isNotEmpty( this.links ) )
{
links.addAll( this.links );
}
links.addAll( getDependenciesLinks() );
return links;
}
private Set collectGroups()
throws MavenReportException
{
Set groups = new LinkedHashSet<>();
if ( includeDependencySources )
{
try
{
resolveDependencyBundles();
}
catch ( IOException e )
{
throw new MavenReportException(
"Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
}
if ( isNotEmpty( dependencyJavadocBundles ) )
{
for ( JavadocBundle bundle : dependencyJavadocBundles )
{
JavadocOptions options = bundle.getOptions();
if ( options != null && isNotEmpty( options.getGroups() ) )
{
groups.addAll( options.getGroups() );
}
}
}
}
if ( this.groups != null && this.groups.length > 0 )
{
groups.addAll( Arrays.asList( this.groups ) );
}
return groups;
}
private Set collectResourcesArtifacts()
throws MavenReportException
{
Set result = new LinkedHashSet<>();
if ( includeDependencySources )
{
try
{
resolveDependencyBundles();
}
catch ( IOException e )
{
throw new MavenReportException(
"Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
}
if ( isNotEmpty( dependencyJavadocBundles ) )
{
for ( JavadocBundle bundle : dependencyJavadocBundles )
{
JavadocOptions options = bundle.getOptions();
if ( options != null && isNotEmpty( options.getResourcesArtifacts() ) )
{
result.addAll( options.getResourcesArtifacts() );
}
}
}
}
if ( this.resourcesArtifacts != null && this.resourcesArtifacts.length > 0 )
{
result.addAll( Arrays.asList( this.resourcesArtifacts ) );
}
return result;
}
private Set collectBootClasspathArtifacts()
throws MavenReportException
{
Set result = new LinkedHashSet<>();
if ( includeDependencySources )
{
try
{
resolveDependencyBundles();
}
catch ( IOException e )
{
throw new MavenReportException(
"Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
}
if ( isNotEmpty( dependencyJavadocBundles ) )
{
for ( JavadocBundle bundle : dependencyJavadocBundles )
{
JavadocOptions options = bundle.getOptions();
if ( options != null && isNotEmpty( options.getBootclasspathArtifacts() ) )
{
result.addAll( options.getBootclasspathArtifacts() );
}
}
}
}
if ( this.bootclasspathArtifacts != null && this.bootclasspathArtifacts.length > 0 )
{
result.addAll( Arrays.asList( this.bootclasspathArtifacts ) );
}
return result;
}
private Set collectOfflineLinks()
throws MavenReportException
{
Set result = new LinkedHashSet<>();
OfflineLink javaApiLink = getDefaultJavadocApiLink();
if ( javaApiLink != null )
{
result.add( javaApiLink );
}
if ( includeDependencySources )
{
try
{
resolveDependencyBundles();
}
catch ( IOException e )
{
throw new MavenReportException(
"Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
}
if ( isNotEmpty( dependencyJavadocBundles ) )
{
for ( JavadocBundle bundle : dependencyJavadocBundles )
{
JavadocOptions options = bundle.getOptions();
if ( options != null && isNotEmpty( options.getOfflineLinks() ) )
{
result.addAll( options.getOfflineLinks() );
}
}
}
}
if ( this.offlineLinks != null && this.offlineLinks.length > 0 )
{
result.addAll( Arrays.asList( this.offlineLinks ) );
}
return result;
}
private Set collectTags()
throws MavenReportException
{
Set tags = new LinkedHashSet<>();
if ( includeDependencySources )
{
try
{
resolveDependencyBundles();
}
catch ( IOException e )
{
throw new MavenReportException(
"Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
}
if ( isNotEmpty( dependencyJavadocBundles ) )
{
for ( JavadocBundle bundle : dependencyJavadocBundles )
{
JavadocOptions options = bundle.getOptions();
if ( options != null && isNotEmpty( options.getTags() ) )
{
tags.addAll( options.getTags() );
}
}
}
}
if ( this.tags != null && this.tags.length > 0 )
{
tags.addAll( Arrays.asList( this.tags ) );
}
return tags;
}
private Set collectTagletArtifacts()
throws MavenReportException
{
Set tArtifacts = new LinkedHashSet<>();
if ( includeDependencySources )
{
try
{
resolveDependencyBundles();
}
catch ( IOException e )
{
throw new MavenReportException(
"Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
}
if ( isNotEmpty( dependencyJavadocBundles ) )
{
for ( JavadocBundle bundle : dependencyJavadocBundles )
{
JavadocOptions options = bundle.getOptions();
if ( options != null && isNotEmpty( options.getTagletArtifacts() ) )
{
tArtifacts.addAll( options.getTagletArtifacts() );
}
}
}
}
if ( tagletArtifact != null )
{
tArtifacts.add( tagletArtifact );
}
if ( tagletArtifacts != null && tagletArtifacts.length > 0 )
{
tArtifacts.addAll( Arrays.asList( tagletArtifacts ) );
}
return tArtifacts;
}
private Set collectDocletArtifacts()
throws MavenReportException
{
Set dArtifacts = new LinkedHashSet<>();
if ( includeDependencySources )
{
try
{
resolveDependencyBundles();
}
catch ( IOException e )
{
throw new MavenReportException(
"Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
}
if ( isNotEmpty( dependencyJavadocBundles ) )
{
for ( JavadocBundle bundle : dependencyJavadocBundles )
{
JavadocOptions options = bundle.getOptions();
if ( options != null && isNotEmpty( options.getDocletArtifacts() ) )
{
dArtifacts.addAll( options.getDocletArtifacts() );
}
}
}
}
if ( docletArtifact != null )
{
dArtifacts.add( docletArtifact );
}
if ( docletArtifacts != null && docletArtifacts.length > 0 )
{
dArtifacts.addAll( Arrays.asList( docletArtifacts ) );
}
return dArtifacts;
}
private Set collectTaglets()
throws MavenReportException
{
Set result = new LinkedHashSet<>();
if ( includeDependencySources )
{
try
{
resolveDependencyBundles();
}
catch ( IOException e )
{
throw new MavenReportException(
"Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
}
if ( isNotEmpty( dependencyJavadocBundles ) )
{
for ( JavadocBundle bundle : dependencyJavadocBundles )
{
JavadocOptions options = bundle.getOptions();
if ( options != null && isNotEmpty( options.getTaglets() ) )
{
result.addAll( options.getTaglets() );
}
}
}
}
if ( taglets != null && taglets.length > 0 )
{
result.addAll( Arrays.asList( taglets ) );
}
return result;
}
/**
* Return the Javadoc artifact path and its transitive dependencies path from the local repository
*
* @param javadocArtifact not null
* @return a list of locale artifacts absolute path
* @throws MavenReportException if any
*/
private List getArtifactsAbsolutePath( JavadocPathArtifact javadocArtifact )
throws MavenReportException
{
if ( ( StringUtils.isEmpty( javadocArtifact.getGroupId() ) ) && ( StringUtils.isEmpty(
javadocArtifact.getArtifactId() ) ) && ( StringUtils.isEmpty( javadocArtifact.getVersion() ) ) )
{
return Collections.emptyList();
}
List path = new ArrayList<>();
try
{
Artifact artifact = createAndResolveArtifact( javadocArtifact );
path.add( artifact.getFile().getAbsolutePath() );
DefaultDependableCoordinate coordinate = new DefaultDependableCoordinate();
coordinate.setGroupId( javadocArtifact.getGroupId() );
coordinate.setArtifactId( javadocArtifact.getArtifactId() );
coordinate.setVersion( javadocArtifact.getVersion() );
Iterable deps =
dependencyResolver.resolveDependencies( session.getProjectBuildingRequest(), coordinate,
ScopeFilter.including( "compile", "provided" ) );
for ( ArtifactResult a : deps )
{
path.add( a.getArtifact().getFile().getAbsolutePath() );
}
return path;
}
catch ( ArtifactResolverException e )
{
throw new MavenReportException( "Unable to resolve artifact:" + javadocArtifact, e );
}
catch ( DependencyResolverException e )
{
throw new MavenReportException( "Unable to resolve dependencies for:" + javadocArtifact, e );
}
}
/**
* creates an {@link Artifact} representing the configured {@link JavadocPathArtifact} and resolves it.
*
* @param javadocArtifact the {@link JavadocPathArtifact} to resolve
* @return a resolved {@link Artifact}
* @throws ArtifactResolverException
*/
private Artifact createAndResolveArtifact( JavadocPathArtifact javadocArtifact )
throws ArtifactResolverException
{
DefaultArtifactCoordinate coordinate = new DefaultArtifactCoordinate();
coordinate.setGroupId( javadocArtifact.getGroupId() );
coordinate.setArtifactId( javadocArtifact.getArtifactId() );
coordinate.setVersion( javadocArtifact.getVersion() );
return artifactResolver.resolveArtifact( session.getProjectBuildingRequest(), coordinate ).getArtifact();
}
/**
* Method that adds/sets the java memory parameters in the command line execution.
*
* @param cmd the command line execution object where the argument will be added
* @param arg the argument parameter name
* @param memory the JVM memory value to be set
* @see JavadocUtil#parseJavadocMemory(String)
*/
private void addMemoryArg( Commandline cmd, String arg, String memory )
{
if ( StringUtils.isNotEmpty( memory ) )
{
try
{
cmd.createArg().setValue( "-J" + arg + JavadocUtil.parseJavadocMemory( memory ) );
}
catch ( IllegalArgumentException e )
{
if ( getLog().isErrorEnabled() )
{
getLog().error( "Malformed memory pattern for '" + arg + memory + "'. Ignore this option." );
}
}
}
}
/**
* Method that adds/sets the javadoc proxy parameters in the command line execution.
*
* @param cmd the command line execution object where the argument will be added
*/
private void addProxyArg( Commandline cmd )
{
if ( settings == null || settings.getActiveProxy() == null )
{
return;
}
Proxy activeProxy = settings.getActiveProxy();
String protocol = StringUtils.isNotEmpty( activeProxy.getProtocol() ) ? activeProxy.getProtocol() + "." : "";
if ( StringUtils.isNotEmpty( activeProxy.getHost() ) )
{
cmd.createArg().setValue( "-J-D" + protocol + "proxySet=true" );
cmd.createArg().setValue( "-J-D" + protocol + "proxyHost=" + activeProxy.getHost() );
if ( activeProxy.getPort() > 0 )
{
cmd.createArg().setValue( "-J-D" + protocol + "proxyPort=" + activeProxy.getPort() );
}
if ( StringUtils.isNotEmpty( activeProxy.getNonProxyHosts() ) )
{
cmd.createArg().setValue(
"-J-D" + protocol + "nonProxyHosts=\"" + activeProxy.getNonProxyHosts() + "\"" );
}
if ( StringUtils.isNotEmpty( activeProxy.getUsername() ) )
{
cmd.createArg().setValue( "-J-Dhttp.proxyUser=\"" + activeProxy.getUsername() + "\"" );
if ( StringUtils.isNotEmpty( activeProxy.getPassword() ) )
{
cmd.createArg().setValue( "-J-Dhttp.proxyPassword=\"" + activeProxy.getPassword() + "\"" );
}
}
}
}
/**
* Get the path of the Javadoc tool executable depending the user entry or try to find it depending the OS
* or the java.home system property or the JAVA_HOME environment variable.
*
* @return the path of the Javadoc tool
* @throws IOException if not found
*/
private String getJavadocExecutable()
throws IOException
{
Toolchain tc = getToolchain();
if ( tc != null )
{
getLog().info( "Toolchain in maven-javadoc-plugin: " + tc );
if ( javadocExecutable != null )
{
getLog().warn( "Toolchains are ignored, 'javadocExecutable' parameter is set to " + javadocExecutable );
}
else
{
javadocExecutable = tc.findTool( "javadoc" );
}
}
String javadocCommand = "javadoc" + ( SystemUtils.IS_OS_WINDOWS ? ".exe" : "" );
File javadocExe;
// ----------------------------------------------------------------------
// The javadoc executable is defined by the user
// ----------------------------------------------------------------------
if ( StringUtils.isNotEmpty( javadocExecutable ) )
{
javadocExe = new File( javadocExecutable );
if ( javadocExe.isDirectory() )
{
javadocExe = new File( javadocExe, javadocCommand );
}
if ( SystemUtils.IS_OS_WINDOWS && javadocExe.getName().indexOf( '.' ) < 0 )
{
javadocExe = new File( javadocExe.getPath() + ".exe" );
}
if ( !javadocExe.isFile() )
{
throw new IOException( "The javadoc executable '" + javadocExe
+ "' doesn't exist or is not a file. Verify the parameter." );
}
return javadocExe.getAbsolutePath();
}
// ----------------------------------------------------------------------
// Try to find javadocExe from System.getProperty( "java.home" )
// By default, System.getProperty( "java.home" ) = JRE_HOME and JRE_HOME
// should be in the JDK_HOME
// ----------------------------------------------------------------------
// For IBM's JDK 1.2
if ( SystemUtils.IS_OS_AIX )
{
javadocExe =
new File( SystemUtils.getJavaHome() + File.separator + ".." + File.separator + "sh", javadocCommand );
}
// For Apple's JDK 1.6.x (and older?) on Mac OSX
// CHECKSTYLE_OFF: MagicNumber
else if ( SystemUtils.IS_OS_MAC_OSX && !SystemUtils.isJavaVersionAtLeast( JavaVersion.JAVA_1_7 ) )
// CHECKSTYLE_ON: MagicNumber
{
javadocExe = new File( SystemUtils.getJavaHome() + File.separator + "bin", javadocCommand );
}
else
{
javadocExe =
new File( SystemUtils.getJavaHome() + File.separator + ".." + File.separator + "bin", javadocCommand );
}
// ----------------------------------------------------------------------
// Try to find javadocExe from JAVA_HOME environment variable
// ----------------------------------------------------------------------
if ( !javadocExe.exists() || !javadocExe.isFile() )
{
Properties env = CommandLineUtils.getSystemEnvVars();
String javaHome = env.getProperty( "JAVA_HOME" );
if ( StringUtils.isEmpty( javaHome ) )
{
throw new IOException( "The environment variable JAVA_HOME is not correctly set." );
}
if ( ( !new File( javaHome ).getCanonicalFile().exists() )
|| ( new File( javaHome ).getCanonicalFile().isFile() ) )
{
throw new IOException( "The environment variable JAVA_HOME=" + javaHome
+ " doesn't exist or is not a valid directory." );
}
javadocExe = new File( javaHome + File.separator + "bin", javadocCommand );
}
if ( !javadocExe.getCanonicalFile().exists() || !javadocExe.getCanonicalFile().isFile() )
{
throw new IOException( "The javadoc executable '" + javadocExe
+ "' doesn't exist or is not a file. Verify the JAVA_HOME environment variable." );
}
return javadocExe.getAbsolutePath();
}
/**
* Set a new value for javadocRuntimeVersion
*
* @param jExecutable not null
* @throws MavenReportException if not found
* @see JavadocUtil#getJavadocVersion(File)
*/
private void setFJavadocVersion( File jExecutable )
throws MavenReportException
{
JavadocVersion jVersion;
try
{
jVersion = JavadocUtil.getJavadocVersion( jExecutable );
}
catch ( IOException e )
{
if ( getLog().isWarnEnabled() )
{
getLog().warn( "Unable to find the javadoc version: " + e.getMessage() );
getLog().warn( "Using the Java version instead of, i.e. " + JAVA_VERSION );
}
jVersion = JAVA_VERSION;
}
catch ( CommandLineException e )
{
if ( getLog().isWarnEnabled() )
{
getLog().warn( "Unable to find the javadoc version: " + e.getMessage() );
getLog().warn( "Using the Java version instead of, i.e. " + JAVA_VERSION );
}
jVersion = JAVA_VERSION;
}
catch ( IllegalArgumentException e )
{
if ( getLog().isWarnEnabled() )
{
getLog().warn( "Unable to find the javadoc version: " + e.getMessage() );
getLog().warn( "Using the Java version instead of, i.e. " + JAVA_VERSION );
}
jVersion = JAVA_VERSION;
}
if ( StringUtils.isNotEmpty( javadocVersion ) )
{
try
{
javadocRuntimeVersion = JavadocVersion.parse( javadocVersion );
}
catch ( NumberFormatException e )
{
throw new MavenReportException( "Unable to parse javadoc version: " + e.getMessage(), e );
}
if ( javadocRuntimeVersion != jVersion && getLog().isWarnEnabled() )
{
getLog().warn( "Are you sure about the parameter? It seems to be " + jVersion );
}
}
else
{
javadocRuntimeVersion = jVersion;
}
}
/**
* Is the Javadoc version at least the requested version.
*
* @param requiredVersion the required version, for example 1.5f
* @return true if the javadoc version is equal or greater than the
* required version
*/
private boolean isJavaDocVersionAtLeast( JavadocVersion requiredVersion )
{
return JAVA_VERSION.compareTo( requiredVersion ) >= 0;
}
/**
* Convenience method to add an argument to the command line
* conditionally based on the given flag.
*
* @param arguments a list of arguments, not null
* @param b the flag which controls if the argument is added or not.
* @param value the argument value to be added.
*/
private void addArgIf( List arguments, boolean b, String value )
{
if ( b )
{
arguments.add( value );
}
}
/**
* Convenience method to add an argument to the command line
* regarding the requested Java version.
*
* @param arguments a list of arguments, not null
* @param b the flag which controls if the argument is added or not.
* @param value the argument value to be added.
* @param requiredJavaVersion the required Java version, for example 1.31f or 1.4f
* @see #addArgIf(java.util.List, boolean, String)
* @see #isJavaDocVersionAtLeast(float)
*/
private void addArgIf( List arguments, boolean b, String value, JavadocVersion requiredJavaVersion )
{
if ( b )
{
if ( isJavaDocVersionAtLeast( requiredJavaVersion ) )
{
addArgIf( arguments, true, value );
}
else
{
if ( getLog().isWarnEnabled() )
{
getLog().warn( value + " option is not supported on Java version < " + requiredJavaVersion
+ ". Ignore this option." );
}
}
}
}
/**
* Convenience method to add an argument to the command line
* if the the value is not null or empty.
*
* Moreover, the value could be comma separated.
*
* @param arguments a list of arguments, not null
* @param key the argument name.
* @param value the argument value to be added.
* @see #addArgIfNotEmpty(java.util.List, String, String, boolean)
*/
private void addArgIfNotEmpty( List arguments, String key, String value )
{
addArgIfNotEmpty( arguments, key, value, false );
}
/**
* Convenience method to add an argument to the command line
* if the the value is not null or empty.
*
* Moreover, the value could be comma separated.
*
* @param arguments a list of arguments, not null
* @param key the argument name.
* @param value the argument value to be added.
* @param repeatKey repeat or not the key in the command line
* @param splitValue if true given value will be tokenized by comma
* @param requiredJavaVersion the required Java version, for example 1.31f or 1.4f
* @see #addArgIfNotEmpty(List, String, String, boolean, boolean)
* @see #isJavaDocVersionAtLeast(float)
*/
private void addArgIfNotEmpty( List arguments, String key, String value, boolean repeatKey,
boolean splitValue, JavadocVersion requiredJavaVersion )
{
if ( StringUtils.isNotEmpty( value ) )
{
if ( isJavaDocVersionAtLeast( requiredJavaVersion ) )
{
addArgIfNotEmpty( arguments, key, value, repeatKey, splitValue );
}
else
{
if ( getLog().isWarnEnabled() )
{
getLog().warn( key + " option is not supported on Java version < " + requiredJavaVersion
+ ". Ignore this option." );
}
}
}
}
/**
* Convenience method to add an argument to the command line
* if the the value is not null or empty.
*
* Moreover, the value could be comma separated.
*
* @param arguments a list of arguments, not null
* @param key the argument name.
* @param value the argument value to be added.
* @param repeatKey repeat or not the key in the command line
* @param splitValue if true given value will be tokenized by comma
*/
private void addArgIfNotEmpty( List arguments, String key, String value, boolean repeatKey,
boolean splitValue )
{
if ( StringUtils.isNotEmpty( value ) )
{
if ( StringUtils.isNotEmpty( key ) )
{
arguments.add( key );
}
if ( splitValue )
{
StringTokenizer token = new StringTokenizer( value, "," );
while ( token.hasMoreTokens() )
{
String current = token.nextToken().trim();
if ( StringUtils.isNotEmpty( current ) )
{
arguments.add( current );
if ( token.hasMoreTokens() && repeatKey )
{
arguments.add( key );
}
}
}
}
else
{
arguments.add( value );
}
}
}
/**
* Convenience method to add an argument to the command line
* if the the value is not null or empty.
*
* Moreover, the value could be comma separated.
*
* @param arguments a list of arguments, not null
* @param key the argument name.
* @param value the argument value to be added.
* @param repeatKey repeat or not the key in the command line
*/
private void addArgIfNotEmpty( List arguments, String key, String value, boolean repeatKey )
{
addArgIfNotEmpty( arguments, key, value, repeatKey, true );
}
/**
* Convenience method to add an argument to the command line
* regarding the requested Java version.
*
* @param arguments a list of arguments, not null
* @param key the argument name.
* @param value the argument value to be added.
* @param requiredJavaVersion the required Java version, for example 1.31f or 1.4f
* @see #addArgIfNotEmpty(java.util.List, String, String, float, boolean)
*/
private void addArgIfNotEmpty( List arguments, String key, String value,
JavadocVersion requiredJavaVersion )
{
addArgIfNotEmpty( arguments, key, value, requiredJavaVersion, false );
}
/**
* Convenience method to add an argument to the command line
* regarding the requested Java version.
*
* @param arguments a list of arguments, not null
* @param key the argument name.
* @param value the argument value to be added.
* @param requiredJavaVersion the required Java version, for example 1.31f or 1.4f
* @param repeatKey repeat or not the key in the command line
* @see #addArgIfNotEmpty(java.util.List, String, String)
* @see #isJavaDocVersionAtLeast(float)
*/
private void addArgIfNotEmpty( List arguments, String key, String value, JavadocVersion requiredJavaVersion,
boolean repeatKey )
{
if ( StringUtils.isNotEmpty( value ) )
{
if ( isJavaDocVersionAtLeast( requiredJavaVersion ) )
{
addArgIfNotEmpty( arguments, key, value, repeatKey );
}
else
{
if ( getLog().isWarnEnabled() )
{
getLog().warn( key + " option is not supported on Java version < " + requiredJavaVersion );
}
}
}
}
/**
* Convenience method to process {@link #offlineLinks} values as individual -linkoffline
* javadoc options.
*
* If {@link #detectOfflineLinks}, try to add javadoc apidocs according Maven conventions for all modules given
* in the project.
*
* @param arguments a list of arguments, not null
* @throws MavenReportException if any
* @see #offlineLinks
* @see #getModulesLinks()
* @see package-list spec
*/
private void addLinkofflineArguments( List arguments )
throws MavenReportException
{
Set offlineLinksList = collectOfflineLinks();
offlineLinksList.addAll( getModulesLinks() );
for ( OfflineLink offlineLink : offlineLinksList )
{
String url = offlineLink.getUrl();
if ( StringUtils.isEmpty( url ) )
{
continue;
}
url = cleanUrl( url );
String location = offlineLink.getLocation();
if ( StringUtils.isEmpty( location ) )
{
continue;
}
if ( isValidJavadocLink( location, false ) )
{
addArgIfNotEmpty( arguments, "-linkoffline",
JavadocUtil.quotedPathArgument( url ) + " " + JavadocUtil.quotedPathArgument(
location ), true );
}
}
}
/**
* Convenience method to process {@link #links} values as individual -link javadoc options.
* If {@link #detectLinks}, try to add javadoc apidocs according Maven conventions for all dependencies given
* in the project.
*
* According the Javadoc documentation, all defined link should have ${link}/package-list fetchable.
*
* Note: when a link is not fetchable:
*
*
Javadoc 1.4 and less throw an exception
*
Javadoc 1.5 and more display a warning
*
*
* @param arguments a list of arguments, not null
* @throws MavenReportException
* @see #detectLinks
* @see #getDependenciesLinks()
* @see package-list spec
*/
private void addLinkArguments( List arguments )
throws MavenReportException
{
Set links = collectLinks();
for ( String link : links )
{
if ( StringUtils.isEmpty( link ) )
{
continue;
}
while ( link.endsWith( "/" ) )
{
link = link.substring( 0, link.lastIndexOf( "/" ) );
}
addArgIfNotEmpty( arguments, "-link", JavadocUtil.quotedPathArgument( link ), true, false );
}
}
/**
* Coppy all resources to the output directory
*
* @param javadocOutputDirectory not null
* @throws MavenReportException if any
* @see #copyDefaultStylesheet(File)
* @see #copyJavadocResources(File)
* @see #copyAdditionalJavadocResources(File)
*/
private void copyAllResources( File javadocOutputDirectory )
throws MavenReportException
{
// ----------------------------------------------------------------------
// Copy default resources
// ----------------------------------------------------------------------
try
{
copyDefaultStylesheet( javadocOutputDirectory );
}
catch ( IOException e )
{
throw new MavenReportException( "Unable to copy default stylesheet: " + e.getMessage(), e );
}
// ----------------------------------------------------------------------
// Copy javadoc resources
// ----------------------------------------------------------------------
if ( docfilessubdirs )
{
/*
* Workaround since -docfilessubdirs doesn't seem to be used correctly by the javadoc tool
* (see other note about -sourcepath). Take care of the -excludedocfilessubdir option.
*/
try
{
copyJavadocResources( javadocOutputDirectory );
}
catch ( IOException e )
{
throw new MavenReportException( "Unable to copy javadoc resources: " + e.getMessage(), e );
}
}
// ----------------------------------------------------------------------
// Copy additional javadoc resources in artifacts
// ----------------------------------------------------------------------
copyAdditionalJavadocResources( javadocOutputDirectory );
}
/**
* Copies the {@link #DEFAULT_CSS_NAME} css file from the current class
* loader to the outputDirectory only if {@link #stylesheetfile} is empty and
* {@link #stylesheet} is equals to maven.
*
* @param anOutputDirectory the output directory
* @throws java.io.IOException if any
* @see #DEFAULT_CSS_NAME
* @see JavadocUtil#copyResource(java.net.URL, java.io.File)
*/
private void copyDefaultStylesheet( File anOutputDirectory )
throws IOException
{
if ( StringUtils.isNotEmpty( stylesheetfile ) )
{
return;
}
if ( !stylesheet.equalsIgnoreCase( "maven" ) )
{
return;
}
URL url = getClass().getClassLoader().getResource( RESOURCE_CSS_DIR + "/" + DEFAULT_CSS_NAME );
File outFile = new File( anOutputDirectory, DEFAULT_CSS_NAME );
JavadocUtil.copyResource( url, outFile );
}
/**
* Method that copy all doc-files directories from javadocDirectory of
* the current project or of the projects in the reactor to the outputDirectory.
*
* @param anOutputDirectory the output directory
* @throws java.io.IOException if any
* @see Reference
* Guide, Copies new "doc-files" directory for holding images and examples
* @see #docfilessubdirs
*/
private void copyJavadocResources( File anOutputDirectory )
throws IOException
{
if ( anOutputDirectory == null || !anOutputDirectory.exists() )
{
throw new IOException( "The outputDirectory " + anOutputDirectory + " doesn't exists." );
}
if ( includeDependencySources )
{
resolveDependencyBundles();
if ( isNotEmpty( dependencyJavadocBundles ) )
{
for ( JavadocBundle bundle : dependencyJavadocBundles )
{
File dir = bundle.getResourcesDirectory();
JavadocOptions options = bundle.getOptions();
if ( dir != null && dir.isDirectory() )
{
JavadocUtil.copyJavadocResources( anOutputDirectory, dir, options == null
? null
: options.getExcludedDocfilesSubdirs() );
}
}
}
}
if ( getJavadocDirectory() != null )
{
JavadocUtil.copyJavadocResources( anOutputDirectory, getJavadocDirectory(), excludedocfilessubdir );
}
if ( isAggregator() && project.isExecutionRoot() )
{
for ( MavenProject subProject : reactorProjects )
{
if ( subProject != project && getJavadocDirectory() != null )
{
String javadocDirRelative =
PathUtils.toRelative( project.getBasedir(), getJavadocDirectory().getAbsolutePath() );
File javadocDir = new File( subProject.getBasedir(), javadocDirRelative );
JavadocUtil.copyJavadocResources( anOutputDirectory, javadocDir, excludedocfilessubdir );
}
}
}
}
private synchronized void resolveDependencyBundles()
throws IOException
{
if ( dependencyJavadocBundles == null )
{
dependencyJavadocBundles =
resourceResolver.resolveDependencyJavadocBundles( getDependencySourceResolverConfig() );
if ( dependencyJavadocBundles == null )
{
dependencyJavadocBundles = new ArrayList<>();
}
}
}
/**
* Method that copy additional Javadoc resources from given artifacts.
*
* @param anOutputDirectory the output directory
* @throws MavenReportException if any
* @see #resourcesArtifacts
*/
private void copyAdditionalJavadocResources( File anOutputDirectory )
throws MavenReportException
{
Set resourcesArtifacts = collectResourcesArtifacts();
if ( isEmpty( resourcesArtifacts ) )
{
return;
}
UnArchiver unArchiver;
try
{
unArchiver = archiverManager.getUnArchiver( "jar" );
}
catch ( NoSuchArchiverException e )
{
throw new MavenReportException(
"Unable to extract resources artifact. " + "No archiver for 'jar' available.", e );
}
for ( ResourcesArtifact item : resourcesArtifacts )
{
Artifact artifact;
try
{
artifact = createAndResolveArtifact( item );
}
catch ( ArtifactResolverException e )
{
throw new MavenReportException( "Unable to resolve artifact:" + item, e );
}
unArchiver.setSourceFile( artifact.getFile() );
unArchiver.setDestDirectory( anOutputDirectory );
// remove the META-INF directory from resource artifact
IncludeExcludeFileSelector[] selectors =
new IncludeExcludeFileSelector[]{ new IncludeExcludeFileSelector() };
selectors[0].setExcludes( new String[]{ "META-INF/**" } );
unArchiver.setFileSelectors( selectors );
getLog().info( "Extracting contents of resources artifact: " + artifact.getArtifactId() );
try
{
unArchiver.extract();
}
catch ( ArchiverException e )
{
throw new MavenReportException(
"Extraction of resources failed. Artifact that failed was: " + artifact.getArtifactId(), e );
}
}
}
/**
* @param sourcePaths could be null
* @param files not null
* @return the list of package names for files in the sourcePaths
*/
private List getPackageNames( Collection sourcePaths, List files )
{
return getPackageNamesOrFilesWithUnnamedPackages( sourcePaths, files, true );
}
/**
* @param sourcePaths could be null
* @param files not null
* @return a list files with unnamed package names for files in the sourecPaths
*/
private List getFilesWithUnnamedPackages( Collection sourcePaths, List files )
{
return getPackageNamesOrFilesWithUnnamedPackages( sourcePaths, files, false );
}
/**
* @param sourcePaths not null, containing absolute and relative paths
* @param files not null, containing list of quoted files
* @param onlyPackageName boolean for only package name
* @return a list of package names or files with unnamed package names, depending the value of the unnamed flag
* @see #getFiles(List)
* @see #getSourcePaths()
*/
private List getPackageNamesOrFilesWithUnnamedPackages( Collection sourcePaths, List files,
boolean onlyPackageName )
{
List returnList = new ArrayList<>();
if ( !StringUtils.isEmpty( sourcepath ) )
{
return returnList;
}
for ( String currentFile : files )
{
currentFile = currentFile.replace( '\\', '/' );
for ( String currentSourcePath : sourcePaths )
{
currentSourcePath = currentSourcePath.replace( '\\', '/' );
if ( !currentSourcePath.endsWith( "/" ) )
{
currentSourcePath += "/";
}
if ( currentFile.contains( currentSourcePath ) )
{
String packagename = currentFile.substring( currentSourcePath.length() + 1 );
/*
* Remove the miscellaneous files
* http://docs.oracle.com/javase/1.4.2/docs/tooldocs/solaris/javadoc.html#unprocessed
*/
if ( packagename.contains( "doc-files" ) )
{
continue;
}
if ( onlyPackageName && packagename.lastIndexOf( "/" ) != -1 )
{
packagename = packagename.substring( 0, packagename.lastIndexOf( "/" ) );
packagename = packagename.replace( '/', '.' );
if ( !returnList.contains( packagename ) )
{
returnList.add( packagename );
}
}
if ( !onlyPackageName && packagename.lastIndexOf( "/" ) == -1 )
{
returnList.add( currentFile );
}
}
}
}
return returnList;
}
/**
* Generate an options file for all options and arguments and add the @options in the
* command line.
*
* @param cmd not null
* @param arguments not null
* @param javadocOutputDirectory not null
* @throws MavenReportException if any
* @see
* Reference Guide, Command line argument files
* @see #OPTIONS_FILE_NAME
*/
private void addCommandLineOptions( Commandline cmd, List arguments, File javadocOutputDirectory )
throws MavenReportException
{
File optionsFile = new File( javadocOutputDirectory, OPTIONS_FILE_NAME );
StringBuilder options = new StringBuilder();
options.append( StringUtils.join( arguments.toArray( new String[arguments.size()] ),
SystemUtils.LINE_SEPARATOR ) );
try
{
FileUtils.fileWrite( optionsFile.getAbsolutePath(), null /* platform encoding */, options.toString() );
}
catch ( IOException e )
{
throw new MavenReportException(
"Unable to write '" + optionsFile.getName() + "' temporary file for command execution", e );
}
cmd.createArg().setValue( "@" + OPTIONS_FILE_NAME );
}
/**
* Generate a file called argfile (or files, depending the JDK) to hold files and add
* the @argfile (or @file, depending the JDK) in the command line.
*
* @param cmd not null
* @param javadocOutputDirectory not null
* @param files not null
* @throws MavenReportException if any
* @see
* Reference Guide, Command line argument files
*
* @see
* What s New in Javadoc 1.4
*
* @see #isJavaDocVersionAtLeast(float)
* @see #ARGFILE_FILE_NAME
* @see #FILES_FILE_NAME
*/
private void addCommandLineArgFile( Commandline cmd, File javadocOutputDirectory, List files )
throws MavenReportException
{
File argfileFile;
if ( JAVA_VERSION.compareTo( SINCE_JAVADOC_1_4 ) >= 0 )
{
argfileFile = new File( javadocOutputDirectory, ARGFILE_FILE_NAME );
cmd.createArg().setValue( "@" + ARGFILE_FILE_NAME );
}
else
{
argfileFile = new File( javadocOutputDirectory, FILES_FILE_NAME );
cmd.createArg().setValue( "@" + FILES_FILE_NAME );
}
try
{
FileUtils.fileWrite( argfileFile.getAbsolutePath(), null /* platform encoding */,
StringUtils.join( files.iterator(), SystemUtils.LINE_SEPARATOR ) );
}
catch ( IOException e )
{
throw new MavenReportException(
"Unable to write '" + argfileFile.getName() + "' temporary file for command execution", e );
}
}
/**
* Generate a file called packages to hold all package names and add the @packages in
* the command line.
*
* @param cmd not null
* @param javadocOutputDirectory not null
* @param packageNames not null
* @throws MavenReportException if any
* @see
* Reference Guide, Command line argument files
* @see #PACKAGES_FILE_NAME
*/
private void addCommandLinePackages( Commandline cmd, File javadocOutputDirectory, List packageNames )
throws MavenReportException
{
File packagesFile = new File( javadocOutputDirectory, PACKAGES_FILE_NAME );
try
{
FileUtils.fileWrite( packagesFile.getAbsolutePath(), null /* platform encoding */,
StringUtils.join( packageNames.iterator(), SystemUtils.LINE_SEPARATOR ) );
}
catch ( IOException e )
{
throw new MavenReportException(
"Unable to write '" + packagesFile.getName() + "' temporary file for command execution", e );
}
cmd.createArg().setValue( "@" + PACKAGES_FILE_NAME );
}
/**
* Checks for the validity of the Javadoc options used by the user.
*
* @throws MavenReportException if error
*/
private void validateJavadocOptions()
throws MavenReportException
{
// encoding
if ( StringUtils.isNotEmpty( getEncoding() ) && !JavadocUtil.validateEncoding( getEncoding() ) )
{
throw new MavenReportException( "Unsupported option '" + getEncoding() + "'" );
}
// locale
if ( StringUtils.isNotEmpty( this.locale ) )
{
StringTokenizer tokenizer = new StringTokenizer( this.locale, "_" );
final int maxTokens = 3;
if ( tokenizer.countTokens() > maxTokens )
{
throw new MavenReportException(
"Unsupported option '" + this.locale + "', should be language_country_variant." );
}
Locale localeObject = null;
if ( tokenizer.hasMoreTokens() )
{
String language = tokenizer.nextToken().toLowerCase( Locale.ENGLISH );
if ( !Arrays.asList( Locale.getISOLanguages() ).contains( language ) )
{
throw new MavenReportException(
"Unsupported language '" + language + "' in option '" + this.locale + "'" );
}
localeObject = new Locale( language );
if ( tokenizer.hasMoreTokens() )
{
String country = tokenizer.nextToken().toUpperCase( Locale.ENGLISH );
if ( !Arrays.asList( Locale.getISOCountries() ).contains( country ) )
{
throw new MavenReportException(
"Unsupported country '" + country + "' in option '" + this.locale + "'" );
}
localeObject = new Locale( language, country );
if ( tokenizer.hasMoreTokens() )
{
String variant = tokenizer.nextToken();
localeObject = new Locale( language, country, variant );
}
}
}
if ( localeObject == null )
{
throw new MavenReportException(
"Unsupported option '" + this.locale + "', should be language_country_variant." );
}
this.locale = localeObject.toString();
final List availableLocalesList = Arrays.asList( Locale.getAvailableLocales() );
if ( StringUtils.isNotEmpty( localeObject.getVariant() ) && !availableLocalesList.contains( localeObject ) )
{
StringBuilder sb = new StringBuilder();
sb.append( "Unsupported option with variant '" ).append( this.locale );
sb.append( "'" );
localeObject = new Locale( localeObject.getLanguage(), localeObject.getCountry() );
this.locale = localeObject.toString();
sb.append( ", trying to use without variant, i.e. '" ).append( this.locale ).append( "'" );
if ( getLog().isWarnEnabled() )
{
getLog().warn( sb.toString() );
}
}
if ( !availableLocalesList.contains( localeObject ) )
{
throw new MavenReportException( "Unsupported option '" + this.locale + "'" );
}
}
}
/**
* Checks for the validity of the Standard Doclet options.
*
* For example, throw an exception if <nohelp/> and <helpfile/> options are used together.
*
* @throws MavenReportException if error or conflict found
*/
private void validateStandardDocletOptions()
throws MavenReportException
{
// docencoding
if ( StringUtils.isNotEmpty( getDocencoding() ) && !JavadocUtil.validateEncoding( getDocencoding() ) )
{
throw new MavenReportException( "Unsupported option '" + getDocencoding() + "'" );
}
// charset
if ( StringUtils.isNotEmpty( getCharset() ) && !JavadocUtil.validateEncoding( getCharset() ) )
{
throw new MavenReportException( "Unsupported option '" + getCharset() + "'" );
}
// helpfile
if ( StringUtils.isNotEmpty( helpfile ) && nohelp )
{
throw new MavenReportException( "Option conflicts with " );
}
// overview
if ( ( getOverview() != null ) && nooverview )
{
throw new MavenReportException( "Option conflicts with " );
}
// index
if ( splitindex && noindex )
{
throw new MavenReportException( "Option conflicts with " );
}
// stylesheet
if ( StringUtils.isNotEmpty( stylesheet ) && !( stylesheet.equalsIgnoreCase( "maven" )
|| stylesheet.equalsIgnoreCase( "java" ) ) )
{
throw new MavenReportException( "Option supports only \"maven\" or \"java\" value." );
}
// default java api links
if ( javaApiLinks == null || javaApiLinks.size() == 0 )
{
javaApiLinks = DEFAULT_JAVA_API_LINKS;
}
}
/**
* Add Standard Javadoc Options.
*
* The package documentation details the
* Standard Javadoc Options wrapped by this Plugin.
*
* @param javadocOutputDirectory not null
* @param arguments not null
* @param sourcePaths not null
* @throws MavenReportException if any
* @see http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#javadocoptions
*/
private void addJavadocOptions( File javadocOutputDirectory,
List arguments,
Map> allSourcePaths )
throws MavenReportException
{
Collection sourcePaths = collect( allSourcePaths.values() );
validateJavadocOptions();
// see com.sun.tools.javadoc.Start#parseAndExecute(String argv[])
addArgIfNotEmpty( arguments, "-locale", JavadocUtil.quotedArgument( this.locale ) );
// all options in alphabetical order
if ( old && isJavaDocVersionAtLeast( SINCE_JAVADOC_1_4 ) )
{
if ( getLog().isWarnEnabled() )
{
getLog().warn( "Javadoc 1.4+ doesn't support the -1.1 switch anymore. Ignore this option." );
}
}
else
{
addArgIf( arguments, old, "-1.1" );
}
addArgIfNotEmpty( arguments, "-bootclasspath", JavadocUtil.quotedPathArgument( getBootclassPath() ) );
if ( isJavaDocVersionAtLeast( SINCE_JAVADOC_1_5 ) )
{
addArgIf( arguments, breakiterator, "-breakiterator", SINCE_JAVADOC_1_5 );
}
List roots = getProjectSourceRoots( getProject() );
File mainDescriptor = findMainDescriptor( roots );
final LocationManager locationManager = new LocationManager();
if ( mainDescriptor != null && !isTest() )
{
ResolvePathsRequest request =
ResolvePathsRequest.withFiles( getPathElements() ).setMainModuleDescriptor( mainDescriptor );
try
{
ResolvePathsResult result = locationManager.resolvePaths( request );
String classpath = StringUtils.join( result.getClasspathElements().iterator(), File.pathSeparator );
addArgIfNotEmpty( arguments, "--class-path", JavadocUtil.quotedPathArgument( classpath ) );
Set modulePathElements = new HashSet<>( result.getModulepathElements().keySet() ) ;
if ( allSourcePaths.size() > 1 )
{
// Probably required due to bug in javadoc (Java 9+)
modulePathElements.addAll( getProjectBuildOutputDirs( getProject() ) );
}
String modulepath =
StringUtils.join( modulePathElements.iterator(), File.pathSeparator );
addArgIfNotEmpty( arguments, "--module-path", JavadocUtil.quotedPathArgument( modulepath ) );
}
catch ( IOException e )
{
throw new MavenReportException( e.getMessage(), e );
}
}
else
{
String classpath = StringUtils.join( getPathElements().iterator(), File.pathSeparator );
addArgIfNotEmpty( arguments, "-classpath", JavadocUtil.quotedPathArgument( classpath ) );
}
Collection reactorKeys = new HashSet<>( session.getProjects().size() );
for ( MavenProject reactorProject : session.getProjects() )
{
reactorKeys.add( ArtifactUtils.versionlessKey( reactorProject.getGroupId(),
reactorProject.getArtifactId() ) );
}
Path moduleSourceDir = null;
if ( allSourcePaths.size() > 1 )
{
for ( Map.Entry> projectSourcepaths : allSourcePaths.entrySet() )
{
if ( reactorKeys.contains( projectSourcepaths.getKey() ) )
{
File moduleDescriptor = findMainDescriptor( projectSourcepaths.getValue() );
if ( moduleDescriptor != null )
{
moduleSourceDir = javadocOutputDirectory.toPath().resolve( "src" );
try
{
moduleSourceDir = Files.createDirectories( moduleSourceDir );
ResolvePathsRequest request =
ResolvePathsRequest.withFiles( Collections.emptyList() )
.setMainModuleDescriptor( moduleDescriptor );
String moduleName =
locationManager.resolvePaths( request ).getMainModuleDescriptor().name();
addArgIfNotEmpty( arguments, "--patch-module", moduleName + '='
+ JavadocUtil.quotedPathArgument( getSourcePath( projectSourcepaths.getValue() ) ) );
Files.createDirectory( moduleSourceDir.resolve( moduleName ) );
}
catch ( IOException e )
{
throw new MavenReportException( e.getMessage() );
}
}
else
{
// todo
getLog().error( "no module descriptor for " + projectSourcepaths.getKey() );
}
}
else
{
// todo
getLog().error( "no reactor project: " + projectSourcepaths.getKey() );
}
}
}
if ( StringUtils.isNotEmpty( doclet ) )
{
addArgIfNotEmpty( arguments, "-doclet", JavadocUtil.quotedArgument( doclet ) );
addArgIfNotEmpty( arguments, "-docletpath", JavadocUtil.quotedPathArgument( getDocletPath() ) );
}
if ( StringUtils.isEmpty( encoding ) )
{
getLog().warn(
"Source files encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING
+ ", i.e. build is platform dependent!" );
}
addArgIfNotEmpty( arguments, "-encoding", JavadocUtil.quotedArgument( getEncoding() ) );
addArgIfNotEmpty( arguments, "-extdirs",
JavadocUtil.quotedPathArgument( JavadocUtil.unifyPathSeparator( extdirs ) ) );
if ( ( getOverview() != null ) && ( getOverview().exists() ) )
{
addArgIfNotEmpty( arguments, "-overview",
JavadocUtil.quotedPathArgument( getOverview().getAbsolutePath() ) );
}
arguments.add( getAccessLevel() );
if ( isJavaDocVersionAtLeast( SINCE_JAVADOC_1_5 ) )
{
addArgIf( arguments, quiet, "-quiet", SINCE_JAVADOC_1_5 );
}
addArgIfNotEmpty( arguments, "-source", JavadocUtil.quotedArgument( source ), SINCE_JAVADOC_1_4 );
if ( ( StringUtils.isEmpty( sourcepath ) ) && ( StringUtils.isNotEmpty( subpackages ) ) )
{
sourcepath = StringUtils.join( sourcePaths.iterator(), File.pathSeparator );
}
if ( moduleSourceDir != null )
{
addArgIfNotEmpty( arguments, "--module-source-path",
JavadocUtil.quotedPathArgument( moduleSourceDir.toString() ) );
}
else
{
addArgIfNotEmpty( arguments, "-sourcepath",
JavadocUtil.quotedPathArgument( getSourcePath( sourcePaths ) ) );
}
if ( StringUtils.isNotEmpty( sourcepath ) && isJavaDocVersionAtLeast( SINCE_JAVADOC_1_5 ) )
{
addArgIfNotEmpty( arguments, "-subpackages", subpackages, SINCE_JAVADOC_1_5 );
}
// [MJAVADOC-497] must be after sourcepath is recalculated, since getExcludedPackages() depends on it
addArgIfNotEmpty( arguments, "-exclude", getExcludedPackages( sourcePaths ), SINCE_JAVADOC_1_4 );
addArgIf( arguments, verbose, "-verbose" );
if ( additionalOptions != null && additionalOptions.length > 0 )
{
for ( String option : additionalOptions )
{
arguments.add( option );
}
}
}
private File findMainDescriptor( Collection roots )
{
for ( String root : roots )
{
File descriptorFile = new File( root, "module-info.java" ).getAbsoluteFile();
if ( descriptorFile.exists() )
{
return descriptorFile;
}
}
return null;
}
/**
* Add Standard Doclet Options.
*
* The package documentation details the
* Standard Doclet Options wrapped by this Plugin.
*
* @param javadocOutputDirectory not null
* @param arguments not null
* @throws MavenReportException if any
* @see
* http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#standard
*/
private void addStandardDocletOptions( File javadocOutputDirectory, List arguments )
throws MavenReportException
{
validateStandardDocletOptions();
// all options in alphabetical order
addArgIf( arguments, author, "-author" );
addArgIfNotEmpty( arguments, "-bottom", JavadocUtil.quotedArgument( getBottomText() ), false, false );
if ( !isJavaDocVersionAtLeast( SINCE_JAVADOC_1_5 ) )
{
addArgIf( arguments, breakiterator, "-breakiterator", SINCE_JAVADOC_1_4 );
}
addArgIfNotEmpty( arguments, "-charset", JavadocUtil.quotedArgument( getCharset() ) );
addArgIfNotEmpty( arguments, "-d", JavadocUtil.quotedPathArgument( javadocOutputDirectory.toString() ) );
addArgIfNotEmpty( arguments, "-docencoding", JavadocUtil.quotedArgument( getDocencoding() ) );
addArgIf( arguments, docfilessubdirs, "-docfilessubdirs", SINCE_JAVADOC_1_4 );
addArgIf( arguments, StringUtils.isNotEmpty( doclint ), "-Xdoclint:" + getDoclint(), SINCE_JAVADOC_1_8 );
addArgIfNotEmpty( arguments, "-doctitle", JavadocUtil.quotedArgument( getDoctitle() ), false, false );
if ( docfilessubdirs )
{
addArgIfNotEmpty( arguments, "-excludedocfilessubdir",
JavadocUtil.quotedPathArgument( excludedocfilessubdir ), SINCE_JAVADOC_1_4 );
}
addArgIfNotEmpty( arguments, "-footer", JavadocUtil.quotedArgument( footer ), false, false );
addGroups( arguments );
addArgIfNotEmpty( arguments, "-header", JavadocUtil.quotedArgument( header ), false, false );
addArgIfNotEmpty( arguments, "-helpfile",
JavadocUtil.quotedPathArgument( getHelpFile( javadocOutputDirectory ) ) );
addArgIf( arguments, keywords, "-keywords", SINCE_JAVADOC_1_4_2 );
if ( !isOffline )
{
addLinkArguments( arguments );
}
addLinkofflineArguments( arguments );
addArgIf( arguments, linksource, "-linksource", SINCE_JAVADOC_1_4 );
if ( sourcetab > 0 )
{
if ( javadocRuntimeVersion == SINCE_JAVADOC_1_4_2 )
{
addArgIfNotEmpty( arguments, "-linksourcetab", String.valueOf( sourcetab ) );
}
addArgIfNotEmpty( arguments, "-sourcetab", String.valueOf( sourcetab ), SINCE_JAVADOC_1_5 );
}
addArgIf( arguments, nocomment, "-nocomment", SINCE_JAVADOC_1_4 );
addArgIf( arguments, nodeprecated, "-nodeprecated" );
addArgIf( arguments, nodeprecatedlist, "-nodeprecatedlist" );
addArgIf( arguments, nohelp, "-nohelp" );
addArgIf( arguments, noindex, "-noindex" );
addArgIf( arguments, nonavbar, "-nonavbar" );
addArgIf( arguments, nooverview, "-nooverview" );
addArgIfNotEmpty( arguments, "-noqualifier", JavadocUtil.quotedArgument( noqualifier ), SINCE_JAVADOC_1_4 );
addArgIf( arguments, nosince, "-nosince" );
addArgIf( arguments, notimestamp, "-notimestamp", SINCE_JAVADOC_1_5 );
addArgIf( arguments, notree, "-notree" );
addArgIfNotEmpty( arguments, "-packagesheader", JavadocUtil.quotedArgument( packagesheader ),
SINCE_JAVADOC_1_4_2 );
if ( !isJavaDocVersionAtLeast( SINCE_JAVADOC_1_5 ) ) // Sun bug: 4714350
{
addArgIf( arguments, quiet, "-quiet", SINCE_JAVADOC_1_4 );
}
addArgIf( arguments, serialwarn, "-serialwarn" );
addArgIf( arguments, splitindex, "-splitindex" );
addArgIfNotEmpty( arguments, "-stylesheetfile",
JavadocUtil.quotedPathArgument( getStylesheetFile( javadocOutputDirectory ) ) );
if ( StringUtils.isNotEmpty( sourcepath ) && !isJavaDocVersionAtLeast( SINCE_JAVADOC_1_5 ) )
{
addArgIfNotEmpty( arguments, "-subpackages", subpackages, SINCE_JAVADOC_1_4 );
}
addArgIfNotEmpty( arguments, "-taglet", JavadocUtil.quotedArgument( taglet ), SINCE_JAVADOC_1_4 );
addTaglets( arguments );
addTagletsFromTagletArtifacts( arguments );
addArgIfNotEmpty( arguments, "-tagletpath", JavadocUtil.quotedPathArgument( getTagletPath() ),
SINCE_JAVADOC_1_4 );
addTags( arguments );
addArgIfNotEmpty( arguments, "-top", JavadocUtil.quotedArgument( top ), false, false, SINCE_JAVADOC_1_6 );
addArgIf( arguments, use, "-use" );
addArgIf( arguments, version, "-version" );
addArgIfNotEmpty( arguments, "-windowtitle", JavadocUtil.quotedArgument( getWindowtitle() ), false, false );
}
/**
* Add groups parameter to arguments.
*
* @param arguments not null
* @throws MavenReportException
*/
private void addGroups( List arguments )
throws MavenReportException
{
Set groups = collectGroups();
if ( isEmpty( groups ) )
{
return;
}
for ( Group group : groups )
{
if ( group == null || StringUtils.isEmpty( group.getTitle() ) || StringUtils.isEmpty(
group.getPackages() ) )
{
if ( getLog().isWarnEnabled() )
{
getLog().warn( "A group option is empty. Ignore this option." );
}
}
else
{
String groupTitle = StringUtils.replace( group.getTitle(), ",", "," );
addArgIfNotEmpty( arguments, "-group",
JavadocUtil.quotedArgument( groupTitle ) + " " + JavadocUtil.quotedArgument(
group.getPackages() ), true );
}
}
}
/**
* Add tags parameter to arguments.
*
* @param arguments not null
* @throws MavenReportException
*/
private void addTags( List arguments )
throws MavenReportException
{
Set tags = collectTags();
if ( isEmpty( tags ) )
{
return;
}
for ( Tag tag : tags )
{
if ( StringUtils.isEmpty( tag.getName() ) )
{
if ( getLog().isWarnEnabled() )
{
getLog().warn( "A tag name is empty. Ignore this option." );
}
}
else
{
String value = "\"" + tag.getName();
if ( StringUtils.isNotEmpty( tag.getPlacement() ) )
{
value += ":" + tag.getPlacement();
if ( StringUtils.isNotEmpty( tag.getHead() ) )
{
value += ":" + tag.getHead();
}
}
value += "\"";
addArgIfNotEmpty( arguments, "-tag", value, SINCE_JAVADOC_1_4 );
}
}
}
/**
* Add taglets parameter to arguments.
*
* @param arguments not null
*/
private void addTaglets( List arguments )
{
if ( taglets == null )
{
return;
}
for ( Taglet taglet1 : taglets )
{
if ( ( taglet1 == null ) || ( StringUtils.isEmpty( taglet1.getTagletClass() ) ) )
{
if ( getLog().isWarnEnabled() )
{
getLog().warn( "A taglet option is empty. Ignore this option." );
}
}
else
{
addArgIfNotEmpty( arguments, "-taglet", JavadocUtil.quotedArgument( taglet1.getTagletClass() ),
SINCE_JAVADOC_1_4 );
}
}
}
/**
* Auto-detect taglets class name from tagletArtifacts and add them to arguments.
*
* @param arguments not null
* @throws MavenReportException if any
* @see JavadocUtil#getTagletClassNames(File)
*/
private void addTagletsFromTagletArtifacts( List arguments )
throws MavenReportException
{
Set tArtifacts = new LinkedHashSet<>();
if ( tagletArtifacts != null && tagletArtifacts.length > 0 )
{
tArtifacts.addAll( Arrays.asList( tagletArtifacts ) );
}
if ( includeDependencySources )
{
try
{
resolveDependencyBundles();
}
catch ( IOException e )
{
throw new MavenReportException(
"Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
}
if ( isNotEmpty( dependencyJavadocBundles ) )
{
for ( JavadocBundle bundle : dependencyJavadocBundles )
{
JavadocOptions options = bundle.getOptions();
if ( options != null && isNotEmpty( options.getTagletArtifacts() ) )
{
tArtifacts.addAll( options.getTagletArtifacts() );
}
}
}
}
if ( isEmpty( tArtifacts ) )
{
return;
}
List tagletsPath = new ArrayList<>();
for ( TagletArtifact aTagletArtifact : tArtifacts )
{
if ( ( StringUtils.isNotEmpty( aTagletArtifact.getGroupId() ) ) && ( StringUtils.isNotEmpty(
aTagletArtifact.getArtifactId() ) ) && ( StringUtils.isNotEmpty( aTagletArtifact.getVersion() ) ) )
{
Artifact artifact;
try
{
artifact = createAndResolveArtifact( aTagletArtifact );
}
catch ( ArtifactResolverException e )
{
throw new MavenReportException( "Unable to resolve artifact:" + aTagletArtifact, e );
}
tagletsPath.add( artifact.getFile().getAbsolutePath() );
}
}
tagletsPath = JavadocUtil.pruneFiles( tagletsPath );
for ( String tagletJar : tagletsPath )
{
if ( !tagletJar.toLowerCase( Locale.ENGLISH ).endsWith( ".jar" ) )
{
continue;
}
List tagletClasses;
try
{
tagletClasses = JavadocUtil.getTagletClassNames( new File( tagletJar ) );
}
catch ( IOException e )
{
if ( getLog().isWarnEnabled() )
{
getLog().warn( "Unable to auto-detect Taglet class names from '" + tagletJar
+ "'. Try to specify them with ." );
}
if ( getLog().isDebugEnabled() )
{
getLog().debug( "IOException: " + e.getMessage(), e );
}
continue;
}
catch ( ClassNotFoundException e )
{
if ( getLog().isWarnEnabled() )
{
getLog().warn( "Unable to auto-detect Taglet class names from '" + tagletJar
+ "'. Try to specify them with ." );
}
if ( getLog().isDebugEnabled() )
{
getLog().debug( "ClassNotFoundException: " + e.getMessage(), e );
}
continue;
}
catch ( NoClassDefFoundError e )
{
if ( getLog().isWarnEnabled() )
{
getLog().warn( "Unable to auto-detect Taglet class names from '" + tagletJar
+ "'. Try to specify them with ." );
}
if ( getLog().isDebugEnabled() )
{
getLog().debug( "NoClassDefFoundError: " + e.getMessage(), e );
}
continue;
}
if ( tagletClasses != null && !tagletClasses.isEmpty() )
{
for ( String tagletClass : tagletClasses )
{
addArgIfNotEmpty( arguments, "-taglet", JavadocUtil.quotedArgument( tagletClass ),
SINCE_JAVADOC_1_4 );
}
}
}
}
/**
* Execute the Javadoc command line
*
* @param cmd not null
* @param javadocOutputDirectory not null
* @throws MavenReportException if any errors occur
*/
private void executeJavadocCommandLine( Commandline cmd, File javadocOutputDirectory )
throws MavenReportException
{
if ( getLog().isDebugEnabled() )
{
// no quoted arguments
getLog().debug( CommandLineUtils.toString( cmd.getCommandline() ).replaceAll( "'", "" ) );
}
String cmdLine = null;
if ( debug )
{
cmdLine = CommandLineUtils.toString( cmd.getCommandline() ).replaceAll( "'", "" );
cmdLine = JavadocUtil.hideProxyPassword( cmdLine, settings );
writeDebugJavadocScript( cmdLine, javadocOutputDirectory );
}
CommandLineUtils.StringStreamConsumer err = new CommandLineUtils.StringStreamConsumer();
CommandLineUtils.StringStreamConsumer out = new CommandLineUtils.StringStreamConsumer();
try
{
int exitCode = CommandLineUtils.executeCommandLine( cmd, out, err );
String output = ( StringUtils.isEmpty( out.getOutput() ) ? null : '\n' + out.getOutput().trim() );
if ( exitCode != 0 )
{
if ( cmdLine == null )
{
cmdLine = CommandLineUtils.toString( cmd.getCommandline() ).replaceAll( "'", "" );
cmdLine = JavadocUtil.hideProxyPassword( cmdLine, settings );
}
writeDebugJavadocScript( cmdLine, javadocOutputDirectory );
if ( StringUtils.isNotEmpty( output ) && StringUtils.isEmpty( err.getOutput() )
&& isJavadocVMInitError( output ) )
{
throw new MavenReportException( output + '\n' + '\n' + JavadocUtil.ERROR_INIT_VM + '\n'
+ "Or, try to reduce the Java heap size for the Javadoc goal using "
+ "-Dminmemory= and -Dmaxmemory=." + '\n' + '\n' + "Command line was: " + cmdLine
+ '\n' + '\n' + "Refer to the generated Javadoc files in '" + javadocOutputDirectory
+ "' dir.\n" );
}
if ( StringUtils.isNotEmpty( output ) )
{
getLog().info( output );
}
StringBuilder msg = new StringBuilder( "\nExit code: " );
msg.append( exitCode );
if ( StringUtils.isNotEmpty( err.getOutput() ) )
{
msg.append( " - " ).append( err.getOutput() );
}
msg.append( '\n' );
msg.append( "Command line was: " ).append( cmdLine ).append( '\n' ).append( '\n' );
msg.append( "Refer to the generated Javadoc files in '" ).append( javadocOutputDirectory )
.append( "' dir.\n" );
throw new MavenReportException( msg.toString() );
}
if ( StringUtils.isNotEmpty( output ) )
{
getLog().info( output );
}
}
catch ( CommandLineException e )
{
throw new MavenReportException( "Unable to execute javadoc command: " + e.getMessage(), e );
}
// ----------------------------------------------------------------------
// Handle Javadoc warnings
// ----------------------------------------------------------------------
if ( StringUtils.isNotEmpty( err.getOutput() ) && getLog().isWarnEnabled() )
{
getLog().warn( "Javadoc Warnings" );
StringTokenizer token = new StringTokenizer( err.getOutput(), "\n" );
while ( token.hasMoreTokens() )
{
String current = token.nextToken().trim();
getLog().warn( current );
}
}
}
/**
* Patches the given Javadoc output directory to work around CVE-2013-1571
* (see http://www.kb.cert.org/vuls/id/225657).
*
* @param javadocOutputDirectory directory to scan for vulnerabilities
* @param outputEncoding encoding used by the javadoc tool (-docencoding parameter).
* If {@code null}, the platform's default encoding is used (like javadoc does).
* @return the number of patched files
*/
private int fixFrameInjectionBug( File javadocOutputDirectory, String outputEncoding )
throws IOException
{
final String fixData;
InputStream in = null;
try
{
in = this.getClass().getResourceAsStream( "frame-injection-fix.txt" );
if ( in == null )
{
throw new FileNotFoundException( "Missing resource 'frame-injection-fix.txt' in classpath." );
}
fixData = StringUtils.unifyLineSeparators( IOUtil.toString( in, "US-ASCII" ) ).trim();
in.close();
in = null;
}
finally
{
IOUtil.close( in );
}
final DirectoryScanner ds = new DirectoryScanner();
ds.setBasedir( javadocOutputDirectory );
ds.setCaseSensitive( false );
ds.setIncludes( new String[]{ "**/index.html", "**/index.htm", "**/toc.html", "**/toc.htm" } );
ds.addDefaultExcludes();
ds.scan();
int patched = 0;
for ( String f : ds.getIncludedFiles() )
{
final File file = new File( javadocOutputDirectory, f );
// we load the whole file as one String (toc/index files are
// generally small, because they only contain frameset declaration):
final String fileContents = FileUtils.fileRead( file, outputEncoding );
// check if file may be vulnerable because it was not patched with "validURL(url)":
if ( !StringUtils.contains( fileContents, "function validURL(url) {" ) )
{
// we need to patch the file!
final String patchedFileContents =
StringUtils.replaceOnce( fileContents, "function loadFrames() {", fixData );
if ( !patchedFileContents.equals( fileContents ) )
{
FileUtils.fileWrite( file, outputEncoding, patchedFileContents );
patched++;
}
}
}
return patched;
}
/**
* @param outputFile not nul
* @param inputResourceName a not null resource in src/main/java, src/main/resources or
* src/main/javadoc or in the Javadoc plugin dependencies.
* @return the resource file absolute path as String
* @since 2.6
*/
private String getResource( File outputFile, String inputResourceName )
{
if ( inputResourceName.startsWith( "/" ) )
{
inputResourceName = inputResourceName.replaceFirst( "//*", "" );
}
List classPath = new ArrayList<>();
classPath.add( project.getBuild().getSourceDirectory() );
URL resourceURL = getResource( classPath, inputResourceName );
if ( resourceURL != null )
{
getLog().debug( inputResourceName + " found in the main src directory of the project." );
return FileUtils.toFile( resourceURL ).getAbsolutePath();
}
classPath.clear();
List resources = project.getBuild().getResources();
for ( Resource resource : resources )
{
classPath.add( resource.getDirectory() );
}
resourceURL = getResource( classPath, inputResourceName );
if ( resourceURL != null )
{
getLog().debug( inputResourceName + " found in the main resources directories of the project." );
return FileUtils.toFile( resourceURL ).getAbsolutePath();
}
if ( javadocDirectory.exists() )
{
classPath.clear();
classPath.add( javadocDirectory.getAbsolutePath() );
resourceURL = getResource( classPath, inputResourceName );
if ( resourceURL != null )
{
getLog().debug( inputResourceName + " found in the main javadoc directory of the project." );
return FileUtils.toFile( resourceURL ).getAbsolutePath();
}
}
classPath.clear();
final String pluginId = "org.apache.maven.plugins:maven-javadoc-plugin";
Plugin javadocPlugin = getPlugin( project, pluginId );
if ( javadocPlugin != null && javadocPlugin.getDependencies() != null )
{
List dependencies = javadocPlugin.getDependencies();
for ( Dependency dependency : dependencies )
{
JavadocPathArtifact javadocPathArtifact = new JavadocPathArtifact();
javadocPathArtifact.setGroupId( dependency.getGroupId() );
javadocPathArtifact.setArtifactId( dependency.getArtifactId() );
javadocPathArtifact.setVersion( dependency.getVersion() );
Artifact artifact = null;
try
{
artifact = createAndResolveArtifact( javadocPathArtifact );
}
catch ( Exception e )
{
logError( "Unable to retrieve the dependency: " + dependency + ". Ignored.", e );
}
if ( artifact != null && artifact.getFile().exists() )
{
classPath.add( artifact.getFile().getAbsolutePath() );
}
}
resourceURL = getResource( classPath, inputResourceName );
if ( resourceURL != null )
{
getLog().debug( inputResourceName + " found in javadoc plugin dependencies." );
try
{
JavadocUtil.copyResource( resourceURL, outputFile );
return outputFile.getAbsolutePath();
}
catch ( IOException e )
{
logError( "IOException: " + e.getMessage(), e );
}
}
}
getLog().warn( "Unable to find the resource '" + inputResourceName + "'. Using default Javadoc resources." );
return null;
}
/**
* @param classPath a not null String list of files where resource will be look up.
* @param resource a not null ressource to find in the class path.
* @return the resource from the given classpath or null if not found
* @see ClassLoader#getResource(String)
* @since 2.6
*/
private URL getResource( final List classPath, final String resource )
{
List urls = new ArrayList<>( classPath.size() );
for ( String filename : classPath )
{
try
{
urls.add( new File( filename ).toURL() );
}
catch ( MalformedURLException e )
{
getLog().error( "MalformedURLException: " + e.getMessage() );
}
}
ClassLoader javadocClassLoader = new URLClassLoader( urls.toArray( new URL[urls.size()] ), null );
return javadocClassLoader.getResource( resource );
}
/**
* Get the full javadoc goal. Loads the plugin's pom.properties to get the current plugin version.
*
* @return org.apache.maven.plugins:maven-javadoc-plugin:CURRENT_VERSION:[test-]javadoc
*/
private String getFullJavadocGoal()
{
String javadocPluginVersion = null;
InputStream resourceAsStream = null;
try
{
String resource = "META-INF/maven/org.apache.maven.plugins/maven-javadoc-plugin/pom.properties";
resourceAsStream = AbstractJavadocMojo.class.getClassLoader().getResourceAsStream( resource );
if ( resourceAsStream != null )
{
Properties properties = new Properties();
properties.load( resourceAsStream );
resourceAsStream.close();
resourceAsStream = null;
if ( StringUtils.isNotEmpty( properties.getProperty( "version" ) ) )
{
javadocPluginVersion = properties.getProperty( "version" );
}
}
}
catch ( IOException e )
{
// nop
}
finally
{
IOUtil.close( resourceAsStream );
}
StringBuilder sb = new StringBuilder();
sb.append( "org.apache.maven.plugins:maven-javadoc-plugin:" );
if ( StringUtils.isNotEmpty( javadocPluginVersion ) )
{
sb.append( javadocPluginVersion ).append( ":" );
}
if ( this instanceof TestJavadocReport )
{
sb.append( "test-javadoc" );
}
else
{
sb.append( "javadoc" );
}
return sb.toString();
}
/**
* Using Maven, a Javadoc link is given by ${project.url}/apidocs.
*
* @return the detected Javadoc links using the Maven conventions for all modules defined in the current project
* or an empty list.
* @throws MavenReportException if any
* @see #detectOfflineLinks
* @see #reactorProjects
* @since 2.6
*/
private List getModulesLinks()
throws MavenReportException
{
if ( !detectOfflineLinks || isAggregator() || reactorProjects == null )
{
return Collections.emptyList();
}
getLog().debug( "Trying to add links for modules..." );
Set dependencyArtifactIds = new HashSet<>();
final Set dependencyArtifacts = project.getDependencyArtifacts();
for ( Artifact artifact : dependencyArtifacts )
{
dependencyArtifactIds.add( artifact.getId() );
}
List modulesLinks = new ArrayList<>();
String javadocDirRelative = PathUtils.toRelative( project.getBasedir(), getOutputDirectory() );
for ( MavenProject p : reactorProjects )
{
if ( !dependencyArtifactIds.contains( p.getArtifact().getId() ) || ( p.getUrl() == null ) )
{
continue;
}
File location = new File( p.getBasedir(), javadocDirRelative );
if ( !location.exists() )
{
if ( getLog().isDebugEnabled() )
{
getLog().debug( "Javadoc directory not found: " + location );
}
String javadocGoal = getFullJavadocGoal();
getLog().info(
"The goal '" + javadocGoal + "' has not been previously called for the module: '" + p.getId()
+ "'. Trying to invoke it..." );
File invokerDir = new File( project.getBuild().getDirectory(), "invoker" );
invokerDir.mkdirs();
File invokerLogFile = FileUtils.createTempFile( "maven-javadoc-plugin", ".txt", invokerDir );
try
{
JavadocUtil.invokeMaven( getLog(), new File( localRepository.getBasedir() ), p.getFile(),
Collections.singletonList( javadocGoal ), null, invokerLogFile );
}
catch ( MavenInvocationException e )
{
logError( "MavenInvocationException: " + e.getMessage(), e );
String invokerLogContent = JavadocUtil.readFile( invokerLogFile, null /* platform encoding */ );
// TODO: Why are we only interested in cases where the JVM won't start?
// [MJAVADOC-275][jdcasey] I changed the logic here to only throw an error WHEN
// the JVM won't start (opposite of what it was).
if ( invokerLogContent != null && invokerLogContent.contains( JavadocUtil.ERROR_INIT_VM ) )
{
throw new MavenReportException( e.getMessage(), e );
}
}
finally
{
// just create the directory to prevent repeated invocations..
if ( !location.exists() )
{
getLog().warn( "Creating fake javadoc directory to prevent repeated invocations: " + location );
location.mkdirs();
}
}
}
if ( location.exists() )
{
String url = getJavadocLink( p );
OfflineLink ol = new OfflineLink();
ol.setUrl( url );
ol.setLocation( location.getAbsolutePath() );
if ( getLog().isDebugEnabled() )
{
getLog().debug( "Added Javadoc offline link: " + url + " for the module: " + p.getId() );
}
modulesLinks.add( ol );
}
}
return modulesLinks;
}
/**
* Using Maven, a Javadoc link is given by ${project.url}/apidocs.
*
* @return the detected Javadoc links using the Maven conventions for all dependencies defined in the current
* project or an empty list.
* @see #detectLinks
* @see #isValidJavadocLink(String)
* @since 2.6
*/
private List getDependenciesLinks()
{
if ( !detectLinks )
{
return Collections.emptyList();
}
getLog().debug( "Trying to add links for dependencies..." );
List dependenciesLinks = new ArrayList<>();
final Set dependencies = project.getDependencyArtifacts();
for ( Artifact artifact : dependencies )
{
if ( artifact.getFile() == null || !artifact.getFile().exists() )
{
continue;
}
try
{
MavenProject artifactProject =
mavenProjectBuilder.build( artifact, session.getProjectBuildingRequest() ).getProject();
if ( StringUtils.isNotEmpty( artifactProject.getUrl() ) )
{
String url = getJavadocLink( artifactProject );
if ( isValidJavadocLink( url, true ) )
{
getLog().debug( "Added Javadoc link: " + url + " for " + artifactProject.getId() );
dependenciesLinks.add( url );
}
}
}
catch ( ProjectBuildingException e )
{
logError( "ProjectBuildingException for " + artifact.toString() + ": " + e.getMessage(), e );
}
}
return dependenciesLinks;
}
/**
* @return if {@link #detectJavaApiLink}, the Java API link based on the {@link #javaApiLinks} properties and the
* value of the source parameter in the
* org.apache.maven.plugins:maven-compiler-plugin
* defined in ${project.build.plugins} or in ${project.build.pluginManagement},
* or the {@link #javadocRuntimeVersion}, or null if not defined.
* @see #detectJavaApiLink
* @see #javaApiLinks
* @see #DEFAULT_JAVA_API_LINKS
* @see source parameter
* @since 2.6
*/
private OfflineLink getDefaultJavadocApiLink()
{
if ( !detectJavaApiLink )
{
return null;
}
final String pluginId = "org.apache.maven.plugins:maven-compiler-plugin";
JavadocVersion sourceVersion = javadocRuntimeVersion;
String sourceConfigured = getPluginParameter( project, pluginId, "source" );
if ( sourceConfigured != null )
{
try
{
sourceVersion = JavadocVersion.parse( sourceConfigured );
}
catch ( NumberFormatException e )
{
getLog().debug(
"NumberFormatException for the source parameter in the maven-compiler-plugin. " + "Ignored it", e );
}
}
else
{
getLog().debug( "No maven-compiler-plugin defined in ${build.plugins} or in "
+ "${project.build.pluginManagement} for the " + project.getId()
+ ". Added Javadoc API link according the javadoc executable version i.e.: "
+ javadocRuntimeVersion );
}
String apiVersion;
Matcher apiMatcher = Pattern.compile( "(1\\.\\d|\\d\\d*)" ).matcher( sourceVersion.toString() );
if ( apiMatcher.find() )
{
apiVersion = apiMatcher.group( 1 );
}
else
{
apiVersion = null;
}
String javaApiLink = javaApiLinks.getProperty( "api_" + apiVersion, null );
if ( getLog().isDebugEnabled() )
{
if ( StringUtils.isNotEmpty( javaApiLink ) )
{
getLog().debug( "Found Java API link: " + javaApiLink );
}
else
{
getLog().debug( "No Java API link found." );
}
}
if ( javaApiLink == null )
{
return null;
}
File javaApiPackageListFile = new File( getJavadocOptionsFile().getParentFile(), "package-list" );
OfflineLink link = new OfflineLink();
link.setLocation( javaApiPackageListFile.getParentFile().getAbsolutePath() );
link.setUrl( javaApiLink );
InputStream in = null;
OutputStream out = null;
try
{
in = this.getClass().getResourceAsStream( "java-api-package-list-" + apiVersion );
out = new FileOutputStream( javaApiPackageListFile );
IOUtil.copy( in, out );
out.close();
out = null;
in.close();
in = null;
}
catch ( IOException ioe )
{
logError( "Can't get java-api-package-list-" + apiVersion + ": " + ioe.getMessage(), ioe );
return null;
}
finally
{
IOUtil.close( in );
IOUtil.close( out );
}
return link;
}
/**
* @param link not null
* @param detecting true if the link is generated by
* detectLinks, or false otherwise
* @return true if the link has a /package-list, false otherwise.
* @see
* package-list spec
* @since 2.6
*/
protected boolean isValidJavadocLink( String link, boolean detecting )
{
try
{
URI linkUri;
if ( link.trim().toLowerCase( Locale.ENGLISH ).startsWith( "http:" ) || link.trim().toLowerCase(
Locale.ENGLISH ).startsWith( "https:" ) || link.trim().toLowerCase( Locale.ENGLISH ).startsWith(
"ftp:" ) || link.trim().toLowerCase( Locale.ENGLISH ).startsWith( "file:" ) )
{
linkUri = new URI( link + "/package-list" );
}
else
{
// links can be relative paths or files
File dir = new File( link );
if ( !dir.isAbsolute() )
{
dir = new File( getOutputDirectory(), link );
}
if ( !dir.isDirectory() )
{
if ( detecting )
{
getLog().warn( "The given File link: " + dir + " is not a dir." );
}
else
{
getLog().error( "The given File link: " + dir + " is not a dir." );
}
}
linkUri = new File( dir, "package-list" ).toURI();
}
if ( !JavadocUtil.isValidPackageList( linkUri.toURL(), settings, validateLinks ) )
{
if ( getLog().isErrorEnabled() )
{
if ( detecting )
{
getLog().warn( "Invalid link: " + link + "/package-list. Ignored it." );
}
else
{
getLog().error( "Invalid link: " + link + "/package-list. Ignored it." );
}
}
return false;
}
return true;
}
catch ( URISyntaxException e )
{
if ( getLog().isErrorEnabled() )
{
if ( detecting )
{
getLog().warn( "Malformed link: " + link + "/package-list. Ignored it." );
}
else
{
getLog().error( "Malformed link: " + link + "/package-list. Ignored it." );
}
}
return false;
}
catch ( IOException e )
{
if ( getLog().isErrorEnabled() )
{
if ( detecting )
{
getLog().warn( "Error fetching link: " + link + "/package-list. Ignored it." );
}
else
{
getLog().error( "Error fetching link: " + link + "/package-list. Ignored it." );
}
}
return false;
}
}
/**
* Write a debug javadoc script in case of command line error or in debug mode.
*
* @param cmdLine the current command line as string, not null.
* @param javadocOutputDirectory the output dir, not null.
* @see #executeJavadocCommandLine(Commandline, File)
* @since 2.6
*/
private void writeDebugJavadocScript( String cmdLine, File javadocOutputDirectory )
{
File commandLineFile = new File( javadocOutputDirectory, DEBUG_JAVADOC_SCRIPT_NAME );
commandLineFile.getParentFile().mkdirs();
try
{
FileUtils.fileWrite( commandLineFile.getAbsolutePath(), null /* platform encoding */, cmdLine );
if ( !SystemUtils.IS_OS_WINDOWS )
{
Runtime.getRuntime().exec( new String[]{ "chmod", "a+x", commandLineFile.getAbsolutePath() } );
}
}
catch ( IOException e )
{
logError( "Unable to write '" + commandLineFile.getName() + "' debug script file", e );
}
}
/**
* Check if the Javadoc JVM is correctly started or not.
*
* @param output the command line output, not null.
* @return true if Javadoc output command line contains Javadoc word, false otherwise.
* @see #executeJavadocCommandLine(Commandline, File)
* @since 2.6.1
*/
private boolean isJavadocVMInitError( String output )
{
/*
* see main.usage and main.Building_tree keys from
* com.sun.tools.javadoc.resources.javadoc bundle in tools.jar
*/
return !( output.contains( "Javadoc" ) || output.contains( "javadoc" ) );
}
// ----------------------------------------------------------------------
// Static methods
// ----------------------------------------------------------------------
/**
* @param p not null
* @return the javadoc link based on the project url i.e. ${project.url}/${destDir} where
* destDir is configued in the Javadoc plugin configuration (apidocs by default).
* @since 2.6
*/
private static String getJavadocLink( MavenProject p )
{
if ( p.getUrl() == null )
{
return null;
}
String url = cleanUrl( p.getUrl() );
String destDir = "apidocs"; // see JavadocReport#destDir
final String pluginId = "org.apache.maven.plugins:maven-javadoc-plugin";
String destDirConfigured = getPluginParameter( p, pluginId, "destDir" );
if ( destDirConfigured != null )
{
destDir = destDirConfigured;
}
return url + "/" + destDir;
}
/**
* @param url could be null.
* @return the url cleaned or empty if url was null.
* @since 2.6
*/
private static String cleanUrl( String url )
{
if ( url == null )
{
return "";
}
url = url.trim();
while ( url.endsWith( "/" ) )
{
url = url.substring( 0, url.lastIndexOf( "/" ) );
}
return url;
}
/**
* @param p not null
* @param pluginId not null key of the plugin defined in {@link org.apache.maven.model.Build#getPluginsAsMap()}
* or in {@link org.apache.maven.model.PluginManagement#getPluginsAsMap()}
* @return the Maven plugin defined in ${project.build.plugins} or in
* ${project.build.pluginManagement}, or null if not defined.
* @since 2.6
*/
private static Plugin getPlugin( MavenProject p, String pluginId )
{
if ( ( p.getBuild() == null ) || ( p.getBuild().getPluginsAsMap() == null ) )
{
return null;
}
Plugin plugin = p.getBuild().getPluginsAsMap().get( pluginId );
if ( ( plugin == null ) && ( p.getBuild().getPluginManagement() != null ) && (
p.getBuild().getPluginManagement().getPluginsAsMap() != null ) )
{
plugin = p.getBuild().getPluginManagement().getPluginsAsMap().get( pluginId );
}
return plugin;
}
/**
* @param p not null
* @param pluginId not null
* @param param not null
* @return the simple parameter as String defined in the plugin configuration by param key
* or null if not found.
* @since 2.6
*/
private static String getPluginParameter( MavenProject p, String pluginId, String param )
{
// p.getGoalConfiguration( pluginGroupId, pluginArtifactId, executionId, goalId );
Plugin plugin = getPlugin( p, pluginId );
if ( plugin != null )
{
Xpp3Dom xpp3Dom = (Xpp3Dom) plugin.getConfiguration();
if ( xpp3Dom != null && xpp3Dom.getChild( param ) != null
&& StringUtils.isNotEmpty( xpp3Dom.getChild( param ).getValue() ) )
{
return xpp3Dom.getChild( param ).getValue();
}
}
return null;
}
/**
* Construct the output file for the generated javadoc-options XML file, after creating the
* javadocOptionsDir if necessary. This method does NOT write to the file in question.
*
* @return The options {@link File} file.
* @since 2.7
*/
protected final File getJavadocOptionsFile()
{
if ( javadocOptionsDir != null && !javadocOptionsDir.exists() )
{
javadocOptionsDir.mkdirs();
}
return new File( javadocOptionsDir, "javadoc-options-" + getAttachmentClassifier() + ".xml" );
}
/**
* Generate a javadoc-options XML file, for either bundling with a javadoc-resources artifact OR
* supplying to a distro module in a includeDependencySources configuration, so the javadoc options
* from this execution can be reconstructed and merged in the distro build.
*
* @return {@link JavadocOptions}
* @throws IOException {@link IOException}
* @since 2.7
*/
protected final JavadocOptions buildJavadocOptions()
throws IOException
{
JavadocOptions options = new JavadocOptions();
options.setBootclasspathArtifacts( toList( bootclasspathArtifacts ) );
options.setDocfilesSubdirsUsed( docfilessubdirs );
options.setDocletArtifacts( toList( docletArtifact, docletArtifacts ) );
options.setExcludedDocfilesSubdirs( excludedocfilessubdir );
options.setExcludePackageNames( toList( excludePackageNames ) );
options.setGroups( toList( groups ) );
options.setLinks( links );
options.setOfflineLinks( toList( offlineLinks ) );
options.setResourcesArtifacts( toList( resourcesArtifacts ) );
options.setTagletArtifacts( toList( tagletArtifact, tagletArtifacts ) );
options.setTaglets( toList( taglets ) );
options.setTags( toList( tags ) );
if ( getProject() != null && getJavadocDirectory() != null )
{
options.setJavadocResourcesDirectory(
toRelative( getProject().getBasedir(), getJavadocDirectory().getAbsolutePath() ) );
}
File optionsFile = getJavadocOptionsFile();
try ( Writer writer = WriterFactory.newXmlWriter( optionsFile ) )
{
new JavadocOptionsXpp3Writer().write( writer, options );
}
return options;
}
/**
* Override this if you need to provide a bundle attachment classifier, as in the case of test
* javadocs.
* @return The attachment classifier.
*/
protected String getAttachmentClassifier()
{
return JAVADOC_RESOURCES_ATTACHMENT_CLASSIFIER;
}
/**
* Logs an error with throwable content only if in debug.
*
* @param message The message which should be announced.
* @param t The throwable part of the message.
*/
protected void logError( String message, Throwable t )
{
if ( getLog().isDebugEnabled() )
{
getLog().error( message, t );
}
else
{
getLog().error( message );
}
}
/**
* @param prefix The prefix of the exception.
* @param e The exception.
* @throws MojoExecutionException {@link MojoExecutionException}
*/
protected void failOnError( String prefix, Exception e )
throws MojoExecutionException
{
if ( failOnError )
{
if ( e instanceof RuntimeException )
{
throw (RuntimeException) e;
}
throw new MojoExecutionException( prefix + ": " + e.getMessage(), e );
}
getLog().error( prefix + ": " + e.getMessage(), e );
}
}