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