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