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