Coverage Report - org.apache.maven.plugin.ide.AbstractIdeSupportMojo
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractIdeSupportMojo
3%
7/226
0%
0/114
2.463
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *   http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package org.apache.maven.plugin.ide;
 20  
 
 21  
 import java.io.File;
 22  
 import java.io.IOException;
 23  
 import java.util.ArrayList;
 24  
 import java.util.Collections;
 25  
 import java.util.HashMap;
 26  
 import java.util.HashSet;
 27  
 import java.util.Iterator;
 28  
 import java.util.List;
 29  
 import java.util.Map;
 30  
 import java.util.Set;
 31  
 import java.util.TreeSet;
 32  
 import java.util.jar.Attributes;
 33  
 import java.util.jar.JarFile;
 34  
 import java.util.jar.Manifest;
 35  
 import java.util.zip.ZipFile;
 36  
 
 37  
 import org.apache.maven.artifact.Artifact;
 38  
 import org.apache.maven.artifact.factory.ArtifactFactory;
 39  
 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
 40  
 import org.apache.maven.artifact.repository.ArtifactRepository;
 41  
 import org.apache.maven.artifact.resolver.ArtifactCollector;
 42  
 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
 43  
 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
 44  
 import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
 45  
 import org.apache.maven.artifact.resolver.ArtifactResolver;
 46  
 import org.apache.maven.artifact.resolver.DebugResolutionListener;
 47  
 import org.apache.maven.artifact.resolver.ResolutionNode;
 48  
 import org.apache.maven.artifact.resolver.WarningResolutionListener;
 49  
 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
 50  
 import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter;
 51  
 import org.apache.maven.artifact.versioning.ArtifactVersion;
 52  
 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
 53  
 import org.apache.maven.artifact.versioning.VersionRange;
 54  
 import org.apache.maven.execution.RuntimeInformation;
 55  
 import org.apache.maven.model.Dependency;
 56  
 import org.apache.maven.model.DependencyManagement;
 57  
 import org.apache.maven.model.Exclusion;
 58  
 import org.apache.maven.plugin.AbstractMojo;
 59  
 import org.apache.maven.plugin.MojoExecutionException;
 60  
 import org.apache.maven.plugin.MojoFailureException;
 61  
 import org.apache.maven.plugin.eclipse.Constants;
 62  
 import org.apache.maven.plugin.eclipse.Messages;
 63  
 import org.apache.maven.project.MavenProject;
 64  
 import org.codehaus.plexus.logging.LogEnabled;
 65  
 import org.codehaus.plexus.logging.Logger;
 66  
 
 67  
 /**
 68  
  * Abstract base plugin which takes care of the common stuff usually needed by maven IDE plugins. A plugin extending
 69  
  * AbstractIdeSupportMojo should implement the <code>setup()</code> and <code>writeConfiguration()</code> methods, plus
 70  
  * the getters needed to get the various configuration flags and required components. The lifecycle:
 71  
  * 
 72  
  * <pre>
 73  
  *       *** calls setup() where you can configure your specific stuff and stop the mojo from execute if appropriate ***
 74  
  *       - manually resolve project dependencies, NOT failing if a dependency is missing
 75  
  *       - compute project references (reactor projects) if the getUseProjectReferences() flag is set
 76  
  *       - download sources/javadocs if the getDownloadSources() flag is set
 77  
  *       *** calls writeConfiguration(), passing the list of resolved referenced dependencies ***
 78  
  *       - report the list of missing sources or just tell how to turn this feature on if the flag was disabled
 79  
  * </pre>
 80  
  * 
 81  
  * @author Fabrizio Giustina
 82  
  * @version $Id: AbstractIdeSupportMojo.java 775071 2009-05-15 09:38:39Z aheritier $
 83  
  */
 84  5
 public abstract class AbstractIdeSupportMojo
 85  
     extends AbstractMojo
 86  
     implements LogEnabled
 87  
 {
 88  
 
 89  
     /**
 90  
      * The project whose project files to create.
 91  
      * 
 92  
      * @parameter expression="${project}"
 93  
      * @required
 94  
      * @readonly
 95  
      */
 96  
     protected MavenProject project;
 97  
 
 98  
     /**
 99  
      * The currently executed project (can be a reactor project).
 100  
      * 
 101  
      * @parameter expression="${executedProject}"
 102  
      * @readonly
 103  
      */
 104  
     protected MavenProject executedProject;
 105  
 
 106  
     /**
 107  
      * The project packaging.
 108  
      * 
 109  
      * @parameter expression="${project.packaging}"
 110  
      */
 111  
     protected String packaging;
 112  
 
 113  
     /**
 114  
      * Artifact factory, needed to download source jars for inclusion in classpath.
 115  
      * 
 116  
      * @component role="org.apache.maven.artifact.factory.ArtifactFactory"
 117  
      * @required
 118  
      * @readonly
 119  
      */
 120  
     protected ArtifactFactory artifactFactory;
 121  
 
 122  
     /**
 123  
      * Artifact resolver, needed to download source jars for inclusion in classpath.
 124  
      * 
 125  
      * @component role="org.apache.maven.artifact.resolver.ArtifactResolver"
 126  
      * @required
 127  
      * @readonly
 128  
      */
 129  
     protected ArtifactResolver artifactResolver;
 130  
 
 131  
     /**
 132  
      * Artifact collector, needed to resolve dependencies.
 133  
      * 
 134  
      * @component role="org.apache.maven.artifact.resolver.ArtifactCollector"
 135  
      * @required
 136  
      * @readonly
 137  
      */
 138  
     protected ArtifactCollector artifactCollector;
 139  
 
 140  
     /**
 141  
      * @component role="org.apache.maven.artifact.metadata.ArtifactMetadataSource" hint="maven"
 142  
      */
 143  
     protected ArtifactMetadataSource artifactMetadataSource;
 144  
 
 145  
     /**
 146  
      * The runtime information for Maven, used to retrieve Maven's version number.
 147  
      * 
 148  
      * @component
 149  
      */
 150  
     private RuntimeInformation runtimeInformation;
 151  
 
 152  
     /**
 153  
      * Remote repositories which will be searched for source attachments.
 154  
      * 
 155  
      * @parameter expression="${project.remoteArtifactRepositories}"
 156  
      * @required
 157  
      * @readonly
 158  
      */
 159  
     protected List remoteArtifactRepositories;
 160  
 
 161  
     /**
 162  
      * Local maven repository.
 163  
      * 
 164  
      * @parameter expression="${localRepository}"
 165  
      * @required
 166  
      * @readonly
 167  
      */
 168  
     protected ArtifactRepository localRepository;
 169  
 
 170  
     /**
 171  
      * If the executed project is a reactor project, this will contains the full list of projects in the reactor.
 172  
      * 
 173  
      * @parameter expression="${reactorProjects}"
 174  
      * @required
 175  
      * @readonly
 176  
      */
 177  
     protected List reactorProjects;
 178  
 
 179  
     /**
 180  
      * Skip the operation when true.
 181  
      * 
 182  
      * @parameter expression="${eclipse.skip}" default-value="false"
 183  
      */
 184  
     private boolean skip;
 185  
 
 186  
     /**
 187  
      * Enables/disables the downloading of source attachments. Defaults to false. When this flag is <code>true</code>
 188  
      * remote repositories are checked for sources: in order to avoid repeated check for unavailable source archives, a
 189  
      * status cache is mantained. With versions 2.6+ of the plugin to reset this cache run 
 190  
      * <code>mvn eclipse:remove-cache</code>, or use the <code>forceRecheck</code> option with versions.
 191  
      * With older versions delete the file <code>mvn-eclipse-cache.properties</code> in the target directory.
 192  
      * 
 193  
      * @parameter expression="${downloadSources}"
 194  
      */
 195  
     protected boolean downloadSources;
 196  
 
 197  
     /**
 198  
      * Enables/disables the downloading of javadoc attachments. Defaults to false. When this flag is <code>true</code>
 199  
      * remote repositories are checked for javadocs: in order to avoid repeated check for unavailable javadoc archives,
 200  
      * a status cache is mantained. With versions 2.6+ of the plugin to reset this cache run 
 201  
      * <code>mvn eclipse:remove-cache</code>, or use the <code>forceRecheck</code> option with versions.
 202  
      * With older versions delete the file <code>mvn-eclipse-cache.properties</code> in the target directory.
 203  
      * 
 204  
      * @parameter expression="${downloadJavadocs}"
 205  
      */
 206  
     protected boolean downloadJavadocs;
 207  
     
 208  
     /**
 209  
      * Enables/disables the rechecking of the remote repository for downloading source/javadoc attachments. Defaults to
 210  
      * false. When this flag is <code>true</code> and the source or javadoc attachment has a status cache to indicate
 211  
      * that it is not available, then the remote repository will be rechecked for a source or javadoc attachment and the
 212  
      * status cache updated to reflect the new state.
 213  
      * 
 214  
      * @parameter expression="${forceRecheck}"
 215  
      */
 216  
     protected boolean forceRecheck;
 217  
 
 218  
     /**
 219  
      * Plexus logger needed for debugging manual artifact resolution.
 220  
      */
 221  
     protected Logger logger;
 222  
 
 223  
     /**
 224  
      * Getter for <code>artifactMetadataSource</code>.
 225  
      * 
 226  
      * @return Returns the artifactMetadataSource.
 227  
      */
 228  
     public ArtifactMetadataSource getArtifactMetadataSource()
 229  
     {
 230  0
         return artifactMetadataSource;
 231  
     }
 232  
 
 233  
     /**
 234  
      * Setter for <code>artifactMetadataSource</code>.
 235  
      * 
 236  
      * @param artifactMetadataSource The artifactMetadataSource to set.
 237  
      */
 238  
     public void setArtifactMetadataSource( ArtifactMetadataSource artifactMetadataSource )
 239  
     {
 240  0
         this.artifactMetadataSource = artifactMetadataSource;
 241  0
     }
 242  
 
 243  
     /**
 244  
      * Getter for <code>project</code>.
 245  
      * 
 246  
      * @return Returns the project.
 247  
      */
 248  
     public MavenProject getProject()
 249  
     {
 250  0
         return project;
 251  
     }
 252  
 
 253  
     /**
 254  
      * Setter for <code>project</code>.
 255  
      * 
 256  
      * @param project The project to set.
 257  
      */
 258  
     public void setProject( MavenProject project )
 259  
     {
 260  0
         this.project = project;
 261  0
     }
 262  
 
 263  
     /**
 264  
      * Getter for <code>reactorProjects</code>.
 265  
      * 
 266  
      * @return Returns the reactorProjects.
 267  
      */
 268  
     public List getReactorProjects()
 269  
     {
 270  0
         return reactorProjects;
 271  
     }
 272  
 
 273  
     /**
 274  
      * Setter for <code>reactorProjects</code>.
 275  
      * 
 276  
      * @param reactorProjects The reactorProjects to set.
 277  
      */
 278  
     public void setReactorProjects( List reactorProjects )
 279  
     {
 280  0
         this.reactorProjects = reactorProjects;
 281  0
     }
 282  
 
 283  
     /**
 284  
      * Getter for <code>remoteArtifactRepositories</code>.
 285  
      * 
 286  
      * @return Returns the remoteArtifactRepositories.
 287  
      */
 288  
     public List getRemoteArtifactRepositories()
 289  
     {
 290  0
         return remoteArtifactRepositories;
 291  
     }
 292  
 
 293  
     /**
 294  
      * Setter for <code>remoteArtifactRepositories</code>.
 295  
      * 
 296  
      * @param remoteArtifactRepositories The remoteArtifactRepositories to set.
 297  
      */
 298  
     public void setRemoteArtifactRepositories( List remoteArtifactRepositories )
 299  
     {
 300  0
         this.remoteArtifactRepositories = remoteArtifactRepositories;
 301  0
     }
 302  
 
 303  
     /**
 304  
      * Getter for <code>artifactFactory</code>.
 305  
      * 
 306  
      * @return Returns the artifactFactory.
 307  
      */
 308  
     public ArtifactFactory getArtifactFactory()
 309  
     {
 310  0
         return artifactFactory;
 311  
     }
 312  
 
 313  
     /**
 314  
      * Setter for <code>artifactFactory</code>.
 315  
      * 
 316  
      * @param artifactFactory The artifactFactory to set.
 317  
      */
 318  
     public void setArtifactFactory( ArtifactFactory artifactFactory )
 319  
     {
 320  0
         this.artifactFactory = artifactFactory;
 321  0
     }
 322  
 
 323  
     /**
 324  
      * Getter for <code>artifactResolver</code>.
 325  
      * 
 326  
      * @return Returns the artifactResolver.
 327  
      */
 328  
     public ArtifactResolver getArtifactResolver()
 329  
     {
 330  0
         return artifactResolver;
 331  
     }
 332  
 
 333  
     /**
 334  
      * Setter for <code>artifactResolver</code>.
 335  
      * 
 336  
      * @param artifactResolver The artifactResolver to set.
 337  
      */
 338  
     public void setArtifactResolver( ArtifactResolver artifactResolver )
 339  
     {
 340  0
         this.artifactResolver = artifactResolver;
 341  0
     }
 342  
 
 343  
     /**
 344  
      * Getter for <code>executedProject</code>.
 345  
      * 
 346  
      * @return Returns the executedProject.
 347  
      */
 348  
     public MavenProject getExecutedProject()
 349  
     {
 350  0
         return executedProject;
 351  
     }
 352  
 
 353  
     /**
 354  
      * Setter for <code>executedProject</code>.
 355  
      * 
 356  
      * @param executedProject The executedProject to set.
 357  
      */
 358  
     public void setExecutedProject( MavenProject executedProject )
 359  
     {
 360  0
         this.executedProject = executedProject;
 361  0
     }
 362  
 
 363  
     /**
 364  
      * Getter for <code>localRepository</code>.
 365  
      * 
 366  
      * @return Returns the localRepository.
 367  
      */
 368  
     public ArtifactRepository getLocalRepository()
 369  
     {
 370  0
         return localRepository;
 371  
     }
 372  
 
 373  
     /**
 374  
      * Setter for <code>localRepository</code>.
 375  
      * 
 376  
      * @param localRepository The localRepository to set.
 377  
      */
 378  
     public void setLocalRepository( ArtifactRepository localRepository )
 379  
     {
 380  0
         this.localRepository = localRepository;
 381  0
     }
 382  
 
 383  
     /**
 384  
      * Getter for <code>downloadJavadocs</code>.
 385  
      * 
 386  
      * @return Returns the downloadJavadocs.
 387  
      */
 388  
     public boolean getDownloadJavadocs()
 389  
     {
 390  0
         return downloadJavadocs;
 391  
     }
 392  
 
 393  
     /**
 394  
      * Setter for <code>downloadJavadocs</code>.
 395  
      * 
 396  
      * @param downloadJavadoc The downloadJavadocs to set.
 397  
      */
 398  
     public void setDownloadJavadocs( boolean downloadJavadoc )
 399  
     {
 400  0
         downloadJavadocs = downloadJavadoc;
 401  0
     }
 402  
 
 403  
     /**
 404  
      * Getter for <code>downloadSources</code>.
 405  
      * 
 406  
      * @return Returns the downloadSources.
 407  
      */
 408  
     public boolean getDownloadSources()
 409  
     {
 410  0
         return downloadSources;
 411  
     }
 412  
 
 413  
     /**
 414  
      * Setter for <code>downloadSources</code>.
 415  
      * 
 416  
      * @param downloadSources The downloadSources to set.
 417  
      */
 418  
     public void setDownloadSources( boolean downloadSources )
 419  
     {
 420  0
         this.downloadSources = downloadSources;
 421  0
     }
 422  
 
 423  
     protected void setResolveDependencies( boolean resolveDependencies )
 424  
     {
 425  0
         this.resolveDependencies = resolveDependencies;
 426  0
     }
 427  
 
 428  
     protected boolean isResolveDependencies()
 429  
     {
 430  0
         return resolveDependencies;
 431  
     }
 432  
 
 433  
     /**
 434  
      * return <code>false</code> if projects available in a reactor build should be considered normal dependencies,
 435  
      * <code>true</code> if referenced project will be linked and not need artifact resolution.
 436  
      * 
 437  
      * @return <code>true</code> if referenced project will be linked and not need artifact resolution
 438  
      */
 439  
     protected abstract boolean getUseProjectReferences();
 440  
 
 441  
     /**
 442  
      * Hook for preparation steps before the actual plugin execution.
 443  
      * 
 444  
      * @return <code>true</code> if execution should continue or <code>false</code> if not.
 445  
      * @throws MojoExecutionException generic mojo exception
 446  
      */
 447  
     protected abstract boolean setup()
 448  
         throws MojoExecutionException;
 449  
 
 450  
     /**
 451  
      * Main plugin method where dependencies should be processed in order to generate IDE configuration files.
 452  
      * 
 453  
      * @param deps list of <code>IdeDependency</code> objects, with artifacts, sources and javadocs already resolved
 454  
      * @throws MojoExecutionException generic mojo exception
 455  
      */
 456  
     protected abstract void writeConfiguration( IdeDependency[] deps )
 457  
         throws MojoExecutionException;
 458  
 
 459  
     /**
 460  
      * Not a plugin parameter. Collect the list of dependencies with a missing source artifact for the final report.
 461  
      */
 462  5
     private List missingSourceDependencies = new ArrayList();
 463  
 
 464  
     /**
 465  
      * Not a plugin parameter. Collect the list of dependencies with a missing javadoc artifact for the final report.
 466  
      */
 467  
     // TODO merge this with the missingSourceDependencies in a classifier based map?
 468  5
     private List missingJavadocDependencies = new ArrayList();
 469  
 
 470  
     /**
 471  
      * Cached array of resolved dependencies.
 472  
      */
 473  
     private IdeDependency[] ideDeps;
 474  
 
 475  
     /**
 476  
      * Flag for mojo implementations to control whether normal maven dependencies should be resolved. Default value is
 477  
      * true.
 478  
      */
 479  5
     private boolean resolveDependencies = true;
 480  
 
 481  
     /**
 482  
      * @see org.codehaus.plexus.logging.LogEnabled#enableLogging(org.codehaus.plexus.logging.Logger)
 483  
      */
 484  
     public void enableLogging( Logger logger )
 485  
     {
 486  0
         this.logger = logger;
 487  0
     }
 488  
 
 489  
     /**
 490  
      * @see org.apache.maven.plugin.Mojo#execute()
 491  
      */
 492  
     public final void execute()
 493  
         throws MojoExecutionException, MojoFailureException
 494  
     {
 495  0
         if ( skip )
 496  
         {
 497  0
             return;
 498  
         }
 499  
 
 500  0
         boolean processProject = setup();
 501  0
         if ( !processProject )
 502  
         {
 503  0
             return;
 504  
         }
 505  
 
 506  
         // resolve artifacts
 507  0
         IdeDependency[] deps = doDependencyResolution();
 508  
 
 509  0
         resolveSourceAndJavadocArtifacts( deps );
 510  
 
 511  0
         writeConfiguration( deps );
 512  
 
 513  0
         reportMissingArtifacts();
 514  
 
 515  0
     }
 516  
 
 517  
     /**
 518  
      * Resolve project dependencies. Manual resolution is needed in order to avoid resolution of multiproject artifacts
 519  
      * (if projects will be linked each other an installed jar is not needed) and to avoid a failure when a jar is
 520  
      * missing.
 521  
      * 
 522  
      * @throws MojoExecutionException if dependencies can't be resolved
 523  
      * @return resolved IDE dependencies, with attached jars for non-reactor dependencies
 524  
      */
 525  
     protected IdeDependency[] doDependencyResolution()
 526  
         throws MojoExecutionException
 527  
     {
 528  0
         if ( ideDeps == null )
 529  
         {
 530  0
             if ( resolveDependencies )
 531  
             {
 532  0
                 MavenProject project = getProject();
 533  0
                 ArtifactRepository localRepo = getLocalRepository();
 534  
 
 535  0
                 List deps = getProject().getDependencies();
 536  
 
 537  
                 // Collect the list of resolved IdeDependencies.
 538  0
                 List dependencies = new ArrayList();
 539  
 
 540  0
                 if ( deps != null )
 541  
                 {
 542  0
                     Map managedVersions =
 543  
                         createManagedVersionMap( getArtifactFactory(), project.getId(),
 544  
                                                  project.getDependencyManagement() );
 545  
 
 546  0
                     ArtifactResolutionResult artifactResolutionResult = null;
 547  
 
 548  
                     try
 549  
                     {
 550  
 
 551  0
                         List listeners = new ArrayList();
 552  
 
 553  0
                         if ( logger.isDebugEnabled() )
 554  
                         {
 555  0
                             listeners.add( new DebugResolutionListener( logger ) );
 556  
                         }
 557  
 
 558  0
                         listeners.add( new WarningResolutionListener( logger ) );
 559  
 
 560  0
                         artifactResolutionResult =
 561  
                             artifactCollector.collect( getProjectArtifacts(), project.getArtifact(), managedVersions,
 562  
                                                        localRepo, project.getRemoteArtifactRepositories(),
 563  
                                                        getArtifactMetadataSource(), null, listeners );
 564  
                     }
 565  0
                     catch ( ArtifactResolutionException e )
 566  
                     {
 567  0
                         getLog().debug( e.getMessage(), e );
 568  0
                         getLog().error(
 569  
                                         Messages.getString( "AbstractIdeSupportMojo.artifactresolution", new Object[] { //$NON-NLS-1$
 570  
                                                             e.getGroupId(), e.getArtifactId(), e.getVersion(),
 571  
                                                                 e.getMessage() } ) );
 572  
 
 573  
                         // if we are here artifactResolutionResult is null, create a project without dependencies but
 574  
                         // don't fail
 575  
                         // (this could be a reactor projects, we don't want to fail everything)
 576  
                         // Causes MECLIPSE-185. Not sure if it should be handled this way??
 577  0
                         return new IdeDependency[0];
 578  0
                     }
 579  
 
 580  
                     // keep track of added reactor projects in order to avoid duplicates
 581  0
                     Set emittedReactorProjectId = new HashSet();
 582  
 
 583  0
                     for ( Iterator i = artifactResolutionResult.getArtifactResolutionNodes().iterator(); i.hasNext(); )
 584  
                     {
 585  
 
 586  0
                         ResolutionNode node = (ResolutionNode) i.next();
 587  0
                         int dependencyDepth = node.getDepth();
 588  0
                         Artifact art = node.getArtifact();
 589  
                         // don't resolve jars for reactor projects
 590  0
                         if ( hasToResolveJar( art ) )
 591  
                         {
 592  
                             try
 593  
                             {
 594  0
                                 artifactResolver.resolve( art, node.getRemoteRepositories(), localRepository );
 595  
                             }
 596  0
                             catch ( ArtifactNotFoundException e )
 597  
                             {
 598  0
                                 getLog().debug( e.getMessage(), e );
 599  0
                                 getLog().warn(
 600  
                                                Messages.getString( "AbstractIdeSupportMojo.artifactdownload", new Object[] { //$NON-NLS-1$
 601  
                                                                    e.getGroupId(), e.getArtifactId(), e.getVersion(),
 602  
                                                                        e.getMessage() } ) );
 603  
                             }
 604  0
                             catch ( ArtifactResolutionException e )
 605  
                             {
 606  0
                                 getLog().debug( e.getMessage(), e );
 607  0
                                 getLog().warn(
 608  
                                                Messages.getString( "AbstractIdeSupportMojo.artifactresolution", new Object[] { //$NON-NLS-1$
 609  
                                                                    e.getGroupId(), e.getArtifactId(), e.getVersion(),
 610  
                                                                        e.getMessage() } ) );
 611  0
                             }
 612  
                         }
 613  
 
 614  0
                         boolean includeArtifact = true;
 615  0
                         if ( getExcludes() != null )
 616  
                         {
 617  0
                             String artifactFullId = art.getGroupId() + ":" + art.getArtifactId();
 618  0
                             if ( getExcludes().contains( artifactFullId ) )
 619  
                             {
 620  0
                                 getLog().info( "excluded: " + artifactFullId );
 621  0
                                 includeArtifact = false;
 622  
                             }
 623  
                         }
 624  
 
 625  0
                         if ( includeArtifact
 626  
                             && ( !( getUseProjectReferences() && isAvailableAsAReactorProject( art ) ) || emittedReactorProjectId.add( art.getGroupId()
 627  
                                 + '-' + art.getArtifactId() ) ) )
 628  
                         {
 629  
 
 630  
                             // the following doesn't work: art.getArtifactHandler().getPackaging() always returns "jar"
 631  
                             // also
 632  
                             // if the packaging specified in pom.xml is different.
 633  
 
 634  
                             // osgi-bundle packaging is provided by the felix osgi plugin
 635  
                             // eclipse-plugin packaging is provided by this eclipse plugin
 636  
                             // String packaging = art.getArtifactHandler().getPackaging();
 637  
                             // boolean isOsgiBundle = "osgi-bundle".equals( packaging ) || "eclipse-plugin".equals(
 638  
                             // packaging );
 639  
 
 640  
                             // we need to check the manifest, if "Bundle-SymbolicName" is there the artifact can be
 641  
                             // considered
 642  
                             // an osgi bundle
 643  0
                             boolean isOsgiBundle = false;
 644  0
                             String osgiSymbolicName = null;
 645  0
                             if ( art.getFile() != null )
 646  
                             {
 647  0
                                 JarFile jarFile = null;
 648  
                                 try
 649  
                                 {
 650  0
                                     jarFile = new JarFile( art.getFile(), false, ZipFile.OPEN_READ );
 651  
 
 652  0
                                     Manifest manifest = jarFile.getManifest();
 653  0
                                     if ( manifest != null )
 654  
                                     {
 655  0
                                         osgiSymbolicName =
 656  
                                             manifest.getMainAttributes().getValue(
 657  
                                                                                    new Attributes.Name(
 658  
                                                                                                         "Bundle-SymbolicName" ) );
 659  
                                     }
 660  0
                                 }
 661  0
                                 catch ( IOException e )
 662  
                                 {
 663  0
                                     getLog().info( "Unable to read jar manifest from " + art.getFile() );
 664  0
                                 }
 665  
                                 finally
 666  
                                 {
 667  0
                                     if ( jarFile != null )
 668  
                                     {
 669  
                                         try
 670  
                                         {
 671  0
                                             jarFile.close();
 672  
                                         }
 673  0
                                         catch ( IOException e )
 674  
                                         {
 675  
                                             // ignore
 676  0
                                         }
 677  
                                     }
 678  0
                                 }
 679  
                             }
 680  
 
 681  0
                             isOsgiBundle = osgiSymbolicName != null;
 682  
 
 683  0
                             IdeDependency dep =
 684  
                                 new IdeDependency( art.getGroupId(), art.getArtifactId(), art.getVersion(),
 685  
                                                    art.getClassifier(), useProjectReference( art ),
 686  
                                                    Artifact.SCOPE_TEST.equals( art.getScope() ),
 687  
                                                    Artifact.SCOPE_SYSTEM.equals( art.getScope() ),
 688  
                                                    Artifact.SCOPE_PROVIDED.equals( art.getScope() ),
 689  
                                                    art.getArtifactHandler().isAddedToClasspath(), art.getFile(),
 690  
                                                    art.getType(), isOsgiBundle, osgiSymbolicName, dependencyDepth,
 691  
                                                    getProjectNameForArifact( art ) );
 692  
                             // no duplicate entries allowed. System paths can cause this problem.
 693  0
                             if ( !dependencies.contains( dep ) )
 694  
                             {
 695  0
                                 dependencies.add( dep );
 696  
                             }
 697  
                         }
 698  
 
 699  
                     }
 700  
 
 701  
                     // @todo a final report with the list of
 702  
                     // missingArtifacts?
 703  
 
 704  
                 }
 705  
 
 706  0
                 ideDeps = (IdeDependency[]) dependencies.toArray( new IdeDependency[dependencies.size()] );
 707  
             }
 708  
             else
 709  
             {
 710  0
                 ideDeps = new IdeDependency[0];
 711  
             }
 712  
         }
 713  
 
 714  0
         return ideDeps;
 715  
     }
 716  
 
 717  
     /**
 718  
      * Find the name of the project as used in eclipse.
 719  
      * 
 720  
      * @param artifact The artifact to find the eclipse name for.
 721  
      * @return The name os the eclipse project.
 722  
      */
 723  
     abstract public String getProjectNameForArifact( Artifact artifact );
 724  
 
 725  
     /**
 726  
      * Returns the list of project artifacts. Also artifacts generated from referenced projects will be added, but with
 727  
      * the <code>resolved</code> property set to true.
 728  
      * 
 729  
      * @return list of projects artifacts
 730  
      * @throws MojoExecutionException if unable to parse dependency versions
 731  
      */
 732  
     private Set getProjectArtifacts()
 733  
         throws MojoExecutionException
 734  
     {
 735  
         // keep it sorted, this should avoid random classpath order in tests
 736  0
         Set artifacts = new TreeSet();
 737  
 
 738  0
         for ( Iterator dependencies = getProject().getDependencies().iterator(); dependencies.hasNext(); )
 739  
         {
 740  0
             Dependency dependency = (Dependency) dependencies.next();
 741  
 
 742  0
             String groupId = dependency.getGroupId();
 743  0
             String artifactId = dependency.getArtifactId();
 744  
             VersionRange versionRange;
 745  
             try
 746  
             {
 747  0
                 versionRange = VersionRange.createFromVersionSpec( dependency.getVersion() );
 748  
             }
 749  0
             catch ( InvalidVersionSpecificationException e )
 750  
             {
 751  0
                 throw new MojoExecutionException(
 752  
                                                   Messages.getString(
 753  
                                                                       "AbstractIdeSupportMojo.unabletoparseversion", new Object[] { //$NON-NLS-1$
 754  
                                                                       dependency.getArtifactId(),
 755  
                                                                           dependency.getVersion(),
 756  
                                                                           dependency.getManagementKey(), e.getMessage() } ),
 757  
                                                   e );
 758  0
             }
 759  
 
 760  0
             String type = dependency.getType();
 761  0
             if ( type == null )
 762  
             {
 763  0
                 type = Constants.PROJECT_PACKAGING_JAR;
 764  
             }
 765  0
             String classifier = dependency.getClassifier();
 766  0
             boolean optional = dependency.isOptional();
 767  0
             String scope = dependency.getScope();
 768  0
             if ( scope == null )
 769  
             {
 770  0
                 scope = Artifact.SCOPE_COMPILE;
 771  
             }
 772  
 
 773  0
             Artifact art =
 774  
                 getArtifactFactory().createDependencyArtifact( groupId, artifactId, versionRange, type, classifier,
 775  
                                                                scope, optional );
 776  
 
 777  0
             if ( scope.equalsIgnoreCase( Artifact.SCOPE_SYSTEM ) )
 778  
             {
 779  0
                 art.setFile( new File( dependency.getSystemPath() ) );
 780  
             }
 781  
 
 782  0
             List exclusions = new ArrayList();
 783  0
             for ( Iterator j = dependency.getExclusions().iterator(); j.hasNext(); )
 784  
             {
 785  0
                 Exclusion e = (Exclusion) j.next();
 786  0
                 exclusions.add( e.getGroupId() + ":" + e.getArtifactId() ); //$NON-NLS-1$
 787  
             }
 788  
 
 789  0
             ArtifactFilter newFilter = new ExcludesArtifactFilter( exclusions );
 790  
 
 791  0
             art.setDependencyFilter( newFilter );
 792  
 
 793  0
             artifacts.add( art );
 794  
         }
 795  
 
 796  0
         return artifacts;
 797  
     }
 798  
 
 799  
     /**
 800  
      * Utility method that locates a project producing the given artifact.
 801  
      * 
 802  
      * @param artifact the artifact a project should produce.
 803  
      * @return <code>true</code> if the artifact is produced by a reactor projectart.
 804  
      */
 805  
     protected boolean isAvailableAsAReactorProject( Artifact artifact )
 806  
     {
 807  0
         return getReactorProject( artifact ) != null;
 808  
     }
 809  
     
 810  
     /**
 811  
      * Checks the list of reactor projects to see if the artifact is included.
 812  
      * 
 813  
      * @param artifact the artifact to check if it is in the reactor
 814  
      * @return the reactor project or null if it is not in the reactor
 815  
      */
 816  
     protected MavenProject getReactorProject( Artifact artifact ) {
 817  0
         if ( reactorProjects != null )
 818  
         {
 819  0
             for ( Iterator iter = reactorProjects.iterator(); iter.hasNext(); )
 820  
             {
 821  0
                 MavenProject reactorProject = (MavenProject) iter.next();
 822  
 
 823  0
                 if ( reactorProject.getGroupId().equals( artifact.getGroupId() )
 824  
                     && reactorProject.getArtifactId().equals( artifact.getArtifactId() ) )
 825  
                 {
 826  0
                     if ( reactorProject.getVersion().equals( artifact.getVersion() ) )
 827  
                     {
 828  0
                         return reactorProject;
 829  
                     }
 830  
                     else
 831  
                     {
 832  0
                         getLog().info(
 833  
                                        "Artifact "
 834  
                                            + artifact.getId()
 835  
                                            + " already available as a reactor project, but with different version. Expected: "
 836  
                                            + artifact.getVersion() + ", found: " + reactorProject.getVersion() );
 837  
                     }
 838  
                 }
 839  
             }
 840  
         } 
 841  0
         return null;
 842  
     }
 843  
 
 844  
     /**
 845  
      * @return an array with all dependencies avalaible in the workspace, to be implemented by the subclasses.
 846  
      */
 847  
     protected IdeDependency[] getWorkspaceArtefacts()
 848  
     {
 849  0
         return new IdeDependency[0];
 850  
     }
 851  
 
 852  
     private Map createManagedVersionMap( ArtifactFactory artifactFactory, String projectId,
 853  
                                          DependencyManagement dependencyManagement )
 854  
         throws MojoExecutionException
 855  
     {
 856  
         Map map;
 857  0
         if ( dependencyManagement != null && dependencyManagement.getDependencies() != null )
 858  
         {
 859  0
             map = new HashMap();
 860  0
             for ( Iterator i = dependencyManagement.getDependencies().iterator(); i.hasNext(); )
 861  
             {
 862  0
                 Dependency d = (Dependency) i.next();
 863  
 
 864  
                 try
 865  
                 {
 866  0
                     VersionRange versionRange = VersionRange.createFromVersionSpec( d.getVersion() );
 867  0
                     Artifact artifact =
 868  
                         artifactFactory.createDependencyArtifact( d.getGroupId(), d.getArtifactId(), versionRange,
 869  
                                                                   d.getType(), d.getClassifier(), d.getScope(),
 870  
                                                                   d.isOptional() );
 871  0
                     map.put( d.getManagementKey(), artifact );
 872  
                 }
 873  0
                 catch ( InvalidVersionSpecificationException e )
 874  
                 {
 875  0
                     throw new MojoExecutionException( Messages.getString( "AbstractIdeSupportMojo.unabletoparseversion", new Object[] { //$NON-NLS-1$
 876  
                                                                           projectId, d.getVersion(),
 877  
                                                                               d.getManagementKey(), e.getMessage() } ),
 878  
                                                       e );
 879  0
                 }
 880  
             }
 881  
         }
 882  
         else
 883  
         {
 884  0
             map = Collections.EMPTY_MAP;
 885  
         }
 886  0
         return map;
 887  
     }
 888  
 
 889  
     /**
 890  
      * Resolve source artifacts and download them if <code>downloadSources</code> is <code>true</code>. Source and
 891  
      * javadocs artifacts will be attached to the <code>IdeDependency</code> Resolve source and javadoc artifacts. The
 892  
      * resolved artifacts will be downloaded based on the <code>downloadSources</code> and <code>downloadJavadocs</code>
 893  
      * attributes. Source and
 894  
      * 
 895  
      * @param deps resolved dependencies
 896  
      */
 897  
     private void resolveSourceAndJavadocArtifacts( IdeDependency[] deps )
 898  
     {
 899  0
         final List missingSources =
 900  
             resolveDependenciesWithClassifier( deps, "sources", getDownloadSources() );
 901  0
         missingSourceDependencies.addAll( missingSources );
 902  
 
 903  0
         final List missingJavadocs =
 904  
             resolveDependenciesWithClassifier( deps, "javadoc", getDownloadJavadocs() );
 905  0
         missingJavadocDependencies.addAll( missingJavadocs ); 
 906  0
     }   
 907  
 
 908  
     /**
 909  
      * Resolve the required artifacts for each of the dependency. <code>sources</code> or <code>javadoc</code> artifacts
 910  
      * (depending on the <code>classifier</code>) are attached to the dependency.
 911  
      * 
 912  
      * @param deps resolved dependencies
 913  
      * @param inClassifier the classifier we are looking for (either <code>sources</code> or <code>javadoc</code>)
 914  
      * @param includeRemoteRepositories flag whether we should search remote repositories for the artifacts or not
 915  
      * @return the list of dependencies for which the required artifact was not found
 916  
      */
 917  
     private List resolveDependenciesWithClassifier( IdeDependency[] deps, String inClassifier,
 918  
                                                     boolean includeRemoteRepositories )
 919  
     {
 920  0
         List missingClassifierDependencies = new ArrayList();
 921  
 
 922  
         // if downloadSources is off, just check
 923  
         // local repository for reporting missing source jars
 924  0
         List remoteRepos = includeRemoteRepositories ? getRemoteArtifactRepositories() : Collections.EMPTY_LIST;
 925  
 
 926  0
         for ( int j = 0; j < deps.length; j++ )
 927  
         {
 928  0
             IdeDependency dependency = deps[j];
 929  
 
 930  0
             if ( dependency.isReferencedProject() || dependency.isSystemScoped() )
 931  
             {
 932  
                 // artifact not needed
 933  0
                 continue;
 934  
             }
 935  
 
 936  0
             if ( getLog().isDebugEnabled() )
 937  
             {
 938  0
                 getLog().debug(
 939  
                                 "Searching for sources for " + dependency.getId() + ":" + dependency.getClassifier()
 940  
                                     + " at " + dependency.getId() + ":" + inClassifier );
 941  
             }
 942  
 
 943  0
             Artifact baseArtifact =
 944  
                 artifactFactory.createArtifactWithClassifier( dependency.getGroupId(), dependency.getArtifactId(),
 945  
                                                               dependency.getVersion(), dependency.getType(),
 946  
                                                               dependency.getClassifier() );      
 947  0
             baseArtifact =
 948  
                 IdeUtils.resolveArtifact( artifactResolver, baseArtifact, remoteRepos, localRepository, getLog() );
 949  0
             if (!baseArtifact.isResolved()) {
 950  
                 // base artifact does not exist - no point checking for javadoc/sources
 951  0
                 continue;
 952  
             }
 953  
             
 954  0
             Artifact artifact =
 955  
                 IdeUtils.createArtifactWithClassifier( dependency.getGroupId(), dependency.getArtifactId(),
 956  
                                                        dependency.getVersion(), dependency.getClassifier(),
 957  
                                                        inClassifier, artifactFactory );
 958  0
             File notAvailableMarkerFile = IdeUtils.getNotAvailableMarkerFile( localRepository, artifact );
 959  
 
 960  0
             if (forceRecheck && notAvailableMarkerFile.exists()) {
 961  0
                 if (!notAvailableMarkerFile.delete()) {
 962  0
                     getLog().warn( Messages.getString( "AbstractIdeSupportMojo.unabletodeletenotavailablemarkerfile", notAvailableMarkerFile ) );
 963  
                 }
 964  
             }
 965  
             
 966  0
             if ( !notAvailableMarkerFile.exists() )
 967  
             {                
 968  0
                 artifact =
 969  
                     IdeUtils.resolveArtifact( artifactResolver, artifact, remoteRepos, localRepository, getLog() );
 970  0
                 if ( artifact.isResolved() )
 971  
                 {
 972  0
                     if ( "sources".equals( inClassifier ) )
 973  
                     {
 974  0
                         dependency.setSourceAttachment( artifact.getFile() );
 975  
                     }
 976  0
                     else if ( "javadoc".equals( inClassifier ) )
 977  
                     {
 978  0
                         dependency.setJavadocAttachment( artifact.getFile() );
 979  
                     }
 980  
                 }
 981  
                 else
 982  
                 {
 983  0
                     if ( includeRemoteRepositories )
 984  
                     {
 985  
                         try
 986  
                         {
 987  0
                             notAvailableMarkerFile.createNewFile();
 988  0
                             getLog().debug( Messages.getString( "AbstractIdeSupportMojo.creatednotavailablemarkerfile", notAvailableMarkerFile ) );
 989  
                         }
 990  0
                         catch ( IOException e )
 991  
                         {
 992  0
                             getLog().warn( Messages.getString( "AbstractIdeSupportMojo.failedtocreatenotavailablemarkerfile",
 993  
                                                                notAvailableMarkerFile ) );
 994  0
                         }
 995  
                     }
 996  
                     // add the dependencies to the list
 997  
                     // of those lacking the required
 998  
                     // artifact
 999  0
                     missingClassifierDependencies.add( dependency );
 1000  
                 }
 1001  
             }
 1002  
         }
 1003  
 
 1004  
         // return the list of dependencies missing the
 1005  
         // required artifact
 1006  0
         return missingClassifierDependencies;
 1007  
 
 1008  
     }
 1009  
 
 1010  
     /**
 1011  
      * Output a message with the list of missing dependencies and info on how turn download on if it was disabled.
 1012  
      */
 1013  
     private void reportMissingArtifacts()
 1014  
     {
 1015  0
         StringBuffer msg = new StringBuffer();
 1016  
 
 1017  0
         if ( !missingSourceDependencies.isEmpty() )
 1018  
         {
 1019  0
             if ( getDownloadSources() )
 1020  
             {
 1021  0
                 msg.append( Messages.getString( "AbstractIdeSupportMojo.sourcesnotavailable" ) ); //$NON-NLS-1$
 1022  
             }
 1023  
             else
 1024  
             {
 1025  0
                 msg.append( Messages.getString( "AbstractIdeSupportMojo.sourcesnotdownloaded" ) ); //$NON-NLS-1$
 1026  
             }
 1027  
 
 1028  0
             for ( Iterator it = missingSourceDependencies.iterator(); it.hasNext(); )
 1029  
             {
 1030  0
                 IdeDependency art = (IdeDependency) it.next();
 1031  0
                 msg.append( Messages.getString( "AbstractIdeSupportMojo.sourcesmissingitem", art.getId() ) ); //$NON-NLS-1$
 1032  
             }
 1033  0
             msg.append( "\n" ); //$NON-NLS-1$
 1034  
         }
 1035  
 
 1036  0
         if ( !missingJavadocDependencies.isEmpty() )
 1037  
         {
 1038  0
             if ( getDownloadJavadocs() )
 1039  
             {
 1040  0
                 msg.append( Messages.getString( "AbstractIdeSupportMojo.javadocnotavailable" ) ); //$NON-NLS-1$
 1041  
             }
 1042  
             else
 1043  
             {
 1044  0
                 msg.append( Messages.getString( "AbstractIdeSupportMojo.javadocnotdownloaded" ) ); //$NON-NLS-1$
 1045  
             }
 1046  
 
 1047  0
             for ( Iterator it = missingJavadocDependencies.iterator(); it.hasNext(); )
 1048  
             {
 1049  0
                 IdeDependency art = (IdeDependency) it.next();
 1050  0
                 msg.append( Messages.getString( "AbstractIdeSupportMojo.javadocmissingitem", art.getId() ) ); //$NON-NLS-1$
 1051  
             }
 1052  0
             msg.append( "\n" ); //$NON-NLS-1$
 1053  
         }
 1054  0
         getLog().info( msg );
 1055  0
     }
 1056  
 
 1057  
     /**
 1058  
      * @return List of dependencies to exclude from eclipse classpath.
 1059  
      * @since 2.5
 1060  
      */
 1061  
     public abstract List getExcludes();
 1062  
 
 1063  
     /**
 1064  
      * Checks if jar has to be resolved for the given artifact
 1065  
      * 
 1066  
      * @param art the artifact to check
 1067  
      * @return true if resolution should happen
 1068  
      */
 1069  
     protected boolean hasToResolveJar( Artifact art )
 1070  
     {
 1071  0
         return !( getUseProjectReferences() && isAvailableAsAReactorProject( art ) );
 1072  
     }
 1073  
 
 1074  
     /**
 1075  
      * Checks if a projects reference has to be used for the given artifact
 1076  
      * 
 1077  
      * @param art the artifact to check
 1078  
      * @return true if a project reference has to be used.
 1079  
      */
 1080  
     protected boolean useProjectReference( Artifact art )
 1081  
     {
 1082  0
         return getUseProjectReferences() && isAvailableAsAReactorProject( art );
 1083  
     }
 1084  
 
 1085  
     /**
 1086  
      * Checks whether the currently running Maven satisfies the specified version (range).
 1087  
      * 
 1088  
      * @param version The version range to test for, must not be <code>null</code>.
 1089  
      * @return <code>true</code> if the current Maven version matches the specified version range, <code>false</code>
 1090  
      *         otherwise.
 1091  
      */
 1092  
     protected boolean isMavenVersion( String version )
 1093  
     {
 1094  
         try
 1095  
         {
 1096  1
             VersionRange versionRange = VersionRange.createFromVersionSpec( version );
 1097  1
             ArtifactVersion mavenVersion = runtimeInformation.getApplicationVersion();
 1098  1
             return versionRange.containsVersion( mavenVersion );
 1099  
         }
 1100  0
         catch ( InvalidVersionSpecificationException e )
 1101  
         {
 1102  0
             throw new IllegalArgumentException( e.getMessage() );
 1103  
         }
 1104  
     }
 1105  
 
 1106  
 }