View Javadoc

1   package org.apache.maven.plugin.javadoc;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *      http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.commons.lang.ClassUtils;
23  import org.apache.commons.lang.SystemUtils;
24  import org.apache.maven.artifact.Artifact;
25  import org.apache.maven.artifact.factory.ArtifactFactory;
26  import org.apache.maven.artifact.handler.ArtifactHandler;
27  import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
28  import org.apache.maven.artifact.repository.ArtifactRepository;
29  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
30  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
31  import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
32  import org.apache.maven.artifact.resolver.ArtifactResolver;
33  import org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException;
34  import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
35  import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
36  import org.apache.maven.artifact.resolver.filter.IncludesArtifactFilter;
37  import org.apache.maven.artifact.versioning.ArtifactVersion;
38  import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
39  import org.apache.maven.execution.MavenSession;
40  import org.apache.maven.model.Dependency;
41  import org.apache.maven.model.Plugin;
42  import org.apache.maven.model.Resource;
43  import org.apache.maven.plugin.AbstractMojo;
44  import org.apache.maven.plugin.MojoExecutionException;
45  import org.apache.maven.plugin.javadoc.options.BootclasspathArtifact;
46  import org.apache.maven.plugin.javadoc.options.DocletArtifact;
47  import org.apache.maven.plugin.javadoc.options.Group;
48  import org.apache.maven.plugin.javadoc.options.JavadocOptions;
49  import org.apache.maven.plugin.javadoc.options.JavadocPathArtifact;
50  import org.apache.maven.plugin.javadoc.options.OfflineLink;
51  import org.apache.maven.plugin.javadoc.options.ResourcesArtifact;
52  import org.apache.maven.plugin.javadoc.options.Tag;
53  import org.apache.maven.plugin.javadoc.options.Taglet;
54  import org.apache.maven.plugin.javadoc.options.TagletArtifact;
55  import org.apache.maven.plugin.javadoc.options.io.xpp3.JavadocOptionsXpp3Writer;
56  import org.apache.maven.plugin.javadoc.resolver.JavadocBundle;
57  import org.apache.maven.plugin.javadoc.resolver.ResourceResolver;
58  import org.apache.maven.plugin.javadoc.resolver.SourceResolverConfig;
59  import org.apache.maven.plugins.annotations.Component;
60  import org.apache.maven.plugins.annotations.Parameter;
61  import org.apache.maven.project.MavenProject;
62  import org.apache.maven.project.MavenProjectBuilder;
63  import org.apache.maven.project.ProjectBuildingException;
64  import org.apache.maven.project.artifact.InvalidDependencyVersionException;
65  import org.apache.maven.reporting.MavenReportException;
66  import org.apache.maven.settings.Proxy;
67  import org.apache.maven.settings.Settings;
68  import org.apache.maven.shared.artifact.filter.PatternExcludesArtifactFilter;
69  import org.apache.maven.shared.artifact.filter.PatternIncludesArtifactFilter;
70  import org.apache.maven.shared.invoker.MavenInvocationException;
71  import org.apache.maven.toolchain.Toolchain;
72  import org.apache.maven.toolchain.ToolchainManager;
73  import org.apache.maven.wagon.PathUtils;
74  import org.codehaus.plexus.archiver.ArchiverException;
75  import org.codehaus.plexus.archiver.UnArchiver;
76  import org.codehaus.plexus.archiver.manager.ArchiverManager;
77  import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
78  import org.codehaus.plexus.components.io.fileselectors.IncludeExcludeFileSelector;
79  import org.codehaus.plexus.util.FileUtils;
80  import org.codehaus.plexus.util.IOUtil;
81  import org.codehaus.plexus.util.ReaderFactory;
82  import org.codehaus.plexus.util.StringUtils;
83  import org.codehaus.plexus.util.WriterFactory;
84  import org.codehaus.plexus.util.cli.CommandLineException;
85  import org.codehaus.plexus.util.cli.CommandLineUtils;
86  import org.codehaus.plexus.util.cli.Commandline;
87  import org.codehaus.plexus.util.xml.Xpp3Dom;
88  
89  import java.io.File;
90  import java.io.FileOutputStream;
91  import java.io.IOException;
92  import java.io.InputStream;
93  import java.io.OutputStream;
94  import java.io.Writer;
95  import java.net.MalformedURLException;
96  import java.net.URI;
97  import java.net.URISyntaxException;
98  import java.net.URL;
99  import java.net.URLClassLoader;
100 import java.util.ArrayList;
101 import java.util.Arrays;
102 import java.util.Calendar;
103 import java.util.Collection;
104 import java.util.Collections;
105 import java.util.HashMap;
106 import java.util.HashSet;
107 import java.util.LinkedHashSet;
108 import java.util.LinkedList;
109 import java.util.List;
110 import java.util.Locale;
111 import java.util.Map;
112 import java.util.Properties;
113 import java.util.Set;
114 import java.util.StringTokenizer;
115 
116 import static org.apache.maven.plugin.javadoc.JavadocUtil.isEmpty;
117 import static org.apache.maven.plugin.javadoc.JavadocUtil.isNotEmpty;
118 import static org.apache.maven.plugin.javadoc.JavadocUtil.toList;
119 import static org.apache.maven.plugin.javadoc.JavadocUtil.toRelative;
120 import static org.codehaus.plexus.util.IOUtil.close;
121 
122 /**
123  * Base class with majority of Javadoc functionalities.
124  *
125  * @author <a href="mailto:brett@apache.org">Brett Porter</a>
126  * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
127  * @version $Id: AbstractJavadocMojo.java 1385250 2012-09-16 12:23:12Z bimargulies $
128  * @see <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html">
129  *      The Java API Documentation Generator, 1.4.2</a>
130  * @since 2.0
131  */
132 public abstract class AbstractJavadocMojo
133     extends AbstractMojo
134 {
135     /**
136      * Classifier used in the name of the javadoc-options XML file, and in the resources bundle
137      * artifact that gets attached to the project. This one is used for non-test javadocs.
138      *
139      * @see #TEST_JAVADOC_RESOURCES_ATTACHMENT_CLASSIFIER
140      * @since 2.7
141      */
142     public static final String JAVADOC_RESOURCES_ATTACHMENT_CLASSIFIER = "javadoc-resources";
143 
144     /**
145      * Classifier used in the name of the javadoc-options XML file, and in the resources bundle
146      * artifact that gets attached to the project. This one is used for test-javadocs.
147      *
148      * @see #JAVADOC_RESOURCES_ATTACHMENT_CLASSIFIER
149      * @since 2.7
150      */
151     public static final String TEST_JAVADOC_RESOURCES_ATTACHMENT_CLASSIFIER = "test-javadoc-resources";
152 
153     /**
154      * The default Javadoc API urls according the
155      * <a href="http://www.oracle.com/technetwork/java/javase/documentation/api-jsp-136079.html">Sun API Specifications</a>:
156      * <pre>
157      * &lt;javaApiLinks&gt;
158      *   &lt;property&gt;
159      *     &lt;name&gt;api_1.3&lt;/name&gt;
160      *     &lt;value&gt;http://docs.oracle.com/javase/1.3/docs/api/&lt;/value&gt;
161      *   &lt;/property&gt;
162      *   &lt;property&gt;
163      *     &lt;name&gt;api_1.4&lt;/name&gt;
164      *     &lt;value&gt;http://docs.oracle.com/javase/1.4.2/docs/api/&lt;/value&gt;
165      *   &lt;/property&gt;
166      *   &lt;property&gt;
167      *     &lt;name&gt;api_1.5&lt;/name&gt;
168      *     &lt;value&gt;http://docs.oracle.com/javase/1.5.0/docs/api/&lt;/value&gt;
169      *   &lt;/property&gt;
170      *   &lt;property&gt;
171      *     &lt;name&gt;api_1.6&lt;/name&gt;
172      *     &lt;value&gt;http://docs.oracle.com/javase/6/docs/api/&lt;/value&gt;
173      *   &lt;/property&gt;
174      *   &lt;property&gt;
175      *     &lt;name&gt;api_1.7&lt;/name&gt;
176      *     &lt;value&gt;http://docs.oracle.com/javase/7/docs/api/&lt;/value&gt;
177      *   &lt;/property&gt;
178      * &lt;/javaApiLinks&gt;
179      * </pre>
180      *
181      * @since 2.6
182      */
183     public static final Properties DEFAULT_JAVA_API_LINKS = new Properties();
184 
185     /**
186      * The Javadoc script file name when <code>debug</code> parameter is on, i.e. javadoc.bat or javadoc.sh
187      */
188     protected static final String DEBUG_JAVADOC_SCRIPT_NAME = "javadoc." + ( SystemUtils.IS_OS_WINDOWS ? "bat" : "sh" );
189 
190     /**
191      * The <code>options</code> file name in the output directory when calling:
192      * <code>javadoc.exe(or .sh) &#x40;options &#x40;packages | &#x40;argfile | &#x40;files</code>
193      */
194     protected static final String OPTIONS_FILE_NAME = "options";
195 
196     /**
197      * The <code>packages</code> file name in the output directory when calling:
198      * <code>javadoc.exe(or .sh) &#x40;options &#x40;packages | &#x40;argfile | &#x40;files</code>
199      */
200     protected static final String PACKAGES_FILE_NAME = "packages";
201 
202     /**
203      * The <code>argfile</code> file name in the output directory when calling:
204      * <code>javadoc.exe(or .sh) &#x40;options &#x40;packages | &#x40;argfile | &#x40;files</code>
205      */
206     protected static final String ARGFILE_FILE_NAME = "argfile";
207 
208     /**
209      * The <code>files</code> file name in the output directory when calling:
210      * <code>javadoc.exe(or .sh) &#x40;options &#x40;packages | &#x40;argfile | &#x40;files</code>
211      */
212     protected static final String FILES_FILE_NAME = "files";
213 
214     /**
215      * The current class directory
216      */
217     private static final String RESOURCE_DIR = ClassUtils.getPackageName( JavadocReport.class ).replace( '.', '/' );
218 
219     /**
220      * Default css file name
221      */
222     private static final String DEFAULT_CSS_NAME = "stylesheet.css";
223 
224     /**
225      * Default location for css
226      */
227     private static final String RESOURCE_CSS_DIR = RESOURCE_DIR + "/css";
228 
229     /**
230      * For Javadoc options appears since Java 1.4.
231      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/javadoc/whatsnew-1.4.html#summary">
232      * What's New in Javadoc 1.4</a>
233      *
234      * @since 2.1
235      */
236     private static final float SINCE_JAVADOC_1_4 = 1.4f;
237 
238     /**
239      * For Javadoc options appears since Java 1.4.2.
240      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/javadoc/whatsnew-1.4.2.html#commandlineoptions">
241      * What's New in Javadoc 1.4.2</a>
242      *
243      * @since 2.1
244      */
245     private static final float SINCE_JAVADOC_1_4_2 = 1.42f;
246 
247     /**
248      * For Javadoc options appears since Java 5.0.
249      * See <a href="http://docs.oracle.com/javase/1.5.0/docs/guide/javadoc/whatsnew-1.5.0.html#commandlineoptions">
250      * What's New in Javadoc 5.0</a>
251      *
252      * @since 2.1
253      */
254     private static final float SINCE_JAVADOC_1_5 = 1.5f;
255 
256     /**
257      * For Javadoc options appears since Java 6.0.
258      * See <a href="http://docs.oracle.com/javase/6/docs/technotes/guides/javadoc/index.html">
259      * Javadoc Technology</a>
260      *
261      * @since 2.4
262      */
263     private static final float SINCE_JAVADOC_1_6 = 1.6f;
264 
265     // ----------------------------------------------------------------------
266     // Mojo components
267     // ----------------------------------------------------------------------
268 
269     /**
270      * Archiver manager
271      *
272      * @since 2.5
273      */
274     @Component
275     private ArchiverManager archiverManager;
276 
277     /**
278      * Factory for creating artifact objects
279      */
280     @Component
281     private ArtifactFactory factory;
282 
283     /**
284      * Used to resolve artifacts of aggregated modules
285      *
286      * @since 2.1
287      */
288     @Component
289     private ArtifactMetadataSource artifactMetadataSource;
290 
291     /**
292      * Used for resolving artifacts
293      */
294     @Component
295     private ArtifactResolver resolver;
296 
297     /**
298      * Project builder
299      *
300      * @since 2.5
301      */
302     @Component
303     private MavenProjectBuilder mavenProjectBuilder;
304 
305     /** */
306     @Component
307     private ToolchainManager toolchainManager;
308 
309     // ----------------------------------------------------------------------
310     // Mojo parameters
311     // ----------------------------------------------------------------------
312 
313     /**
314      * The current build session instance. This is used for
315      * toolchain manager API calls.
316      */
317     @Component
318     private MavenSession session;
319 
320     /**
321      * The Maven Settings.
322      *
323      * @since 2.3
324      */
325     @Component
326     private Settings settings;
327 
328     /**
329      * The Maven Project Object
330      */
331     @Component
332     protected MavenProject project;
333 
334     /**
335      * Specify if the Javadoc should operate in offline mode.
336      */
337     @Parameter( defaultValue = "${settings.offline}", required = true, readonly = true )
338     private boolean isOffline;
339 
340     /**
341      * Specifies the Javadoc resources directory to be included in the Javadoc (i.e. package.html, images...).
342      * <br/>
343      * Could be used in addition of <code>docfilessubdirs</code> parameter.
344      * <br/>
345      * See <a href="#docfilessubdirs">docfilessubdirs</a>.
346      *
347      * @see #docfilessubdirs
348      * @since 2.1
349      */
350     @Parameter( defaultValue = "${basedir}/src/main/javadoc" )
351     private File javadocDirectory;
352 
353     /**
354      * Set an additional parameter(s) on the command line. This value should include quotes as necessary for
355      * parameters that include spaces. Useful for a custom doclet.
356      */
357     @Parameter( property = "additionalparam" )
358     private String additionalparam;
359 
360     /**
361      * Set an additional Javadoc option(s) (i.e. JVM options) on the command line.
362      * Example:
363      * <pre>
364      * &lt;additionalJOption&gt;-J-Xss128m&lt;/additionalJOption&gt;
365      * </pre>
366      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#J">Jflag</a>.
367      * <br/>
368      * See <a href="http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp">vmoptions</a>.
369      * <br/>
370      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/guide/net/properties.html">Networking Properties</a>.
371      *
372      * @since 2.3
373      */
374     @Parameter( property = "additionalJOption" )
375     private String additionalJOption;
376 
377     /**
378      * Set additional JVM options for the execution of the javadoc command via the '-J' option to javadoc.
379      * Example:
380      * <pre>
381      *     &lt;additionalJOptions&gt;
382      *         &lt;additionalJOption&gt;-J-Xmx1g &lt;/additionalJOption&gt;
383      *     &lt;/additionalJOptions&gt;
384      * </pre>
385      * @since 2.9
386      */
387     @Parameter
388     private String[] additionalJOptions;
389 
390     /**
391      * A list of artifacts containing resources which should be copied into the
392      * Javadoc output directory (like stylesheets, icons, etc.).
393      * <br/>
394      * Example:
395      * <pre>
396      * &lt;resourcesArtifacts&gt;
397      * &nbsp;&nbsp;&lt;resourcesArtifact&gt;
398      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;groupId&gt;external.group.id&lt;/groupId&gt;
399      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;artifactId&gt;external-resources&lt;/artifactId&gt;
400      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;version&gt;1.0&lt;/version&gt;
401      * &nbsp;&nbsp;&lt;/resourcesArtifact&gt;
402      * &lt;/resourcesArtifacts&gt;
403      * </pre>
404      * <br/>
405      * See <a href="./apidocs/org/apache/maven/plugin/javadoc/options/ResourcesArtifact.html">Javadoc</a>.
406      * <br/>
407      *
408      * @since 2.5
409      */
410     @Parameter( property = "resourcesArtifacts" )
411     private ResourcesArtifact[] resourcesArtifacts;
412 
413     /**
414      * The local repository where the artifacts are located.
415      */
416     @Parameter( property = "localRepository" )
417     private ArtifactRepository localRepository;
418 
419     /**
420      * The remote repositories where artifacts are located.
421      */
422     @Parameter( property = "project.remoteArtifactRepositories" )
423     private List<ArtifactRepository> remoteRepositories;
424 
425     /**
426      * The projects in the reactor for aggregation report.
427      */
428     @Parameter( property = "reactorProjects", readonly = true )
429     private List<MavenProject> reactorProjects;
430 
431     /**
432      * Whether to build an aggregated report at the root, or build individual reports.
433      *
434      * @deprecated since 2.5. Use the goals <code>javadoc:aggregate</code> and <code>javadoc:test-aggregate</code> instead.
435      */
436     @Parameter( property = "aggregate", defaultValue = "false" )
437     protected boolean aggregate;
438 
439     /**
440      * Set this to <code>true</code> to debug the Javadoc plugin. With this, <code>javadoc.bat(or.sh)</code>,
441      * <code>options</code>, <code>@packages</code> or <code>argfile</code> files are provided in the output directory.
442      * <br/>
443      *
444      * @since 2.1
445      */
446     @Parameter( property = "debug", defaultValue = "false" )
447     private boolean debug;
448 
449     /**
450      * Sets the absolute path of the Javadoc Tool executable to use. Since version 2.5, a mere directory specification
451      * is sufficient to have the plugin use "javadoc" or "javadoc.exe" respectively from this directory.
452      *
453      * @since 2.3
454      */
455     @Parameter( property = "javadocExecutable" )
456     private String javadocExecutable;
457 
458     /**
459      * Version of the Javadoc Tool executable to use, ex. "1.3", "1.5".
460      *
461      * @since 2.3
462      */
463     @Parameter( property = "javadocVersion" )
464     private String javadocVersion;
465 
466     /**
467      * Version of the Javadoc Tool executable to use as float.
468      */
469     private float fJavadocVersion = 0.0f;
470 
471     /**
472      * Specifies whether the Javadoc generation should be skipped.
473      *
474      * @since 2.5
475      */
476     @Parameter( property = "maven.javadoc.skip", defaultValue = "false" )
477     protected boolean skip;
478 
479     /**
480      * Specifies if the build will fail if there are errors during javadoc execution or not.
481      *
482      * @since 2.5
483      */
484     @Parameter( property = "maven.javadoc.failOnError", defaultValue = "true" )
485     protected boolean failOnError;
486 
487     /**
488      * Specifies to use the <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#standard">
489      * options provided by the Standard Doclet</a> for a custom doclet.
490      * <br/>
491      * Example:
492      * <pre>
493      * &lt;docletArtifacts&gt;
494      * &nbsp;&nbsp;&lt;docletArtifact&gt;
495      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;groupId&gt;com.sun.tools.doclets&lt;/groupId&gt;
496      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;artifactId&gt;doccheck&lt;/artifactId&gt;
497      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;version&gt;1.2b2&lt;/version&gt;
498      * &nbsp;&nbsp;&lt;/docletArtifact&gt;
499      * &lt;/docletArtifacts&gt;
500      * &lt;useStandardDocletOptions&gt;true&lt;/useStandardDocletOptions&gt;
501      * </pre>
502      *
503      * @since 2.5
504      */
505     @Parameter( property = "useStandardDocletOptions", defaultValue = "true" )
506     protected boolean useStandardDocletOptions;
507 
508     /**
509      * Detect the Javadoc links for all dependencies defined in the project. The detection is based on the default
510      * Maven conventions, i.e.: <code>${project.url}/apidocs</code>.
511      * <br/>
512      * For instance, if the project has a dependency to
513      * <a href="http://commons.apache.org/lang/">Apache Commons Lang</a> i.e.:
514      * <pre>
515      * &lt;dependency&gt;
516      *   &lt;groupId&gt;commons-lang&lt;/groupId&gt;
517      *   &lt;artifactId&gt;commons-lang&lt;/artifactId&gt;
518      * &lt;/dependency&gt;
519      * </pre>
520      * The added Javadoc <code>-link</code> parameter will be <code>http://commons.apache.org/lang/apidocs</code>.
521      *
522      * @see #links
523      * @since 2.6
524      */
525     @Parameter( property = "detectLinks", defaultValue = "false" )
526     private boolean detectLinks;
527 
528     /**
529      * Detect the links for all modules defined in the project.
530      * <br/>
531      * If {@link #reactorProjects} is defined in a non-aggregator way, it generates default offline links
532      * between modules based on the defined project's urls. For instance, if a parent project has two projects
533      * <code>module1</code> and <code>module2</code>, the <code>-linkoffline</code> will be:
534      * <br/>
535      * The added Javadoc <code>-linkoffline</code> parameter for <b>module1</b> will be
536      * <code>/absolute/path/to/</code><b>module2</b><code>/target/site/apidocs</code>
537      * <br/>
538      * The added Javadoc <code>-linkoffline</code> parameter for <b>module2</b> will be
539      * <code>/absolute/path/to/</code><b>module1</b><code>/target/site/apidocs</code>
540      *
541      * @see #offlineLinks
542      * @since 2.6
543      */
544     @Parameter( property = "detectOfflineLinks", defaultValue = "true" )
545     private boolean detectOfflineLinks;
546 
547     /**
548      * Detect the Java API link for the current build, i.e. <code>http://docs.oracle.com/javase/1.4.2/docs/api/</code>
549      * for Java source 1.4.
550      * <br/>
551      * By default, the goal detects the Javadoc API link depending the value of the <code>source</code>
552      * parameter in the <code>org.apache.maven.plugins:maven-compiler-plugin</code>
553      * (defined in <code>${project.build.plugins}</code> or in <code>${project.build.pluginManagement}</code>),
554      * or try to compute it from the {@link #javadocExecutable} version.
555      * <br/>
556      * See <a href="./apidocs/org/apache/maven/plugin/javadoc/AbstractJavadocMojo.html#DEFAULT_JAVA_API_LINKS">Javadoc</a> for the default values.
557      * <br/>
558      *
559      * @see #links
560      * @see #javaApiLinks
561      * @see #DEFAULT_JAVA_API_LINKS
562      * @since 2.6
563      */
564     @Parameter( property = "detectJavaApiLink", defaultValue = "true" )
565     private boolean detectJavaApiLink;
566 
567     /**
568      * Use this parameter <b>only</b> if the <a href="http://java.sun.com/reference/api/index.html">Sun Javadoc API</a>
569      * urls have been changed or to use custom urls for Javadoc API url.
570      * <br/>
571      * See <a href="./apidocs/org/apache/maven/plugin/javadoc/AbstractJavadocMojo.html#DEFAULT_JAVA_API_LINKS">Javadoc</a>
572      * for the default values.
573      * <br/>
574      *
575      * @see #DEFAULT_JAVA_API_LINKS
576      * @since 2.6
577      */
578     @Parameter( property = "javaApiLinks" )
579     private Properties javaApiLinks;
580 
581     /**
582      * Flag controlling content validation of <code>package-list</code> resources. If set, the content of
583      * <code>package-list</code> resources will be validated.
584      *
585      * @since 2.8
586      */
587     @Parameter( property = "validateLinks", defaultValue = "false" )
588     private boolean validateLinks;
589 
590     // ----------------------------------------------------------------------
591     // Javadoc Options - all alphabetical
592     // ----------------------------------------------------------------------
593 
594     /**
595      * Specifies the paths where the boot classes reside. The <code>bootclasspath</code> can contain multiple paths
596      * by separating them with a colon (<code>:</code>) or a semi-colon (<code>;</code>).
597      * <br/>
598      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#bootclasspath">bootclasspath</a>.
599      * <br/>
600      *
601      * @since 2.5
602      */
603     @Parameter( property = "bootclasspath" )
604     private String bootclasspath;
605 
606     /**
607      * Specifies the artifacts where the boot classes reside.
608      * <br/>
609      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#bootclasspath">bootclasspath</a>.
610      * <br/>
611      * Example:
612      * <pre>
613      * &lt;bootclasspathArtifacts&gt;
614      * &nbsp;&nbsp;&lt;bootclasspathArtifact&gt;
615      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;groupId&gt;my-groupId&lt;/groupId&gt;
616      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;artifactId&gt;my-artifactId&lt;/artifactId&gt;
617      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;version&gt;my-version&lt;/version&gt;
618      * &nbsp;&nbsp;&lt;/bootclasspathArtifact&gt;
619      * &lt;/bootclasspathArtifacts&gt;
620      * </pre>
621      * <br/>
622      * See <a href="./apidocs/org/apache/maven/plugin/javadoc/options/BootclasspathArtifact.html">Javadoc</a>.
623      * <br/>
624      *
625      * @since 2.5
626      */
627     @Parameter( property = "bootclasspathArtifacts" )
628     private BootclasspathArtifact[] bootclasspathArtifacts;
629 
630     /**
631      * Uses the sentence break iterator to determine the end of the first sentence.
632      * <br/>
633      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#breakiterator">breakiterator</a>.
634      * <br/>
635      * Since <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/javadoc/whatsnew-1.4.html#summary">Java 1.4</a>.
636      * <br/>
637      */
638     @Parameter( property = "breakiterator", defaultValue = "false" )
639     private boolean breakiterator;
640 
641     /**
642      * Specifies the class file that starts the doclet used in generating the documentation.
643      * <br/>
644      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#doclet">doclet</a>.
645      */
646     @Parameter( property = "doclet" )
647     private String doclet;
648 
649     /**
650      * Specifies the artifact containing the doclet starting class file (specified with the <code>-doclet</code>
651      * option).
652      * <br/>
653      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#docletpath">docletpath</a>.
654      * <br/>
655      * Example:
656      * <pre>
657      * &lt;docletArtifact&gt;
658      * &nbsp;&nbsp;&lt;groupId&gt;com.sun.tools.doclets&lt;/groupId&gt;
659      * &nbsp;&nbsp;&lt;artifactId&gt;doccheck&lt;/artifactId&gt;
660      * &nbsp;&nbsp;&lt;version&gt;1.2b2&lt;/version&gt;
661      * &lt;/docletArtifact&gt;
662      * </pre>
663      * <br/>
664      * See <a href="./apidocs/org/apache/maven/plugin/javadoc/options/DocletArtifact.html">Javadoc</a>.
665      * <br/>
666      */
667     @Parameter( property = "docletArtifact" )
668     private DocletArtifact docletArtifact;
669 
670     /**
671      * Specifies multiple artifacts containing the path for the doclet starting class file (specified with the
672      * <code>-doclet</code> option).
673      * <br/>
674      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#docletpath">docletpath</a>.
675      * <br/>
676      * Example:
677      * <pre>
678      * &lt;docletArtifacts&gt;
679      * &nbsp;&nbsp;&lt;docletArtifact&gt;
680      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;groupId&gt;com.sun.tools.doclets&lt;/groupId&gt;
681      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;artifactId&gt;doccheck&lt;/artifactId&gt;
682      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;version&gt;1.2b2&lt;/version&gt;
683      * &nbsp;&nbsp;&lt;/docletArtifact&gt;
684      * &lt;/docletArtifacts&gt;
685      * </pre>
686      * <br/>
687      * See <a href="./apidocs/org/apache/maven/plugin/javadoc/options/DocletArtifact.html">Javadoc</a>.
688      * <br/>
689      *
690      * @since 2.1
691      */
692     @Parameter( property = "docletArtifacts" )
693     private DocletArtifact[] docletArtifacts;
694 
695     /**
696      * Specifies the path to the doclet starting class file (specified with the <code>-doclet</code> option) and
697      * any jar files it depends on. The <code>docletPath</code> can contain multiple paths by separating them with
698      * a colon (<code>:</code>) or a semi-colon (<code>;</code>).
699      * <br/>
700      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#docletpath">docletpath</a>.
701      */
702     @Parameter( property = "docletPath" )
703     private String docletPath;
704 
705     /**
706      * Specifies the encoding name of the source files. If not specificed, the encoding value will be the value of the
707      * <code>file.encoding</code> system property.
708      * <br/>
709      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#encoding">encoding</a>.
710      * <br/>
711      * <b>Note</b>: In 2.4, the default value was locked to <code>ISO-8859-1</code> to ensure reproducing build, but
712      * this was reverted in 2.5.
713      * <br/>
714      */
715     @Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}" )
716     private String encoding;
717 
718     /**
719      * Unconditionally excludes the specified packages and their subpackages from the list formed by
720      * <code>-subpackages</code>. Multiple packages can be separated by commas (<code>,</code>), colons (<code>:</code>)
721      * or semicolons (<code>;</code>).
722      * <br/>
723      * Example:
724      * <pre>
725      * &lt;excludePackageNames&gt;*.internal:org.acme.exclude1.*:org.acme.exclude2&lt;/excludePackageNames&gt;
726      * </pre>
727      * <br/>
728      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#exclude">exclude</a>.
729      * <br/>
730      * Since <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/javadoc/whatsnew-1.4.html#summary">Java 1.4</a>.
731      */
732     @Parameter( property = "excludePackageNames" )
733     private String excludePackageNames;
734 
735     /**
736      * Specifies the directories where extension classes reside. Separate directories in <code>extdirs</code> with a
737      * colon (<code>:</code>) or a semi-colon (<code>;</code>).
738      * <br/>
739      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#extdirs">extdirs</a>.
740      */
741     @Parameter( property = "extdirs" )
742     private String extdirs;
743 
744     /**
745      * Specifies the locale that javadoc uses when generating documentation.
746      * <br/>
747      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#locale">locale</a>.
748      */
749     @Parameter( property = "locale" )
750     private String locale;
751 
752     /**
753      * Specifies the maximum Java heap size to be used when launching the Javadoc tool.
754      * JVMs refer to this property as the <code>-Xmx</code> parameter. Example: '512' or '512m'.
755      * The memory unit depends on the JVM used. The units supported could be: <code>k</code>, <code>kb</code>,
756      * <code>m</code>, <code>mb</code>, <code>g</code>, <code>gb</code>, <code>t</code>, <code>tb</code>.
757      * If no unit specified, the default unit is <code>m</code>.
758      */
759     @Parameter( property = "maxmemory" )
760     private String maxmemory;
761 
762     /**
763      * Specifies the minimum Java heap size to be used when launching the Javadoc tool.
764      * JVMs refer to this property as the <code>-Xms</code> parameter. Example: '512' or '512m'.
765      * The memory unit depends on the JVM used. The units supported could be: <code>k</code>, <code>kb</code>,
766      * <code>m</code>, <code>mb</code>, <code>g</code>, <code>gb</code>, <code>t</code>, <code>tb</code>.
767      * If no unit specified, the default unit is <code>m</code>.
768      */
769     @Parameter( property = "minmemory" )
770     private String minmemory;
771 
772     /**
773      * This option creates documentation with the appearance and functionality of documentation generated by
774      * Javadoc 1.1.
775      * <br/>
776      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#1.1">1.1</a>.
777      * <br/>
778      */
779     @Parameter( property = "old", defaultValue = "false" )
780     private boolean old;
781 
782     /**
783      * Specifies that javadoc should retrieve the text for the overview documentation from the "source" file
784      * specified by path/filename and place it on the Overview page (overview-summary.html).
785      * <br/>
786      * <b>Note</b>: could be in conflict with &lt;nooverview/&gt;.
787      * <br/>
788      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#overview">overview</a>.
789      * <br/>
790      */
791     @Parameter( property = "overview", defaultValue = "${basedir}/src/main/javadoc/overview.html" )
792     private File overview;
793 
794     /**
795      * Specifies the proxy host where the javadoc web access in <code>-link</code> would pass through.
796      * It defaults to the proxy host of the active proxy set in the <code>settings.xml</code>, otherwise it gets the
797      * proxy configuration set in the pom.
798      * <br/>
799      *
800      * @deprecated since 2.4. Instead of, configure an active proxy host in <code>settings.xml</code>.
801      */
802     @Parameter( property = "proxyHost" )
803     private String proxyHost;
804 
805     /**
806      * Specifies the proxy port where the javadoc web access in <code>-link</code> would pass through.
807      * It defaults to the proxy port of the active proxy set in the <code>settings.xml</code>, otherwise it gets the
808      * proxy configuration set in the pom.
809      * <br/>
810      *
811      * @deprecated since 2.4. Instead of, configure an active proxy port in <code>settings.xml</code>.
812      */
813     @Parameter( property = "proxyPort" )
814     private int proxyPort;
815 
816     /**
817      * Shuts off non-error and non-warning messages, leaving only the warnings and errors appear, making them
818      * easier to view.
819      * <br/>
820      * Note: was a standard doclet in Java 1.4.2 (refer to bug ID
821      * <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4714350">4714350</a>).
822      * <br/>
823      * See <a href="http://docs.oracle.com/javase/1.5.0/docs/tooldocs/windows/javadoc.html#quiet">quiet</a>.
824      * <br/>
825      * Since Java 5.0.
826      * <br/>
827      */
828     @Parameter( property = "quiet", defaultValue = "false" )
829     private boolean quiet;
830 
831     /**
832      * Specifies the access level for classes and members to show in the Javadocs.
833      * Possible values are:
834      * <ul>
835      * <li><a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#public">public</a>
836      * (shows only public classes and members)</li>
837      * <li><a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#protected">protected</a>
838      * (shows only public and protected classes and members)</li>
839      * <li><a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#package">package</a>
840      * (shows all classes and members not marked private)</li>
841      * <li><a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#private">private</a>
842      * (shows all classes and members)</li>
843      * </ul>
844      * <br/>
845      */
846     @Parameter( property = "show", defaultValue = "protected" )
847     private String show;
848 
849     /**
850      * Necessary to enable javadoc to handle assertions introduced in J2SE v 1.4 source code or generics introduced in J2SE v5.
851      * <br/>
852      * See <a href="http://docs.oracle.com/javase/6/docs/technotes/tools/windows/javadoc.html#source">source</a>.
853      * <br/>
854      * Since <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/javadoc/whatsnew-1.4.html#summary">Java 1.4</a>.
855      */
856     @Parameter( property = "source" )
857     private String source;
858 
859     /**
860      * Specifies the source paths where the subpackages are located. The <code>sourcepath</code> can contain
861      * multiple paths by separating them with a colon (<code>:</code>) or a semi-colon (<code>;</code>).
862      * <br/>
863      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#sourcepath">sourcepath</a>.
864      */
865     @Parameter( property = "sourcepath" )
866     private String sourcepath;
867 
868     /**
869      * Specifies the package directory where javadoc will be executed. Multiple packages can be separated by
870      * colons (<code>:</code>).
871      * <br/>
872      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#subpackages">subpackages</a>.
873      * <br/>
874      * Since <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/javadoc/whatsnew-1.4.html#summary">Java 1.4</a>.
875      */
876     @Parameter( property = "subpackages" )
877     private String subpackages;
878 
879     /**
880      * Provides more detailed messages while javadoc is running.
881      * <br/>
882      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#verbose">verbose</a>.
883      * <br/>
884      */
885     @Parameter( property = "verbose", defaultValue = "false" )
886     private boolean verbose;
887 
888     // ----------------------------------------------------------------------
889     // Standard Doclet Options - all alphabetical
890     // ----------------------------------------------------------------------
891 
892     /**
893      * Specifies whether or not the author text is included in the generated Javadocs.
894      * <br/>
895      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#author">author</a>.
896      * <br/>
897      */
898     @Parameter( property = "author", defaultValue = "true" )
899     private boolean author;
900 
901     /**
902      * Specifies the text to be placed at the bottom of each output file.<br/>
903      * If you want to use html you have to put it in a CDATA section, <br/>
904      * eg. <code>&lt;![CDATA[Copyright 2005, &lt;a href="http://www.mycompany.com">MyCompany, Inc.&lt;a>]]&gt;</code>
905      * <br/>
906      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#bottom">bottom</a>.
907      * <br/>
908      */
909     @Parameter( property = "bottom",
910                 defaultValue = "Copyright &#169; {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved." )
911     private String bottom;
912 
913     /**
914      * Specifies the HTML character set for this document. If not specificed, the charset value will be the value of
915      * the <code>docencoding</code> parameter.
916      * <br/>
917      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#charset">charset</a>.
918      * <br/>
919      */
920     @Parameter( property = "charset" )
921     private String charset;
922 
923     /**
924      * Specifies the encoding of the generated HTML files. If not specificed, the docencoding value will be
925      * <code>UTF-8</code>.
926      * <br/>
927      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#docencoding">docencoding</a>.
928      */
929     @Parameter( property = "docencoding", defaultValue = "${project.reporting.outputEncoding}" )
930     private String docencoding;
931 
932     /**
933      * Enables deep copying of the <code>&#42;&#42;/doc-files</code> directories and the specifc <code>resources</code>
934      * directory from the <code>javadocDirectory</code> directory (for instance,
935      * <code>src/main/javadoc/com/mycompany/myapp/doc-files</code> and <code>src/main/javadoc/resources</code>).
936      * <br/>
937      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#docfilessubdirs">
938      * docfilessubdirs</a>.
939      * <br/>
940      * Since <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/javadoc/whatsnew-1.4.html#summary">Java 1.4</a>.
941      * <br/>
942      * See <a href="#javadocDirectory">javadocDirectory</a>.
943      * <br/>
944      *
945      * @see #excludedocfilessubdir
946      * @see #javadocDirectory
947      */
948     @Parameter( property = "docfilessubdirs", defaultValue = "false" )
949     private boolean docfilessubdirs;
950 
951     /**
952      * Specifies the title to be placed near the top of the overview summary file.
953      * <br/>
954      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#doctitle">doctitle</a>.
955      * <br/>
956      */
957     @Parameter( property = "doctitle", defaultValue = "${project.name} ${project.version} API" )
958     private String doctitle;
959 
960     /**
961      * Excludes any "doc-files" subdirectories with the given names. Multiple patterns can be excluded
962      * by separating them with colons (<code>:</code>).
963      * <br/>
964      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#excludedocfilessubdir">
965      * excludedocfilessubdir</a>.
966      * <br/>
967      * Since <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/javadoc/whatsnew-1.4.html#summary">Java 1.4</a>.
968      *
969      * @see #docfilessubdirs
970      */
971     @Parameter( property = "excludedocfilessubdir" )
972     private String excludedocfilessubdir;
973 
974     /**
975      * Specifies the footer text to be placed at the bottom of each output file.
976      * <br/>
977      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#footer">footer</a>.
978      */
979     @Parameter( property = "footer" )
980     private String footer;
981 
982     /**
983      * Separates packages on the overview page into whatever groups you specify, one group per table. The
984      * packages pattern can be any package name, or can be the start of any package name followed by an asterisk
985      * (<code>*</code>) meaning "match any characters". Multiple patterns can be included in a group
986      * by separating them with colons (<code>:</code>).
987      * <br/>
988      * Example:
989      * <pre>
990      * &lt;groups&gt;
991      * &nbsp;&nbsp;&lt;group&gt;
992      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;title&gt;Core Packages&lt;/title&gt;
993      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;!-- To includes java.lang, java.lang.ref,
994      * &nbsp;&nbsp;&nbsp;&nbsp;java.lang.reflect and only java.util
995      * &nbsp;&nbsp;&nbsp;&nbsp;(i.e. not java.util.jar) --&gt;
996      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;packages&gt;java.lang*:java.util&lt;/packages&gt;
997      * &nbsp;&nbsp;&lt;/group&gt;
998      * &nbsp;&nbsp;&lt;group&gt;
999      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;title&gt;Extension Packages&lt;/title&gt;
1000      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!-- To include javax.accessibility,
1001      * &nbsp;&nbsp;&nbsp;&nbsp;javax.crypto, ... (among others) --&gt;
1002      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;packages&gt;javax.*&lt;/packages&gt;
1003      * &nbsp;&nbsp;&lt;/group&gt;
1004      * &lt;/groups&gt;
1005      * </pre>
1006      * <b>Note</b>: using <code>java.lang.*</code> for <code>packages</code> would omit the <code>java.lang</code>
1007      * package but using <code>java.lang*</code> will include it.
1008      * <br/>
1009      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#group">group</a>.
1010      * <br/>
1011      * See <a href="./apidocs/org/apache/maven/plugin/javadoc/options/Group.html">Javadoc</a>.
1012      * <br/>
1013      */
1014     @Parameter( property = "groups" )
1015     private Group[] groups;
1016 
1017     /**
1018      * Specifies the header text to be placed at the top of each output file.
1019      * <br/>
1020      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#header">header</a>.
1021      */
1022     @Parameter( property = "header" )
1023     private String header;
1024 
1025     /**
1026      * Specifies the path of an alternate help file path\filename that the HELP link in the top and bottom
1027      * navigation bars link to.
1028      * <br/>
1029      * <b>Note</b>: could be in conflict with &lt;nohelp/&gt;.
1030      * <br/>
1031      * The <code>helpfile</code> could be an absolute File path.
1032      * <br/>
1033      * Since 2.6, it could be also be a path from a resource in the current project source directories
1034      * (i.e. <code>src/main/java</code>, <code>src/main/resources</code> or <code>src/main/javadoc</code>)
1035      * or from a resource in the Javadoc plugin dependencies, for instance:
1036      * <pre>
1037      * &lt;helpfile&gt;path/to/your/resource/yourhelp-doc.html&lt;/helpfile&gt;
1038      * </pre>
1039      * Where <code>path/to/your/resource/yourhelp-doc.html</code> could be in <code>src/main/javadoc</code>.
1040      * <pre>
1041      * &lt;build&gt;
1042      * &nbsp;&nbsp;&lt;plugins&gt;
1043      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;plugin&gt;
1044      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
1045      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;artifactId&gt;maven-javadoc-plugin&lt;/artifactId&gt;
1046      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;configuration&gt;
1047      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;helpfile&gt;path/to/your/resource/yourhelp-doc.html&lt;/helpfile&gt;
1048      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...
1049      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/configuration&gt;
1050      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;dependencies&gt;
1051      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;dependency&gt;
1052      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;groupId&gt;groupId&lt;/groupId&gt;
1053      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;artifactId&gt;artifactId&lt;/artifactId&gt;
1054      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;version&gt;version&lt;/version&gt;
1055      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/dependency&gt;
1056      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/dependencies&gt;
1057      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;/plugin&gt;
1058      * &nbsp;&nbsp;&nbsp;&nbsp;...
1059      * &nbsp;&nbsp;&lt;plugins&gt;
1060      * &lt;/build&gt;
1061      * </pre>
1062      * Where <code>path/to/your/resource/yourhelp-doc.html</code> is defined in the
1063      * <code>groupId:artifactId:version</code> javadoc plugin dependency.
1064      * <br/>
1065      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#helpfile">helpfile</a>.
1066      */
1067     @Parameter( property = "helpfile" )
1068     private String helpfile;
1069 
1070     /**
1071      * Adds HTML meta keyword tags to the generated file for each class.
1072      * <br/>
1073      * See <a href="http://docs.oracle.com/javase/1.5.0/docs/tooldocs/windows/javadoc.html#keywords">keywords</a>.
1074      * <br/>
1075      * Since <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/javadoc/whatsnew-1.4.2.html#commandlineoptions">
1076      * Java 1.4.2</a>.
1077      * <br/>
1078      * Since <a href="http://docs.oracle.com/javase/1.5.0/docs/guide/javadoc/whatsnew-1.5.0.html#commandlineoptions">
1079      * Java 5.0</a>.
1080      * <br/>
1081      *
1082      * @since 2.1
1083      */
1084     @Parameter( property = "keywords", defaultValue = "false" )
1085     private boolean keywords;
1086 
1087     /**
1088      * Creates links to existing javadoc-generated documentation of external referenced classes.
1089      * <br/>
1090      * <b>Notes</b>:
1091      * <ol>
1092      * <li>only used if {@link #isOffline} is set to <code>false</code>.</li>
1093      * <li>all given links should have a fetchable <code>/package-list</code> file. For instance:
1094      * <pre>
1095      * &lt;links&gt;
1096      * &nbsp;&nbsp;&lt;link&gt;http://docs.oracle.com/javase/1.4.2/docs/api&lt;/link&gt;
1097      * &lt;links&gt;
1098      * </pre>
1099      * will be used because <code>http://docs.oracle.com/javase/1.4.2/docs/api/package-list</code> exists.</li>
1100      * <li>if {@link #detectLinks} is defined, the links between the project dependencies are
1101      * automatically added.</li>
1102      * <li>if {@link #detectJavaApiLink} is defined, a Java API link, based on the Java version of the
1103      * project's sources, will be added automatically.</li>
1104      * </ol>
1105      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#link">link</a>.
1106      *
1107      * @see #detectLinks
1108      * @see #detectJavaApiLink
1109      */
1110     @Parameter( property = "links" )
1111     protected ArrayList<String> links;
1112 
1113     /**
1114      * Creates an HTML version of each source file (with line numbers) and adds links to them from the standard
1115      * HTML documentation.
1116      * <br/>
1117      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#linksource">linksource</a>.
1118      * <br/>
1119      * Since <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/javadoc/whatsnew-1.4.html#summary">Java 1.4</a>.
1120      * <br/>
1121      */
1122     @Parameter( property = "linksource", defaultValue = "false" )
1123     private boolean linksource;
1124 
1125     /**
1126      * Suppress the entire comment body, including the main description and all tags, generating only declarations.
1127      * <br/>
1128      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#nocomment">nocomment</a>.
1129      * <br/>
1130      * Since <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/javadoc/whatsnew-1.4.html#summary">Java 1.4</a>.
1131      * <br/>
1132      */
1133     @Parameter( property = "nocomment", defaultValue = "false" )
1134     private boolean nocomment;
1135 
1136     /**
1137      * Prevents the generation of any deprecated API at all in the documentation.
1138      * <br/>
1139      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#nodeprecated">nodeprecated</a>.
1140      * <br/>
1141      */
1142     @Parameter( property = "nodeprecated", defaultValue = "false" )
1143     private boolean nodeprecated;
1144 
1145     /**
1146      * Prevents the generation of the file containing the list of deprecated APIs (deprecated-list.html) and the
1147      * link in the navigation bar to that page.
1148      * <br/>
1149      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#nodeprecatedlist">
1150      * nodeprecatedlist</a>.
1151      * <br/>
1152      */
1153     @Parameter( property = "nodeprecatedlist", defaultValue = "false" )
1154     private boolean nodeprecatedlist;
1155 
1156     /**
1157      * Omits the HELP link in the navigation bars at the top and bottom of each page of output.
1158      * <br/>
1159      * <b>Note</b>: could be in conflict with &lt;helpfile/&gt;.
1160      * <br/>
1161      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#nohelp">nohelp</a>.
1162      * <br/>
1163      */
1164     @Parameter( property = "nohelp", defaultValue = "false" )
1165     private boolean nohelp;
1166 
1167     /**
1168      * Omits the index from the generated docs.
1169      * <br/>
1170      * <b>Note</b>: could be in conflict with &lt;splitindex/&gt;.
1171      * <br/>
1172      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#noindex">noindex</a>.
1173      * <br/>
1174      */
1175     @Parameter( property = "noindex", defaultValue = "false" )
1176     private boolean noindex;
1177 
1178     /**
1179      * Omits the navigation bar from the generated docs.
1180      * <br/>
1181      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#nonavbar">nonavbar</a>.
1182      * <br/>
1183      */
1184     @Parameter( property = "nonavbar", defaultValue = "false" )
1185     private boolean nonavbar;
1186 
1187     /**
1188      * Omits the entire overview page from the generated docs.
1189      * <br/>
1190      * <b>Note</b>: could be in conflict with &lt;overview/&gt;.
1191      * <br/>
1192      * Standard Doclet undocumented option.
1193      * <br/>
1194      *
1195      * @since 2.4
1196      */
1197     @Parameter( property = "nooverview", defaultValue = "false" )
1198     private boolean nooverview;
1199 
1200     /**
1201      * Omits qualifying package name from ahead of class names in output.
1202      * Example:
1203      * <pre>
1204      * &lt;noqualifier&gt;all&lt;/noqualifier&gt;
1205      * or
1206      * &lt;noqualifier&gt;packagename1:packagename2&lt;/noqualifier&gt;
1207      * </pre>
1208      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#noqualifier">noqualifier</a>.
1209      * <br/>
1210      * Since <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/javadoc/whatsnew-1.4.html#summary">Java 1.4</a>.
1211      */
1212     @Parameter( property = "noqualifier" )
1213     private String noqualifier;
1214 
1215     /**
1216      * Omits from the generated docs the "Since" sections associated with the since tags.
1217      * <br/>
1218      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#nosince">nosince</a>.
1219      * <br/>
1220      */
1221     @Parameter( property = "nosince", defaultValue = "false" )
1222     private boolean nosince;
1223 
1224     /**
1225      * Suppresses the timestamp, which is hidden in an HTML comment in the generated HTML near the top of each page.
1226      * <br/>
1227      * See <a href="http://docs.oracle.com/javase/1.5.0/docs/tooldocs/windows/javadoc.html#notimestamp">notimestamp</a>.
1228      * <br/>
1229      * Since <a href="http://docs.oracle.com/javase/1.5.0/docs/guide/javadoc/whatsnew-1.5.0.html#commandlineoptions">
1230      * Java 5.0</a>.
1231      * <br/>
1232      *
1233      * @since 2.1
1234      */
1235     @Parameter( property = "notimestamp", defaultValue = "false" )
1236     private boolean notimestamp;
1237 
1238     /**
1239      * Omits the class/interface hierarchy pages from the generated docs.
1240      * <br/>
1241      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#notree">notree</a>.
1242      * <br/>
1243      */
1244     @Parameter( property = "notree", defaultValue = "false" )
1245     private boolean notree;
1246 
1247     /**
1248      * This option is a variation of <code>-link</code>; they both create links to javadoc-generated documentation
1249      * for external referenced classes.
1250      * <br/>
1251      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#linkoffline">linkoffline</a>.
1252      * <br/>
1253      * Example:
1254      * <pre>
1255      * &lt;offlineLinks&gt;
1256      * &nbsp;&nbsp;&lt;offlineLink&gt;
1257      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;url&gt;http://docs.oracle.com/javase/1.5.0/docs/api/&lt;/url&gt;
1258      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;location&gt;../javadoc/jdk-5.0/&lt;/location&gt;
1259      * &nbsp;&nbsp;&lt;/offlineLink&gt;
1260      * &lt;/offlineLinks&gt;
1261      * </pre>
1262      * <br/>
1263      * <b>Note</b>: if {@link #detectOfflineLinks} is defined, the offline links between the project modules are
1264      * automatically added if the goal is calling in a non-aggregator way.
1265      * <br/>
1266      * See <a href="./apidocs/org/apache/maven/plugin/javadoc/options/OfflineLink.html">Javadoc</a>.
1267      * <br/>
1268      */
1269     @Parameter( property = "offlineLinks" )
1270     private OfflineLink[] offlineLinks;
1271 
1272     /**
1273      * Specifies the destination directory where javadoc saves the generated HTML files.
1274      * <br/>
1275      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#d">d</a>.
1276      * <br/>
1277      */
1278     @Parameter( property = "destDir", alias = "destDir", defaultValue = "${project.build.directory}/apidocs",
1279                     required = true )
1280     protected File outputDirectory;
1281 
1282     /**
1283      * Specify the text for upper left frame.
1284      * <br/>
1285      * Since <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/javadoc/whatsnew-1.4.2.html#commandlineoptions">
1286      * Java 1.4.2</a>.
1287      *
1288      * @since 2.1
1289      */
1290     @Parameter( property = "packagesheader" )
1291     private String packagesheader;
1292 
1293     /**
1294      * Generates compile-time warnings for missing serial tags.
1295      * <br/>
1296      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#serialwarn">serialwarn</a>
1297      * <br/>
1298      */
1299     @Parameter( property = "serialwarn", defaultValue = "false" )
1300     private boolean serialwarn;
1301 
1302     /**
1303      * Specify the number of spaces each tab takes up in the source. If no tab is used in source, the default
1304      * space is used.
1305      * <br/>
1306      * Note: was <code>linksourcetab</code> in Java 1.4.2 (refer to bug ID
1307      * <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4788919">4788919</a>).
1308      * <br/>
1309      * Since <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/javadoc/whatsnew-1.4.2.html#commandlineoptions">
1310      * 1.4.2</a>.
1311      * <br/>
1312      * Since Java 5.0.
1313      *
1314      * @since 2.1
1315      */
1316     @Parameter( property = "sourcetab", alias = "linksourcetab" )
1317     private int sourcetab;
1318 
1319     /**
1320      * Splits the index file into multiple files, alphabetically, one file per letter, plus a file for any index
1321      * entries that start with non-alphabetical characters.
1322      * <br/>
1323      * <b>Note</b>: could be in conflict with &lt;noindex/&gt;.
1324      * <br/>
1325      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#splitindex">splitindex</a>.
1326      * <br/>
1327      */
1328     @Parameter( property = "splitindex", defaultValue = "false" )
1329     private boolean splitindex;
1330 
1331     /**
1332      * Specifies whether the stylesheet to be used is the <code>maven</code>'s javadoc stylesheet or
1333      * <code>java</code>'s default stylesheet when a <i>stylesheetfile</i> parameter is not specified.
1334      * <br/>
1335      * Possible values: <code>maven<code> or <code>java</code>.
1336      * <br/>
1337      */
1338     @Parameter( property = "stylesheet", defaultValue = "java" )
1339     private String stylesheet;
1340 
1341     /**
1342      * Specifies the path of an alternate HTML stylesheet file.
1343      * <br/>
1344      * The <code>stylesheetfile</code> could be an absolute File path.
1345      * <br/>
1346      * Since 2.6, it could be also be a path from a resource in the current project source directories
1347      * (i.e. <code>src/main/java</code>, <code>src/main/resources</code> or <code>src/main/javadoc</code>)
1348      * or from a resource in the Javadoc plugin dependencies, for instance:
1349      * <pre>
1350      * &lt;stylesheetfile&gt;path/to/your/resource/yourstylesheet.css&lt;/stylesheetfile&gt;
1351      * </pre>
1352      * Where <code>path/to/your/resource/yourstylesheet.css</code> could be in <code>src/main/javadoc</code>.
1353      * <pre>
1354      * &lt;build&gt;
1355      * &nbsp;&nbsp;&lt;plugins&gt;
1356      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;plugin&gt;
1357      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
1358      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;artifactId&gt;maven-javadoc-plugin&lt;/artifactId&gt;
1359      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;configuration&gt;
1360      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;stylesheetfile&gt;path/to/your/resource/yourstylesheet.css&lt;/stylesheetfile&gt;
1361      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...
1362      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/configuration&gt;
1363      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;dependencies&gt;
1364      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;dependency&gt;
1365      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;groupId&gt;groupId&lt;/groupId&gt;
1366      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;artifactId&gt;artifactId&lt;/artifactId&gt;
1367      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;version&gt;version&lt;/version&gt;
1368      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/dependency&gt;
1369      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/dependencies&gt;
1370      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;/plugin&gt;
1371      * &nbsp;&nbsp;&nbsp;&nbsp;...
1372      * &nbsp;&nbsp;&lt;plugins&gt;
1373      * &lt;/build&gt;
1374      * </pre>
1375      * Where <code>path/to/your/resource/yourstylesheet.css</code> is defined in the
1376      * <code>groupId:artifactId:version</code> javadoc plugin dependency.
1377      * <br/>
1378      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#stylesheetfile">
1379      * stylesheetfile</a>.
1380      */
1381     @Parameter( property = "stylesheetfile" )
1382    private String stylesheetfile;
1383 
1384     /**
1385      * Specifies the class file that starts the taglet used in generating the documentation for that tag.
1386      * <br/>
1387      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#taglet">taglet</a>.
1388      * <br/>
1389      * Since <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/javadoc/whatsnew-1.4.html#summary">Java 1.4</a>.
1390      */
1391     @Parameter( property = "taglet" )
1392     private String taglet;
1393 
1394     /**
1395      * Specifies the Taglet artifact containing the taglet class files (.class).
1396      * <br/>
1397      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#tagletpath">tagletpath</a>.
1398      * <br/>
1399      * Example:
1400      * <pre>
1401      * &lt;taglets&gt;
1402      * &nbsp;&nbsp;&lt;taglet&gt;
1403      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;tagletClass&gt;com.sun.tools.doclets.ToDoTaglet&lt;/tagletClass&gt;
1404      * &nbsp;&nbsp;&lt;/taglet&gt;
1405      * &nbsp;&nbsp;&lt;taglet&gt;
1406      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;tagletClass&gt;package.to.AnotherTagletClass&lt;/tagletClass&gt;
1407      * &nbsp;&nbsp;&lt;/taglet&gt;
1408      * &nbsp;&nbsp;...
1409      * &lt;/taglets&gt;
1410      * &lt;tagletArtifact&gt;
1411      * &nbsp;&nbsp;&lt;groupId&gt;group-Taglet&lt;/groupId&gt;
1412      * &nbsp;&nbsp;&lt;artifactId&gt;artifact-Taglet&lt;/artifactId&gt;
1413      * &nbsp;&nbsp;&lt;version&gt;version-Taglet&lt;/version&gt;
1414      * &lt;/tagletArtifact&gt;
1415      * </pre>
1416      * <br/>
1417      * See <a href="./apidocs/org/apache/maven/plugin/javadoc/options/TagletArtifact.html">Javadoc</a>.
1418      * <br/>
1419      *
1420      * @since 2.1
1421      */
1422     @Parameter( property = "tagletArtifact" )
1423     private TagletArtifact tagletArtifact;
1424 
1425     /**
1426      * Specifies several Taglet artifacts containing the taglet class files (.class). These taglets class names will be
1427      * auto-detect and so no need to specify them.
1428      * <br/>
1429      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#taglet">taglet</a>.
1430      * <br/>
1431      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#tagletpath">tagletpath</a>.
1432      * <br/>
1433      * Example:
1434      * <pre>
1435      * &lt;tagletArtifacts&gt;
1436      * &nbsp;&nbsp;&lt;tagletArtifact&gt;
1437      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;groupId&gt;group-Taglet&lt;/groupId&gt;
1438      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;artifactId&gt;artifact-Taglet&lt;/artifactId&gt;
1439      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;version&gt;version-Taglet&lt;/version&gt;
1440      * &nbsp;&nbsp;&lt;/tagletArtifact&gt;
1441      * &nbsp;&nbsp;...
1442      * &lt;/tagletArtifacts&gt;
1443      * </pre>
1444      * <br/>
1445      * See <a href="./apidocs/org/apache/maven/plugin/javadoc/options/TagletArtifact.html">Javadoc</a>.
1446      * <br/>
1447      *
1448      * @since 2.5
1449      */
1450     @Parameter( property = "tagletArtifacts" )
1451     private TagletArtifact[] tagletArtifacts;
1452 
1453     /**
1454      * Specifies the search paths for finding taglet class files (.class). The <code>tagletpath</code> can contain
1455      * multiple paths by separating them with a colon (<code>:</code>) or a semi-colon (<code>;</code>).
1456      * <br/>
1457      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#tagletpath">tagletpath</a>.
1458      * <br/>
1459      * Since <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/javadoc/whatsnew-1.4.html#summary">Java 1.4</a>.
1460      */
1461     @Parameter( property = "tagletpath" )
1462     private String tagletpath;
1463 
1464     /**
1465      * Enables the Javadoc tool to interpret multiple taglets.
1466      * <br/>
1467      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#taglet">taglet</a>.
1468      * <br/>
1469      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#tagletpath">tagletpath</a>.
1470      * <br/>
1471      * Example:
1472      * <pre>
1473      * &lt;taglets&gt;
1474      * &nbsp;&nbsp;&lt;taglet&gt;
1475      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;tagletClass&gt;com.sun.tools.doclets.ToDoTaglet&lt;/tagletClass&gt;
1476      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;!--&lt;tagletpath&gt;/home/taglets&lt;/tagletpath&gt;--&gt;
1477      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;tagletArtifact&gt;
1478      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;groupId&gt;group-Taglet&lt;/groupId&gt;
1479      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;artifactId&gt;artifact-Taglet&lt;/artifactId&gt;
1480      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;version&gt;version-Taglet&lt;/version&gt;
1481      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;/tagletArtifact&gt;
1482      * &nbsp;&nbsp;&lt;/taglet&gt;
1483      * &lt;/taglets&gt;
1484      * </pre>
1485      * <br/>
1486      * See <a href="./apidocs/org/apache/maven/plugin/javadoc/options/Taglet.html">Javadoc</a>.
1487      * <br/>
1488      *
1489      * @since 2.1
1490      */
1491     @Parameter( property = "taglets" )
1492     private Taglet[] taglets;
1493 
1494     /**
1495      * Enables the Javadoc tool to interpret a simple, one-argument custom block tag tagname in doc comments.
1496      * <br/>
1497      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#tag">tag</a>.
1498      * <br/>
1499      * Since <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/javadoc/whatsnew-1.4.html#summary">Java 1.4</a>.
1500      * <br/>
1501      * Example:
1502      * <pre>
1503      * &lt;tags&gt;
1504      * &nbsp;&nbsp;&lt;tag&gt;
1505      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;todo&lt;/name&gt;
1506      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;placement&gt;a&lt;/placement&gt;
1507      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;head&gt;To Do:&lt;/head&gt;
1508      * &nbsp;&nbsp;&lt;/tag&gt;
1509      * &lt;/tags&gt;
1510      * </pre>
1511      * <b>Note</b>: the placement should be a combinaison of Xaoptcmf letters:
1512      * <ul>
1513      * <li><b><code>X</code></b> (disable tag)</li>
1514      * <li><b><code>a</code></b> (all)</li>
1515      * <li><b><code>o</code></b> (overview)</li>
1516      * <li><b><code>p</code></b> (packages)</li>
1517      * <li><b><code>t</code></b> (types, that is classes and interfaces)</li>
1518      * <li><b><code>c</code></b> (constructors)</li>
1519      * <li><b><code>m</code></b> (methods)</li>
1520      * <li><b><code>f</code></b> (fields)</li>
1521      * </ul>
1522      * See <a href="./apidocs/org/apache/maven/plugin/javadoc/options/Tag.html">Javadoc</a>.
1523      * <br/>
1524      */
1525     @Parameter( property = "tags" )
1526     private Tag[] tags;
1527 
1528     /**
1529      * Specifies the top text to be placed at the top of each output file.
1530      * <br/>
1531      * See <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6227616">6227616</a>.
1532      * <br/>
1533      * Since Java 6.0
1534      *
1535      * @since 2.4
1536      */
1537     @Parameter( property = "top" )
1538     private String top;
1539 
1540     /**
1541      * Includes one "Use" page for each documented class and package.
1542      * <br/>
1543      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#use">use</a>.
1544      * <br/>
1545      */
1546     @Parameter( property = "use", defaultValue = "true" )
1547     private boolean use;
1548 
1549     /**
1550      * Includes the version text in the generated docs.
1551      * <br/>
1552      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#version">version</a>.
1553      * <br/>
1554      */
1555     @Parameter( property = "version", defaultValue = "true" )
1556     private boolean version;
1557 
1558     /**
1559      * Specifies the title to be placed in the HTML title tag.
1560      * <br/>
1561      * See <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#windowtitle">windowtitle</a>.
1562      * <br/>
1563      */
1564     @Parameter( property = "windowtitle", defaultValue = "${project.name} ${project.version} API" )
1565     private String windowtitle;
1566 
1567     /**
1568      * Whether dependency -sources jars should be resolved and included as source paths for javadoc generation.
1569      * This is useful when creating javadocs for a distribution project.
1570      *
1571      * @since 2.7
1572      */
1573     @Parameter( defaultValue = "false" )
1574     private boolean includeDependencySources;
1575 
1576     /**
1577      * Directory where unpacked project sources / test-sources should be cached.
1578      *
1579      * @see #includeDependencySources
1580      * @since 2.7
1581      */
1582     @Parameter( defaultValue = "${project.build.directory}/distro-javadoc-sources" )
1583     private File sourceDependencyCacheDir;
1584 
1585     /**
1586      * Whether to include transitive dependencies in the list of dependency -sources jars to include
1587      * in this javadoc run.
1588      *
1589      * @see #includeDependencySources
1590      * @since 2.7
1591      */
1592     @Parameter( defaultValue = "false" )
1593     private boolean includeTransitiveDependencySources;
1594 
1595     /**
1596      * List of included dependency-source patterns. Example: <code>org.apache.maven:*</code>
1597      *
1598      * @see #includeDependencySources
1599      * @since 2.7
1600      */
1601     @Parameter
1602     private List<String> dependencySourceIncludes;
1603 
1604     /**
1605      * List of excluded dependency-source patterns. Example: <code>org.apache.maven.shared:*</code>
1606      *
1607      * @see #includeDependencySources
1608      * @since 2.7
1609      */
1610     @Parameter
1611     private List<String> dependencySourceExcludes;
1612 
1613     /**
1614      * Directory into which assembled {@link JavadocOptions} instances will be written before they
1615      * are added to javadoc resources bundles.
1616      *
1617      * @since 2.7
1618      */
1619     @Parameter( defaultValue = "${project.build.directory}/javadoc-bundle-options", readonly = true )
1620     private File javadocOptionsDir;
1621 
1622     /**
1623      * Transient variable to allow lazy-resolution of javadoc bundles from dependencies, so they can
1624      * be used at various points in the javadoc generation process.
1625      *
1626      * @since 2.7
1627      */
1628     private transient List<JavadocBundle> dependencyJavadocBundles;
1629 
1630     /**
1631      * capability to add optionnal dependencies to the javadoc classpath.
1632      * Exemple:
1633      * <pre>
1634      * &lt;additionalDependencies&gt;
1635      * &nbsp;&nbsp;&lt;additionalDependency&gt;
1636      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;groupId&gt;geronimo-spec&lt;/groupId&gt;
1637      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;artifactId&gt;geronimo-spec-jta&lt;/artifactId&gt;
1638      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;version&gt;1.0.1B-rc4:&lt;/version&gt;
1639      * &nbsp;&nbsp;&lt;/additionalDependency&gt;
1640      * &lt;/additionalDependencies&gt;
1641      * </pre>
1642      *
1643      * @since 2.8.1
1644      */
1645     @Parameter
1646     private List<AdditionalDependency> additionalDependencies;
1647 
1648     /**
1649      * Include filters on the source files. Default is **\/\*.java.
1650      * These are ignored if you specify subpackages or subpackage excludes.
1651      */
1652     @Parameter
1653     private List<String> sourceFileIncludes;
1654 
1655     /**
1656      * exclude filters on the source files.
1657      * These are ignored if you specify subpackages or subpackage excludes.
1658      */
1659     @Parameter
1660     private List<String> sourceFileExcludes;
1661     
1662     // ----------------------------------------------------------------------
1663     // static
1664     // ----------------------------------------------------------------------
1665 
1666     static
1667     {
1668         DEFAULT_JAVA_API_LINKS.put( "api_1.3", "http://docs.oracle.com/javase/1.3/docs/api/" );
1669         DEFAULT_JAVA_API_LINKS.put( "api_1.4", "http://docs.oracle.com/javase/1.4.2/docs/api/" );
1670         DEFAULT_JAVA_API_LINKS.put( "api_1.5", "http://docs.oracle.com/javase/1.5.0/docs/api/" );
1671         DEFAULT_JAVA_API_LINKS.put( "api_1.6", "http://docs.oracle.com/javase/6/docs/api/" );
1672         DEFAULT_JAVA_API_LINKS.put( "api_1.7", "http://docs.oracle.com/javase/7/docs/api/" );
1673     }
1674 
1675     // ----------------------------------------------------------------------
1676     // protected methods
1677     // ----------------------------------------------------------------------
1678 
1679     /**
1680      * Indicates whether this goal is flagged with <code>@aggregator</code>.
1681      *
1682      * @return <code>true</code> if the goal is designed as an aggregator, <code>false</code> otherwise.
1683      * @see AggregatorJavadocReport
1684      * @see AggregatorTestJavadocReport
1685      */
1686     protected boolean isAggregator()
1687     {
1688         return false;
1689     }
1690 
1691     /**
1692      * @return the output directory
1693      */
1694     protected String getOutputDirectory()
1695     {
1696         return outputDirectory.getAbsoluteFile().toString();
1697     }
1698 
1699     protected MavenProject getProject()
1700     {
1701         return project;
1702     }
1703 
1704     /**
1705      * @param p not null maven project
1706      * @return the list of directories where compiled classes are placed for the given project. These dirs are
1707      *         added in the javadoc classpath.
1708      */
1709     protected List<String> getProjectBuildOutputDirs( MavenProject p )
1710     {
1711         if ( StringUtils.isEmpty( p.getBuild().getOutputDirectory() ) )
1712         {
1713             return Collections.emptyList();
1714         }
1715 
1716         return Collections.singletonList( p.getBuild().getOutputDirectory() );
1717     }
1718 
1719     /**
1720      * @param p not null maven project
1721      * @return the list of source paths for the given project
1722      */
1723     protected List<String> getProjectSourceRoots( MavenProject p )
1724     {
1725         if ( "pom".equals( p.getPackaging().toLowerCase() ) )
1726         {
1727             return Collections.emptyList();
1728         }
1729 
1730         return ( p.getCompileSourceRoots() == null
1731             ? Collections.<String>emptyList()
1732             : new LinkedList<String>( p.getCompileSourceRoots() ) );
1733     }
1734 
1735     /**
1736      * @param p not null maven project
1737      * @return the list of source paths for the execution project of the given project
1738      */
1739     protected List<String> getExecutionProjectSourceRoots( MavenProject p )
1740     {
1741         if ( "pom".equals( p.getExecutionProject().getPackaging().toLowerCase() ) )
1742         {
1743             return Collections.emptyList();
1744         }
1745 
1746         return ( p.getExecutionProject().getCompileSourceRoots() == null
1747             ? Collections.<String>emptyList()
1748             : new LinkedList<String>( p.getExecutionProject().getCompileSourceRoots() ) );
1749     }
1750 
1751     /**
1752      * @param p not null maven project
1753      * @return the list of artifacts for the given project
1754      */
1755     protected List<Artifact> getProjectArtifacts( MavenProject p )
1756     {
1757         return ( p.getCompileArtifacts() == null
1758             ? Collections.<Artifact>emptyList()
1759             : new LinkedList<Artifact>( p.getCompileArtifacts() ) );
1760     }
1761 
1762     /**
1763      * @return the current javadoc directory
1764      */
1765     protected File getJavadocDirectory()
1766     {
1767         return javadocDirectory;
1768     }
1769 
1770     /**
1771      * @return the title to be placed near the top of the overview summary file
1772      */
1773     protected String getDoctitle()
1774     {
1775         return doctitle;
1776     }
1777 
1778     /**
1779      * @return the overview documentation file from the user parameter or from the <code>javadocdirectory</code>
1780      */
1781     protected File getOverview()
1782     {
1783         return overview;
1784     }
1785 
1786     /**
1787      * @return the title to be placed in the HTML title tag
1788      */
1789     protected String getWindowtitle()
1790     {
1791         return windowtitle;
1792     }
1793 
1794     /**
1795      * @return the charset attribute or the value of {@link #getDocencoding()} if <code>null</code>.
1796      */
1797     private String getCharset()
1798     {
1799         return ( StringUtils.isEmpty( charset ) ) ? getDocencoding() : charset;
1800     }
1801 
1802     /**
1803      * @return the docencoding attribute or <code>UTF-8</code> if <code>null</code>.
1804      */
1805     private String getDocencoding()
1806     {
1807         return ( StringUtils.isEmpty( docencoding ) ) ? ReaderFactory.UTF_8 : docencoding;
1808     }
1809 
1810     /**
1811      * @return the encoding attribute or the value of <code>file.encoding</code> system property if <code>null</code>.
1812      */
1813     private String getEncoding()
1814     {
1815         return ( StringUtils.isEmpty( encoding ) ) ? ReaderFactory.FILE_ENCODING : encoding;
1816     }
1817 
1818     /**
1819      * The <a href="package-summary.html">package documentation</a> details the
1820      * Javadoc Options used by this Plugin.
1821      *
1822      * @param unusedLocale the wanted locale (actually unused).
1823      * @throws MavenReportException if any
1824      */
1825     protected void executeReport( Locale unusedLocale )
1826         throws MavenReportException
1827     {
1828         if ( skip )
1829         {
1830             getLog().info( "Skipping javadoc generation" );
1831             return;
1832         }
1833 
1834         if ( isAggregator() && !project.isExecutionRoot() )
1835         {
1836             return;
1837         }
1838 
1839         if ( getLog().isDebugEnabled() )
1840         {
1841             this.debug = true;
1842         }
1843 
1844         // NOTE: Always generate this file, to allow javadocs from modules to be aggregated via
1845         // useDependencySources in a distro module build.
1846         try
1847         {
1848             buildJavadocOptions();
1849         }
1850         catch ( IOException e )
1851         {
1852             throw new MavenReportException( "Failed to generate javadoc options file: " + e.getMessage(), e );
1853         }
1854 
1855         List<String> sourcePaths = getSourcePaths();
1856         List<String> files = getFiles( sourcePaths );
1857         if ( !canGenerateReport( files ) )
1858         {
1859             return;
1860         }
1861 
1862         List<String> packageNames = getPackageNames( sourcePaths, files );
1863         List<String> filesWithUnnamedPackages = getFilesWithUnnamedPackages( sourcePaths, files );
1864 
1865         // ----------------------------------------------------------------------
1866         // Find the javadoc executable and version
1867         // ----------------------------------------------------------------------
1868 
1869         String jExecutable;
1870         try
1871         {
1872             jExecutable = getJavadocExecutable();
1873         }
1874         catch ( IOException e )
1875         {
1876             throw new MavenReportException( "Unable to find javadoc command: " + e.getMessage(), e );
1877         }
1878         setFJavadocVersion( new File( jExecutable ) );
1879 
1880         // ----------------------------------------------------------------------
1881         // Javadoc output directory as File
1882         // ----------------------------------------------------------------------
1883 
1884         File javadocOutputDirectory = new File( getOutputDirectory() );
1885         if ( javadocOutputDirectory.exists() && !javadocOutputDirectory.isDirectory() )
1886         {
1887             throw new MavenReportException( "IOException: " + getOutputDirectory() + " is not a directory." );
1888         }
1889         if ( javadocOutputDirectory.exists() && !javadocOutputDirectory.canWrite() )
1890         {
1891             throw new MavenReportException( "IOException: " + getOutputDirectory() + " is not writable." );
1892         }
1893         javadocOutputDirectory.mkdirs();
1894 
1895         // ----------------------------------------------------------------------
1896         // Copy all resources
1897         // ----------------------------------------------------------------------
1898 
1899         copyAllResources( javadocOutputDirectory );
1900 
1901         // ----------------------------------------------------------------------
1902         // Create command line for Javadoc
1903         // ----------------------------------------------------------------------
1904 
1905         Commandline cmd = new Commandline();
1906         cmd.getShell().setQuotedArgumentsEnabled( false ); // for Javadoc JVM args
1907         cmd.setWorkingDirectory( javadocOutputDirectory.getAbsolutePath() );
1908         cmd.setExecutable( jExecutable );
1909 
1910         // ----------------------------------------------------------------------
1911         // Wrap Javadoc JVM args
1912         // ----------------------------------------------------------------------
1913 
1914         addMemoryArg( cmd, "-Xmx", this.maxmemory );
1915         addMemoryArg( cmd, "-Xms", this.minmemory );
1916         addProxyArg( cmd );
1917 
1918         if ( StringUtils.isNotEmpty( additionalJOption ) )
1919         {
1920             cmd.createArg().setValue( additionalJOption );
1921         }
1922 
1923         if ( additionalJOptions != null && additionalJOptions.length != 0 )
1924         {
1925             for ( String jo : additionalJOptions )
1926             {
1927                 cmd.createArg().setValue( jo );
1928             }
1929         }
1930 
1931         List<String> arguments = new ArrayList<String>();
1932 
1933         // ----------------------------------------------------------------------
1934         // Wrap Javadoc options
1935         // ----------------------------------------------------------------------
1936 
1937         addJavadocOptions( arguments, sourcePaths );
1938 
1939         // ----------------------------------------------------------------------
1940         // Wrap Standard doclet Options
1941         // ----------------------------------------------------------------------
1942 
1943         if ( StringUtils.isEmpty( doclet ) || useStandardDocletOptions )
1944         {
1945             addStandardDocletOptions( javadocOutputDirectory, arguments );
1946         }
1947 
1948         // ----------------------------------------------------------------------
1949         // Write options file and include it in the command line
1950         // ----------------------------------------------------------------------
1951 
1952         if ( arguments.size() > 0 )
1953         {
1954             addCommandLineOptions( cmd, arguments, javadocOutputDirectory );
1955         }
1956 
1957         // ----------------------------------------------------------------------
1958         // Write packages file and include it in the command line
1959         // ----------------------------------------------------------------------
1960 
1961         if ( !packageNames.isEmpty() )
1962         {
1963             addCommandLinePackages( cmd, javadocOutputDirectory, packageNames );
1964 
1965             // ----------------------------------------------------------------------
1966             // Write argfile file and include it in the command line
1967             // ----------------------------------------------------------------------
1968 
1969             if ( !filesWithUnnamedPackages.isEmpty() )
1970             {
1971                 addCommandLineArgFile( cmd, javadocOutputDirectory, filesWithUnnamedPackages );
1972             }
1973         }
1974         else
1975         {
1976             // ----------------------------------------------------------------------
1977             // Write argfile file and include it in the command line
1978             // ----------------------------------------------------------------------
1979 
1980             if ( !files.isEmpty() )
1981             {
1982                 addCommandLineArgFile( cmd, javadocOutputDirectory, files );
1983             }
1984         }
1985 
1986         // ----------------------------------------------------------------------
1987         // Execute command line
1988         // ----------------------------------------------------------------------
1989 
1990         executeJavadocCommandLine( cmd, javadocOutputDirectory );
1991 
1992         // delete generated javadoc files only if no error and no debug mode
1993         // [MJAVADOC-336] Use File.delete() instead of File.deleteOnExit() to
1994         // prevent these files from making their way into archives.
1995         if ( !debug )
1996         {
1997             for ( int i = 0; i < cmd.getArguments().length; i++ )
1998             {
1999                 String arg = cmd.getArguments()[i].trim();
2000 
2001                 if ( !arg.startsWith( "@" ) )
2002                 {
2003                     continue;
2004                 }
2005 
2006                 File argFile = new File( javadocOutputDirectory, arg.substring( 1 ) );
2007                 if ( argFile.exists() )
2008                 {
2009                     argFile.delete();
2010                 }
2011             }
2012 
2013             File scriptFile = new File( javadocOutputDirectory, DEBUG_JAVADOC_SCRIPT_NAME );
2014             if ( scriptFile.exists() )
2015             {
2016                 scriptFile.delete();
2017             }
2018         }
2019     }
2020 
2021     /**
2022      * Method to get the files on the specified source paths
2023      *
2024      * @param sourcePaths a List that contains the paths to the source files
2025      * @return a List that contains the specific path for every source file
2026      * @throws MavenReportException
2027      */
2028     protected List<String> getFiles( List<String> sourcePaths )
2029         throws MavenReportException
2030     {
2031         List<String> files = new ArrayList<String>();
2032         if ( StringUtils.isEmpty( subpackages ) )
2033         {
2034             String[] excludedPackages = getExcludedPackages();
2035 
2036             for ( String sourcePath : sourcePaths )
2037             {
2038                 File sourceDirectory = new File( sourcePath );
2039                 JavadocUtil.addFilesFromSource( files, sourceDirectory, sourceFileIncludes, sourceFileExcludes, excludedPackages );
2040             }
2041         }
2042 
2043         return files;
2044     }
2045 
2046     /**
2047      * Method to get the source paths. If no source path is specified in the parameter, the compile source roots
2048      * of the project will be used.
2049      *
2050      * @return a List of the project absolute source paths as <code>String</code>
2051      * @see JavadocUtil#pruneDirs(MavenProject, List)
2052      */
2053     protected List<String> getSourcePaths()
2054         throws MavenReportException
2055     {
2056         List<String> sourcePaths;
2057 
2058         if ( StringUtils.isEmpty( sourcepath ) )
2059         {
2060             sourcePaths = new ArrayList<String>( JavadocUtil.pruneDirs( project, getProjectSourceRoots( project ) ) );
2061 
2062             if ( project.getExecutionProject() != null )
2063             {
2064                 sourcePaths.addAll( JavadocUtil.pruneDirs( project, getExecutionProjectSourceRoots( project ) ) );
2065             }
2066 
2067             /*
2068              * Should be after the source path (i.e. -sourcepath '.../src/main/java;.../src/main/javadoc') and
2069              * *not* the opposite. If not, the javadoc tool always copies doc files, even if -docfilessubdirs is
2070              * not setted.
2071              */
2072             if ( getJavadocDirectory() != null )
2073             {
2074                 File javadocDir = getJavadocDirectory();
2075                 if ( javadocDir.exists() && javadocDir.isDirectory() )
2076                 {
2077                     List<String> l = JavadocUtil.pruneDirs( project, Collections.singletonList(
2078                         getJavadocDirectory().getAbsolutePath() ) );
2079                     sourcePaths.addAll( l );
2080                 }
2081             }
2082 
2083             if ( includeDependencySources )
2084             {
2085                 sourcePaths.addAll( getDependencySourcePaths() );
2086             }
2087 
2088             if ( isAggregator() && project.isExecutionRoot() )
2089             {
2090                 for ( MavenProject subProject : reactorProjects )
2091                 {
2092                     if ( subProject != project )
2093                     {
2094                         List<String> sourceRoots = getProjectSourceRoots( subProject );
2095 
2096                         if ( subProject.getExecutionProject() != null )
2097                         {
2098                             sourceRoots.addAll( getExecutionProjectSourceRoots( subProject ) );
2099                         }
2100 
2101                         ArtifactHandler artifactHandler = subProject.getArtifact().getArtifactHandler();
2102                         if ( "java".equals( artifactHandler.getLanguage() ) )
2103                         {
2104                             sourcePaths.addAll( JavadocUtil.pruneDirs( subProject, sourceRoots ) );
2105                         }
2106 
2107                         if ( getJavadocDirectory() != null )
2108                         {
2109                             String javadocDirRelative =
2110                                     PathUtils.toRelative( project.getBasedir(), getJavadocDirectory().getAbsolutePath() );
2111                             File javadocDir = new File( subProject.getBasedir(), javadocDirRelative );
2112                             if ( javadocDir.exists() && javadocDir.isDirectory() )
2113                             {
2114                                 List<String> l = JavadocUtil.pruneDirs( subProject, Collections.singletonList(
2115                                         javadocDir.getAbsolutePath() ) );
2116                                 sourcePaths.addAll( l );
2117                             }
2118                         }
2119                     }
2120                 }
2121             }
2122         }
2123         else
2124         {
2125             sourcePaths = new ArrayList<String>( Arrays.asList( JavadocUtil.splitPath( sourcepath ) ) );
2126             sourcePaths = JavadocUtil.pruneDirs( project, sourcePaths );
2127             if ( getJavadocDirectory() != null )
2128             {
2129                 List<String> l = JavadocUtil.pruneDirs( project, Collections.singletonList(
2130                     getJavadocDirectory().getAbsolutePath() ) );
2131                 sourcePaths.addAll( l );
2132             }
2133         }
2134 
2135         sourcePaths = JavadocUtil.pruneDirs( project, sourcePaths );
2136 
2137         return sourcePaths;
2138     }
2139 
2140     /**
2141      * Override this method to customize the configuration for resolving dependency sources. The default
2142      * behavior enables the resolution of -sources jar files.
2143      */
2144     protected SourceResolverConfig configureDependencySourceResolution( final SourceResolverConfig config )
2145     {
2146         return config.withCompileSources();
2147     }
2148 
2149     /**
2150      * Resolve dependency sources so they can be included directly in the javadoc process. To customize this,
2151      * override {@link AbstractJavadocMojo#configureDependencySourceResolution(SourceResolverConfig)}.
2152      */
2153     protected final List<String> getDependencySourcePaths()
2154         throws MavenReportException
2155     {
2156         try
2157         {
2158             if ( sourceDependencyCacheDir.exists() )
2159             {
2160                 FileUtils.forceDelete( sourceDependencyCacheDir );
2161                 sourceDependencyCacheDir.mkdirs();
2162             }
2163         }
2164         catch ( IOException e )
2165         {
2166             throw new MavenReportException(
2167                 "Failed to delete cache directory: " + sourceDependencyCacheDir + "\nReason: " + e.getMessage(), e );
2168         }
2169 
2170         final SourceResolverConfig config = getDependencySourceResolverConfig();
2171 
2172         final AndArtifactFilter andFilter = new AndArtifactFilter();
2173 
2174         final List<String> dependencyIncludes = dependencySourceIncludes;
2175         final List<String> dependencyExcludes = dependencySourceExcludes;
2176 
2177         if ( !includeTransitiveDependencySources || isNotEmpty( dependencyIncludes ) || isNotEmpty(
2178             dependencyExcludes ) )
2179         {
2180             if ( !includeTransitiveDependencySources )
2181             {
2182                 andFilter.add( createDependencyArtifactFilter() );
2183             }
2184 
2185             if ( isNotEmpty( dependencyIncludes ) )
2186             {
2187                 andFilter.add( new PatternIncludesArtifactFilter( dependencyIncludes, false ) );
2188             }
2189 
2190             if ( isNotEmpty( dependencyExcludes ) )
2191             {
2192                 andFilter.add( new PatternExcludesArtifactFilter( dependencyExcludes, false ) );
2193             }
2194 
2195             config.withFilter( andFilter );
2196         }
2197 
2198         try
2199         {
2200             return ResourceResolver.resolveDependencySourcePaths( config );
2201         }
2202         catch ( final ArtifactResolutionException e )
2203         {
2204             throw new MavenReportException(
2205                 "Failed to resolve one or more javadoc source/resource artifacts:\n\n" + e.getMessage(), e );
2206         }
2207         catch ( final ArtifactNotFoundException e )
2208         {
2209             throw new MavenReportException(
2210                 "Failed to resolve one or more javadoc source/resource artifacts:\n\n" + e.getMessage(), e );
2211         }
2212     }
2213 
2214     /**
2215      * Returns a ArtifactFilter that only includes direct dependencies of this project
2216      * (verified via groupId and artifactId).
2217      *
2218      * @return
2219      */
2220     private ArtifactFilter createDependencyArtifactFilter()
2221     {
2222         Set<Artifact> dependencyArtifacts = project.getDependencyArtifacts();
2223 
2224         List<String> artifactPatterns = new ArrayList<String>( dependencyArtifacts.size() );
2225         for ( Artifact artifact : dependencyArtifacts )
2226         {
2227             artifactPatterns.add( artifact.getGroupId() + ":" + artifact.getArtifactId() );
2228         }
2229 
2230         return new IncludesArtifactFilter( artifactPatterns );
2231     }
2232 
2233     /**
2234      * Construct a SourceResolverConfig for resolving dependency sources and resources in a consistent
2235      * way, so it can be reused for both source and resource resolution.
2236      *
2237      * @since 2.7
2238      */
2239     private SourceResolverConfig getDependencySourceResolverConfig()
2240     {
2241         return configureDependencySourceResolution(
2242             new SourceResolverConfig( getLog(), project, localRepository, sourceDependencyCacheDir, resolver, factory,
2243                                       artifactMetadataSource, archiverManager ).withReactorProjects(
2244                 reactorProjects ) );
2245     }
2246 
2247     /**
2248      * Method that indicates whether the javadoc can be generated or not. If the project does not contain any source
2249      * files and no subpackages are specified, the plugin will terminate.
2250      *
2251      * @param files the project files
2252      * @return a boolean that indicates whether javadoc report can be generated or not
2253      */
2254     protected boolean canGenerateReport( List<String> files )
2255     {
2256         boolean canGenerate = true;
2257 
2258         if ( files.isEmpty() && StringUtils.isEmpty( subpackages ) )
2259         {
2260             canGenerate = false;
2261         }
2262 
2263         return canGenerate;
2264     }
2265 
2266     /**
2267      * @param result not null
2268      * @return the compile artifacts from the result
2269      * @see JavadocUtil#getCompileArtifacts(Set, boolean)
2270      */
2271     protected List<Artifact> getCompileArtifacts( ArtifactResolutionResult result )
2272     {
2273         return JavadocUtil.getCompileArtifacts( result.getArtifacts(), false );
2274     }
2275 
2276     // ----------------------------------------------------------------------
2277     // private methods
2278     // ----------------------------------------------------------------------
2279 
2280     /**
2281      * Method to get the excluded source files from the javadoc and create the argument string
2282      * that will be included in the javadoc commandline execution.
2283      *
2284      * @param sourcePaths the list of paths to the source files
2285      * @return a String that contains the exclude argument that will be used by javadoc
2286      * @throws MavenReportException
2287      */
2288     private String getExcludedPackages( List<String> sourcePaths )
2289         throws MavenReportException
2290     {
2291         List<String> excludedNames = null;
2292 
2293         if ( StringUtils.isNotEmpty( sourcepath ) && StringUtils.isNotEmpty( subpackages ) )
2294         {
2295             String[] excludedPackages = getExcludedPackages();
2296             String[] subpackagesList = subpackages.split( "[:]" );
2297 
2298             excludedNames = JavadocUtil.getExcludedNames( sourcePaths, subpackagesList, excludedPackages );
2299         }
2300 
2301         String excludeArg = "";
2302         if ( StringUtils.isNotEmpty( subpackages ) && excludedNames != null )
2303         {
2304             // add the excludedpackage names
2305             excludeArg = StringUtils.join( excludedNames.iterator(), ":" );
2306         }
2307 
2308         return excludeArg;
2309     }
2310 
2311     /**
2312      * Method to format the specified source paths that will be accepted by the javadoc tool.
2313      *
2314      * @param sourcePaths the list of paths to the source files that will be included in the javadoc.
2315      * @return a String that contains the formatted source path argument, separated by the System pathSeparator
2316      *         string (colon (<code>:</code>) on Solaris or semi-colon (<code>;</code>) on Windows).
2317      * @see File#pathSeparator
2318      */
2319     private String getSourcePath( List<String> sourcePaths )
2320     {
2321         String sourcePath = null;
2322 
2323         if ( StringUtils.isEmpty( subpackages ) || StringUtils.isNotEmpty( sourcepath ) )
2324         {
2325             sourcePath = StringUtils.join( sourcePaths.iterator(), File.pathSeparator );
2326         }
2327 
2328         return sourcePath;
2329     }
2330 
2331     /**
2332      * Method to get the packages specified in the <code>excludePackageNames</code> parameter. The packages are split
2333      * with ',', ':', or ';' and then formatted.
2334      *
2335      * @return an array of String objects that contain the package names
2336      * @throws MavenReportException
2337      */
2338     private String[] getExcludedPackages()
2339         throws MavenReportException
2340     {
2341         Set<String> excluded = new LinkedHashSet<String>();
2342 
2343         if ( includeDependencySources )
2344         {
2345             try
2346             {
2347                 resolveDependencyBundles();
2348             }
2349             catch ( IOException e )
2350             {
2351                 throw new MavenReportException(
2352                     "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
2353             }
2354 
2355             if ( isNotEmpty( dependencyJavadocBundles ) )
2356             {
2357                 for ( JavadocBundle bundle : dependencyJavadocBundles )
2358                 {
2359                     JavadocOptions options = bundle.getOptions();
2360                     if ( options != null && isNotEmpty( options.getExcludePackageNames() ) )
2361                     {
2362                         excluded.addAll( options.getExcludePackageNames() );
2363                     }
2364                 }
2365             }
2366         }
2367 
2368         // for the specified excludePackageNames
2369         if ( StringUtils.isNotEmpty( excludePackageNames ) )
2370         {
2371             excluded.addAll( Arrays.asList( excludePackageNames.split( "[,:;]" ) ) );
2372         }
2373 
2374         String[] result = new String[excluded.size()];
2375         if ( isNotEmpty( excluded ) )
2376         {
2377             int idx = 0;
2378             for ( String exclude : excluded )
2379             {
2380                 result[idx] = exclude.replace( '.', File.separatorChar );
2381                 idx++;
2382             }
2383         }
2384 
2385         return result;
2386     }
2387 
2388     /**
2389      * Method that sets the classpath elements that will be specified in the javadoc <code>-classpath</code>
2390      * parameter.
2391      *
2392      * @return a String that contains the concatenated classpath elements, separated by the System pathSeparator
2393      *         string (colon (<code>:</code>) on Solaris or semi-colon (<code>;</code>) on Windows).
2394      * @throws MavenReportException if any.
2395      * @see File#pathSeparator
2396      */
2397     private String getClasspath()
2398         throws MavenReportException
2399     {
2400         List<String> classpathElements = new ArrayList<String>();
2401         Map<String, Artifact> compileArtifactMap = new HashMap<String, Artifact>();
2402 
2403         classpathElements.addAll( getProjectBuildOutputDirs( project ) );
2404 
2405         populateCompileArtifactMap( compileArtifactMap, getProjectArtifacts( project ) );
2406 
2407         if ( isAggregator() && project.isExecutionRoot() )
2408         {
2409             try
2410             {
2411                 for ( MavenProject subProject : reactorProjects )
2412                 {
2413                     if ( subProject != project )
2414                     {
2415                         classpathElements.addAll( getProjectBuildOutputDirs( subProject ) );
2416 
2417                         Set<Artifact> dependencyArtifacts = subProject.createArtifacts( factory, null, null );
2418                         if ( !dependencyArtifacts.isEmpty() )
2419                         {
2420                             ArtifactResolutionResult result = null;
2421                             try
2422                             {
2423                                 result = resolver.resolveTransitively( dependencyArtifacts, subProject.getArtifact(),
2424                                                                        subProject.getManagedVersionMap(),
2425                                                                        localRepository,
2426                                                                        subProject.getRemoteArtifactRepositories(),
2427                                                                        artifactMetadataSource );
2428                             }
2429                             catch ( MultipleArtifactsNotFoundException e )
2430                             {
2431                                 if ( checkMissingArtifactsInReactor( dependencyArtifacts, e.getMissingArtifacts() ) )
2432                                 {
2433                                     getLog().warn( "IGNORED to add some artifacts in the classpath. See above." );
2434                                 }
2435                                 else
2436                                 {
2437                                     // we can't find all the artifacts in the reactor so bubble the exception up.
2438                                     throw new MavenReportException( e.getMessage(), e );
2439                                 }
2440                             }
2441                             catch ( ArtifactNotFoundException e )
2442                             {
2443                                 throw new MavenReportException( e.getMessage(), e );
2444                             }
2445                             catch ( ArtifactResolutionException e )
2446                             {
2447                                 throw new MavenReportException( e.getMessage(), e );
2448                             }
2449 
2450                             if ( result == null )
2451                             {
2452                                 continue;
2453                             }
2454 
2455                             populateCompileArtifactMap( compileArtifactMap, getCompileArtifacts( result ) );
2456 
2457                             if ( getLog().isDebugEnabled() )
2458                             {
2459                                 StringBuilder sb = new StringBuilder();
2460 
2461                                 sb.append( "Compiled artifacts for " );
2462                                 sb.append( subProject.getGroupId() ).append( ":" );
2463                                 sb.append( subProject.getArtifactId() ).append( ":" );
2464                                 sb.append( subProject.getVersion() ).append( '\n' );
2465                                 for ( Artifact a : compileArtifactMap.values() )
2466                                 {
2467                                     sb.append( a.getFile() ).append( '\n' );
2468                                 }
2469 
2470                                 getLog().debug( sb.toString() );
2471                             }
2472                         }
2473                     }
2474                 }
2475             }
2476             catch ( InvalidDependencyVersionException e )
2477             {
2478                 throw new MavenReportException( e.getMessage(), e );
2479             }
2480         }
2481 
2482         for ( Artifact a : compileArtifactMap.values() )
2483         {
2484             classpathElements.add( a.getFile().toString() );
2485         }
2486 
2487         if ( additionalDependencies != null )
2488         {
2489             for ( Dependency dependency : additionalDependencies )
2490             {
2491                 Artifact artifact = resolveDependency( dependency );
2492                 String path = artifact.getFile().toString();
2493                 getLog().debug( "add additional artifact with path " + path );
2494                 classpathElements.add( path );
2495             }
2496         }
2497 
2498         return StringUtils.join( classpathElements.iterator(), File.pathSeparator );
2499     }
2500 
2501     public Artifact resolveDependency( Dependency dependency )
2502         throws MavenReportException
2503     {
2504         Artifact artifact = factory.createArtifactWithClassifier( dependency.getGroupId(), dependency.getArtifactId(),
2505                                                                   dependency.getVersion(), dependency.getType(),
2506                                                                   dependency.getClassifier() );
2507         try
2508         {
2509             resolver.resolve( artifact, remoteRepositories, localRepository );
2510         }
2511         catch ( ArtifactNotFoundException e )
2512         {
2513             throw new MavenReportException( "artifact not found - " + e.getMessage(), e );
2514         }
2515         catch ( ArtifactResolutionException e )
2516         {
2517             throw new MavenReportException( "artifact resolver problem - " + e.getMessage(), e );
2518         }
2519         return artifact;
2520     }
2521 
2522 
2523     /**
2524      * TODO remove the part with ToolchainManager lookup once we depend on
2525      * 2.0.9 (have it as prerequisite). Define as regular component field then.
2526      *
2527      * @return Toolchain instance
2528      */
2529     private Toolchain getToolchain()
2530     {
2531         Toolchain tc = null;
2532         if ( toolchainManager != null )
2533         {
2534             tc = toolchainManager.getToolchainFromBuildContext( "jdk", session );
2535         }
2536 
2537         return tc;
2538     }
2539 
2540     /**
2541      * Method to put the artifacts in the hashmap.
2542      *
2543      * @param compileArtifactMap the hashmap that will contain the artifacts
2544      * @param artifactList       the list of artifacts that will be put in the map
2545      * @throws MavenReportException if any
2546      */
2547     private void populateCompileArtifactMap( Map<String, Artifact> compileArtifactMap,
2548                                              Collection<Artifact> artifactList )
2549         throws MavenReportException
2550     {
2551         if ( artifactList == null )
2552         {
2553             return;
2554         }
2555 
2556         for ( Artifact newArtifact : artifactList )
2557         {
2558             File file = newArtifact.getFile();
2559 
2560             if ( file == null )
2561             {
2562                 throw new MavenReportException(
2563                     "Error in plugin descriptor - " + "dependency was not resolved for artifact: "
2564                         + newArtifact.getGroupId() + ":" + newArtifact.getArtifactId() + ":"
2565                         + newArtifact.getVersion() );
2566             }
2567 
2568             if ( compileArtifactMap.get( newArtifact.getDependencyConflictId() ) != null )
2569             {
2570                 Artifact oldArtifact = compileArtifactMap.get( newArtifact.getDependencyConflictId() );
2571 
2572                 ArtifactVersion oldVersion = new DefaultArtifactVersion( oldArtifact.getVersion() );
2573                 ArtifactVersion newVersion = new DefaultArtifactVersion( newArtifact.getVersion() );
2574                 if ( newVersion.compareTo( oldVersion ) > 0 )
2575                 {
2576                     compileArtifactMap.put( newArtifact.getDependencyConflictId(), newArtifact );
2577                 }
2578             }
2579             else
2580             {
2581                 compileArtifactMap.put( newArtifact.getDependencyConflictId(), newArtifact );
2582             }
2583         }
2584     }
2585 
2586     /**
2587      * Method that sets the bottom text that will be displayed on the bottom of the
2588      * javadocs.
2589      *
2590      * @return a String that contains the text that will be displayed at the bottom of the javadoc
2591      */
2592     private String getBottomText()
2593     {
2594         int actualYear = Calendar.getInstance().get( Calendar.YEAR );
2595         String year = String.valueOf( actualYear );
2596 
2597         String inceptionYear = project.getInceptionYear();
2598 
2599         String theBottom = StringUtils.replace( this.bottom, "{currentYear}", year );
2600 
2601         if ( inceptionYear != null )
2602         {
2603             if ( inceptionYear.equals( year ) )
2604             {
2605                 theBottom = StringUtils.replace( theBottom, "{inceptionYear}-", "" );
2606             }
2607             else
2608             {
2609                 theBottom = StringUtils.replace( theBottom, "{inceptionYear}", inceptionYear );
2610             }
2611         }
2612         else
2613         {
2614             theBottom = StringUtils.replace( theBottom, "{inceptionYear}-", "" );
2615         }
2616 
2617         if ( project.getOrganization() == null )
2618         {
2619             theBottom = StringUtils.replace( theBottom, " {organizationName}", "" );
2620         }
2621         else
2622         {
2623             if ( StringUtils.isNotEmpty( project.getOrganization().getName() ) )
2624             {
2625                 if ( StringUtils.isNotEmpty( project.getOrganization().getUrl() ) )
2626                 {
2627                     theBottom = StringUtils.replace( theBottom, "{organizationName}",
2628                                                      "<a href=\"" + project.getOrganization().getUrl() + "\">"
2629                                                          + project.getOrganization().getName() + "</a>" );
2630                 }
2631                 else
2632                 {
2633                     theBottom =
2634                         StringUtils.replace( theBottom, "{organizationName}", project.getOrganization().getName() );
2635                 }
2636             }
2637             else
2638             {
2639                 theBottom = StringUtils.replace( theBottom, " {organizationName}", "" );
2640             }
2641         }
2642 
2643         return theBottom;
2644     }
2645 
2646     /**
2647      * Method to get the stylesheet path file to be used by the Javadoc Tool.
2648      * <br/>
2649      * If the {@link #stylesheetfile} is empty, return the file as String definded by {@link #stylesheet} value.
2650      * <br/>
2651      * If the {@link #stylesheetfile} is defined, return the file as String.
2652      * <br/>
2653      * Note: since 2.6, the {@link #stylesheetfile} could be a path from a resource in the project source
2654      * directories (i.e. <code>src/main/java</code>, <code>src/main/resources</code> or <code>src/main/javadoc</code>)
2655      * or from a resource in the Javadoc plugin dependencies.
2656      *
2657      * @param javadocOutputDirectory the output directory
2658      * @return the stylesheet file absolute path as String.
2659      * @see #getResource(List, String)
2660      */
2661     private String getStylesheetFile( final File javadocOutputDirectory )
2662     {
2663         if ( StringUtils.isEmpty( stylesheetfile ) )
2664         {
2665             if ( "java".equalsIgnoreCase( stylesheet ) )
2666             {
2667                 // use the default Javadoc tool stylesheet
2668                 return null;
2669             }
2670 
2671             // maven, see #copyDefaultStylesheet(File)
2672             return new File( javadocOutputDirectory, DEFAULT_CSS_NAME ).getAbsolutePath();
2673         }
2674 
2675         if ( new File( stylesheetfile ).exists() )
2676         {
2677             return new File( stylesheetfile ).getAbsolutePath();
2678         }
2679 
2680         return getResource( new File( javadocOutputDirectory, DEFAULT_CSS_NAME ), stylesheetfile );
2681     }
2682 
2683     /**
2684      * Method to get the help file to be used by the Javadoc Tool.
2685      * <br/>
2686      * Since 2.6, the {@link #helpfile} could be a path from a resource in the project source
2687      * directories (i.e. <code>src/main/java</code>, <code>src/main/resources</code> or <code>src/main/javadoc</code>)
2688      * or from a resource in the Javadoc plugin dependencies.
2689      *
2690      * @param javadocOutputDirectory the output directory.
2691      * @return the help file absolute path as String.
2692      * @see #getResource(File, String)
2693      * @since 2.6
2694      */
2695     private String getHelpFile( final File javadocOutputDirectory )
2696     {
2697         if ( StringUtils.isEmpty( helpfile ) )
2698         {
2699             return null;
2700         }
2701 
2702         if ( new File( helpfile ).exists() )
2703         {
2704             return new File( helpfile ).getAbsolutePath();
2705         }
2706 
2707         return getResource( new File( javadocOutputDirectory, "help-doc.html" ), helpfile );
2708     }
2709 
2710     /**
2711      * Method to get the access level for the classes and members to be shown in the generated javadoc.
2712      * If the specified access level is not public, protected, package or private, the access level
2713      * is set to protected.
2714      *
2715      * @return the access level
2716      */
2717     private String getAccessLevel()
2718     {
2719         String accessLevel;
2720         if ( "public".equalsIgnoreCase( show ) || "protected".equalsIgnoreCase( show ) || "package".equalsIgnoreCase(
2721             show ) || "private".equalsIgnoreCase( show ) )
2722         {
2723             accessLevel = "-" + show;
2724         }
2725         else
2726         {
2727             if ( getLog().isErrorEnabled() )
2728             {
2729                 getLog().error( "Unrecognized access level to show '" + show + "'. Defaulting to protected." );
2730             }
2731             accessLevel = "-protected";
2732         }
2733 
2734         return accessLevel;
2735     }
2736 
2737     /**
2738      * Method to get the path of the bootclass artifacts used in the <code>-bootclasspath</code> option.
2739      *
2740      * @return a string that contains bootclass path, separated by the System pathSeparator string
2741      *         (colon (<code>:</code>) on Solaris or semi-colon (<code>;</code>) on Windows).
2742      * @throws MavenReportException if any
2743      * @see File#pathSeparator
2744      */
2745     private String getBootclassPath()
2746         throws MavenReportException
2747     {
2748         Set<BootclasspathArtifact> bootclasspathArtifacts = collectBootClasspathArtifacts();
2749 
2750         List<String> bootclassPath = new ArrayList<String>();
2751         for ( BootclasspathArtifact aBootclasspathArtifact : bootclasspathArtifacts )
2752         {
2753             if ( ( StringUtils.isNotEmpty( aBootclasspathArtifact.getGroupId() ) ) && ( StringUtils.isNotEmpty(
2754                 aBootclasspathArtifact.getArtifactId() ) ) && ( StringUtils.isNotEmpty(
2755                 aBootclasspathArtifact.getVersion() ) ) )
2756             {
2757                 bootclassPath.addAll( getArtifactsAbsolutePath( aBootclasspathArtifact ) );
2758             }
2759         }
2760 
2761         bootclassPath = JavadocUtil.pruneFiles( bootclassPath );
2762 
2763         StringBuilder path = new StringBuilder();
2764         path.append( StringUtils.join( bootclassPath.iterator(), File.pathSeparator ) );
2765 
2766         if ( StringUtils.isNotEmpty( bootclasspath ) )
2767         {
2768             path.append( JavadocUtil.unifyPathSeparator( bootclasspath ) );
2769         }
2770 
2771         return path.toString();
2772     }
2773 
2774     /**
2775      * Method to get the path of the doclet artifacts used in the <code>-docletpath</code> option.
2776      * <p/>
2777      * Either docletArtifact or doclectArtifacts can be defined and used, not both, docletArtifact
2778      * takes precedence over doclectArtifacts. docletPath is always appended to any result path
2779      * definition.
2780      *
2781      * @return a string that contains doclet path, separated by the System pathSeparator string
2782      *         (colon (<code>:</code>) on Solaris or semi-colon (<code>;</code>) on Windows).
2783      * @throws MavenReportException if any
2784      * @see File#pathSeparator
2785      */
2786     private String getDocletPath()
2787         throws MavenReportException
2788     {
2789         Set<DocletArtifact> docletArtifacts = collectDocletArtifacts();
2790         List<String> pathParts = new ArrayList<String>();
2791 
2792         for ( DocletArtifact docletArtifact : docletArtifacts )
2793         {
2794             if ( !isDocletArtifactEmpty( docletArtifact ) )
2795             {
2796                 pathParts.addAll( getArtifactsAbsolutePath( docletArtifact ) );
2797             }
2798         }
2799 
2800         if ( !StringUtils.isEmpty( docletPath ) )
2801         {
2802             pathParts.add( JavadocUtil.unifyPathSeparator( docletPath ) );
2803         }
2804 
2805         String path = StringUtils.join( pathParts.iterator(), File.pathSeparator );
2806 
2807         if ( StringUtils.isEmpty( path ) && getLog().isWarnEnabled() )
2808         {
2809             getLog().warn( "No docletpath option was found. Please review <docletpath/> or <docletArtifact/>"
2810                                + " or <doclets/>." );
2811         }
2812 
2813         return path.toString();
2814     }
2815 
2816     /**
2817      * Verify if a doclet artifact is empty or not
2818      *
2819      * @param aDocletArtifact could be null
2820      * @return <code>true</code> if aDocletArtifact or the groupId/artifactId/version of the doclet artifact is null,
2821      *         <code>false</code> otherwise.
2822      */
2823     private boolean isDocletArtifactEmpty( DocletArtifact aDocletArtifact )
2824     {
2825         if ( aDocletArtifact == null )
2826         {
2827             return true;
2828         }
2829 
2830         return StringUtils.isEmpty( aDocletArtifact.getGroupId() ) && StringUtils.isEmpty(
2831             aDocletArtifact.getArtifactId() ) && StringUtils.isEmpty( aDocletArtifact.getVersion() );
2832     }
2833 
2834     /**
2835      * Method to get the path of the taglet artifacts used in the <code>-tagletpath</code> option.
2836      *
2837      * @return a string that contains taglet path, separated by the System pathSeparator string
2838      *         (colon (<code>:</code>) on Solaris or semi-colon (<code>;</code>) on Windows).
2839      * @throws MavenReportException if any
2840      * @see File#pathSeparator
2841      */
2842     private String getTagletPath()
2843         throws MavenReportException
2844     {
2845         Set<TagletArtifact> tArtifacts = collectTagletArtifacts();
2846         List<String> pathParts = new ArrayList<String>();
2847 
2848         for ( TagletArtifact tagletArtifact : tArtifacts )
2849         {
2850             if ( ( tagletArtifact != null ) && ( StringUtils.isNotEmpty( tagletArtifact.getGroupId() ) )
2851                 && ( StringUtils.isNotEmpty( tagletArtifact.getArtifactId() ) ) && ( StringUtils.isNotEmpty(
2852                 tagletArtifact.getVersion() ) ) )
2853             {
2854                 pathParts.addAll( getArtifactsAbsolutePath( tagletArtifact ) );
2855             }
2856         }
2857 
2858         Set<Taglet> taglets = collectTaglets();
2859         for ( Taglet taglet : taglets )
2860         {
2861             if ( taglet == null )
2862             {
2863                 continue;
2864             }
2865 
2866             if ( ( taglet.getTagletArtifact() != null ) && ( StringUtils.isNotEmpty(
2867                 taglet.getTagletArtifact().getGroupId() ) ) && ( StringUtils.isNotEmpty(
2868                 taglet.getTagletArtifact().getArtifactId() ) ) && ( StringUtils.isNotEmpty(
2869                 taglet.getTagletArtifact().getVersion() ) ) )
2870             {
2871                 pathParts.addAll( getArtifactsAbsolutePath( taglet.getTagletArtifact() ) );
2872 
2873                 pathParts = JavadocUtil.pruneFiles( pathParts );
2874             }
2875             else if ( StringUtils.isNotEmpty( taglet.getTagletpath() ) )
2876             {
2877                 pathParts.add( taglet.getTagletpath() );
2878 
2879                 pathParts = JavadocUtil.pruneDirs( project, pathParts );
2880             }
2881         }
2882 
2883         StringBuilder path = new StringBuilder();
2884         path.append( StringUtils.join( pathParts.iterator(), File.pathSeparator ) );
2885 
2886         if ( StringUtils.isNotEmpty( tagletpath ) )
2887         {
2888             path.append( JavadocUtil.unifyPathSeparator( tagletpath ) );
2889         }
2890 
2891         return path.toString();
2892     }
2893 
2894     private Set<String> collectLinks()
2895         throws MavenReportException
2896     {
2897         Set<String> links = new LinkedHashSet<String>();
2898 
2899         if ( includeDependencySources )
2900         {
2901             try
2902             {
2903                 resolveDependencyBundles();
2904             }
2905             catch ( IOException e )
2906             {
2907                 throw new MavenReportException(
2908                     "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
2909             }
2910 
2911             if ( isNotEmpty( dependencyJavadocBundles ) )
2912             {
2913                 for ( JavadocBundle bundle : dependencyJavadocBundles )
2914                 {
2915                     JavadocOptions options = bundle.getOptions();
2916                     if ( options != null && isNotEmpty( options.getLinks() ) )
2917                     {
2918                         links.addAll( options.getLinks() );
2919                     }
2920                 }
2921             }
2922         }
2923 
2924         if ( isNotEmpty( this.links ) )
2925         {
2926             links.addAll( this.links );
2927         }
2928 
2929         links.addAll( getDependenciesLinks() );
2930 
2931         return links;
2932     }
2933 
2934     private Set<Group> collectGroups()
2935         throws MavenReportException
2936     {
2937         Set<Group> groups = new LinkedHashSet<Group>();
2938 
2939         if ( includeDependencySources )
2940         {
2941             try
2942             {
2943                 resolveDependencyBundles();
2944             }
2945             catch ( IOException e )
2946             {
2947                 throw new MavenReportException(
2948                     "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
2949             }
2950 
2951             if ( isNotEmpty( dependencyJavadocBundles ) )
2952             {
2953                 for ( JavadocBundle bundle : dependencyJavadocBundles )
2954                 {
2955                     JavadocOptions options = bundle.getOptions();
2956                     if ( options != null && isNotEmpty( options.getGroups() ) )
2957                     {
2958                         groups.addAll( options.getGroups() );
2959                     }
2960                 }
2961             }
2962         }
2963 
2964         if ( this.groups != null && this.groups.length > 0 )
2965         {
2966             groups.addAll( Arrays.asList( this.groups ) );
2967         }
2968 
2969         return groups;
2970     }
2971 
2972     private Set<ResourcesArtifact> collectResourcesArtifacts()
2973         throws MavenReportException
2974     {
2975         Set<ResourcesArtifact> result = new LinkedHashSet<ResourcesArtifact>();
2976 
2977         if ( includeDependencySources )
2978         {
2979             try
2980             {
2981                 resolveDependencyBundles();
2982             }
2983             catch ( IOException e )
2984             {
2985                 throw new MavenReportException(
2986                     "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
2987             }
2988 
2989             if ( isNotEmpty( dependencyJavadocBundles ) )
2990             {
2991                 for ( JavadocBundle bundle : dependencyJavadocBundles )
2992                 {
2993                     JavadocOptions options = bundle.getOptions();
2994                     if ( options != null && isNotEmpty( options.getResourcesArtifacts() ) )
2995                     {
2996                         result.addAll( options.getResourcesArtifacts() );
2997                     }
2998                 }
2999             }
3000         }
3001 
3002         if ( this.resourcesArtifacts != null && this.resourcesArtifacts.length > 0 )
3003         {
3004             result.addAll( Arrays.asList( this.resourcesArtifacts ) );
3005         }
3006 
3007         return result;
3008     }
3009 
3010     private Set<BootclasspathArtifact> collectBootClasspathArtifacts()
3011         throws MavenReportException
3012     {
3013         Set<BootclasspathArtifact> result = new LinkedHashSet<BootclasspathArtifact>();
3014 
3015         if ( includeDependencySources )
3016         {
3017             try
3018             {
3019                 resolveDependencyBundles();
3020             }
3021             catch ( IOException e )
3022             {
3023                 throw new MavenReportException(
3024                     "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
3025             }
3026 
3027             if ( isNotEmpty( dependencyJavadocBundles ) )
3028             {
3029                 for ( JavadocBundle bundle : dependencyJavadocBundles )
3030                 {
3031                     JavadocOptions options = bundle.getOptions();
3032                     if ( options != null && isNotEmpty( options.getBootclasspathArtifacts() ) )
3033                     {
3034                         result.addAll( options.getBootclasspathArtifacts() );
3035                     }
3036                 }
3037             }
3038         }
3039 
3040         if ( this.bootclasspathArtifacts != null && this.bootclasspathArtifacts.length > 0 )
3041         {
3042             result.addAll( Arrays.asList( this.bootclasspathArtifacts ) );
3043         }
3044 
3045         return result;
3046     }
3047 
3048     private Set<OfflineLink> collectOfflineLinks()
3049         throws MavenReportException
3050     {
3051         Set<OfflineLink> result = new LinkedHashSet<OfflineLink>();
3052 
3053         OfflineLink javaApiLink = getDefaultJavadocApiLink();
3054         if ( javaApiLink != null )
3055         {
3056             result.add( javaApiLink );
3057         }
3058 
3059         if ( includeDependencySources )
3060         {
3061             try
3062             {
3063                 resolveDependencyBundles();
3064             }
3065             catch ( IOException e )
3066             {
3067                 throw new MavenReportException(
3068                     "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
3069             }
3070 
3071             if ( isNotEmpty( dependencyJavadocBundles ) )
3072             {
3073                 for ( JavadocBundle bundle : dependencyJavadocBundles )
3074                 {
3075                     JavadocOptions options = bundle.getOptions();
3076                     if ( options != null && isNotEmpty( options.getOfflineLinks() ) )
3077                     {
3078                         result.addAll( options.getOfflineLinks() );
3079                     }
3080                 }
3081             }
3082         }
3083 
3084         if ( this.offlineLinks != null && this.offlineLinks.length > 0 )
3085         {
3086             result.addAll( Arrays.asList( this.offlineLinks ) );
3087         }
3088 
3089         return result;
3090     }
3091 
3092     private Set<Tag> collectTags()
3093         throws MavenReportException
3094     {
3095         Set<Tag> tags = new LinkedHashSet<Tag>();
3096 
3097         if ( includeDependencySources )
3098         {
3099             try
3100             {
3101                 resolveDependencyBundles();
3102             }
3103             catch ( IOException e )
3104             {
3105                 throw new MavenReportException(
3106                     "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
3107             }
3108 
3109             if ( isNotEmpty( dependencyJavadocBundles ) )
3110             {
3111                 for ( JavadocBundle bundle : dependencyJavadocBundles )
3112                 {
3113                     JavadocOptions options = bundle.getOptions();
3114                     if ( options != null && isNotEmpty( options.getTags() ) )
3115                     {
3116                         tags.addAll( options.getTags() );
3117                     }
3118                 }
3119             }
3120         }
3121 
3122         if ( this.tags != null && this.tags.length > 0 )
3123         {
3124             tags.addAll( Arrays.asList( this.tags ) );
3125         }
3126 
3127         return tags;
3128     }
3129 
3130     private Set<TagletArtifact> collectTagletArtifacts()
3131         throws MavenReportException
3132     {
3133         Set<TagletArtifact> tArtifacts = new LinkedHashSet<TagletArtifact>();
3134 
3135         if ( includeDependencySources )
3136         {
3137             try
3138             {
3139                 resolveDependencyBundles();
3140             }
3141             catch ( IOException e )
3142             {
3143                 throw new MavenReportException(
3144                     "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
3145             }
3146 
3147             if ( isNotEmpty( dependencyJavadocBundles ) )
3148             {
3149                 for ( JavadocBundle bundle : dependencyJavadocBundles )
3150                 {
3151                     JavadocOptions options = bundle.getOptions();
3152                     if ( options != null && isNotEmpty( options.getTagletArtifacts() ) )
3153                     {
3154                         tArtifacts.addAll( options.getTagletArtifacts() );
3155                     }
3156                 }
3157             }
3158         }
3159 
3160         if ( tagletArtifact != null )
3161         {
3162             tArtifacts.add( tagletArtifact );
3163         }
3164 
3165         if ( tagletArtifacts != null && tagletArtifacts.length > 0 )
3166         {
3167             tArtifacts.addAll( Arrays.asList( tagletArtifacts ) );
3168         }
3169 
3170         return tArtifacts;
3171     }
3172 
3173     private Set<DocletArtifact> collectDocletArtifacts()
3174         throws MavenReportException
3175     {
3176         Set<DocletArtifact> dArtifacts = new LinkedHashSet<DocletArtifact>();
3177 
3178         if ( includeDependencySources )
3179         {
3180             try
3181             {
3182                 resolveDependencyBundles();
3183             }
3184             catch ( IOException e )
3185             {
3186                 throw new MavenReportException(
3187                     "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
3188             }
3189 
3190             if ( isNotEmpty( dependencyJavadocBundles ) )
3191             {
3192                 for ( JavadocBundle bundle : dependencyJavadocBundles )
3193                 {
3194                     JavadocOptions options = bundle.getOptions();
3195                     if ( options != null && isNotEmpty( options.getDocletArtifacts() ) )
3196                     {
3197                         dArtifacts.addAll( options.getDocletArtifacts() );
3198                     }
3199                 }
3200             }
3201         }
3202 
3203         if ( docletArtifact != null )
3204         {
3205             dArtifacts.add( docletArtifact );
3206         }
3207 
3208         if ( docletArtifacts != null && docletArtifacts.length > 0 )
3209         {
3210             dArtifacts.addAll( Arrays.asList( docletArtifacts ) );
3211         }
3212 
3213         return dArtifacts;
3214     }
3215 
3216     private Set<Taglet> collectTaglets()
3217         throws MavenReportException
3218     {
3219         Set<Taglet> result = new LinkedHashSet<Taglet>();
3220 
3221         if ( includeDependencySources )
3222         {
3223             try
3224             {
3225                 resolveDependencyBundles();
3226             }
3227             catch ( IOException e )
3228             {
3229                 throw new MavenReportException(
3230                     "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
3231             }
3232 
3233             if ( isNotEmpty( dependencyJavadocBundles ) )
3234             {
3235                 for ( JavadocBundle bundle : dependencyJavadocBundles )
3236                 {
3237                     JavadocOptions options = bundle.getOptions();
3238                     if ( options != null && isNotEmpty( options.getTaglets() ) )
3239                     {
3240                         result.addAll( options.getTaglets() );
3241                     }
3242                 }
3243             }
3244         }
3245 
3246         if ( taglets != null && taglets.length > 0 )
3247         {
3248             result.addAll( Arrays.asList( taglets ) );
3249         }
3250 
3251         return result;
3252     }
3253 
3254     /**
3255      * Return the Javadoc artifact path and its transitive dependencies path from the local repository
3256      *
3257      * @param javadocArtifact not null
3258      * @return a list of locale artifacts absolute path
3259      * @throws MavenReportException if any
3260      */
3261     private List<String> getArtifactsAbsolutePath( JavadocPathArtifact javadocArtifact )
3262         throws MavenReportException
3263     {
3264         if ( ( StringUtils.isEmpty( javadocArtifact.getGroupId() ) ) && ( StringUtils.isEmpty(
3265             javadocArtifact.getArtifactId() ) ) && ( StringUtils.isEmpty( javadocArtifact.getVersion() ) ) )
3266         {
3267             return Collections.emptyList();
3268         }
3269 
3270         List<String> path = new ArrayList<String>();
3271 
3272         try
3273         {
3274             Artifact artifact = createAndResolveArtifact( javadocArtifact );
3275             path.add( artifact.getFile().getAbsolutePath() );
3276 
3277             // Find its transitive dependencies in the local repo
3278             MavenProject artifactProject =
3279                 mavenProjectBuilder.buildFromRepository( artifact, remoteRepositories, localRepository );
3280             Set<Artifact> dependencyArtifacts = artifactProject.createArtifacts( factory, null, null );
3281             if ( !dependencyArtifacts.isEmpty() )
3282             {
3283                 ArtifactResolutionResult result =
3284                     resolver.resolveTransitively( dependencyArtifacts, artifactProject.getArtifact(),
3285                                                   artifactProject.getRemoteArtifactRepositories(), localRepository,
3286                                                   artifactMetadataSource );
3287                 Set<Artifact> artifacts = result.getArtifacts();
3288 
3289                 Map<String, Artifact> compileArtifactMap = new HashMap<String, Artifact>();
3290                 populateCompileArtifactMap( compileArtifactMap, artifacts );
3291 
3292                 for ( Artifact a : compileArtifactMap.values() )
3293                 {
3294                     path.add( a.getFile().getAbsolutePath() );
3295                 }
3296             }
3297 
3298             return path;
3299         }
3300         catch ( ArtifactResolutionException e )
3301         {
3302             throw new MavenReportException( "Unable to resolve artifact:" + javadocArtifact, e );
3303         }
3304         catch ( ArtifactNotFoundException e )
3305         {
3306             throw new MavenReportException( "Unable to find artifact:" + javadocArtifact, e );
3307         }
3308         catch ( ProjectBuildingException e )
3309         {
3310             throw new MavenReportException( "Unable to build the Maven project for the artifact:" + javadocArtifact,
3311                                             e );
3312         }
3313         catch ( InvalidDependencyVersionException e )
3314         {
3315             throw new MavenReportException( "Unable to resolve artifact:" + javadocArtifact, e );
3316         }
3317     }
3318 
3319     /**
3320      * creates an {@link Artifact} representing the configured {@link JavadocPathArtifact} and resolves it.
3321      *
3322      * @param javadocArtifact the {@link JavadocPathArtifact} to resolve
3323      * @return a resolved {@link Artifact}
3324      * @throws ArtifactResolutionException if the resolution of the artifact failed.
3325      * @throws ArtifactNotFoundException   if the artifact hasn't been found.
3326      * @throws ProjectBuildingException    if the artifact POM could not be build.
3327      */
3328     private Artifact createAndResolveArtifact( JavadocPathArtifact javadocArtifact )
3329         throws ArtifactResolutionException, ArtifactNotFoundException, ProjectBuildingException
3330     {
3331         Artifact artifact =
3332             factory.createProjectArtifact( javadocArtifact.getGroupId(), javadocArtifact.getArtifactId(),
3333                                            javadocArtifact.getVersion(), Artifact.SCOPE_COMPILE );
3334 
3335         if ( artifact.getFile() == null )
3336         {
3337             MavenProject pluginProject =
3338                 mavenProjectBuilder.buildFromRepository( artifact, remoteRepositories, localRepository );
3339             artifact = pluginProject.getArtifact();
3340 
3341             resolver.resolve( artifact, remoteRepositories, localRepository );
3342         }
3343 
3344         return artifact;
3345     }
3346 
3347     /**
3348      * Method that adds/sets the java memory parameters in the command line execution.
3349      *
3350      * @param cmd    the command line execution object where the argument will be added
3351      * @param arg    the argument parameter name
3352      * @param memory the JVM memory value to be set
3353      * @see JavadocUtil#parseJavadocMemory(String)
3354      */
3355     private void addMemoryArg( Commandline cmd, String arg, String memory )
3356     {
3357         if ( StringUtils.isNotEmpty( memory ) )
3358         {
3359             try
3360             {
3361                 cmd.createArg().setValue( "-J" + arg + JavadocUtil.parseJavadocMemory( memory ) );
3362             }
3363             catch ( IllegalArgumentException e )
3364             {
3365                 if ( getLog().isErrorEnabled() )
3366                 {
3367                     getLog().error( "Malformed memory pattern for '" + arg + memory + "'. Ignore this option." );
3368                 }
3369             }
3370         }
3371     }
3372 
3373     /**
3374      * Method that adds/sets the javadoc proxy parameters in the command line execution.
3375      *
3376      * @param cmd the command line execution object where the argument will be added
3377      */
3378     private void addProxyArg( Commandline cmd )
3379     {
3380         // backward compatible
3381         if ( StringUtils.isNotEmpty( proxyHost ) )
3382         {
3383             if ( getLog().isWarnEnabled() )
3384             {
3385                 getLog().warn( "The Javadoc plugin parameter 'proxyHost' is deprecated since 2.4. "
3386                                    + "Please configure an active proxy in your settings.xml." );
3387             }
3388             cmd.createArg().setValue( "-J-DproxyHost=" + proxyHost );
3389 
3390             if ( proxyPort > 0 )
3391             {
3392                 if ( getLog().isWarnEnabled() )
3393                 {
3394                     getLog().warn( "The Javadoc plugin parameter 'proxyPort' is deprecated since 2.4. "
3395                                        + "Please configure an active proxy in your settings.xml." );
3396                 }
3397                 cmd.createArg().setValue( "-J-DproxyPort=" + proxyPort );
3398             }
3399         }
3400 
3401         if ( settings == null || settings.getActiveProxy() == null )
3402         {
3403             return;
3404         }
3405 
3406         Proxy activeProxy = settings.getActiveProxy();
3407         String protocol = StringUtils.isNotEmpty( activeProxy.getProtocol() ) ? activeProxy.getProtocol() + "." : "";
3408 
3409         if ( StringUtils.isNotEmpty( activeProxy.getHost() ) )
3410         {
3411             cmd.createArg().setValue( "-J-D" + protocol + "proxySet=true" );
3412             cmd.createArg().setValue( "-J-D" + protocol + "proxyHost=" + activeProxy.getHost() );
3413 
3414             if ( activeProxy.getPort() > 0 )
3415             {
3416                 cmd.createArg().setValue( "-J-D" + protocol + "proxyPort=" + activeProxy.getPort() );
3417             }
3418 
3419             if ( StringUtils.isNotEmpty( activeProxy.getNonProxyHosts() ) )
3420             {
3421                 cmd.createArg().setValue(
3422                     "-J-D" + protocol + "nonProxyHosts=\"" + activeProxy.getNonProxyHosts() + "\"" );
3423             }
3424 
3425             if ( StringUtils.isNotEmpty( activeProxy.getUsername() ) )
3426             {
3427                 cmd.createArg().setValue( "-J-Dhttp.proxyUser=\"" + activeProxy.getUsername() + "\"" );
3428 
3429                 if ( StringUtils.isNotEmpty( activeProxy.getPassword() ) )
3430                 {
3431                     cmd.createArg().setValue( "-J-Dhttp.proxyPassword=\"" + activeProxy.getPassword() + "\"" );
3432                 }
3433             }
3434         }
3435     }
3436 
3437     /**
3438      * Get the path of the Javadoc tool executable depending the user entry or try to find it depending the OS
3439      * or the <code>java.home</code> system property or the <code>JAVA_HOME</code> environment variable.
3440      *
3441      * @return the path of the Javadoc tool
3442      * @throws IOException if not found
3443      */
3444     private String getJavadocExecutable()
3445         throws IOException
3446     {
3447         Toolchain tc = getToolchain();
3448 
3449         if ( tc != null )
3450         {
3451             getLog().info( "Toolchain in javadoc-plugin: " + tc );
3452             if ( javadocExecutable != null )
3453             {
3454                 getLog().warn( "Toolchains are ignored, 'javadocExecutable' parameter is set to " + javadocExecutable );
3455             }
3456             else
3457             {
3458                 javadocExecutable = tc.findTool( "javadoc" );
3459             }
3460         }
3461 
3462         String javadocCommand = "javadoc" + ( SystemUtils.IS_OS_WINDOWS ? ".exe" : "" );
3463 
3464         File javadocExe;
3465 
3466         // ----------------------------------------------------------------------
3467         // The javadoc executable is defined by the user
3468         // ----------------------------------------------------------------------
3469         if ( StringUtils.isNotEmpty( javadocExecutable ) )
3470         {
3471             javadocExe = new File( javadocExecutable );
3472 
3473             if ( javadocExe.isDirectory() )
3474             {
3475                 javadocExe = new File( javadocExe, javadocCommand );
3476             }
3477 
3478             if ( SystemUtils.IS_OS_WINDOWS && javadocExe.getName().indexOf( '.' ) < 0 )
3479             {
3480                 javadocExe = new File( javadocExe.getPath() + ".exe" );
3481             }
3482 
3483             if ( !javadocExe.isFile() )
3484             {
3485                 throw new IOException( "The javadoc executable '" + javadocExe
3486                                            + "' doesn't exist or is not a file. Verify the <javadocExecutable/> parameter." );
3487             }
3488 
3489             return javadocExe.getAbsolutePath();
3490         }
3491 
3492         // ----------------------------------------------------------------------
3493         // Try to find javadocExe from System.getProperty( "java.home" )
3494         // By default, System.getProperty( "java.home" ) = JRE_HOME and JRE_HOME
3495         // should be in the JDK_HOME
3496         // ----------------------------------------------------------------------
3497         // For IBM's JDK 1.2
3498         if ( SystemUtils.IS_OS_AIX )
3499         {
3500             javadocExe =
3501                 new File( SystemUtils.getJavaHome() + File.separator + ".." + File.separator + "sh", javadocCommand );
3502         }
3503         else if ( SystemUtils.IS_OS_MAC_OSX )
3504         {
3505             javadocExe = new File( SystemUtils.getJavaHome() + File.separator + "bin", javadocCommand );
3506         }
3507         else
3508         {
3509             javadocExe =
3510                 new File( SystemUtils.getJavaHome() + File.separator + ".." + File.separator + "bin", javadocCommand );
3511         }
3512 
3513         // ----------------------------------------------------------------------
3514         // Try to find javadocExe from JAVA_HOME environment variable
3515         // ----------------------------------------------------------------------
3516         if ( !javadocExe.exists() || !javadocExe.isFile() )
3517         {
3518             Properties env = CommandLineUtils.getSystemEnvVars();
3519             String javaHome = env.getProperty( "JAVA_HOME" );
3520             if ( StringUtils.isEmpty( javaHome ) )
3521             {
3522                 throw new IOException( "The environment variable JAVA_HOME is not correctly set." );
3523             }
3524             if ( ( !new File( javaHome ).exists() ) || ( !new File( javaHome ).isDirectory() ) )
3525             {
3526                 throw new IOException(
3527                     "The environment variable JAVA_HOME=" + javaHome + " doesn't exist or is not a valid directory." );
3528             }
3529 
3530             javadocExe = new File( env.getProperty( "JAVA_HOME" ) + File.separator + "bin", javadocCommand );
3531         }
3532 
3533         if ( !javadocExe.exists() || !javadocExe.isFile() )
3534         {
3535             throw new IOException( "The javadoc executable '" + javadocExe
3536                                        + "' doesn't exist or is not a file. Verify the JAVA_HOME environment variable." );
3537         }
3538 
3539         return javadocExe.getAbsolutePath();
3540     }
3541 
3542     /**
3543      * Set a new value for <code>fJavadocVersion</code>
3544      *
3545      * @param jExecutable not null
3546      * @throws MavenReportException if not found
3547      * @see JavadocUtil#getJavadocVersion(File)
3548      */
3549     private void setFJavadocVersion( File jExecutable )
3550         throws MavenReportException
3551     {
3552         float jVersion;
3553         try
3554         {
3555             jVersion = JavadocUtil.getJavadocVersion( jExecutable );
3556         }
3557         catch ( IOException e )
3558         {
3559             if ( getLog().isWarnEnabled() )
3560             {
3561                 getLog().warn( "Unable to find the javadoc version: " + e.getMessage() );
3562                 getLog().warn( "Using the Java version instead of, i.e. " + SystemUtils.JAVA_VERSION_FLOAT );
3563             }
3564             jVersion = SystemUtils.JAVA_VERSION_FLOAT;
3565         }
3566         catch ( CommandLineException e )
3567         {
3568             if ( getLog().isWarnEnabled() )
3569             {
3570                 getLog().warn( "Unable to find the javadoc version: " + e.getMessage() );
3571                 getLog().warn( "Using the Java the version instead of, i.e. " + SystemUtils.JAVA_VERSION_FLOAT );
3572             }
3573             jVersion = SystemUtils.JAVA_VERSION_FLOAT;
3574         }
3575         catch ( IllegalArgumentException e )
3576         {
3577             if ( getLog().isWarnEnabled() )
3578             {
3579                 getLog().warn( "Unable to find the javadoc version: " + e.getMessage() );
3580                 getLog().warn( "Using the Java the version instead of, i.e. " + SystemUtils.JAVA_VERSION_FLOAT );
3581             }
3582             jVersion = SystemUtils.JAVA_VERSION_FLOAT;
3583         }
3584 
3585         if ( StringUtils.isNotEmpty( javadocVersion ) )
3586         {
3587             try
3588             {
3589                 fJavadocVersion = Float.parseFloat( javadocVersion );
3590             }
3591             catch ( NumberFormatException e )
3592             {
3593                 throw new MavenReportException( "Unable to parse javadoc version: " + e.getMessage(), e );
3594             }
3595 
3596             if ( fJavadocVersion != jVersion && getLog().isWarnEnabled() )
3597             {
3598                 getLog().warn( "Are you sure about the <javadocVersion/> parameter? It seems to be " + jVersion );
3599             }
3600         }
3601         else
3602         {
3603             fJavadocVersion = jVersion;
3604         }
3605     }
3606 
3607     /**
3608      * Is the Javadoc version at least the requested version.
3609      *
3610      * @param requiredVersion the required version, for example 1.5f
3611      * @return <code>true</code> if the javadoc version is equal or greater than the
3612      *         required version
3613      */
3614     private boolean isJavaDocVersionAtLeast( float requiredVersion )
3615     {
3616         return fJavadocVersion >= requiredVersion;
3617     }
3618 
3619     /**
3620      * Convenience method to add an argument to the <code>command line</code>
3621      * conditionally based on the given flag.
3622      *
3623      * @param arguments a list of arguments, not null
3624      * @param b         the flag which controls if the argument is added or not.
3625      * @param value     the argument value to be added.
3626      */
3627     private void addArgIf( List<String> arguments, boolean b, String value )
3628     {
3629         if ( b )
3630         {
3631             arguments.add( value );
3632         }
3633     }
3634 
3635     /**
3636      * Convenience method to add an argument to the <code>command line</code>
3637      * regarding the requested Java version.
3638      *
3639      * @param arguments           a list of arguments, not null
3640      * @param b                   the flag which controls if the argument is added or not.
3641      * @param value               the argument value to be added.
3642      * @param requiredJavaVersion the required Java version, for example 1.31f or 1.4f
3643      * @see #addArgIf(java.util.List, boolean, String)
3644      * @see #isJavaDocVersionAtLeast(float)
3645      */
3646     private void addArgIf( List<String> arguments, boolean b, String value, float requiredJavaVersion )
3647     {
3648         if ( b )
3649         {
3650             if ( isJavaDocVersionAtLeast( requiredJavaVersion ) )
3651             {
3652                 addArgIf( arguments, b, value );
3653             }
3654             else
3655             {
3656                 if ( getLog().isWarnEnabled() )
3657                 {
3658                     getLog().warn( value + " option is not supported on Java version < " + requiredJavaVersion
3659                                        + ". Ignore this option." );
3660                 }
3661             }
3662         }
3663     }
3664 
3665     /**
3666      * Convenience method to add an argument to the <code>command line</code>
3667      * if the the value is not null or empty.
3668      * <p/>
3669      * Moreover, the value could be comma separated.
3670      *
3671      * @param arguments a list of arguments, not null
3672      * @param key       the argument name.
3673      * @param value     the argument value to be added.
3674      * @see #addArgIfNotEmpty(java.util.List, String, String, boolean)
3675      */
3676     private void addArgIfNotEmpty( List<String> arguments, String key, String value )
3677     {
3678         addArgIfNotEmpty( arguments, key, value, false );
3679     }
3680 
3681     /**
3682      * Convenience method to add an argument to the <code>command line</code>
3683      * if the the value is not null or empty.
3684      * <p/>
3685      * Moreover, the value could be comma separated.
3686      *
3687      * @param arguments           a list of arguments, not null
3688      * @param key                 the argument name.
3689      * @param value               the argument value to be added.
3690      * @param repeatKey           repeat or not the key in the command line
3691      * @param splitValue          if <code>true</code> given value will be tokenized by comma
3692      * @param requiredJavaVersion the required Java version, for example 1.31f or 1.4f
3693      * @see #addArgIfNotEmpty(List, String, String, boolean, boolean)
3694      * @see #isJavaDocVersionAtLeast(float)
3695      */
3696     private void addArgIfNotEmpty( List<String> arguments, String key, String value, boolean repeatKey,
3697                                    boolean splitValue, float requiredJavaVersion )
3698     {
3699         if ( StringUtils.isNotEmpty( value ) )
3700         {
3701             if ( isJavaDocVersionAtLeast( requiredJavaVersion ) )
3702             {
3703                 addArgIfNotEmpty( arguments, key, value, repeatKey, splitValue );
3704             }
3705             else
3706             {
3707                 if ( getLog().isWarnEnabled() )
3708                 {
3709                     getLog().warn( key + " option is not supported on Java version < " + requiredJavaVersion
3710                                        + ". Ignore this option." );
3711                 }
3712             }
3713         }
3714     }
3715 
3716     /**
3717      * Convenience method to add an argument to the <code>command line</code>
3718      * if the the value is not null or empty.
3719      * <p/>
3720      * Moreover, the value could be comma separated.
3721      *
3722      * @param arguments  a list of arguments, not null
3723      * @param key        the argument name.
3724      * @param value      the argument value to be added.
3725      * @param repeatKey  repeat or not the key in the command line
3726      * @param splitValue if <code>true</code> given value will be tokenized by comma
3727      */
3728     private void addArgIfNotEmpty( List<String> arguments, String key, String value, boolean repeatKey,
3729                                    boolean splitValue )
3730     {
3731         if ( StringUtils.isNotEmpty( value ) )
3732         {
3733             if ( StringUtils.isNotEmpty( key ) )
3734             {
3735                 arguments.add( key );
3736             }
3737 
3738             if ( splitValue )
3739             {
3740                 StringTokenizer token = new StringTokenizer( value, "," );
3741                 while ( token.hasMoreTokens() )
3742                 {
3743                     String current = token.nextToken().trim();
3744 
3745                     if ( StringUtils.isNotEmpty( current ) )
3746                     {
3747                         arguments.add( current );
3748 
3749                         if ( token.hasMoreTokens() && repeatKey )
3750                         {
3751                             arguments.add( key );
3752                         }
3753                     }
3754                 }
3755             }
3756             else
3757             {
3758                 arguments.add( value );
3759             }
3760         }
3761     }
3762 
3763     /**
3764      * Convenience method to add an argument to the <code>command line</code>
3765      * if the the value is not null or empty.
3766      * <p/>
3767      * Moreover, the value could be comma separated.
3768      *
3769      * @param arguments a list of arguments, not null
3770      * @param key       the argument name.
3771      * @param value     the argument value to be added.
3772      * @param repeatKey repeat or not the key in the command line
3773      */
3774     private void addArgIfNotEmpty( List<String> arguments, String key, String value, boolean repeatKey )
3775     {
3776         addArgIfNotEmpty( arguments, key, value, repeatKey, true );
3777     }
3778 
3779     /**
3780      * Convenience method to add an argument to the <code>command line</code>
3781      * regarding the requested Java version.
3782      *
3783      * @param arguments           a list of arguments, not null
3784      * @param key                 the argument name.
3785      * @param value               the argument value to be added.
3786      * @param requiredJavaVersion the required Java version, for example 1.31f or 1.4f
3787      * @see #addArgIfNotEmpty(java.util.List, String, String, float, boolean)
3788      */
3789     private void addArgIfNotEmpty( List<String> arguments, String key, String value, float requiredJavaVersion )
3790     {
3791         addArgIfNotEmpty( arguments, key, value, requiredJavaVersion, false );
3792     }
3793 
3794     /**
3795      * Convenience method to add an argument to the <code>command line</code>
3796      * regarding the requested Java version.
3797      *
3798      * @param arguments           a list of arguments, not null
3799      * @param key                 the argument name.
3800      * @param value               the argument value to be added.
3801      * @param requiredJavaVersion the required Java version, for example 1.31f or 1.4f
3802      * @param repeatKey           repeat or not the key in the command line
3803      * @see #addArgIfNotEmpty(java.util.List, String, String)
3804      * @see #isJavaDocVersionAtLeast(float)
3805      */
3806     private void addArgIfNotEmpty( List<String> arguments, String key, String value, float requiredJavaVersion,
3807                                    boolean repeatKey )
3808     {
3809         if ( StringUtils.isNotEmpty( value ) )
3810         {
3811             if ( isJavaDocVersionAtLeast( requiredJavaVersion ) )
3812             {
3813                 addArgIfNotEmpty( arguments, key, value, repeatKey );
3814             }
3815             else
3816             {
3817                 if ( getLog().isWarnEnabled() )
3818                 {
3819                     getLog().warn( key + " option is not supported on Java version < " + requiredJavaVersion );
3820                 }
3821             }
3822         }
3823     }
3824 
3825     /**
3826      * Convenience method to process {@link #offlineLinks} values as individual <code>-linkoffline</code>
3827      * javadoc options.
3828      * <br/>
3829      * If {@link #detectOfflineLinks}, try to add javadoc apidocs according Maven conventions for all modules given
3830      * in the project.
3831      *
3832      * @param arguments a list of arguments, not null
3833      * @throws MavenReportException if any
3834      * @see #offlineLinks
3835      * @see #getModulesLinks()
3836      * @see <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#package-list">package-list spec</a>
3837      */
3838     private void addLinkofflineArguments( List<String> arguments )
3839         throws MavenReportException
3840     {
3841         Set<OfflineLink> offlineLinksList = collectOfflineLinks();
3842 
3843         offlineLinksList.addAll( getModulesLinks() );
3844 
3845         for ( OfflineLink offlineLink : offlineLinksList )
3846         {
3847             String url = offlineLink.getUrl();
3848             if ( StringUtils.isEmpty( url ) )
3849             {
3850                 continue;
3851             }
3852             url = cleanUrl( url );
3853 
3854             String location = offlineLink.getLocation();
3855             if ( StringUtils.isEmpty( location ) )
3856             {
3857                 continue;
3858             }
3859             if ( isValidJavadocLink( location ) )
3860             {
3861                 addArgIfNotEmpty( arguments, "-linkoffline",
3862                                   JavadocUtil.quotedPathArgument( url ) + " " + JavadocUtil.quotedPathArgument(
3863                                       location ), true );
3864             }
3865         }
3866     }
3867 
3868     /**
3869      * Convenience method to process {@link #links} values as individual <code>-link</code> javadoc options.
3870      * If {@link #detectLinks}, try to add javadoc apidocs according Maven conventions for all dependencies given
3871      * in the project.
3872      * <br/>
3873      * According the Javadoc documentation, all defined link should have <code>${link}/package-list</code> fetchable.
3874      * <br/>
3875      * <b>Note</b>: when a link is not fetchable:
3876      * <ul>
3877      * <li>Javadoc 1.4 and less throw an exception</li>
3878      * <li>Javadoc 1.5 and more display a warning</li>
3879      * </ul>
3880      *
3881      * @param arguments a list of arguments, not null
3882      * @throws MavenReportException
3883      * @see #detectLinks
3884      * @see #getDependenciesLinks()
3885      * @see <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#package-list">package-list spec</a>
3886      */
3887     private void addLinkArguments( List<String> arguments )
3888         throws MavenReportException
3889     {
3890         Set<String> links = collectLinks();
3891 
3892         for ( String link : links )
3893         {
3894             if ( StringUtils.isEmpty( link ) )
3895             {
3896                 continue;
3897             }
3898 
3899             while ( link.endsWith( "/" ) )
3900             {
3901                 link = link.substring( 0, link.lastIndexOf( "/" ) );
3902             }
3903 
3904             addArgIfNotEmpty( arguments, "-link", JavadocUtil.quotedPathArgument( link ), true, false );
3905         }
3906     }
3907 
3908     /**
3909      * Coppy all resources to the output directory
3910      *
3911      * @param javadocOutputDirectory not null
3912      * @throws MavenReportException if any
3913      * @see #copyDefaultStylesheet(File)
3914      * @see #copyJavadocResources(File)
3915      * @see #copyAdditionalJavadocResources(File)
3916      */
3917     private void copyAllResources( File javadocOutputDirectory )
3918         throws MavenReportException
3919     {
3920         // ----------------------------------------------------------------------
3921         // Copy default resources
3922         // ----------------------------------------------------------------------
3923 
3924         try
3925         {
3926             copyDefaultStylesheet( javadocOutputDirectory );
3927         }
3928         catch ( IOException e )
3929         {
3930             throw new MavenReportException( "Unable to copy default stylesheet: " + e.getMessage(), e );
3931         }
3932 
3933         // ----------------------------------------------------------------------
3934         // Copy javadoc resources
3935         // ----------------------------------------------------------------------
3936 
3937         if ( docfilessubdirs )
3938         {
3939             /*
3940              * Workaround since -docfilessubdirs doesn't seem to be used correctly by the javadoc tool
3941              * (see other note about -sourcepath). Take care of the -excludedocfilessubdir option.
3942              */
3943             try
3944             {
3945                 copyJavadocResources( javadocOutputDirectory );
3946             }
3947             catch ( IOException e )
3948             {
3949                 throw new MavenReportException( "Unable to copy javadoc resources: " + e.getMessage(), e );
3950             }
3951         }
3952 
3953         // ----------------------------------------------------------------------
3954         // Copy additional javadoc resources in artifacts
3955         // ----------------------------------------------------------------------
3956 
3957         copyAdditionalJavadocResources( javadocOutputDirectory );
3958     }
3959 
3960     /**
3961      * Copies the {@link #DEFAULT_CSS_NAME} css file from the current class
3962      * loader to the <code>outputDirectory</code> only if {@link #stylesheetfile} is empty and
3963      * {@link #stylesheet} is equals to <code>maven</code>.
3964      *
3965      * @param anOutputDirectory the output directory
3966      * @throws java.io.IOException if any
3967      * @see #DEFAULT_CSS_NAME
3968      * @see JavadocUtil#copyResource(java.net.URL, java.io.File)
3969      */
3970     private void copyDefaultStylesheet( File anOutputDirectory )
3971         throws IOException
3972     {
3973         if ( StringUtils.isNotEmpty( stylesheetfile ) )
3974         {
3975             return;
3976         }
3977 
3978         if ( !stylesheet.equalsIgnoreCase( "maven" ) )
3979         {
3980             return;
3981         }
3982 
3983         URL url = getClass().getClassLoader().getResource( RESOURCE_CSS_DIR + "/" + DEFAULT_CSS_NAME );
3984         File outFile = new File( anOutputDirectory, DEFAULT_CSS_NAME );
3985         JavadocUtil.copyResource( url, outFile );
3986     }
3987 
3988     /**
3989      * Method that copy all <code>doc-files</code> directories from <code>javadocDirectory</code> of
3990      * the current project or of the projects in the reactor to the <code>outputDirectory</code>.
3991      *
3992      * @param anOutputDirectory the output directory
3993      * @throws java.io.IOException if any
3994      * @see <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/javadoc/whatsnew-1.2.html#docfiles">Reference
3995      *      Guide, Copies new "doc-files" directory for holding images and examples</a>
3996      * @see #docfilessubdirs
3997      */
3998     private void copyJavadocResources( File anOutputDirectory )
3999         throws IOException
4000     {
4001         if ( anOutputDirectory == null || !anOutputDirectory.exists() )
4002         {
4003             throw new IOException( "The outputDirectory " + anOutputDirectory + " doesn't exists." );
4004         }
4005 
4006         if ( includeDependencySources )
4007         {
4008             resolveDependencyBundles();
4009             if ( isNotEmpty( dependencyJavadocBundles ) )
4010             {
4011                 for ( JavadocBundle bundle : dependencyJavadocBundles )
4012                 {
4013                     File dir = bundle.getResourcesDirectory();
4014                     JavadocOptions options = bundle.getOptions();
4015                     if ( dir != null && dir.isDirectory() )
4016                     {
4017                         JavadocUtil.copyJavadocResources( anOutputDirectory, dir, options == null
4018                             ? null
4019                             : options.getExcludedDocfilesSubdirs() );
4020                     }
4021                 }
4022             }
4023         }
4024 
4025         if ( getJavadocDirectory() != null )
4026         {
4027             JavadocUtil.copyJavadocResources( anOutputDirectory, getJavadocDirectory(), excludedocfilessubdir );
4028         }
4029 
4030         if ( isAggregator() && project.isExecutionRoot() )
4031         {
4032             for ( MavenProject subProject : reactorProjects )
4033             {
4034                 if ( subProject != project && getJavadocDirectory() != null )
4035                 {
4036                     String javadocDirRelative =
4037                         PathUtils.toRelative( project.getBasedir(), getJavadocDirectory().getAbsolutePath() );
4038                     File javadocDir = new File( subProject.getBasedir(), javadocDirRelative );
4039                     JavadocUtil.copyJavadocResources( anOutputDirectory, javadocDir, excludedocfilessubdir );
4040                 }
4041             }
4042         }
4043     }
4044 
4045     private synchronized void resolveDependencyBundles()
4046         throws IOException
4047     {
4048         if ( dependencyJavadocBundles == null )
4049         {
4050             dependencyJavadocBundles =
4051                 ResourceResolver.resolveDependencyJavadocBundles( getDependencySourceResolverConfig() );
4052             if ( dependencyJavadocBundles == null )
4053             {
4054                 dependencyJavadocBundles = new ArrayList<JavadocBundle>();
4055             }
4056         }
4057     }
4058 
4059     /**
4060      * Method that copy additional Javadoc resources from given artifacts.
4061      *
4062      * @param anOutputDirectory the output directory
4063      * @throws MavenReportException if any
4064      * @see #resourcesArtifacts
4065      */
4066     private void copyAdditionalJavadocResources( File anOutputDirectory )
4067         throws MavenReportException
4068     {
4069         Set<ResourcesArtifact> resourcesArtifacts = collectResourcesArtifacts();
4070         if ( isEmpty( resourcesArtifacts ) )
4071         {
4072             return;
4073         }
4074 
4075         UnArchiver unArchiver;
4076         try
4077         {
4078             unArchiver = archiverManager.getUnArchiver( "jar" );
4079         }
4080         catch ( NoSuchArchiverException e )
4081         {
4082             throw new MavenReportException(
4083                 "Unable to extract resources artifact. " + "No archiver for 'jar' available.", e );
4084         }
4085 
4086         for ( ResourcesArtifact item : resourcesArtifacts )
4087         {
4088             Artifact artifact;
4089             try
4090             {
4091                 artifact = createAndResolveArtifact( item );
4092             }
4093             catch ( ArtifactResolutionException e )
4094             {
4095                 throw new MavenReportException( "Unable to resolve artifact:" + item, e );
4096             }
4097             catch ( ArtifactNotFoundException e )
4098             {
4099                 throw new MavenReportException( "Unable to find artifact:" + item, e );
4100             }
4101             catch ( ProjectBuildingException e )
4102             {
4103                 throw new MavenReportException( "Unable to build the Maven project for the artifact:" + item, e );
4104             }
4105 
4106             unArchiver.setSourceFile( artifact.getFile() );
4107             unArchiver.setDestDirectory( anOutputDirectory );
4108             // remove the META-INF directory from resource artifact
4109             IncludeExcludeFileSelector[] selectors =
4110                 new IncludeExcludeFileSelector[]{ new IncludeExcludeFileSelector() };
4111             selectors[0].setExcludes( new String[]{ "META-INF/**" } );
4112             unArchiver.setFileSelectors( selectors );
4113 
4114             getLog().info( "Extracting contents of resources artifact: " + artifact.getArtifactId() );
4115             try
4116             {
4117                 unArchiver.extract();
4118             }
4119             catch ( ArchiverException e )
4120             {
4121                 throw new MavenReportException(
4122                     "Extraction of resources failed. Artifact that failed was: " + artifact.getArtifactId(), e );
4123             }
4124         }
4125     }
4126 
4127     /**
4128      * @param sourcePaths could be null
4129      * @param files       not null
4130      * @return the list of package names for files in the sourcePaths
4131      */
4132     private List<String> getPackageNames( List<String> sourcePaths, List<String> files )
4133     {
4134         return getPackageNamesOrFilesWithUnnamedPackages( sourcePaths, files, true );
4135     }
4136 
4137     /**
4138      * @param sourcePaths could be null
4139      * @param files       not null
4140      * @return a list files with unnamed package names for files in the sourecPaths
4141      */
4142     private List<String> getFilesWithUnnamedPackages( List<String> sourcePaths, List<String> files )
4143     {
4144         return getPackageNamesOrFilesWithUnnamedPackages( sourcePaths, files, false );
4145     }
4146 
4147     /**
4148      * @param sourcePaths     not null, containing absolute and relative paths
4149      * @param files           not null, containing list of quoted files
4150      * @param onlyPackageName boolean for only package name
4151      * @return a list of package names or files with unnamed package names, depending the value of the unnamed flag
4152      * @see #getFiles(List)
4153      * @see #getSourcePaths()
4154      */
4155     private List<String> getPackageNamesOrFilesWithUnnamedPackages( List<String> sourcePaths, List<String> files,
4156                                                                     boolean onlyPackageName )
4157     {
4158         List<String> returnList = new ArrayList<String>();
4159 
4160         if ( !StringUtils.isEmpty( sourcepath ) )
4161         {
4162             return returnList;
4163         }
4164 
4165         for ( String currentFile : files )
4166         {
4167             currentFile = currentFile.replace( '\\', '/' );
4168 
4169             for ( String currentSourcePath : sourcePaths )
4170             {
4171                 currentSourcePath = currentSourcePath.replace( '\\', '/' );
4172 
4173                 if ( !currentSourcePath.endsWith( "/" ) )
4174                 {
4175                     currentSourcePath += "/";
4176                 }
4177 
4178                 if ( currentFile.indexOf( currentSourcePath ) != -1 )
4179                 {
4180                     String packagename = currentFile.substring( currentSourcePath.length() + 1 );
4181 
4182                     /*
4183                      * Remove the miscellaneous files
4184                      * http://docs.oracle.com/javase/1.4.2/docs/tooldocs/solaris/javadoc.html#unprocessed
4185                      */
4186                     if ( packagename.indexOf( "doc-files" ) != -1 )
4187                     {
4188                         continue;
4189                     }
4190 
4191                     if ( onlyPackageName && packagename.lastIndexOf( "/" ) != -1 )
4192                     {
4193                         packagename = packagename.substring( 0, packagename.lastIndexOf( "/" ) );
4194                         packagename = packagename.replace( '/', '.' );
4195 
4196                         if ( !returnList.contains( packagename ) )
4197                         {
4198                             returnList.add( packagename );
4199                         }
4200                     }
4201                     if ( !onlyPackageName && packagename.lastIndexOf( "/" ) == -1 )
4202                     {
4203                         returnList.add( currentFile );
4204                     }
4205                 }
4206             }
4207         }
4208 
4209         return returnList;
4210     }
4211 
4212     /**
4213      * Generate an <code>options</code> file for all options and arguments and add the <code>@options</code> in the
4214      * command line.
4215      *
4216      * @param cmd                    not null
4217      * @param arguments              not null
4218      * @param javadocOutputDirectory not null
4219      * @throws MavenReportException if any
4220      * @see <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#argumentfiles">
4221      *      Reference Guide, Command line argument files</a>
4222      * @see #OPTIONS_FILE_NAME
4223      */
4224     private void addCommandLineOptions( Commandline cmd, List<String> arguments, File javadocOutputDirectory )
4225         throws MavenReportException
4226     {
4227         File optionsFile = new File( javadocOutputDirectory, OPTIONS_FILE_NAME );
4228 
4229         StringBuilder options = new StringBuilder();
4230         options.append( StringUtils.join( arguments.toArray( new String[0] ), SystemUtils.LINE_SEPARATOR ) );
4231 
4232         try
4233         {
4234             FileUtils.fileWrite( optionsFile.getAbsolutePath(), options.toString() );
4235         }
4236         catch ( IOException e )
4237         {
4238             throw new MavenReportException(
4239                 "Unable to write '" + optionsFile.getName() + "' temporary file for command execution", e );
4240         }
4241 
4242         cmd.createArg().setValue( "@" + OPTIONS_FILE_NAME );
4243     }
4244 
4245     /**
4246      * Generate a file called <code>argfile</code> (or <code>files</code>, depending the JDK) to hold files and add
4247      * the <code>@argfile</code> (or <code>@file</code>, depending the JDK) in the command line.
4248      *
4249      * @param cmd                    not null
4250      * @param javadocOutputDirectory not null
4251      * @param files                  not null
4252      * @throws MavenReportException if any
4253      * @see <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#argumentfiles">
4254      *      Reference Guide, Command line argument files
4255      *      </a>
4256      * @see <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/javadoc/whatsnew-1.4.html#runningjavadoc">
4257      *      What s New in Javadoc 1.4
4258      *      </a>
4259      * @see #isJavaDocVersionAtLeast(float)
4260      * @see #ARGFILE_FILE_NAME
4261      * @see #FILES_FILE_NAME
4262      */
4263     private void addCommandLineArgFile( Commandline cmd, File javadocOutputDirectory, List<String> files )
4264         throws MavenReportException
4265     {
4266         File argfileFile;
4267         if ( isJavaDocVersionAtLeast( SINCE_JAVADOC_1_4 ) )
4268         {
4269             argfileFile = new File( javadocOutputDirectory, ARGFILE_FILE_NAME );
4270             cmd.createArg().setValue( "@" + ARGFILE_FILE_NAME );
4271         }
4272         else
4273         {
4274             argfileFile = new File( javadocOutputDirectory, FILES_FILE_NAME );
4275             cmd.createArg().setValue( "@" + FILES_FILE_NAME );
4276         }
4277 
4278         try
4279         {
4280             FileUtils.fileWrite( argfileFile.getAbsolutePath(), null /* platform encoding */,
4281                                  StringUtils.join( files.iterator(), SystemUtils.LINE_SEPARATOR ) );
4282         }
4283         catch ( IOException e )
4284         {
4285             throw new MavenReportException(
4286                 "Unable to write '" + argfileFile.getName() + "' temporary file for command execution", e );
4287         }
4288     }
4289 
4290     /**
4291      * Generate a file called <code>packages</code> to hold all package names and add the <code>@packages</code> in
4292      * the command line.
4293      *
4294      * @param cmd                    not null
4295      * @param javadocOutputDirectory not null
4296      * @param packageNames           not null
4297      * @throws MavenReportException if any
4298      * @see <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#argumentfiles">
4299      *      Reference Guide, Command line argument files</a>
4300      * @see #PACKAGES_FILE_NAME
4301      */
4302     private void addCommandLinePackages( Commandline cmd, File javadocOutputDirectory, List<String> packageNames )
4303         throws MavenReportException
4304     {
4305         File packagesFile = new File( javadocOutputDirectory, PACKAGES_FILE_NAME );
4306 
4307         try
4308         {
4309             FileUtils.fileWrite( packagesFile.getAbsolutePath(), null /* platform encoding */,
4310                                  StringUtils.join( packageNames.iterator(), SystemUtils.LINE_SEPARATOR ) );
4311         }
4312         catch ( IOException e )
4313         {
4314             throw new MavenReportException(
4315                 "Unable to write '" + packagesFile.getName() + "' temporary file for command execution", e );
4316         }
4317 
4318         cmd.createArg().setValue( "@" + PACKAGES_FILE_NAME );
4319     }
4320 
4321     /**
4322      * Checks for the validity of the Javadoc options used by the user.
4323      *
4324      * @throws MavenReportException if error
4325      */
4326     private void validateJavadocOptions()
4327         throws MavenReportException
4328     {
4329         // encoding
4330         if ( StringUtils.isNotEmpty( getEncoding() ) && !JavadocUtil.validateEncoding( getEncoding() ) )
4331         {
4332             throw new MavenReportException( "Unsupported option <encoding/> '" + getEncoding() + "'" );
4333         }
4334 
4335         // locale
4336         if ( StringUtils.isNotEmpty( this.locale ) )
4337         {
4338             StringTokenizer tokenizer = new StringTokenizer( this.locale, "_" );
4339             final int maxTokens = 3;
4340             if ( tokenizer.countTokens() > maxTokens )
4341             {
4342                 throw new MavenReportException(
4343                     "Unsupported option <locale/> '" + this.locale + "', should be language_country_variant." );
4344             }
4345 
4346             Locale localeObject = null;
4347             if ( tokenizer.hasMoreTokens() )
4348             {
4349                 String language = tokenizer.nextToken().toLowerCase( Locale.ENGLISH );
4350                 if ( !Arrays.asList( Locale.getISOLanguages() ).contains( language ) )
4351                 {
4352                     throw new MavenReportException(
4353                         "Unsupported language '" + language + "' in option <locale/> '" + this.locale + "'" );
4354                 }
4355                 localeObject = new Locale( language );
4356 
4357                 if ( tokenizer.hasMoreTokens() )
4358                 {
4359                     String country = tokenizer.nextToken().toUpperCase( Locale.ENGLISH );
4360                     if ( !Arrays.asList( Locale.getISOCountries() ).contains( country ) )
4361                     {
4362                         throw new MavenReportException(
4363                             "Unsupported country '" + country + "' in option <locale/> '" + this.locale + "'" );
4364                     }
4365                     localeObject = new Locale( language, country );
4366 
4367                     if ( tokenizer.hasMoreTokens() )
4368                     {
4369                         String variant = tokenizer.nextToken();
4370                         localeObject = new Locale( language, country, variant );
4371                     }
4372                 }
4373             }
4374 
4375             if ( localeObject == null )
4376             {
4377                 throw new MavenReportException(
4378                     "Unsupported option <locale/> '" + this.locale + "', should be language_country_variant." );
4379             }
4380 
4381             this.locale = localeObject.toString();
4382             final List<Locale> availableLocalesList = Arrays.asList( Locale.getAvailableLocales() );
4383             if ( StringUtils.isNotEmpty( localeObject.getVariant() ) && !availableLocalesList.contains( localeObject ) )
4384             {
4385                 StringBuilder sb = new StringBuilder();
4386                 sb.append( "Unsupported option <locale/> with variant '" ).append( this.locale );
4387                 sb.append( "'" );
4388 
4389                 localeObject = new Locale( localeObject.getLanguage(), localeObject.getCountry() );
4390                 this.locale = localeObject.toString();
4391 
4392                 sb.append( ", trying to use <locale/> without variant, i.e. '" ).append( this.locale ).append( "'" );
4393                 if ( getLog().isWarnEnabled() )
4394                 {
4395                     getLog().warn( sb.toString() );
4396                 }
4397             }
4398 
4399             if ( !availableLocalesList.contains( localeObject ) )
4400             {
4401                 throw new MavenReportException( "Unsupported option <locale/> '" + this.locale + "'" );
4402             }
4403         }
4404     }
4405 
4406     /**
4407      * Checks for the validity of the Standard Doclet options.
4408      * <br/>
4409      * For example, throw an exception if &lt;nohelp/&gt; and &lt;helpfile/&gt; options are used together.
4410      *
4411      * @throws MavenReportException if error or conflict found
4412      */
4413     private void validateStandardDocletOptions()
4414         throws MavenReportException
4415     {
4416         // docencoding
4417         if ( StringUtils.isNotEmpty( getDocencoding() ) && !JavadocUtil.validateEncoding( getDocencoding() ) )
4418         {
4419             throw new MavenReportException( "Unsupported option <docencoding/> '" + getDocencoding() + "'" );
4420         }
4421 
4422         // charset
4423         if ( StringUtils.isNotEmpty( getCharset() ) && !JavadocUtil.validateEncoding( getCharset() ) )
4424         {
4425             throw new MavenReportException( "Unsupported option <charset/> '" + getCharset() + "'" );
4426         }
4427 
4428         // helpfile
4429         if ( StringUtils.isNotEmpty( helpfile ) && nohelp )
4430         {
4431             throw new MavenReportException( "Option <nohelp/> conflicts with <helpfile/>" );
4432         }
4433 
4434         // overview
4435         if ( ( getOverview() != null ) && nooverview )
4436         {
4437             throw new MavenReportException( "Option <nooverview/> conflicts with <overview/>" );
4438         }
4439 
4440         // index
4441         if ( splitindex && noindex )
4442         {
4443             throw new MavenReportException( "Option <noindex/> conflicts with <splitindex/>" );
4444         }
4445 
4446         // stylesheet
4447         if ( StringUtils.isNotEmpty( stylesheet ) && !( stylesheet.equalsIgnoreCase( "maven" )
4448             || stylesheet.equalsIgnoreCase( "java" ) ) )
4449         {
4450             throw new MavenReportException( "Option <stylesheet/> supports only \"maven\" or \"java\" value." );
4451         }
4452 
4453         // default java api links
4454         if ( javaApiLinks == null || javaApiLinks.size() == 0 )
4455         {
4456             javaApiLinks = DEFAULT_JAVA_API_LINKS;
4457         }
4458     }
4459 
4460     /**
4461      * This method is checking to see if the artifacts that can't be resolved are all
4462      * part of this reactor. This is done to prevent a chicken or egg scenario with
4463      * fresh projects. See MJAVADOC-116 for more info.
4464      *
4465      * @param dependencyArtifacts the sibling projects in the reactor
4466      * @param missing             the artifacts that can't be found
4467      * @return true if ALL missing artifacts are found in the reactor.
4468      */
4469     private boolean checkMissingArtifactsInReactor( Collection<Artifact> dependencyArtifacts,
4470                                                     Collection<Artifact> missing )
4471     {
4472         Set<MavenProject> foundInReactor = new HashSet<MavenProject>();
4473         for ( Artifact mArtifact : missing )
4474         {
4475             for ( MavenProject p : reactorProjects )
4476             {
4477                 if ( p.getArtifactId().equals( mArtifact.getArtifactId() ) && p.getGroupId().equals(
4478                     mArtifact.getGroupId() ) && p.getVersion().equals( mArtifact.getVersion() ) )
4479                 {
4480                     getLog().warn( "The dependency: [" + p.getId()
4481                                        + "] can't be resolved but has been found in the reactor (probably snapshots).\n"
4482                                        + "This dependency has been excluded from the Javadoc classpath. "
4483                                        + "You should rerun javadoc after executing mvn install." );
4484 
4485                     // found it, move on.
4486                     foundInReactor.add( p );
4487                     break;
4488                 }
4489             }
4490         }
4491 
4492         // if all of them have been found, we can continue.
4493         return foundInReactor.size() == missing.size();
4494     }
4495 
4496     /**
4497      * Add Standard Javadoc Options.
4498      * <br/>
4499      * The <a href="package-summary.html#Standard_Javadoc_Options">package documentation</a> details the
4500      * Standard Javadoc Options wrapped by this Plugin.
4501      *
4502      * @param arguments   not null
4503      * @param sourcePaths not null
4504      * @throws MavenReportException if any
4505      * @see <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#javadocoptions">http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#javadocoptions</a>
4506      */
4507     private void addJavadocOptions( List<String> arguments, List<String> sourcePaths )
4508         throws MavenReportException
4509     {
4510         validateJavadocOptions();
4511 
4512         // see com.sun.tools.javadoc.Start#parseAndExecute(String argv[])
4513         addArgIfNotEmpty( arguments, "-locale", JavadocUtil.quotedArgument( this.locale ) );
4514 
4515         // all options in alphabetical order
4516 
4517         if ( old && isJavaDocVersionAtLeast( SINCE_JAVADOC_1_4 ) )
4518         {
4519             if ( getLog().isWarnEnabled() )
4520             {
4521                 getLog().warn( "Javadoc 1.4+ doesn't support the -1.1 switch anymore. Ignore this option." );
4522             }
4523         }
4524         else
4525         {
4526             addArgIf( arguments, old, "-1.1" );
4527         }
4528 
4529         addArgIfNotEmpty( arguments, "-bootclasspath", JavadocUtil.quotedPathArgument( getBootclassPath() ) );
4530 
4531         if ( isJavaDocVersionAtLeast( SINCE_JAVADOC_1_5 ) )
4532         {
4533             addArgIf( arguments, breakiterator, "-breakiterator", SINCE_JAVADOC_1_5 );
4534         }
4535 
4536         addArgIfNotEmpty( arguments, "-classpath", JavadocUtil.quotedPathArgument( getClasspath() ) );
4537 
4538         if ( StringUtils.isNotEmpty( doclet ) )
4539         {
4540             addArgIfNotEmpty( arguments, "-doclet", JavadocUtil.quotedArgument( doclet ) );
4541             addArgIfNotEmpty( arguments, "-docletpath", JavadocUtil.quotedPathArgument( getDocletPath() ) );
4542         }
4543 
4544         if ( StringUtils.isEmpty( encoding ) )
4545         {
4546             getLog().warn(
4547                 "Source files encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING
4548                     + ", i.e. build is platform dependent!" );
4549         }
4550         addArgIfNotEmpty( arguments, "-encoding", JavadocUtil.quotedArgument( getEncoding() ) );
4551 
4552         addArgIfNotEmpty( arguments, "-exclude", getExcludedPackages( sourcePaths ), SINCE_JAVADOC_1_4 );
4553 
4554         addArgIfNotEmpty( arguments, "-extdirs",
4555                           JavadocUtil.quotedPathArgument( JavadocUtil.unifyPathSeparator( extdirs ) ) );
4556 
4557         if ( ( getOverview() != null ) && ( getOverview().exists() ) )
4558         {
4559             addArgIfNotEmpty( arguments, "-overview",
4560                               JavadocUtil.quotedPathArgument( getOverview().getAbsolutePath() ) );
4561         }
4562 
4563         arguments.add( getAccessLevel() );
4564 
4565         if ( isJavaDocVersionAtLeast( SINCE_JAVADOC_1_5 ) )
4566         {
4567             addArgIf( arguments, quiet, "-quiet", SINCE_JAVADOC_1_5 );
4568         }
4569 
4570         addArgIfNotEmpty( arguments, "-source", JavadocUtil.quotedArgument( source ), SINCE_JAVADOC_1_4 );
4571 
4572         if ( ( StringUtils.isEmpty( sourcepath ) ) && ( StringUtils.isNotEmpty( subpackages ) ) )
4573         {
4574             sourcepath = StringUtils.join( sourcePaths.iterator(), File.pathSeparator );
4575         }
4576         addArgIfNotEmpty( arguments, "-sourcepath", JavadocUtil.quotedPathArgument( getSourcePath( sourcePaths ) ) );
4577 
4578         if ( StringUtils.isNotEmpty( sourcepath ) && isJavaDocVersionAtLeast( SINCE_JAVADOC_1_5 ) )
4579         {
4580             addArgIfNotEmpty( arguments, "-subpackages", subpackages, SINCE_JAVADOC_1_5 );
4581         }
4582 
4583         addArgIf( arguments, verbose, "-verbose" );
4584 
4585         addArgIfNotEmpty( arguments, null, additionalparam );
4586     }
4587 
4588     /**
4589      * Add Standard Doclet Options.
4590      * <br/>
4591      * The <a href="package-summary.html#Standard_Doclet_Options">package documentation</a> details the
4592      * Standard Doclet Options wrapped by this Plugin.
4593      *
4594      * @param javadocOutputDirectory not null
4595      * @param arguments              not null
4596      * @throws MavenReportException if any
4597      * @see <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#standard">
4598      *      http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javadoc.html#standard</a>
4599      */
4600     private void addStandardDocletOptions( File javadocOutputDirectory, List<String> arguments )
4601         throws MavenReportException
4602     {
4603         validateStandardDocletOptions();
4604 
4605         // all options in alphabetical order
4606 
4607         addArgIf( arguments, author, "-author" );
4608 
4609         addArgIfNotEmpty( arguments, "-bottom", JavadocUtil.quotedArgument( getBottomText() ), false, false );
4610 
4611         if ( !isJavaDocVersionAtLeast( SINCE_JAVADOC_1_5 ) )
4612         {
4613             addArgIf( arguments, breakiterator, "-breakiterator", SINCE_JAVADOC_1_4 );
4614         }
4615 
4616         addArgIfNotEmpty( arguments, "-charset", JavadocUtil.quotedArgument( getCharset() ) );
4617 
4618         addArgIfNotEmpty( arguments, "-d", JavadocUtil.quotedPathArgument( javadocOutputDirectory.toString() ) );
4619 
4620         addArgIfNotEmpty( arguments, "-docencoding", JavadocUtil.quotedArgument( getDocencoding() ) );
4621 
4622         addArgIf( arguments, docfilessubdirs, "-docfilessubdirs", SINCE_JAVADOC_1_4 );
4623 
4624         addArgIfNotEmpty( arguments, "-doctitle", JavadocUtil.quotedArgument( getDoctitle() ), false, false );
4625 
4626         if ( docfilessubdirs )
4627         {
4628             addArgIfNotEmpty( arguments, "-excludedocfilessubdir",
4629                               JavadocUtil.quotedPathArgument( excludedocfilessubdir ), SINCE_JAVADOC_1_4 );
4630         }
4631 
4632         addArgIfNotEmpty( arguments, "-footer", JavadocUtil.quotedArgument( footer ), false, false );
4633 
4634         addGroups( arguments );
4635 
4636         addArgIfNotEmpty( arguments, "-header", JavadocUtil.quotedArgument( header ), false, false );
4637 
4638         addArgIfNotEmpty( arguments, "-helpfile",
4639                           JavadocUtil.quotedPathArgument( getHelpFile( javadocOutputDirectory ) ) );
4640 
4641         addArgIf( arguments, keywords, "-keywords", SINCE_JAVADOC_1_4_2 );
4642 
4643         if ( !isOffline )
4644         {
4645             addLinkArguments( arguments );
4646         }
4647 
4648         addLinkofflineArguments( arguments );
4649 
4650         addArgIf( arguments, linksource, "-linksource", SINCE_JAVADOC_1_4 );
4651 
4652         if ( sourcetab > 0 )
4653         {
4654             if ( fJavadocVersion == SINCE_JAVADOC_1_4_2 )
4655             {
4656                 addArgIfNotEmpty( arguments, "-linksourcetab", String.valueOf( sourcetab ) );
4657             }
4658             addArgIfNotEmpty( arguments, "-sourcetab", String.valueOf( sourcetab ), SINCE_JAVADOC_1_5 );
4659         }
4660 
4661         addArgIf( arguments, nocomment, "-nocomment", SINCE_JAVADOC_1_4 );
4662 
4663         addArgIf( arguments, nodeprecated, "-nodeprecated" );
4664 
4665         addArgIf( arguments, nodeprecatedlist, "-nodeprecatedlist" );
4666 
4667         addArgIf( arguments, nohelp, "-nohelp" );
4668 
4669         addArgIf( arguments, noindex, "-noindex" );
4670 
4671         addArgIf( arguments, nonavbar, "-nonavbar" );
4672 
4673         addArgIf( arguments, nooverview, "-nooverview" );
4674 
4675         addArgIfNotEmpty( arguments, "-noqualifier", JavadocUtil.quotedArgument( noqualifier ), SINCE_JAVADOC_1_4 );
4676 
4677         addArgIf( arguments, nosince, "-nosince" );
4678 
4679         addArgIf( arguments, notimestamp, "-notimestamp", SINCE_JAVADOC_1_5 );
4680 
4681         addArgIf( arguments, notree, "-notree" );
4682 
4683         addArgIfNotEmpty( arguments, "-packagesheader", JavadocUtil.quotedArgument( packagesheader ),
4684                           SINCE_JAVADOC_1_4_2 );
4685 
4686         if ( !isJavaDocVersionAtLeast( SINCE_JAVADOC_1_5 ) ) // Sun bug: 4714350
4687         {
4688             addArgIf( arguments, quiet, "-quiet", SINCE_JAVADOC_1_4 );
4689         }
4690 
4691         addArgIf( arguments, serialwarn, "-serialwarn" );
4692 
4693         addArgIf( arguments, splitindex, "-splitindex" );
4694 
4695         addArgIfNotEmpty( arguments, "-stylesheetfile",
4696                           JavadocUtil.quotedPathArgument( getStylesheetFile( javadocOutputDirectory ) ) );
4697 
4698         if ( StringUtils.isNotEmpty( sourcepath ) && !isJavaDocVersionAtLeast( SINCE_JAVADOC_1_5 ) )
4699         {
4700             addArgIfNotEmpty( arguments, "-subpackages", subpackages, SINCE_JAVADOC_1_4 );
4701         }
4702 
4703         addArgIfNotEmpty( arguments, "-taglet", JavadocUtil.quotedArgument( taglet ), SINCE_JAVADOC_1_4 );
4704         addTaglets( arguments );
4705         addTagletsFromTagletArtifacts( arguments );
4706         addArgIfNotEmpty( arguments, "-tagletpath", JavadocUtil.quotedPathArgument( getTagletPath() ),
4707                           SINCE_JAVADOC_1_4 );
4708 
4709         addTags( arguments );
4710 
4711         addArgIfNotEmpty( arguments, "-top", JavadocUtil.quotedArgument( top ), false, false, SINCE_JAVADOC_1_6 );
4712 
4713         addArgIf( arguments, use, "-use" );
4714 
4715         addArgIf( arguments, version, "-version" );
4716 
4717         addArgIfNotEmpty( arguments, "-windowtitle", JavadocUtil.quotedArgument( getWindowtitle() ), false, false );
4718     }
4719 
4720     /**
4721      * Add <code>groups</code> parameter to arguments.
4722      *
4723      * @param arguments not null
4724      * @throws MavenReportException
4725      */
4726     private void addGroups( List<String> arguments )
4727         throws MavenReportException
4728     {
4729         Set<Group> groups = collectGroups();
4730         if ( isEmpty( groups ) )
4731         {
4732             return;
4733         }
4734 
4735         for ( Group group : groups )
4736         {
4737             if ( group == null || StringUtils.isEmpty( group.getTitle() ) || StringUtils.isEmpty(
4738                 group.getPackages() ) )
4739             {
4740                 if ( getLog().isWarnEnabled() )
4741                 {
4742                     getLog().warn( "A group option is empty. Ignore this option." );
4743                 }
4744             }
4745             else
4746             {
4747                 String groupTitle = StringUtils.replace( group.getTitle(), ",", "&#44;" );
4748                 addArgIfNotEmpty( arguments, "-group",
4749                                   JavadocUtil.quotedArgument( groupTitle ) + " " + JavadocUtil.quotedArgument(
4750                                       group.getPackages() ), true );
4751             }
4752         }
4753     }
4754 
4755     /**
4756      * Add <code>tags</code> parameter to arguments.
4757      *
4758      * @param arguments not null
4759      * @throws MavenReportException
4760      */
4761     private void addTags( List<String> arguments )
4762         throws MavenReportException
4763     {
4764         Set<Tag> tags = collectTags();
4765 
4766         if ( isEmpty( tags ) )
4767         {
4768             return;
4769         }
4770 
4771         for ( Tag tag : tags )
4772         {
4773             if ( StringUtils.isEmpty( tag.getName() ) )
4774             {
4775                 if ( getLog().isWarnEnabled() )
4776                 {
4777                     getLog().warn( "A tag name is empty. Ignore this option." );
4778                 }
4779             }
4780             else
4781             {
4782                 String value = "\"" + tag.getName();
4783                 if ( StringUtils.isNotEmpty( tag.getPlacement() ) )
4784                 {
4785                     value += ":" + tag.getPlacement();
4786                     if ( StringUtils.isNotEmpty( tag.getHead() ) )
4787                     {
4788                         value += ":" + tag.getHead();
4789                     }
4790                 }
4791                 value += "\"";
4792                 addArgIfNotEmpty( arguments, "-tag", value, SINCE_JAVADOC_1_4 );
4793             }
4794         }
4795     }
4796 
4797     /**
4798      * Add <code>taglets</code> parameter to arguments.
4799      *
4800      * @param arguments not null
4801      */
4802     private void addTaglets( List<String> arguments )
4803     {
4804         if ( taglets == null )
4805         {
4806             return;
4807         }
4808 
4809         for ( int i = 0; i < taglets.length; i++ )
4810         {
4811             if ( ( taglets[i] == null ) || ( StringUtils.isEmpty( taglets[i].getTagletClass() ) ) )
4812             {
4813                 if ( getLog().isWarnEnabled() )
4814                 {
4815                     getLog().warn( "A taglet option is empty. Ignore this option." );
4816                 }
4817             }
4818             else
4819             {
4820                 addArgIfNotEmpty( arguments, "-taglet", JavadocUtil.quotedArgument( taglets[i].getTagletClass() ),
4821                                   SINCE_JAVADOC_1_4 );
4822             }
4823         }
4824     }
4825 
4826     /**
4827      * Auto-detect taglets class name from <code>tagletArtifacts</code> and add them to arguments.
4828      *
4829      * @param arguments not null
4830      * @throws MavenReportException if any
4831      * @see JavadocUtil#getTagletClassNames(File)
4832      */
4833     private void addTagletsFromTagletArtifacts( List<String> arguments )
4834         throws MavenReportException
4835     {
4836         Set<TagletArtifact> tArtifacts = new LinkedHashSet<TagletArtifact>();
4837         if ( tagletArtifacts != null && tagletArtifacts.length > 0 )
4838         {
4839             tArtifacts.addAll( Arrays.asList( tagletArtifacts ) );
4840         }
4841 
4842         if ( includeDependencySources )
4843         {
4844             try
4845             {
4846                 resolveDependencyBundles();
4847             }
4848             catch ( IOException e )
4849             {
4850                 throw new MavenReportException(
4851                     "Failed to resolve javadoc bundles from dependencies: " + e.getMessage(), e );
4852             }
4853 
4854             if ( isNotEmpty( dependencyJavadocBundles ) )
4855             {
4856                 for ( JavadocBundle bundle : dependencyJavadocBundles )
4857                 {
4858                     JavadocOptions options = bundle.getOptions();
4859                     if ( options != null && isNotEmpty( options.getTagletArtifacts() ) )
4860                     {
4861                         tArtifacts.addAll( options.getTagletArtifacts() );
4862                     }
4863                 }
4864             }
4865         }
4866 
4867         if ( isEmpty( tArtifacts ) )
4868         {
4869             return;
4870         }
4871 
4872         List<String> tagletsPath = new ArrayList<String>();
4873 
4874         for ( TagletArtifact aTagletArtifact : tArtifacts )
4875         {
4876             if ( ( StringUtils.isNotEmpty( aTagletArtifact.getGroupId() ) ) && ( StringUtils.isNotEmpty(
4877                 aTagletArtifact.getArtifactId() ) ) && ( StringUtils.isNotEmpty( aTagletArtifact.getVersion() ) ) )
4878             {
4879                 Artifact artifact;
4880                 try
4881                 {
4882                     artifact = createAndResolveArtifact( aTagletArtifact );
4883                 }
4884                 catch ( ArtifactResolutionException e )
4885                 {
4886                     throw new MavenReportException( "Unable to resolve artifact:" + aTagletArtifact, e );
4887                 }
4888                 catch ( ArtifactNotFoundException e )
4889                 {
4890                     throw new MavenReportException( "Unable to find artifact:" + aTagletArtifact, e );
4891                 }
4892                 catch ( ProjectBuildingException e )
4893                 {
4894                     throw new MavenReportException(
4895                         "Unable to build the Maven project for the artifact:" + aTagletArtifact, e );
4896                 }
4897 
4898                 tagletsPath.add( artifact.getFile().getAbsolutePath() );
4899             }
4900         }
4901 
4902         tagletsPath = JavadocUtil.pruneFiles( tagletsPath );
4903 
4904         for ( String tagletJar : tagletsPath )
4905         {
4906             if ( !tagletJar.toLowerCase( Locale.ENGLISH ).endsWith( ".jar" ) )
4907             {
4908                 continue;
4909             }
4910 
4911             List<String> tagletClasses;
4912             try
4913             {
4914                 tagletClasses = JavadocUtil.getTagletClassNames( new File( tagletJar ) );
4915             }
4916             catch ( IOException e )
4917             {
4918                 if ( getLog().isWarnEnabled() )
4919                 {
4920                     getLog().warn( "Unable to auto-detect Taglet class names from '" + tagletJar
4921                                        + "'. Try to specify them with <taglets/>." );
4922                 }
4923                 if ( getLog().isDebugEnabled() )
4924                 {
4925                     getLog().debug( "IOException: " + e.getMessage(), e );
4926                 }
4927                 continue;
4928             }
4929             catch ( ClassNotFoundException e )
4930             {
4931                 if ( getLog().isWarnEnabled() )
4932                 {
4933                     getLog().warn( "Unable to auto-detect Taglet class names from '" + tagletJar
4934                                        + "'. Try to specify them with <taglets/>." );
4935                 }
4936                 if ( getLog().isDebugEnabled() )
4937                 {
4938                     getLog().debug( "ClassNotFoundException: " + e.getMessage(), e );
4939                 }
4940                 continue;
4941             }
4942             catch ( NoClassDefFoundError e )
4943             {
4944                 if ( getLog().isWarnEnabled() )
4945                 {
4946                     getLog().warn( "Unable to auto-detect Taglet class names from '" + tagletJar
4947                                        + "'. Try to specify them with <taglets/>." );
4948                 }
4949                 if ( getLog().isDebugEnabled() )
4950                 {
4951                     getLog().debug( "NoClassDefFoundError: " + e.getMessage(), e );
4952                 }
4953                 continue;
4954             }
4955 
4956             if ( tagletClasses != null && !tagletClasses.isEmpty() )
4957             {
4958                 for ( String tagletClass : tagletClasses )
4959                 {
4960                     addArgIfNotEmpty( arguments, "-taglet", JavadocUtil.quotedArgument( tagletClass ),
4961                                       SINCE_JAVADOC_1_4 );
4962                 }
4963             }
4964         }
4965     }
4966 
4967     /**
4968      * Execute the Javadoc command line
4969      *
4970      * @param cmd                    not null
4971      * @param javadocOutputDirectory not null
4972      * @throws MavenReportException if any errors occur
4973      */
4974     private void executeJavadocCommandLine( Commandline cmd, File javadocOutputDirectory )
4975         throws MavenReportException
4976     {
4977         if ( getLog().isDebugEnabled() )
4978         {
4979             // no quoted arguments
4980             getLog().debug( CommandLineUtils.toString( cmd.getCommandline() ).replaceAll( "'", "" ) );
4981         }
4982 
4983         String cmdLine = null;
4984         if ( debug )
4985         {
4986             cmdLine = CommandLineUtils.toString( cmd.getCommandline() ).replaceAll( "'", "" );
4987             cmdLine = JavadocUtil.hideProxyPassword( cmdLine, settings );
4988 
4989             writeDebugJavadocScript( cmdLine, javadocOutputDirectory );
4990         }
4991 
4992         CommandLineUtils.StringStreamConsumer err = new CommandLineUtils.StringStreamConsumer();
4993         CommandLineUtils.StringStreamConsumer out = new CommandLineUtils.StringStreamConsumer();
4994         try
4995         {
4996             int exitCode = CommandLineUtils.executeCommandLine( cmd, out, err );
4997 
4998             String output = ( StringUtils.isEmpty( out.getOutput() ) ? null : '\n' + out.getOutput().trim() );
4999 
5000             if ( exitCode != 0 )
5001             {
5002                 if ( cmdLine == null )
5003                 {
5004                     cmdLine = CommandLineUtils.toString( cmd.getCommandline() ).replaceAll( "'", "" );
5005                     cmdLine = JavadocUtil.hideProxyPassword( cmdLine, settings );
5006                 }
5007                 writeDebugJavadocScript( cmdLine, javadocOutputDirectory );
5008 
5009                 if ( StringUtils.isNotEmpty( output ) && StringUtils.isEmpty( err.getOutput() ) && isJavadocVMInitError(
5010                     output ) )
5011                 {
5012                     StringBuilder msg = new StringBuilder();
5013                     msg.append( output );
5014                     msg.append( '\n' ).append( '\n' );
5015                     msg.append( JavadocUtil.ERROR_INIT_VM ).append( '\n' );
5016                     msg.append( "Or, try to reduce the Java heap size for the Javadoc goal using " );
5017                     msg.append( "-Dminmemory=<size> and -Dmaxmemory=<size>." ).append( '\n' ).append( '\n' );
5018 
5019                     msg.append( "Command line was: " ).append( cmdLine ).append( '\n' ).append( '\n' );
5020                     msg.append( "Refer to the generated Javadoc files in '" ).append( javadocOutputDirectory ).append(
5021                         "' dir.\n" );
5022 
5023                     throw new MavenReportException( msg.toString() );
5024                 }
5025 
5026                 if ( StringUtils.isNotEmpty( output ) )
5027                 {
5028                     getLog().info( output );
5029                 }
5030 
5031                 StringBuilder msg = new StringBuilder( "\nExit code: " );
5032                 msg.append( exitCode );
5033                 if ( StringUtils.isNotEmpty( err.getOutput() ) )
5034                 {
5035                     msg.append( " - " ).append( err.getOutput() );
5036                 }
5037                 msg.append( '\n' );
5038                 msg.append( "Command line was: " ).append( cmdLine ).append( '\n' ).append( '\n' );
5039 
5040                 msg.append( "Refer to the generated Javadoc files in '" ).append( javadocOutputDirectory ).append(
5041                     "' dir.\n" );
5042 
5043                 throw new MavenReportException( msg.toString() );
5044             }
5045 
5046             if ( StringUtils.isNotEmpty( output ) )
5047             {
5048                 getLog().info( output );
5049             }
5050         }
5051         catch ( CommandLineException e )
5052         {
5053             throw new MavenReportException( "Unable to execute javadoc command: " + e.getMessage(), e );
5054         }
5055 
5056         // ----------------------------------------------------------------------
5057         // Handle Javadoc warnings
5058         // ----------------------------------------------------------------------
5059 
5060         if ( StringUtils.isNotEmpty( err.getOutput() ) && getLog().isWarnEnabled() )
5061         {
5062             getLog().warn( "Javadoc Warnings" );
5063 
5064             StringTokenizer token = new StringTokenizer( err.getOutput(), "\n" );
5065             while ( token.hasMoreTokens() )
5066             {
5067                 String current = token.nextToken().trim();
5068 
5069                 getLog().warn( current );
5070             }
5071         }
5072     }
5073 
5074     /**
5075      * @param outputFile        not nul
5076      * @param inputResourceName a not null resource in <code>src/main/java</code>, <code>src/main/resources</code> or <code>src/main/javadoc</code>
5077      *                          or in the Javadoc plugin dependencies.
5078      * @return the resource file absolute path as String
5079      * @since 2.6
5080      */
5081     private String getResource( File outputFile, String inputResourceName )
5082     {
5083         if ( inputResourceName.startsWith( "/" ) )
5084         {
5085             inputResourceName = inputResourceName.replaceFirst( "//*", "" );
5086         }
5087 
5088         List<String> classPath = new ArrayList<String>();
5089         classPath.add( project.getBuild().getSourceDirectory() );
5090 
5091         URL resourceURL = getResource( classPath, inputResourceName );
5092         if ( resourceURL != null )
5093         {
5094             getLog().debug( inputResourceName + " found in the main src directory of the project." );
5095             return FileUtils.toFile( resourceURL ).getAbsolutePath();
5096         }
5097 
5098         classPath.clear();
5099         List<Resource> resources = project.getBuild().getResources();
5100         for ( Resource resource : resources )
5101         {
5102             classPath.add( resource.getDirectory() );
5103         }
5104         resourceURL = getResource( classPath, inputResourceName );
5105         if ( resourceURL != null )
5106         {
5107             getLog().debug( inputResourceName + " found in the main resources directories of the project." );
5108             return FileUtils.toFile( resourceURL ).getAbsolutePath();
5109         }
5110 
5111         if ( javadocDirectory.exists() )
5112         {
5113             classPath.clear();
5114             classPath.add( javadocDirectory.getAbsolutePath() );
5115             resourceURL = getResource( classPath, inputResourceName );
5116             if ( resourceURL != null )
5117             {
5118                 getLog().debug( inputResourceName + " found in the main javadoc directory of the project." );
5119                 return FileUtils.toFile( resourceURL ).getAbsolutePath();
5120             }
5121         }
5122 
5123         classPath.clear();
5124         final String pluginId = "org.apache.maven.plugins:maven-javadoc-plugin";
5125         Plugin javadocPlugin = getPlugin( project, pluginId );
5126         if ( javadocPlugin != null && javadocPlugin.getDependencies() != null )
5127         {
5128             List<Dependency> dependencies = javadocPlugin.getDependencies();
5129             for ( Dependency dependency : dependencies )
5130             {
5131                 JavadocPathArtifact javadocPathArtifact = new JavadocPathArtifact();
5132                 javadocPathArtifact.setGroupId( dependency.getGroupId() );
5133                 javadocPathArtifact.setArtifactId( dependency.getArtifactId() );
5134                 javadocPathArtifact.setVersion( dependency.getVersion() );
5135                 Artifact artifact = null;
5136                 try
5137                 {
5138                     artifact = createAndResolveArtifact( javadocPathArtifact );
5139                 }
5140                 catch ( Exception e )
5141                 {
5142                     logError( "Unable to retrieve the dependency: " + dependency + ". Ignored.", e );
5143                 }
5144 
5145                 if ( artifact != null && artifact.getFile().exists() )
5146                 {
5147                     classPath.add( artifact.getFile().getAbsolutePath() );
5148                 }
5149             }
5150             resourceURL = getResource( classPath, inputResourceName );
5151             if ( resourceURL != null )
5152             {
5153                 getLog().debug( inputResourceName + " found in javadoc plugin dependencies." );
5154                 try
5155                 {
5156                     JavadocUtil.copyResource( resourceURL, outputFile );
5157 
5158                     return outputFile.getAbsolutePath();
5159                 }
5160                 catch ( IOException e )
5161                 {
5162                     logError( "IOException: " + e.getMessage(), e );
5163                 }
5164             }
5165         }
5166 
5167         getLog().warn( "Unable to find the resource '" + inputResourceName + "'. Using default Javadoc resources." );
5168 
5169         return null;
5170     }
5171 
5172     /**
5173      * @param classPath a not null String list of files where resource will be look up.
5174      * @param resource  a not null ressource to find in the class path.
5175      * @return the resource from the given classpath or null if not found
5176      * @see ClassLoader#getResource(String)
5177      * @since 2.6
5178      */
5179     private URL getResource( final List<String> classPath, final String resource )
5180     {
5181         List<URL> urls = new ArrayList<URL>( classPath.size() );
5182         for ( String filename : classPath )
5183         {
5184             try
5185             {
5186                 urls.add( new File( filename ).toURL() );
5187             }
5188             catch ( MalformedURLException e )
5189             {
5190                 getLog().error( "MalformedURLException: " + e.getMessage() );
5191             }
5192         }
5193 
5194         ClassLoader javadocClassLoader = new URLClassLoader( (URL[]) urls.toArray( new URL[urls.size()] ), null );
5195 
5196         return javadocClassLoader.getResource( resource );
5197     }
5198 
5199     /**
5200      * Get the full javadoc goal. Loads the plugin's pom.properties to get the current plugin version.
5201      *
5202      * @return <code>org.apache.maven.plugins:maven-javadoc-plugin:CURRENT_VERSION:[test-]javadoc</code>
5203      */
5204     private String getFullJavadocGoal()
5205     {
5206         String javadocPluginVersion = null;
5207         InputStream resourceAsStream = null;
5208         try
5209         {
5210             String resource = "META-INF/maven/org.apache.maven.plugins/maven-javadoc-plugin/pom.properties";
5211             resourceAsStream = AbstractJavadocMojo.class.getClassLoader().getResourceAsStream( resource );
5212 
5213             if ( resourceAsStream != null )
5214             {
5215                 Properties properties = new Properties();
5216                 properties.load( resourceAsStream );
5217 
5218                 if ( StringUtils.isNotEmpty( properties.getProperty( "version" ) ) )
5219                 {
5220                     javadocPluginVersion = properties.getProperty( "version" );
5221                 }
5222             }
5223         }
5224         catch ( IOException e )
5225         {
5226             // nop
5227         }
5228         finally
5229         {
5230             IOUtil.close( resourceAsStream );
5231         }
5232 
5233         StringBuilder sb = new StringBuilder();
5234 
5235         sb.append( "org.apache.maven.plugins:maven-javadoc-plugin:" );
5236         if ( StringUtils.isNotEmpty( javadocPluginVersion ) )
5237         {
5238             sb.append( javadocPluginVersion ).append( ":" );
5239         }
5240 
5241         if ( this instanceof TestJavadocReport )
5242         {
5243             sb.append( "test-javadoc" );
5244         }
5245         else
5246         {
5247             sb.append( "javadoc" );
5248         }
5249 
5250         return sb.toString();
5251     }
5252 
5253     /**
5254      * Using Maven, a Javadoc link is given by <code>${project.url}/apidocs</code>.
5255      *
5256      * @return the detected Javadoc links using the Maven conventions for all modules defined in the current project
5257      *         or an empty list.
5258      * @throws MavenReportException if any
5259      * @see #detectOfflineLinks
5260      * @see #reactorProjects
5261      * @since 2.6
5262      */
5263     private List<OfflineLink> getModulesLinks()
5264         throws MavenReportException
5265     {
5266         if ( !detectOfflineLinks || isAggregator() || reactorProjects == null )
5267         {
5268             return Collections.emptyList();
5269         }
5270 
5271         getLog().debug( "Trying to add links for modules..." );
5272 
5273         Set<String> dependencyArtifactIds = new HashSet<String>();
5274         final Set<Artifact> dependencyArtifacts = project.getDependencyArtifacts();
5275         for ( Artifact artifact : dependencyArtifacts )
5276         {
5277             dependencyArtifactIds.add( artifact.getId() );
5278         }
5279 
5280         List<OfflineLink> modulesLinks = new ArrayList<OfflineLink>();
5281         String javadocDirRelative = PathUtils.toRelative( project.getBasedir(), getOutputDirectory() );
5282         for ( MavenProject p : reactorProjects )
5283         {
5284             if ( !dependencyArtifactIds.contains( p.getArtifact().getId() ) || ( p.getUrl() == null ) )
5285             {
5286                 continue;
5287             }
5288 
5289             File location = new File( p.getBasedir(), javadocDirRelative );
5290 
5291             if ( !location.exists() )
5292             {
5293                 if ( getLog().isDebugEnabled() )
5294                 {
5295                     getLog().debug( "Javadoc directory not found: " + location );
5296                 }
5297 
5298                 String javadocGoal = getFullJavadocGoal();
5299                 getLog().info(
5300                     "The goal '" + javadocGoal + "' has not been previously called for the module: '" + p.getId()
5301                         + "'. Trying to invoke it..." );
5302 
5303                 File invokerDir = new File( project.getBuild().getDirectory(), "invoker" );
5304                 invokerDir.mkdirs();
5305                 File invokerLogFile = FileUtils.createTempFile( "maven-javadoc-plugin", ".txt", invokerDir );
5306                 try
5307                 {
5308                     JavadocUtil.invokeMaven( getLog(), new File( localRepository.getBasedir() ), p.getFile(),
5309                                              Collections.singletonList( javadocGoal ), null, invokerLogFile );
5310                 }
5311                 catch ( MavenInvocationException e )
5312                 {
5313                     logError( "MavenInvocationException: " + e.getMessage(), e );
5314 
5315                     String invokerLogContent = JavadocUtil.readFile( invokerLogFile, null /* platform encoding */ );
5316 
5317                     // TODO: Why are we only interested in cases where the JVM won't start?
5318                     // [MJAVADOC-275][jdcasey] I changed the logic here to only throw an error WHEN 
5319                     //   the JVM won't start (opposite of what it was).
5320                     if ( invokerLogContent != null && invokerLogContent.contains( JavadocUtil.ERROR_INIT_VM ) )
5321                     {
5322                         throw new MavenReportException( e.getMessage(), e );
5323                     }
5324                 }
5325                 finally
5326                 {
5327                     // just create the directory to prevent repeated invocations..
5328                     if ( !location.exists() )
5329                     {
5330                         getLog().warn( "Creating fake javadoc directory to prevent repeated invocations: " + location );
5331                         location.mkdirs();
5332                     }
5333                 }
5334             }
5335 
5336             if ( location.exists() )
5337             {
5338                 String url = getJavadocLink( p );
5339 
5340                 OfflineLink ol = new OfflineLink();
5341                 ol.setUrl( url );
5342                 ol.setLocation( location.getAbsolutePath() );
5343 
5344                 if ( getLog().isDebugEnabled() )
5345                 {
5346                     getLog().debug( "Added Javadoc offline link: " + url + " for the module: " + p.getId() );
5347                 }
5348 
5349                 modulesLinks.add( ol );
5350             }
5351         }
5352 
5353         return modulesLinks;
5354     }
5355 
5356     /**
5357      * Using Maven, a Javadoc link is given by <code>${project.url}/apidocs</code>.
5358      *
5359      * @return the detected Javadoc links using the Maven conventions for all dependencies defined in the current
5360      *         project or an empty list.
5361      * @see #detectLinks
5362      * @see #isValidJavadocLink(String)
5363      * @since 2.6
5364      */
5365     private List<String> getDependenciesLinks()
5366     {
5367         if ( !detectLinks )
5368         {
5369             return Collections.emptyList();
5370         }
5371 
5372         getLog().debug( "Trying to add links for dependencies..." );
5373 
5374         List<String> dependenciesLinks = new ArrayList<String>();
5375 
5376         final Set<Artifact> dependencies = project.getDependencyArtifacts();
5377         for ( Artifact artifact : dependencies )
5378         {
5379             if ( artifact.getFile() == null || !artifact.getFile().exists() )
5380             {
5381                 continue;
5382             }
5383 
5384             try
5385             {
5386                 MavenProject artifactProject =
5387                     mavenProjectBuilder.buildFromRepository( artifact, remoteRepositories, localRepository );
5388 
5389                 if ( StringUtils.isNotEmpty( artifactProject.getUrl() ) )
5390                 {
5391                     String url = getJavadocLink( artifactProject );
5392 
5393                     if ( isValidJavadocLink( url ) )
5394                     {
5395                         getLog().debug( "Added Javadoc link: " + url + " for " + artifactProject.getId() );
5396 
5397                         dependenciesLinks.add( url );
5398                     }
5399                 }
5400             }
5401             catch ( ProjectBuildingException e )
5402             {
5403                 logError( "ProjectBuildingException for " + artifact.toString() + ": " + e.getMessage(), e );
5404             }
5405         }
5406 
5407         return dependenciesLinks;
5408     }
5409 
5410     /**
5411      * @return if {@link #detectJavaApiLink}, the Java API link based on the {@link #javaApiLinks} properties and the
5412      *         value of the <code>source</code> parameter in the <code>org.apache.maven.plugins:maven-compiler-plugin</code>
5413      *         defined in <code>${project.build.plugins}</code> or in <code>${project.build.pluginManagement}</code>,
5414      *         or the {@link #fJavadocVersion}, or <code>null</code> if not defined.
5415      * @see #detectJavaApiLink
5416      * @see #javaApiLinks
5417      * @see #DEFAULT_JAVA_API_LINKS
5418      * @see <a href="http://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html#source">source parameter</a>
5419      * @since 2.6
5420      */
5421     private OfflineLink getDefaultJavadocApiLink()
5422     {
5423         if ( !detectJavaApiLink )
5424         {
5425             return null;
5426         }
5427 
5428         final String pluginId = "org.apache.maven.plugins:maven-compiler-plugin";
5429         float sourceVersion = fJavadocVersion;
5430         String sourceConfigured = getPluginParameter( project, pluginId, "source" );
5431         if ( sourceConfigured != null )
5432         {
5433             try
5434             {
5435                 sourceVersion = Float.parseFloat( sourceConfigured );
5436             }
5437             catch ( NumberFormatException e )
5438             {
5439                 getLog().debug(
5440                     "NumberFormatException for the source parameter in the maven-compiler-plugin. " + "Ignored it", e );
5441             }
5442         }
5443         else
5444         {
5445             getLog().debug( "No maven-compiler-plugin defined in ${build.plugins} or in "
5446                                 + "${project.build.pluginManagement} for the " + project.getId()
5447                                 + ". Added Javadoc API link according the javadoc executable version i.e.: "
5448                                 + fJavadocVersion );
5449         }
5450 
5451         String apiVersion = null;
5452         if ( sourceVersion >= 1.3f && sourceVersion < 1.4f )
5453         {
5454             apiVersion = "1.3";
5455         }
5456         else if ( sourceVersion >= 1.4f && sourceVersion < 1.5f )
5457         {
5458             apiVersion = "1.4";
5459         }
5460         else if ( sourceVersion >= 1.5f && sourceVersion < 1.6f )
5461         {
5462             apiVersion = "1.5";
5463         }
5464         else if ( sourceVersion >= 1.6f && sourceVersion < 1.7f )
5465         {
5466             apiVersion = "1.6";
5467         }
5468         else if ( sourceVersion >= 1.7f )
5469         {
5470             apiVersion = "1.7";
5471         }
5472         String javaApiLink = javaApiLinks.getProperty( "api_" + apiVersion, null );
5473 
5474         if ( getLog().isDebugEnabled() )
5475         {
5476             if ( StringUtils.isNotEmpty( javaApiLink ) )
5477             {
5478                 getLog().debug( "Found Java API link: " + javaApiLink );
5479             }
5480             else
5481             {
5482                 getLog().debug( "No Java API link found." );
5483             }
5484         }
5485 
5486         if ( javaApiLink == null )
5487         {
5488             return null;
5489         }
5490 
5491         File javaApiPackageListFile = new File( getJavadocOptionsFile().getParentFile(), "package-list" );
5492 
5493         OfflineLink link = new OfflineLink();
5494         link.setLocation( javaApiPackageListFile.getParentFile().getAbsolutePath() );
5495         link.setUrl( javaApiLink );
5496 
5497         InputStream in = this.getClass().getResourceAsStream( "java-api-package-list-" + apiVersion );
5498         OutputStream out = null;
5499         try
5500         {
5501             out = new FileOutputStream( javaApiPackageListFile );
5502             IOUtil.copy( in, out );
5503         }
5504         catch ( IOException ioe )
5505         {
5506             logError( "Can't get java-api-package-list-" + apiVersion + ": " + ioe.getMessage(), ioe );
5507             return null;
5508         }
5509         finally
5510         {
5511             IOUtil.close( in );
5512             IOUtil.close( out );
5513         }
5514 
5515         return link;
5516     }
5517 
5518     /**
5519      * @param link not null
5520      * @return <code>true</code> if the link has a <code>/package-list</code>, <code>false</code> otherwise.
5521      * @see <a href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/solaris/javadoc.html#package-list">
5522      *      package-list spec</a>
5523      * @since 2.6
5524      */
5525     private boolean isValidJavadocLink( String link )
5526     {
5527         try
5528         {
5529             URI linkUri;
5530             if ( link.trim().toLowerCase( Locale.ENGLISH ).startsWith( "http:" ) || link.trim().toLowerCase(
5531                 Locale.ENGLISH ).startsWith( "https:" ) || link.trim().toLowerCase( Locale.ENGLISH ).startsWith(
5532                 "ftp:" ) || link.trim().toLowerCase( Locale.ENGLISH ).startsWith( "file:" ) )
5533             {
5534                 linkUri = new URI( link + "/package-list" );
5535             }
5536             else
5537             {
5538                 // links can be relative paths or files
5539                 File dir = new File( link );
5540                 if ( !dir.isAbsolute() )
5541                 {
5542                     dir = new File( getOutputDirectory(), link );
5543                 }
5544                 if ( !dir.isDirectory() )
5545                 {
5546                     getLog().error( "The given File link: " + dir + " is not a dir." );
5547                 }
5548                 linkUri = new File( dir, "package-list" ).toURI();
5549             }
5550 
5551             if ( !JavadocUtil.isValidPackageList( linkUri.toURL(), settings, validateLinks ) )
5552             {
5553                 if ( getLog().isErrorEnabled() )
5554                 {
5555                     getLog().error( "Invalid link: " + link + "/package-list. Ignored it." );
5556                 }
5557 
5558                 return false;
5559             }
5560 
5561             return true;
5562         }
5563         catch ( URISyntaxException e )
5564         {
5565             if ( getLog().isErrorEnabled() )
5566             {
5567                 getLog().error( "Malformed link: " + link + "/package-list. Ignored it." );
5568             }
5569             return false;
5570         }
5571         catch ( IOException e )
5572         {
5573             if ( getLog().isErrorEnabled() )
5574             {
5575                 getLog().error( "Error fetching link: " + link + "/package-list. Ignored it." );
5576             }
5577             return false;
5578         }
5579     }
5580 
5581     /**
5582      * Write a debug javadoc script in case of command line error or in debug mode.
5583      *
5584      * @param cmdLine                the current command line as string, not null.
5585      * @param javadocOutputDirectory the output dir, not null.
5586      * @see #executeJavadocCommandLine(Commandline, File)
5587      * @since 2.6
5588      */
5589     private void writeDebugJavadocScript( String cmdLine, File javadocOutputDirectory )
5590     {
5591         File commandLineFile = new File( javadocOutputDirectory, DEBUG_JAVADOC_SCRIPT_NAME );
5592         commandLineFile.getParentFile().mkdirs();
5593 
5594         try
5595         {
5596             FileUtils.fileWrite( commandLineFile.getAbsolutePath(), null /* platform encoding */, cmdLine );
5597 
5598             if ( !SystemUtils.IS_OS_WINDOWS )
5599             {
5600                 Runtime.getRuntime().exec( new String[]{ "chmod", "a+x", commandLineFile.getAbsolutePath() } );
5601             }
5602         }
5603         catch ( IOException e )
5604         {
5605             logError( "Unable to write '" + commandLineFile.getName() + "' debug script file", e );
5606         }
5607     }
5608 
5609     /**
5610      * Check if the Javadoc JVM is correctly started or not.
5611      *
5612      * @param output the command line output, not null.
5613      * @return <code>true</code> if Javadoc output command line contains Javadoc word, <code>false</code> otherwise.
5614      * @see #executeJavadocCommandLine(Commandline, File)
5615      * @since 2.6.1
5616      */
5617     private boolean isJavadocVMInitError( String output )
5618     {
5619         /*
5620          * see main.usage and main.Building_tree keys from
5621          * com.sun.tools.javadoc.resources.javadoc bundle in tools.jar
5622          */
5623         return !( output.contains( "Javadoc" ) || output.contains( "javadoc" ) );
5624     }
5625 
5626     // ----------------------------------------------------------------------
5627     // Static methods
5628     // ----------------------------------------------------------------------
5629 
5630     /**
5631      * @param p not null
5632      * @return the javadoc link based on the project url i.e. <code>${project.url}/${destDir}</code> where
5633      *         <code>destDir</code> is configued in the Javadoc plugin configuration (<code>apidocs</code> by default).
5634      * @since 2.6
5635      */
5636     private static String getJavadocLink( MavenProject p )
5637     {
5638         if ( p.getUrl() == null )
5639         {
5640             return null;
5641         }
5642 
5643         String url = cleanUrl( p.getUrl() );
5644         String destDir = "apidocs"; // see JavadocReport#destDir
5645 
5646         final String pluginId = "org.apache.maven.plugins:maven-javadoc-plugin";
5647         String destDirConfigured = getPluginParameter( p, pluginId, "destDir" );
5648         if ( destDirConfigured != null )
5649         {
5650             destDir = destDirConfigured;
5651         }
5652 
5653         return url + "/" + destDir;
5654     }
5655 
5656     /**
5657      * @param url could be null.
5658      * @return the url cleaned or empty if url was null.
5659      * @since 2.6
5660      */
5661     private static String cleanUrl( String url )
5662     {
5663         if ( url == null )
5664         {
5665             return "";
5666         }
5667 
5668         url = url.trim();
5669         while ( url.endsWith( "/" ) )
5670         {
5671             url = url.substring( 0, url.lastIndexOf( "/" ) );
5672         }
5673 
5674         return url;
5675     }
5676 
5677     /**
5678      * @param p        not null
5679      * @param pluginId not null key of the plugin defined in {@link org.apache.maven.model.Build#getPluginsAsMap()}
5680      *                 or in {@link org.apache.maven.model.PluginManagement#getPluginsAsMap()}
5681      * @return the Maven plugin defined in <code>${project.build.plugins}</code> or in
5682      *         <code>${project.build.pluginManagement}</code>, or <code>null</code> if not defined.
5683      * @since 2.6
5684      */
5685     private static Plugin getPlugin( MavenProject p, String pluginId )
5686     {
5687         if ( ( p.getBuild() == null ) || ( p.getBuild().getPluginsAsMap() == null ) )
5688         {
5689             return null;
5690         }
5691 
5692         Plugin plugin = (Plugin) p.getBuild().getPluginsAsMap().get( pluginId );
5693 
5694         if ( ( plugin == null ) && ( p.getBuild().getPluginManagement() != null ) && (
5695             p.getBuild().getPluginManagement().getPluginsAsMap() != null ) )
5696         {
5697             plugin = (Plugin) p.getBuild().getPluginManagement().getPluginsAsMap().get( pluginId );
5698         }
5699 
5700         return plugin;
5701     }
5702 
5703     /**
5704      * @param p        not null
5705      * @param pluginId not null
5706      * @param param    not null
5707      * @return the simple parameter as String defined in the plugin configuration by <code>param</code> key
5708      *         or <code>null</code> if not found.
5709      * @since 2.6
5710      */
5711     private static String getPluginParameter( MavenProject p, String pluginId, String param )
5712     {
5713 //        p.getGoalConfiguration( pluginGroupId, pluginArtifactId, executionId, goalId );
5714         Plugin plugin = getPlugin( p, pluginId );
5715         if ( plugin != null )
5716         {
5717             Xpp3Dom xpp3Dom = (Xpp3Dom) plugin.getConfiguration();
5718             if ( xpp3Dom != null && xpp3Dom.getChild( param ) != null
5719                 && StringUtils.isNotEmpty( xpp3Dom.getChild( param ).getValue() ) )
5720             {
5721                 return xpp3Dom.getChild( param ).getValue();
5722             }
5723         }
5724 
5725         return null;
5726     }
5727 
5728     /**
5729      * Construct the output file for the generated javadoc-options XML file, after creating the
5730      * javadocOptionsDir if necessary. This method does NOT write to the file in question.
5731      *
5732      * @since 2.7
5733      */
5734     protected final File getJavadocOptionsFile()
5735     {
5736         if ( javadocOptionsDir != null && !javadocOptionsDir.exists() )
5737         {
5738             javadocOptionsDir.mkdirs();
5739         }
5740 
5741         return new File( javadocOptionsDir, "javadoc-options-" + getAttachmentClassifier() + ".xml" );
5742     }
5743 
5744     /**
5745      * Generate a javadoc-options XML file, for either bundling with a javadoc-resources artifact OR
5746      * supplying to a distro module in a includeDependencySources configuration, so the javadoc options
5747      * from this execution can be reconstructed and merged in the distro build.
5748      *
5749      * @since 2.7
5750      */
5751     protected final JavadocOptions buildJavadocOptions()
5752         throws IOException
5753     {
5754         JavadocOptions options = new JavadocOptions();
5755 
5756         options.setBootclasspathArtifacts( toList( bootclasspathArtifacts ) );
5757         options.setDocfilesSubdirsUsed( docfilessubdirs );
5758         options.setDocletArtifacts( toList( docletArtifact, docletArtifacts ) );
5759         options.setExcludedDocfilesSubdirs( excludedocfilessubdir );
5760         options.setExcludePackageNames( toList( excludePackageNames ) );
5761         options.setGroups( toList( groups ) );
5762         options.setLinks( links );
5763         options.setOfflineLinks( toList( offlineLinks ) );
5764         options.setResourcesArtifacts( toList( resourcesArtifacts ) );
5765         options.setTagletArtifacts( toList( tagletArtifact, tagletArtifacts ) );
5766         options.setTaglets( toList( taglets ) );
5767         options.setTags( toList( tags ) );
5768 
5769         if ( getProject() != null && getJavadocDirectory() != null )
5770         {
5771             options.setJavadocResourcesDirectory(
5772                 toRelative( getProject().getBasedir(), getJavadocDirectory().getAbsolutePath() ) );
5773         }
5774 
5775         File optionsFile = getJavadocOptionsFile();
5776         Writer writer = null;
5777         try
5778         {
5779             writer = WriterFactory.newXmlWriter( optionsFile );
5780             new JavadocOptionsXpp3Writer().write( writer, options );
5781         }
5782         finally
5783         {
5784             close( writer );
5785         }
5786 
5787         return options;
5788     }
5789 
5790     /**
5791      * Override this if you need to provide a bundle attachment classifier, as in the case of test
5792      * javadocs.
5793      */
5794     protected String getAttachmentClassifier()
5795     {
5796         return JAVADOC_RESOURCES_ATTACHMENT_CLASSIFIER;
5797     }
5798 
5799     /**
5800      * Logs an error with throwable content only if in debug.
5801      *
5802      * @param message
5803      * @param t
5804      */
5805     protected void logError( String message, Throwable t )
5806     {
5807         if ( getLog().isDebugEnabled() )
5808         {
5809             getLog().error( message, t );
5810         }
5811         else
5812         {
5813             getLog().error( message );
5814         }
5815     }
5816 
5817     protected void failOnError( String prefix, Exception e )
5818         throws MojoExecutionException
5819     {
5820         if ( failOnError )
5821         {
5822             if ( e instanceof RuntimeException )
5823             {
5824                 throw (RuntimeException) e;
5825             }
5826             throw new MojoExecutionException( prefix + ": " + e.getMessage(), e );
5827         }
5828 
5829         getLog().error( prefix + ": " + e.getMessage(), e );
5830     }
5831 }