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