View Javadoc

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