You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by vs...@apache.org on 2009/07/20 14:37:16 UTC

svn commit: r795801 - in /maven/plugins/trunk/maven-javadoc-plugin/src: it/MJAVADOC-97/ main/java/org/apache/maven/plugin/javadoc/ site/ site/apt/examples/ site/fml/

Author: vsiveton
Date: Mon Jul 20 12:37:16 2009
New Revision: 795801

URL: http://svn.apache.org/viewvc?rev=795801&view=rev
Log:
MJAVADOC-97: enable internal/external dependency references as links 

o try to detect dependencies Javadoc links
o added new parameters detectLinks and detectOfflineLinks
o updated test case
o improved JavadocJar.javao added documentation

Added:
    maven/plugins/trunk/maven-javadoc-plugin/src/site/apt/examples/links-configuration.apt   (with props)
Modified:
    maven/plugins/trunk/maven-javadoc-plugin/src/it/MJAVADOC-97/pom.xml
    maven/plugins/trunk/maven-javadoc-plugin/src/it/MJAVADOC-97/verify.bsh
    maven/plugins/trunk/maven-javadoc-plugin/src/main/java/org/apache/maven/plugin/javadoc/AbstractJavadocMojo.java
    maven/plugins/trunk/maven-javadoc-plugin/src/site/fml/faq.fml
    maven/plugins/trunk/maven-javadoc-plugin/src/site/site.xml

Modified: maven/plugins/trunk/maven-javadoc-plugin/src/it/MJAVADOC-97/pom.xml
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-javadoc-plugin/src/it/MJAVADOC-97/pom.xml?rev=795801&r1=795800&r2=795801&view=diff
==============================================================================
--- maven/plugins/trunk/maven-javadoc-plugin/src/it/MJAVADOC-97/pom.xml (original)
+++ maven/plugins/trunk/maven-javadoc-plugin/src/it/MJAVADOC-97/pom.xml Mon Jul 20 12:37:16 2009
@@ -31,7 +31,27 @@
     <module>module1</module>
     <module>module2</module>
   </modules>
-  
+
+  <dependencies>
+    <!-- known apidocs link -->
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+      <version>2.4</version>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.8.1</version>
+    </dependency>
+    <!-- unknown apidocs link -->
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-core</artifactId>
+      <version>2.2.0</version>
+    </dependency>
+  </dependencies>
+
   <build>
     <pluginManagement>
       <plugins>
@@ -47,6 +67,7 @@
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-javadoc-plugin</artifactId>
         <configuration>
+          <detectLinks>true</detectLinks>
           <debug>true</debug>
           <failOnError>true</failOnError>
         </configuration>

Modified: maven/plugins/trunk/maven-javadoc-plugin/src/it/MJAVADOC-97/verify.bsh
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-javadoc-plugin/src/it/MJAVADOC-97/verify.bsh?rev=795801&r1=795800&r2=795801&view=diff
==============================================================================
--- maven/plugins/trunk/maven-javadoc-plugin/src/it/MJAVADOC-97/verify.bsh (original)
+++ maven/plugins/trunk/maven-javadoc-plugin/src/it/MJAVADOC-97/verify.bsh Mon Jul 20 12:37:16 2009
@@ -24,6 +24,7 @@
 
 try
 {
+    // Generated files checks
     File apidocs1 = new File( basedir, "module1/target/site/apidocs" );
     if ( !apidocs1.exists() || !apidocs1.isDirectory() )
     {
@@ -50,6 +51,7 @@
         return false;
     }
 
+    // Read files
     String strTmp = "";
     String contentOptions1 = "";
     BufferedReader in = new BufferedReader( new FileReader( options1 ) );
@@ -78,6 +80,7 @@
         in.close();
     }
 
+    // Generated files content checks
     if ( contentOptions1.indexOf( "-linkoffline" ) == -1 )
     {
         System.err.println( "-linkoffline not added." );
@@ -88,6 +91,26 @@
         System.err.println( apidocs2.getAbsolutePath().replaceAll( "\\\\", "/" ) + " not added." );
         return false;
     }
+    if ( contentOptions1.indexOf( "-link" ) == -1 )
+    {
+        System.err.println( "-link not added." );
+        return false;
+    }
+    if ( contentOptions1.indexOf( "http://commons.apache.org/lang/apidocs" ) == -1 )
+    {
+        System.err.println( "link for commons-lang not added." );
+        return false;
+    }
+    if ( contentOptions1.indexOf( "http://junit.org/apidocs" ) == -1 )
+    {
+        System.err.println( "link for junit not added." );
+        return false;
+    }
+    if ( contentOptions1.indexOf( "http://maven.apache.org/maven-core/apidocs" ) != -1 )
+    {
+        System.err.println( "link for maven-core added." );
+        return false;
+    }
 
     if ( contentOptions2.indexOf( "-linkoffline" ) == -1 )
     {
@@ -99,6 +122,21 @@
         System.err.println( apidocs1.getAbsolutePath().replaceAll( "\\\\", "/" ) + " not added." );
         return false;
     }
+    if ( contentOptions2.indexOf( "-link" ) == -1 )
+    {
+        System.err.println( "-link not added." );
+        return false;
+    }
+    if ( contentOptions2.indexOf( "http://junit.org/apidocs" ) == -1 )
+    {
+        System.err.println( "link for junit not added." );
+        return false;
+    }
+    if ( contentOptions2.indexOf( "http://maven.apache.org/maven-core/apidocs" ) != -1 )
+    {
+        System.err.println( "link for maven-core added." );
+        return false;
+    }
 }
 catch( RuntimeException e )
 {

Modified: maven/plugins/trunk/maven-javadoc-plugin/src/main/java/org/apache/maven/plugin/javadoc/AbstractJavadocMojo.java
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-javadoc-plugin/src/main/java/org/apache/maven/plugin/javadoc/AbstractJavadocMojo.java?rev=795801&r1=795800&r2=795801&view=diff
==============================================================================
--- maven/plugins/trunk/maven-javadoc-plugin/src/main/java/org/apache/maven/plugin/javadoc/AbstractJavadocMojo.java (original)
+++ maven/plugins/trunk/maven-javadoc-plugin/src/main/java/org/apache/maven/plugin/javadoc/AbstractJavadocMojo.java Mon Jul 20 12:37:16 2009
@@ -103,6 +103,7 @@
  * @version $Id$
  * @since 2.0
  * @requiresDependencyResolution compile
+ * @see <a href="http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/javadoc.html">The Java API Documentation Generator, 1.4.2</a>
  */
 public abstract class AbstractJavadocMojo
     extends AbstractMojo
@@ -412,6 +413,44 @@
      */
     protected boolean useStandardDocletOptions;
 
+    /**
+     * Detect the Javadoc links for all dependencies defined in the project. The detection is based on the Maven
+     * conventions, i.e.: <code>${project.url}/apidocs</code>.
+     * <br/>
+     * For instance, if the project has a dependency to
+     * <a href="http://commons.apache.org/lang/">Apache Commons Lang</a> i.e.:
+     * <pre>
+     * &lt;dependency&gt;
+     *   &lt;groupId&gt;commons-lang&lt;/groupId&gt;
+     *   &lt;artifactId&gt;commons-lang&lt;/artifactId&gt;
+     * &lt;/dependency&gt;
+     * </pre>
+     * The added Javadoc link will be <code>http://commons.apache.org/lang/apidocs</code>.
+     *
+     * @parameter expression="${detectLinks}" default-value="false"
+     * @see #links
+     * @since 2.6
+     */
+    private boolean detectLinks;
+
+    /**
+     * Detect the links for all modules defined in the project.
+     * <br/>
+     * If {@link #reactorProjects} is defined in a non-aggregator way, it generates default offline links
+     * between modules based on the defined project's urls. For instance, if a parent project has two projects
+     * <code>module1</code> and <code>module2</code>, the <code>-linkoffline</code> will be:
+     * <br/>
+     * The offlineLinks for <b>module1</b> will be
+     * <code>/absolute/path/to/</code><b>module2</b><code>/target/site/apidocs</code>
+     * <br/>
+     * The offlineLinks for <b>module2</b> will be <code>/absolute/path/to/</code><b>module1</b><code>/target/site/apidocs</code>
+     *
+     * @parameter expression="${detectOfflineLinks}" default-value="true"
+     * @see #offlineLinks
+     * @since 2.6
+     */
+    private boolean detectOfflineLinks;
+
     // ----------------------------------------------------------------------
     // Javadoc Options - all alphabetical
     // ----------------------------------------------------------------------
@@ -473,7 +512,8 @@
     private String doclet;
 
     /**
-     * Specifies the artifact containing the doclet starting class file (specified with the -doclet option).
+     * Specifies the artifact containing the doclet starting class file (specified with the <code>-doclet</code>
+     * option).
      * <br/>
      * See <a href="http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/javadoc.html#docletpath">docletpath</a>.
      * <br/>
@@ -495,7 +535,7 @@
 
     /**
      * Specifies multiple artifacts containing the path for the doclet starting class file (specified with the
-     *  -doclet option).
+     * <code>-doclet</code> option).
      * <br/>
      * See <a href="http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/javadoc.html#docletpath">docletpath</a>.
      * <br/>
@@ -519,9 +559,9 @@
     private DocletArtifact[] docletArtifacts;
 
     /**
-     * Specifies the path to the doclet starting class file (specified with the -doclet option) and any jar files
-     * it depends on. The docletPath can contain multiple paths by separating them with a colon (<code>:</code>)
-     * on Solaris and a semi-colon (<code>;</code>) on Windows.
+     * Specifies the path to the doclet starting class file (specified with the <code>-doclet</code> option) and
+     * any jar files it depends on. The docletPath can contain multiple paths by separating them with a colon
+     * (<code>:</code>) on Solaris and a semi-colon (<code>;</code>) on Windows.
      * <br/>
      * See <a href="http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/javadoc.html#docletpath">docletpath</a>.
      *
@@ -544,8 +584,8 @@
     private String encoding;
 
     /**
-     * Unconditionally excludes the specified packages and their subpackages from the list formed by -subpackages.
-     * Multiple packages can be separated by colons (<code>:</code>).
+     * Unconditionally excludes the specified packages and their subpackages from the list formed by
+     * <code>-subpackages</code>. Multiple packages can be separated by colons (<code>:</code>).
      * <br/>
      * See <a href="http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/javadoc.html#exclude">exclude</a>.
      * <br/>
@@ -918,6 +958,19 @@
     /**
      * Creates links to existing javadoc-generated documentation of external referenced classes.
      * <br/>
+     * <b>Note 1</b>: only used is {@link #isOffline} is set to <code>false</code>.
+     * <br/>
+     * <b>Note 2</b>: all given links should have a fetchable <code>/package-list</code> file. For instance:
+     * <pre>
+     * &lt;links&gt;
+     *   &lt;link&gt;http://java.sun.com/j2se/1.4.2/docs/api&lt;/link&gt;
+     * &lt;links&gt;
+     * </pre>
+     * will be used because <code>http://java.sun.com/j2se/1.4.2/docs/api/package-list</code> exists.
+     * <br/>
+     * <b>Note</b>: if {@link #detectLinks} is defined, the links between the project dependencies are
+     * automatically added.
+     * <br/>
      * See <a href="http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/javadoc.html#link">link</a>.
      *
      * @parameter expression="${links}"
@@ -1064,8 +1117,8 @@
     private boolean notree;
 
     /**
-     * This option is a variation of -link; they both create links to javadoc-generated documentation for external
-     * referenced classes.
+     * This option is a variation of <code>-link</code>; they both create links to javadoc-generated documentation
+     * for external referenced classes.
      * <br/>
      * See <a href="http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/javadoc.html#linkoffline">linkoffline</a>.
      * <br/>
@@ -1079,50 +1132,8 @@
      * &lt;/offlineLinks&gt;
      * </pre>
      * <br/>
-     * <b>Note</b>: By default, if {@link #reactorProjects} is defined in a non-aggregator way, it generates default offline links
-     * between modules based on the defined project's urls. For instance, if a parent project has two projects
-     * <code>module1</code> and <code>module2</code>, the <code>-linkoffline</code> will be:
-     * <br/>
-     * <table>
-     * <tr>
-     *   <th>Module project</th>
-     *   <th>Option for '-linkoffline'</th>
-     * </tr>
-     * <tr>
-     *   <td>
-     *     <pre>
-     * &lt;project&gt;
-     *   &lt;artifactId&gt;<b>module1</b>&lt;/artifactId&gt;
-     *   &lt;url&gt;http://myhost/<b>module1</b>&lt;/url&gt;
-     *   ...
-     * &lt;/project&gt;
-     *     </pre>
-     *   </td>
-     *   <td>
-     *     <pre>
-     * -linkoffline
-     * 'http://myhost/<b>module2</b>/apidocs' '/absolute/path/to/<b>module2</b>/target/site/apidocs'
-     *     </pre>
-     *   </td>
-     * </tr>
-     * <tr>
-     *   <td>
-     *     <pre>
-     * &lt;project&gt;
-     *   &lt;artifactId&gt;<b>module2</b>&lt;/artifactId&gt;
-     *   &lt;url&gt;http://myhost/<b>module2</b>&lt;/url&gt;
-     *   ...
-     * &lt;/project&gt;
-     *     </pre>
-     *   </td>
-     *   <td>
-     *     <pre>
-     * -linkoffline
-     * 'http://myhost/<b>module1</b>/apidocs' '/absolute/path/to/<b>module1</b>/target/site/apidocs'
-     *     </pre>
-     *   </td>
-     * </tr>
-     * </table>
+     * <b>Note</b>: if {@link #detectOfflineLinks} is defined, the offline links between the project modules are
+     * automatically added if the goal is calling in a non-aggregator way.
      * <br/>
      * See <a href="./apidocs/org/apache/maven/plugin/javadoc/options/OfflineLink.html">Javadoc</a>.
      * <br/>
@@ -1942,7 +1953,8 @@
     }
 
     /**
-     * Method that sets the classpath elements that will be specified in the javadoc -classpath parameter.
+     * Method that sets the classpath elements that will be specified in the javadoc <code>-classpath</code>
+     * parameter.
      *
      * @return a String that contains the concatenated classpath elements
      * @throws MavenReportException if any
@@ -2264,7 +2276,7 @@
     }
 
     /**
-     * Method to get the path of the bootclass artifacts used in the -bootclasspath option.
+     * Method to get the path of the bootclass artifacts used in the <code>-bootclasspath</code> option.
      *
      * @return the path to jar file that contains taglet class file separated with a colon (<code>:</code>)
      * on Solaris and a semi-colon (<code>;</code>) on Windows
@@ -2304,7 +2316,7 @@
     }
 
     /**
-     * Method to get the path of the doclet artifacts used in the -docletpath option.
+     * Method to get the path of the doclet artifacts used in the <code>-docletpath</code> option.
      *
      * Either docletArtifact or doclectArtifacts can be defined and used, not both, docletArtifact
      * takes precedence over doclectArtifacts. docletPath is always appended to any result path
@@ -2375,7 +2387,7 @@
     }
 
     /**
-     * Method to get the path of the taglet artifacts used in the -tagletpath option.
+     * Method to get the path of the taglet artifacts used in the <code>-tagletpath</code> option.
      *
      * @return the path to jar file that contains taglet class file separated with a colon (<code>:</code>)
      * on Solaris and a semi-colon (<code>;</code>) on Windows
@@ -3044,156 +3056,94 @@
     /**
      * Convenience method to process {@link #offlineLinks} values as individual <code>-linkoffline</code>
      * javadoc options.
+     * <br/>
+     * If {@link #detectOfflineLinks}, try to add javadoc apidocs according Maven conventions for all modules given
+     * in the project.
      *
      * @param arguments a list of arguments, not null
      * @see #offlineLinks
+     * @see #getModulesLinks()
+     * @see <a href="http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/javadoc.html#package-list">package-list spec</a>
      */
     private void addLinkofflineArguments( List arguments )
     {
         List offlineLinksList =
             ( offlineLinks != null ? new ArrayList( Arrays.asList( offlineLinks ) ) : new ArrayList() );
 
-        if ( !isAggregator() && reactorProjects != null )
-        {
-            String javadocDirRelative = PathUtils.toRelative( project.getBasedir(), getOutputDirectory() );
+        offlineLinksList.addAll( getModulesLinks() );
 
-            int i = 0;
-            for ( Iterator it = reactorProjects.iterator(); it.hasNext(); )
+        if ( offlineLinksList != null )
+        {
+            for ( int i = 0; i < offlineLinksList.size(); i++ )
             {
-                MavenProject p = (MavenProject) it.next();
+                OfflineLink offlineLink = (OfflineLink) offlineLinksList.get( i );
 
-                if ( p.getPackaging().equals( "pom" ) )
+                String url = offlineLink.getUrl();
+                if ( StringUtils.isEmpty( url ) )
                 {
                     continue;
                 }
+                url = cleanUrl( url );
 
-                if ( p.getId().equals( project.getId() ) )
+                String location = offlineLink.getLocation();
+                if ( StringUtils.isEmpty( location ) )
                 {
                     continue;
                 }
-
-                File location = new File( p.getBasedir(), javadocDirRelative );
-                if ( p.getUrl() != null )
+                if ( isValidJavadocLink( location ) )
                 {
-                    if ( !location.exists() )
-                    {
-                        String javadocGoal = getFullJavadocGoal();
-                        getLog().info(
-                                       "The goal '" + javadocGoal
-                                           + "' has not be previously called for the project: '" + p.getId()
-                                           + "'. Trying to invoke it..." );
-
-                        File invokerLogFile =
-                            new File( project.getBuild().getDirectory(), "invoker-maven-javadoc-plugin-" + i
-                                + ".txt" );
-                        JavadocUtil.invokeMaven( getLog(), p.getFile(), Collections.singletonList( javadocGoal ),
-                                                 null, invokerLogFile );
-                    }
-
-                    if ( location.exists() )
-                    {
-                        String destDir = "apidocs"; // see JavadocReport#destDir
-
-                        Plugin javadocPlugin =
-                            (Plugin) project.getBuild().getPluginsAsMap()
-                                            .get( "org.apache.maven.plugins:maven-javadoc-plugin" );
-                        if ( javadocPlugin != null )
-                        {
-                            Xpp3Dom xpp3Dom = (Xpp3Dom) javadocPlugin.getConfiguration();
-                            if ( xpp3Dom != null && xpp3Dom.getChild( "destDir" ) != null
-                                && StringUtils.isNotEmpty( xpp3Dom.getChild( "destDir" ).getValue() ) )
-                            {
-                                destDir = xpp3Dom.getChild( "destDir" ).getValue();
-                            }
-                        }
-
-                        String url = p.getUrl() + "/" + destDir;
-
-                        OfflineLink ol = new OfflineLink();
-                        ol.setUrl( url );
-                        ol.setLocation( location.getAbsolutePath() );
-
-                        offlineLinksList.add( ol );
-                    }
+                    addArgIfNotEmpty( arguments, "-linkoffline", JavadocUtil.quotedPathArgument( url )
+                                      + " " + JavadocUtil.quotedPathArgument( location ), true );
                 }
-
-                i++;
-            }
-        }
-
-        if ( offlineLinksList != null )
-        {
-            for ( int i = 0; i < offlineLinksList.size(); i++ )
-            {
-                OfflineLink offlineLink = (OfflineLink) offlineLinksList.get( i );
-                addArgIfNotEmpty( arguments, "-linkoffline", JavadocUtil.quotedPathArgument( offlineLink.getUrl() )
-                    + " " + JavadocUtil.quotedPathArgument( offlineLink.getLocation() ), true );
             }
         }
     }
 
     /**
-     * Convenience method to process link values as individual -link javadoc options.
-     * If a <code>package-list</code> in a configured link is not available, remove the link.
+     * Convenience method to process {@link #links} values as individual <code>-link</code> javadoc options.
+     * If {@link #detectLinks}, try to add javadoc apidocs according Maven conventions for all dependencies given
+     * in the project.
+     * <br/>
+     * According the Javadoc documentation, all defined link should have <code>${link}/package-list</code> fetchable.
      * <br/>
-     * <b>Note</b>: if a link is not fetchable:
+     * <b>Note</b>: when a link is not fetchable:
      * <ul>
      * <li>Javadoc 1.4 and less throw an exception</li>
      * <li>Javadoc 1.5 and more display a warning</li>
      * </ul>
      *
      * @param arguments a list of arguments, not null
+     * @see #detectLinks
+     * @see #getDependenciesLinks()
+     * @see JavadocUtil#fetchURL(Settings, URL)
+     * @see <a href="http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/javadoc.html#package-list">package-list spec</a>
      */
     private void addLinkArguments( List arguments )
     {
-        if ( links != null )
+        if ( links == null )
         {
-            for ( int i = 0; i < links.size(); i++ )
-            {
-                String link = (String) links.get( i );
+            links = new ArrayList();
+        }
 
-                if ( StringUtils.isEmpty( link ) )
-                {
-                    continue;
-                }
+        links.addAll( getDependenciesLinks() );
 
-                if ( link.endsWith( "/" ) )
-                {
-                    link = link.substring( 0, link.length() - 1 );
-                }
+        for ( int i = 0; i < links.size(); i++ )
+        {
+            String link = (String) links.get( i );
 
-                try
-                {
-                    URI linkUri;
-                    if ( link.trim().toLowerCase( Locale.ENGLISH ).startsWith( "http" )
-                        || link.trim().toLowerCase( Locale.ENGLISH ).startsWith( "https" )
-                        || link.trim().toLowerCase( Locale.ENGLISH ).startsWith( "ftp" )
-                        || link.trim().toLowerCase( Locale.ENGLISH ).startsWith( "file" ) )
-                    {
-                        linkUri = new URI( link + "/package-list" );
-                    }
-                    else
-                    {
-                        // links can be relative paths or files
-                        linkUri = new File( getOutputDirectory(), link + "/package-list" ).toURI();
-                    }
-                    JavadocUtil.fetchURL( settings, linkUri.toURL() );
-                    addArgIfNotEmpty( arguments, "-link", JavadocUtil.quotedPathArgument( link ), true );
-                }
-                catch ( URISyntaxException e )
-                {
-                    if ( getLog().isErrorEnabled() )
-                    {
-                        getLog().error( "Malformed link: " + link + "/package-list. Ignored it." );
-                    }
-                }
-                catch ( IOException e )
-                {
-                    if ( getLog().isErrorEnabled() )
-                    {
-                        getLog().error( "Error fetching link: " + link + "/package-list. Ignored it." );
-                    }
-                }
+            if ( StringUtils.isEmpty( link ) )
+            {
+                continue;
+            }
+
+            while ( link.endsWith( "/" ) )
+            {
+                link = link.substring( 0, link.lastIndexOf( "/" ) );
+            }
+
+            if ( isValidJavadocLink( link ) )
+            {
+                addArgIfNotEmpty( arguments, "-link", JavadocUtil.quotedPathArgument( link ), true );
             }
         }
     }
@@ -4315,7 +4265,7 @@
     }
 
     /**
-     * @param classPath a not null class path list where resource will be look up.
+     * @param classPath a not null String list of files where resource will be look up.
      * @param resource a not null ressource to find in the class path.
      * @return the resource from the given classpath or null if not found
      * @see ClassLoader#getResource(String)
@@ -4397,4 +4347,243 @@
 
         return sb.toString();
     }
+
+    /**
+     * Using Maven, a Javadoc link is given by <code>${project.url}/apidocs</code>.
+     *
+     * @return the detected Javadoc links using the Maven conventions for all modules defined in the current project
+     * or an empty list.
+     * @see #detectOfflineLinks
+     * @see #reactorProjects
+     * @since 2.6
+     */
+    private List getModulesLinks()
+    {
+        if ( !( detectOfflineLinks && !isAggregator() && reactorProjects != null ) )
+        {
+            return Collections.EMPTY_LIST;
+        }
+
+        getLog().debug( "Try to add links for modules..." );
+
+        List modulesLinks = new ArrayList();
+        String javadocDirRelative = PathUtils.toRelative( project.getBasedir(), getOutputDirectory() );
+        int i = 0;
+        for ( Iterator it = reactorProjects.iterator(); it.hasNext(); )
+        {
+            MavenProject p = (MavenProject) it.next();
+
+            if ( p.getPackaging().equals( "pom" ) )
+            {
+                continue;
+            }
+
+            if ( p.getId().equals( project.getId() ) )
+            {
+                continue;
+            }
+
+            File location = new File( p.getBasedir(), javadocDirRelative );
+            if ( p.getUrl() != null )
+            {
+                if ( !location.exists() )
+                {
+                    String javadocGoal = getFullJavadocGoal();
+                    getLog().info(
+                                   "The goal '" + javadocGoal
+                                       + "' has not be previously called for the project: '" + p.getId()
+                                       + "'. Trying to invoke it..." );
+
+                    File invokerLogFile =
+                        new File( project.getBuild().getDirectory(), "invoker-maven-javadoc-plugin-" + i + ".txt" );
+                    JavadocUtil.invokeMaven( getLog(), p.getFile(), Collections.singletonList( javadocGoal ),
+                                             null, invokerLogFile );
+                }
+
+                if ( location.exists() )
+                {
+                    String url = getJavadocLink( p );
+
+                    OfflineLink ol = new OfflineLink();
+                    ol.setUrl( url );
+                    ol.setLocation( location.getAbsolutePath() );
+
+                    getLog().debug( "Added Javadoc link: " + url + " for the project: " + p.getId() );
+
+                    modulesLinks.add( ol );
+                }
+            }
+
+            i++;
+        }
+
+        return modulesLinks;
+    }
+
+    /**
+     * Using Maven, a Javadoc link is given by <code>${project.url}/apidocs</code>.
+     *
+     * @return the detected Javadoc links using the Maven conventions for all dependencies defined in the current project
+     * or an empty list.
+     * @see #detectLinks
+     * @since 2.6
+     */
+    private List getDependenciesLinks()
+    {
+        if ( !detectLinks )
+        {
+            return Collections.EMPTY_LIST;
+        }
+
+        getLog().debug( "Try to add links for dependencies..." );
+
+        List dependenciesLinks = new ArrayList();
+        for ( Iterator it = project.getDependencyArtifacts().iterator(); it.hasNext(); )
+        {
+            Artifact artifact = (Artifact) it.next();
+
+            if ( artifact != null && artifact.getFile().exists() )
+            {
+                try
+                {
+                    MavenProject artifactProject =
+                        mavenProjectBuilder.buildFromRepository( artifact, remoteRepositories, localRepository );
+
+                    if ( StringUtils.isNotEmpty( artifactProject.getUrl() ) )
+                    {
+                        String url = getJavadocLink( artifactProject );
+
+                        getLog().debug(
+                                        "Added Javadoc link: " + url + " for the project: "
+                                            + artifactProject.getId() );
+                        dependenciesLinks.add( url );
+                    }
+                }
+                catch ( ProjectBuildingException e )
+                {
+                    getLog().debug(
+                                    "Error when building the artifact: " + artifact.toString()
+                                        + ". Ignored to add Javadoc link." );
+                    if ( getLog().isDebugEnabled() )
+                    {
+                        getLog().debug( "ProjectBuildingException: " + e.getMessage(), e );
+                    }
+                    else
+                    {
+                        getLog().debug( "ProjectBuildingException: " + e.getMessage() );
+                    }
+                }
+            }
+        }
+
+        return dependenciesLinks;
+    }
+
+    /**
+     * @param link not null
+     * @return <code>true</code> if the link has a <code>/package-list</code>, <code>false</code> otherwise.
+     * @since 2.6
+     * @see <a href="http://java.sun.com/j2se/1.4.2/docs/tooldocs/solaris/javadoc.html#package-list">
+     * package-list spec</a>
+     */
+    private boolean isValidJavadocLink( String link )
+    {
+        try
+        {
+            URI linkUri;
+            if ( link.trim().toLowerCase( Locale.ENGLISH ).startsWith( "http" )
+                || link.trim().toLowerCase( Locale.ENGLISH ).startsWith( "https" )
+                || link.trim().toLowerCase( Locale.ENGLISH ).startsWith( "ftp" )
+                || link.trim().toLowerCase( Locale.ENGLISH ).startsWith( "file" ) )
+            {
+                linkUri = new URI( link + "/package-list" );
+            }
+            else
+            {
+                // links can be relative paths or files
+                File dir = new File( link );
+                if ( !dir.isAbsolute() )
+                {
+                    dir = new File( getOutputDirectory(), link );
+                }
+                if ( !dir.isDirectory() )
+                {
+                    getLog().error( "The given File link: " + dir + " is not a dir." );
+                }
+                linkUri = new File( dir, "package-list" ).toURI();
+            }
+
+            JavadocUtil.fetchURL( settings, linkUri.toURL() );
+
+            return true;
+        }
+        catch ( URISyntaxException e )
+        {
+            if ( getLog().isErrorEnabled() )
+            {
+                getLog().error( "Malformed link: " + link + "/package-list. Ignored it." );
+            }
+            return false;
+        }
+        catch ( IOException e )
+        {
+            if ( getLog().isErrorEnabled() )
+            {
+                getLog().error( "Error fetching link: " + link + "/package-list. Ignored it." );
+            }
+            return false;
+        }
+    }
+
+    /**
+     * @param p not null
+     * @return the javadoc link based on the project url i.e. <code>${project.url}/${destDir}</code> where
+     * <code>destDir</code> is configued in the Javadoc plugin configuration (<code>apidocs</code> by default).
+     * @since 2.6
+     */
+    private static String getJavadocLink( MavenProject p )
+    {
+        if ( p.getUrl() == null )
+        {
+            return null;
+        }
+
+        String url = cleanUrl( p.getUrl() );
+        String destDir = "apidocs"; // see JavadocReport#destDir
+
+        Plugin javadocPlugin =
+            (Plugin) p.getBuild().getPluginsAsMap().get( "org.apache.maven.plugins:maven-javadoc-plugin" );
+        if ( javadocPlugin != null )
+        {
+            Xpp3Dom xpp3Dom = (Xpp3Dom) javadocPlugin.getConfiguration();
+            if ( xpp3Dom != null && xpp3Dom.getChild( "destDir" ) != null
+                && StringUtils.isNotEmpty( xpp3Dom.getChild( "destDir" ).getValue() ) )
+            {
+                destDir = xpp3Dom.getChild( "destDir" ).getValue();
+            }
+        }
+
+        return url + "/" + destDir;
+    }
+
+    /**
+     * @param url could be null.
+     * @return the url cleaned or empty if url was null.
+     * @since 2.6
+     */
+    private static String cleanUrl( String url )
+    {
+        if ( url == null )
+        {
+            return "";
+        }
+
+        url = url.trim();
+        while ( url.endsWith( "/" ) )
+        {
+            url = url.substring( 0, url.lastIndexOf( "/" ) );
+        }
+
+        return url;
+    }
 }

Added: maven/plugins/trunk/maven-javadoc-plugin/src/site/apt/examples/links-configuration.apt
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-javadoc-plugin/src/site/apt/examples/links-configuration.apt?rev=795801&view=auto
==============================================================================
--- maven/plugins/trunk/maven-javadoc-plugin/src/site/apt/examples/links-configuration.apt (added)
+++ maven/plugins/trunk/maven-javadoc-plugin/src/site/apt/examples/links-configuration.apt Mon Jul 20 12:37:16 2009
@@ -0,0 +1,104 @@
+ ------
+ Configuring links and offlineLinks Parameters
+ ------
+ Vincent Siveton
+ ------
+ 2009-07-20
+ ------
+
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements.  See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership.  The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License.  You may obtain a copy of the License at
+~~
+~~   http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied.  See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+
+~~ NOTE: For help with the syntax of this file, see:
+~~ http://maven.apache.org/doxia/references/apt-format.html
+
+Configuring links Parameters
+
+  You could add cross reference links to external projects. For instance:
+
++-----+
+<project>
+  ...
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <configuration>
+          <links>
+            <link>http://commons.apache.org/dbcp/apidocs/</link>
+            <link>http://commons.apache.org/fileupload/apidocs/</link>
+          </links>
+            ...
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  ...
+</project>
++-----+
+
+  <<Important Note>>: according the {{{http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/javadoc.html#package-list}Javadoc specifications}},
+  all given links should have a fetchable <<</package-list>>> file.
+
+  Since 2.6, you could try to autodetect all Javadoc links for your dependencies. You need to use the
+  {{{./javadoc-mojo.html#detectLinks}detectLinks}} parameter. All detected links are based on the Maven conventions.
+  For instance, if your project has a dependency to {{{http://commons.apache.org/lang/}Apache Commons Lang}} i.e.:
+
++-----+
+<project>
+  ...
+  <dependencies>
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+      <versions>2.4</version>
+    </dependency>
+  </dependencies>
+  ...
+</project>
++-----+
+
+  The added Javadoc link will be {{http://commons.apache.org/lang/apidocs}}.
+
+  Refer to {{{./javadoc-mojo.html#links}links}} parameter for more information.
+
+Configuring offlineLinks Parameters
+
+  If your project has modules, you could add cross reference links to your modules when your goals are not aggregator goals.
+  For instance, if your project has two modules i.e.:
+
++-----+
+<project>
+  ...
+  <modules>
+    <module>module1</module>
+    <module>module2</module>
+  </modules>
+  ...
+</project>
++-----+
+
+  The offlineLinks for <<module1>> will be <<</absolute/path/to/>>><<module2>><<</target/site/apidocs>>> and
+  the offlineLinks for <<module2>> will be <<</absolute/path/to/>>><<module1>><<</target/site/apidocs>>>.
+
+  <<Important Note>>: all offlinelinks are based on the \${project.url}.
+
+  Since 2.6, you could not allowing the cross reference offlinelinks with
+  {{{./javadoc-mojo.html#detectOfflineLinks}detectOfflineLinks}} parameter.
+
+  Refer to {{{./javadoc-mojo.html#offlineLinks}offlineLinks}} parameter for more information.

Propchange: maven/plugins/trunk/maven-javadoc-plugin/src/site/apt/examples/links-configuration.apt
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/plugins/trunk/maven-javadoc-plugin/src/site/apt/examples/links-configuration.apt
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Modified: maven/plugins/trunk/maven-javadoc-plugin/src/site/fml/faq.fml
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-javadoc-plugin/src/site/fml/faq.fml?rev=795801&r1=795800&r2=795801&view=diff
==============================================================================
--- maven/plugins/trunk/maven-javadoc-plugin/src/site/fml/faq.fml (original)
+++ maven/plugins/trunk/maven-javadoc-plugin/src/site/fml/faq.fml Mon Jul 20 12:37:16 2009
@@ -403,14 +403,11 @@
         </dl>
       </answer>
     </faq>
-    <faq id="How to link the multi-modules Javadoc directories">
-      <question>How to link the multi-modules Javadoc directories?</question>
+    <faq id="How to add cross reference link to internal-external projects">
+      <question>How to add cross reference link to internal-external projects?</question>
       <answer>
         <p>
-          By default, the Javadoc Plugin uses
-          <a href="http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/javadoc.html#linkoffline">linkoffline</a>
-          to link the generated multi-modules Javadoc directories together. For more information about the default
-          values, refer you to the Javadoc Plugin <a href="./javadoc-mojo.html#offlineLinks">offlineLinks</a>.
+          Please refer to <a href="./examples/links-configuration.html">Links configuration page</a>.
         </p>
       </answer>
     </faq>

Modified: maven/plugins/trunk/maven-javadoc-plugin/src/site/site.xml
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-javadoc-plugin/src/site/site.xml?rev=795801&r1=795800&r2=795801&view=diff
==============================================================================
--- maven/plugins/trunk/maven-javadoc-plugin/src/site/site.xml (original)
+++ maven/plugins/trunk/maven-javadoc-plugin/src/site/site.xml Mon Jul 20 12:37:16 2009
@@ -18,8 +18,9 @@
 specific language governing permissions and limitations
 under the License.
 -->
-
-<project>
+<project xmlns="http://maven.apache.org/DECORATION/1.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/DECORATION/1.0.0 http://maven.apache.org/xsd/decoration-1.0.0.xsd">
   <body>
     <links>
       <item name="Javadoc Tool" href="http://java.sun.com/j2se/javadoc/"/>
@@ -44,6 +45,7 @@
       <item name="Configuring Helpfile" href="/examples/help-configuration.html"/>
       <item name="Configuring Custom Tags" href="/examples/tag-configuration.html"/>
       <item name="Configuring Custom Taglets" href="/examples/taglet-configuration.html"/>
+      <item name="Configuring links" href="/examples/links-configuration.html"/>
       <item name="Generating Test Javadocs" href="/examples/test-javadocs.html"/>
       <item name="Selective Javadocs Reports" href="/examples/selective-javadocs-report.html"/>
       <item name="Fixing Javadoc Comments" href="/examples/fix-javadocs.html"/>