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