View Javadoc

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