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