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