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