001package org.apache.maven.project;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.apache.maven.RepositoryUtils;
023import org.apache.maven.artifact.Artifact;
024import org.apache.maven.artifact.ArtifactUtils;
025import org.apache.maven.artifact.DependencyResolutionRequiredException;
026import org.apache.maven.artifact.InvalidRepositoryException;
027import org.apache.maven.artifact.factory.ArtifactFactory;
028import org.apache.maven.artifact.repository.ArtifactRepository;
029import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
030import org.apache.maven.model.Build;
031import org.apache.maven.model.CiManagement;
032import org.apache.maven.model.Contributor;
033import org.apache.maven.model.Dependency;
034import org.apache.maven.model.DependencyManagement;
035import org.apache.maven.model.Developer;
036import org.apache.maven.model.DistributionManagement;
037import org.apache.maven.model.Extension;
038import org.apache.maven.model.IssueManagement;
039import org.apache.maven.model.License;
040import org.apache.maven.model.MailingList;
041import org.apache.maven.model.Model;
042import org.apache.maven.model.Organization;
043import org.apache.maven.model.Plugin;
044import org.apache.maven.model.PluginExecution;
045import org.apache.maven.model.PluginManagement;
046import org.apache.maven.model.Prerequisites;
047import org.apache.maven.model.Profile;
048import org.apache.maven.model.ReportPlugin;
049import org.apache.maven.model.ReportSet;
050import org.apache.maven.model.Reporting;
051import org.apache.maven.model.Repository;
052import org.apache.maven.model.Resource;
053import org.apache.maven.model.Scm;
054import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
055import org.apache.maven.project.artifact.InvalidDependencyVersionException;
056import org.apache.maven.project.artifact.MavenMetadataSource;
057import org.apache.maven.repository.RepositorySystem;
058import org.codehaus.plexus.classworlds.realm.ClassRealm;
059import org.codehaus.plexus.logging.Logger;
060import org.codehaus.plexus.util.StringUtils;
061import org.codehaus.plexus.util.xml.Xpp3Dom;
062import org.eclipse.aether.graph.DependencyFilter;
063import org.eclipse.aether.repository.RemoteRepository;
064
065import java.io.File;
066import java.io.IOException;
067import java.io.Writer;
068import java.util.ArrayList;
069import java.util.Arrays;
070import java.util.Collections;
071import java.util.HashMap;
072import java.util.HashSet;
073import java.util.LinkedHashMap;
074import java.util.LinkedHashSet;
075import java.util.List;
076import java.util.Map;
077import java.util.Properties;
078import java.util.Set;
079
080/**
081 * The concern of the project is provide runtime values based on the model.
082 * <p/>
083 * The values in the model remain untouched but during the process of building a project notions
084 * like inheritance and interpolation can be added. This allows to have an entity which is useful in
085 * a runtime while preserving the model so that it can be marshalled and unmarshalled without being
086 * tainted by runtime requirements.
087 * <p/>
088 * We need to leave the model intact because we don't want the following:
089 * <ol>
090 * <li>We don't want interpolated values being written back into the model.
091 * <li>We don't want inherited values being written back into the model.
092 * </ol>
093 */
094public class MavenProject
095    implements Cloneable
096{
097    public static final String EMPTY_PROJECT_GROUP_ID = "unknown";
098
099    public static final String EMPTY_PROJECT_ARTIFACT_ID = "empty-project";
100
101    public static final String EMPTY_PROJECT_VERSION = "0";
102
103    private static final MavenProject ERROR_BUILDING_PARENT = new MavenProject();
104
105    private Model model;
106
107    private MavenProject parent;
108
109    private File file;
110
111    private Set<Artifact> resolvedArtifacts;
112
113    private ArtifactFilter artifactFilter;
114
115    private Set<Artifact> artifacts;
116
117    private Artifact parentArtifact;
118
119    private Set<Artifact> pluginArtifacts;
120
121    private List<ArtifactRepository> remoteArtifactRepositories;
122
123    private List<ArtifactRepository> pluginArtifactRepositories;
124
125    private List<RemoteRepository> remoteProjectRepositories;
126
127    private List<RemoteRepository> remotePluginRepositories;
128
129    private List<Artifact> attachedArtifacts;
130
131    private MavenProject executionProject;
132
133    private List<MavenProject> collectedProjects;
134
135    private List<String> compileSourceRoots = new ArrayList<String>();
136
137    private List<String> testCompileSourceRoots = new ArrayList<String>();
138
139    private List<String> scriptSourceRoots = new ArrayList<String>();
140
141    private ArtifactRepository releaseArtifactRepository;
142
143    private ArtifactRepository snapshotArtifactRepository;
144
145    private List<Profile> activeProfiles = new ArrayList<Profile>();
146
147    private Map<String, List<String>> injectedProfileIds = new LinkedHashMap<String, List<String>>();
148
149    private Set<Artifact> dependencyArtifacts;
150
151    private Artifact artifact;
152
153    // calculated.
154    private Map<String, Artifact> artifactMap;
155
156    private Model originalModel;
157
158    private Map<String, Artifact> pluginArtifactMap;
159
160    private Set<Artifact> reportArtifacts;
161
162    private Map<String, Artifact> reportArtifactMap;
163
164    private Set<Artifact> extensionArtifacts;
165
166    private Map<String, Artifact> extensionArtifactMap;
167
168    private Map<String, Artifact> managedVersionMap;
169
170    private Map<String, MavenProject> projectReferences = new HashMap<String, MavenProject>();
171
172    private boolean executionRoot;
173
174    private Map<String, String> moduleAdjustments;
175
176    private ProjectBuilder mavenProjectBuilder;
177
178    private ProjectBuildingRequest projectBuilderConfiguration;
179
180    private RepositorySystem repositorySystem;
181    
182    private File parentFile;
183
184    private Map<String, Object> context;
185
186    private ClassRealm classRealm;
187
188    private DependencyFilter extensionDependencyFilter;
189
190    private final Set<String> lifecyclePhases = Collections.synchronizedSet( new LinkedHashSet<String>() );
191
192    private Logger logger;
193
194    public MavenProject()
195    {
196        Model model = new Model();
197
198        model.setGroupId( EMPTY_PROJECT_GROUP_ID );
199        model.setArtifactId( EMPTY_PROJECT_ARTIFACT_ID );
200        model.setVersion( EMPTY_PROJECT_VERSION );
201
202        setModel( model );
203    }
204
205    public MavenProject( Model model )
206    {
207        setModel( model );
208    }
209
210    /**
211     * @deprecated use {@link #clone()} so subclasses can provide a copy of the same class
212     */
213    @Deprecated
214    public MavenProject( MavenProject project )
215    {
216        repositorySystem = project.repositorySystem;
217        logger = project.logger;
218        mavenProjectBuilder = project.mavenProjectBuilder;
219        projectBuilderConfiguration = project.projectBuilderConfiguration;
220        deepCopy( project );
221    }
222    
223    @Deprecated
224    public MavenProject( Model model, RepositorySystem repositorySystem )
225    {        
226        this.repositorySystem = repositorySystem;
227        setModel( model );
228    }
229
230    public File getParentFile()
231    {
232        return parentFile;
233    }
234
235    public void setParentFile( File parentFile )
236    {
237        this.parentFile = parentFile;
238    }
239
240    /**
241     * Constructor
242     * 
243     * @param repositorySystem - may not be null
244     * @param mavenProjectBuilder
245     * @param projectBuilderConfiguration
246     * @throws InvalidRepositoryException
247     */
248    MavenProject( RepositorySystem repositorySystem, ProjectBuilder mavenProjectBuilder,
249                  ProjectBuildingRequest projectBuilderConfiguration, Logger logger )
250    {
251        if ( repositorySystem == null )
252        {
253            throw new IllegalArgumentException( "mavenTools: null" );
254        }
255
256        this.mavenProjectBuilder = mavenProjectBuilder;
257        this.projectBuilderConfiguration = projectBuilderConfiguration;
258        this.repositorySystem = repositorySystem;
259        this.logger = logger;
260    }
261
262    @Deprecated
263    public Set<Artifact> createArtifacts( ArtifactFactory artifactFactory, String inheritedScope, ArtifactFilter filter )
264        throws InvalidDependencyVersionException
265    {
266        return MavenMetadataSource.createArtifacts( artifactFactory, getDependencies(), inheritedScope, filter, this );
267    }
268
269    // TODO: Find a way to use <relativePath/> here...it's tricky, because the moduleProject
270    // usually doesn't have a file associated with it yet.
271    public String getModulePathAdjustment( MavenProject moduleProject )
272        throws IOException
273    {
274        // FIXME: This is hacky. What if module directory doesn't match artifactid, and parent
275        // is coming from the repository??
276        String module = moduleProject.getArtifactId();
277
278        File moduleFile = moduleProject.getFile();
279
280        if ( moduleFile != null )
281        {
282            File moduleDir = moduleFile.getCanonicalFile().getParentFile();
283
284            module = moduleDir.getName();
285        }
286
287        if ( moduleAdjustments == null )
288        {
289            moduleAdjustments = new HashMap<String, String>();
290
291            List<String> modules = getModules();
292            if ( modules != null )
293            {
294                for ( String modulePath : modules )
295                {
296                    String moduleName = modulePath;
297
298                    if ( moduleName.endsWith( "/" ) || moduleName.endsWith( "\\" ) )
299                    {
300                        moduleName = moduleName.substring( 0, moduleName.length() - 1 );
301                    }
302
303                    int lastSlash = moduleName.lastIndexOf( '/' );
304
305                    if ( lastSlash < 0 )
306                    {
307                        lastSlash = moduleName.lastIndexOf( '\\' );
308                    }
309
310                    String adjustment = null;
311
312                    if ( lastSlash > -1 )
313                    {
314                        moduleName = moduleName.substring( lastSlash + 1 );
315                        adjustment = modulePath.substring( 0, lastSlash );
316                    }
317
318                    moduleAdjustments.put( moduleName, adjustment );
319                }
320            }
321        }
322
323        return moduleAdjustments.get( module );
324    }
325
326    // ----------------------------------------------------------------------
327    // Accessors
328    // ----------------------------------------------------------------------
329
330    public Artifact getArtifact()
331    {
332        return artifact;
333    }
334
335    public void setArtifact( Artifact artifact )
336    {
337        this.artifact = artifact;
338    }
339
340    //@todo I would like to get rid of this. jvz.
341    public Model getModel()
342    {
343        return model;
344    }
345
346    /**
347     * Returns the project corresponding to a declared parent.
348     * @return the parent, or null if no parent is declared or there was an error building it
349     */
350    public MavenProject getParent()
351    {
352        if ( parent == null )
353        {
354            /*
355             * TODO: This is suboptimal. Without a cache in the project builder, rebuilding the parent chain currently
356             * causes O(n^2) parser invocations for an inheritance hierarchy of depth n.
357             */
358            if ( parentFile != null )
359            {
360                checkProjectBuildingRequest();
361                ProjectBuildingRequest request = new DefaultProjectBuildingRequest( projectBuilderConfiguration );
362                request.setRemoteRepositories( getRemoteArtifactRepositories() );
363
364                try
365                {
366                    parent = mavenProjectBuilder.build( parentFile, request ).getProject();
367                }
368                catch ( ProjectBuildingException e )
369                {
370                    if ( logger != null )
371                    {
372                        logger.error( "Failed to build parent project for " + getId(), e );
373                    }
374                    parent = ERROR_BUILDING_PARENT;
375                }
376            }
377            else if ( model.getParent() != null )
378            {
379                checkProjectBuildingRequest();
380                ProjectBuildingRequest request = new DefaultProjectBuildingRequest( projectBuilderConfiguration );
381                request.setRemoteRepositories( getRemoteArtifactRepositories() );
382                request.setResolveVersionRanges( true );
383
384                try
385                {
386                    parent = mavenProjectBuilder.build( repositorySystem.createProjectArtifact(
387                        model.getParent().getGroupId(), model.getParent().getArtifactId(),
388                        model.getParent().getVersion() ), request ).getProject();
389
390                    if ( !model.getParent().getVersion().equals( parent.getVersion() ) )
391                    {
392                        if ( model.getVersion() == null )
393                        {
394                            if ( logger != null )
395                            {
396                                logger.error( "Failed to build parent project for " + getId()
397                                                  + ": Parent version must be a constant" );
398
399                            }
400                            parent = ERROR_BUILDING_PARENT;
401                        }
402                        else
403                        {
404                            if ( model.getVersion().indexOf( "${" ) > -1 )
405                            {
406                                if ( logger != null )
407                                {
408                                    logger.error( "Failed to build parent project for " + getId() + ": The version '"
409                                                      + model.getParent().getVersion() + "' must be a constant" );
410
411                                }
412                                parent = ERROR_BUILDING_PARENT;
413                            }
414                        }
415
416                        // MNG-2199: What else to check here ?
417                    }
418                }
419                catch ( ProjectBuildingException e )
420                {
421                    if ( logger != null )
422                    {
423                        logger.error( "Failed to build parent project for " + getId(), e );
424                    }
425                    parent = ERROR_BUILDING_PARENT;
426                }
427            }
428        }
429        return parent == ERROR_BUILDING_PARENT ? null : parent;
430    }
431
432    public void setParent( MavenProject parent )
433    {
434        this.parent = parent;
435    }
436    
437    public boolean hasParent()
438    {
439        return getParent() != null;
440    }
441
442    public File getFile()
443    {
444        return file;
445    }
446
447    public void setFile( File file )
448    {
449        this.file = file;
450    }
451
452    public File getBasedir()
453    {
454        if ( getFile() != null )
455        {
456            return getFile().getParentFile();
457        }
458        else
459        {
460            // repository based POM
461            return null;
462        }
463    }
464
465    public void setDependencies( List<Dependency> dependencies )
466    {
467        getModel().setDependencies( dependencies );
468    }
469
470    public List<Dependency> getDependencies()
471    {
472        return getModel().getDependencies();
473    }
474
475    public DependencyManagement getDependencyManagement()
476    {
477        return getModel().getDependencyManagement();
478    }
479
480    // ----------------------------------------------------------------------
481    // Test and compile sourceroots.
482    // ----------------------------------------------------------------------
483
484    private void addPath( List<String> paths, String path )
485    {
486        if ( path != null )
487        {
488            path = path.trim();
489            if ( path.length() > 0 )
490            {
491                File file = new File( path );
492                if ( file.isAbsolute() )
493                {
494                    path = file.getAbsolutePath();
495                }
496                else
497                {
498                    path = new File( getBasedir(), path ).getAbsolutePath();
499                }
500
501                if ( !paths.contains( path ) )
502                {
503                    paths.add( path );
504                }
505            }
506        }
507    }
508
509    public void addCompileSourceRoot( String path )
510    {
511        addPath( getCompileSourceRoots(), path );
512    }
513
514    public void addScriptSourceRoot( String path )
515    {
516        if ( path != null )
517        {
518            path = path.trim();
519            if ( path.length() != 0 && !getScriptSourceRoots().contains( path ) )
520            {
521                getScriptSourceRoots().add( path );
522            }
523        }
524    }
525
526    public void addTestCompileSourceRoot( String path )
527    {
528        addPath( getTestCompileSourceRoots(), path );
529    }
530
531    public List<String> getCompileSourceRoots()
532    {
533        return compileSourceRoots;
534    }
535
536    public List<String> getScriptSourceRoots()
537    {
538        return scriptSourceRoots;
539    }
540
541    public List<String> getTestCompileSourceRoots()
542    {
543        return testCompileSourceRoots;
544    }
545
546    public List<String> getCompileClasspathElements()
547        throws DependencyResolutionRequiredException
548    {
549        List<String> list = new ArrayList<String>( getArtifacts().size() + 1 );
550
551        String d = getBuild().getOutputDirectory();
552        if ( d != null )
553        {
554            list.add( d );
555        }
556
557        for ( Artifact a : getArtifacts() )
558        {                        
559            if ( a.getArtifactHandler().isAddedToClasspath()
560            // TODO: let the scope handler deal with this
561                && ( Artifact.SCOPE_COMPILE.equals( a.getScope() ) || Artifact.SCOPE_PROVIDED.equals( a.getScope() ) || Artifact.SCOPE_SYSTEM.equals( a.getScope() ) ) )
562            {
563                addArtifactPath( a, list );
564            }
565        }
566
567        return list;
568    }
569
570    @Deprecated
571    public List<Artifact> getCompileArtifacts()
572    {
573        List<Artifact> list = new ArrayList<Artifact>( getArtifacts().size() );
574
575        for ( Artifact a : getArtifacts() )
576        {
577            // TODO: classpath check doesn't belong here - that's the other method
578            if ( a.getArtifactHandler().isAddedToClasspath()
579            // TODO: let the scope handler deal with this
580                && ( Artifact.SCOPE_COMPILE.equals( a.getScope() ) || Artifact.SCOPE_PROVIDED.equals( a.getScope() ) || Artifact.SCOPE_SYSTEM.equals( a.getScope() ) ) )
581            {
582                list.add( a );
583            }
584        }
585        return list;
586    }
587
588    @Deprecated
589    public List<Dependency> getCompileDependencies()
590    {
591        Set<Artifact> artifacts = getArtifacts();
592
593        if ( ( artifacts == null ) || artifacts.isEmpty() )
594        {
595            return Collections.emptyList();
596        }
597
598        List<Dependency> list = new ArrayList<Dependency>( artifacts.size() );
599
600        for ( Artifact a : getArtifacts()  )
601        {
602            // TODO: let the scope handler deal with this
603            if ( Artifact.SCOPE_COMPILE.equals( a.getScope() ) || Artifact.SCOPE_PROVIDED.equals( a.getScope() ) || Artifact.SCOPE_SYSTEM.equals( a.getScope() ) )
604            {
605                Dependency dependency = new Dependency();
606
607                dependency.setArtifactId( a.getArtifactId() );
608                dependency.setGroupId( a.getGroupId() );
609                dependency.setVersion( a.getVersion() );
610                dependency.setScope( a.getScope() );
611                dependency.setType( a.getType() );
612                dependency.setClassifier( a.getClassifier() );
613
614                list.add( dependency );
615            }
616        }
617        return list;
618    }
619
620    //TODO: this checking for file == null happens because the resolver has been confused about the root
621    // artifact or not. things like the stupid dummy artifact coming from surefire.
622    public List<String> getTestClasspathElements()
623        throws DependencyResolutionRequiredException
624    {
625        List<String> list = new ArrayList<String>( getArtifacts().size() + 2 );
626
627        String d = getBuild().getTestOutputDirectory();
628        if ( d != null )
629        {
630            list.add( d );
631        }
632
633        d = getBuild().getOutputDirectory();
634        if ( d != null )
635        {
636            list.add( d );
637        }
638        
639        for ( Artifact a : getArtifacts() )
640        {            
641            if ( a.getArtifactHandler().isAddedToClasspath() )
642            {                
643                addArtifactPath( a, list );
644            }
645        }
646
647        return list;
648    }
649
650    @Deprecated
651    public List<Artifact> getTestArtifacts()
652    {
653        List<Artifact> list = new ArrayList<Artifact>( getArtifacts().size() );
654
655        for ( Artifact a : getArtifacts() )
656        {
657            // TODO: classpath check doesn't belong here - that's the other method
658            if ( a.getArtifactHandler().isAddedToClasspath() )
659            {
660                list.add( a );
661            }
662        }
663        return list;
664    }
665
666    @Deprecated
667    public List<Dependency> getTestDependencies()
668    {
669        Set<Artifact> artifacts = getArtifacts();
670
671        if ( ( artifacts == null ) || artifacts.isEmpty() )
672        {
673            return Collections.emptyList();
674        }
675
676        List<Dependency> list = new ArrayList<Dependency>( artifacts.size() );
677
678        for ( Artifact a : getArtifacts()  )
679        {
680            Dependency dependency = new Dependency();
681
682            dependency.setArtifactId( a.getArtifactId() );
683            dependency.setGroupId( a.getGroupId() );
684            dependency.setVersion( a.getVersion() );
685            dependency.setScope( a.getScope() );
686            dependency.setType( a.getType() );
687            dependency.setClassifier( a.getClassifier() );
688
689            list.add( dependency );
690        }
691        return list;
692    }
693
694    public List<String> getRuntimeClasspathElements()
695        throws DependencyResolutionRequiredException
696    {
697        List<String> list = new ArrayList<String>( getArtifacts().size() + 1 );
698
699        String d = getBuild().getOutputDirectory();
700        if ( d != null )
701        {
702            list.add( d );
703        }
704
705        for ( Artifact a : getArtifacts() )
706        {
707            if ( a.getArtifactHandler().isAddedToClasspath()
708            // TODO: let the scope handler deal with this
709                && ( Artifact.SCOPE_COMPILE.equals( a.getScope() ) || Artifact.SCOPE_RUNTIME.equals( a.getScope() ) ) )
710            {
711                addArtifactPath( a, list );
712            }
713        }
714        return list;
715    }
716
717    @Deprecated
718    public List<Artifact> getRuntimeArtifacts()
719    {
720        List<Artifact> list = new ArrayList<Artifact>( getArtifacts().size() );
721
722        for ( Artifact a : getArtifacts()  )
723        {
724            // TODO: classpath check doesn't belong here - that's the other method
725            if ( a.getArtifactHandler().isAddedToClasspath()
726            // TODO: let the scope handler deal with this
727                && ( Artifact.SCOPE_COMPILE.equals( a.getScope() ) || Artifact.SCOPE_RUNTIME.equals( a.getScope() ) ) )
728            {
729                list.add( a );
730            }
731        }
732        return list;
733    }
734
735    @Deprecated
736    public List<Dependency> getRuntimeDependencies()
737    {
738        Set<Artifact> artifacts = getArtifacts();
739
740        if ( ( artifacts == null ) || artifacts.isEmpty() )
741        {
742            return Collections.emptyList();
743        }
744
745        List<Dependency> list = new ArrayList<Dependency>( artifacts.size() );
746
747        for ( Artifact a : getArtifacts()  )
748        {
749            // TODO: let the scope handler deal with this
750            if ( Artifact.SCOPE_COMPILE.equals( a.getScope() ) || Artifact.SCOPE_RUNTIME.equals( a.getScope() ) )
751            {
752                Dependency dependency = new Dependency();
753
754                dependency.setArtifactId( a.getArtifactId() );
755                dependency.setGroupId( a.getGroupId() );
756                dependency.setVersion( a.getVersion() );
757                dependency.setScope( a.getScope() );
758                dependency.setType( a.getType() );
759                dependency.setClassifier( a.getClassifier() );
760
761                list.add( dependency );
762            }
763        }
764        return list;
765    }
766
767    public List<String> getSystemClasspathElements()
768        throws DependencyResolutionRequiredException
769    {
770        List<String> list = new ArrayList<String>( getArtifacts().size() );
771
772        String d = getBuild().getOutputDirectory();
773        if ( d != null )
774        {
775            list.add( d );
776        }
777
778        for ( Artifact a : getArtifacts() )
779        {
780            if ( a.getArtifactHandler().isAddedToClasspath()
781            // TODO: let the scope handler deal with this
782                && Artifact.SCOPE_SYSTEM.equals( a.getScope() ) )
783            {
784                addArtifactPath( a, list );
785            }
786        }
787        return list;
788    }
789
790    @Deprecated
791    public List<Artifact> getSystemArtifacts()
792    {
793        List<Artifact> list = new ArrayList<Artifact>( getArtifacts().size() );
794
795        for ( Artifact a : getArtifacts()  )
796        {
797            // TODO: classpath check doesn't belong here - that's the other method
798            if ( a.getArtifactHandler().isAddedToClasspath()
799            // TODO: let the scope handler deal with this
800                && Artifact.SCOPE_SYSTEM.equals( a.getScope() ) )
801            {
802                list.add( a );
803            }
804        }
805        return list;
806    }
807
808    @Deprecated
809    public List<Dependency> getSystemDependencies()
810    {
811        Set<Artifact> artifacts = getArtifacts();
812
813        if ( ( artifacts == null ) || artifacts.isEmpty() )
814        {
815            return Collections.emptyList();
816        }
817
818        List<Dependency> list = new ArrayList<Dependency>( artifacts.size() );
819
820        for ( Artifact a : getArtifacts()  )
821        {
822            // TODO: let the scope handler deal with this
823            if ( Artifact.SCOPE_SYSTEM.equals( a.getScope() ) )
824            {
825                Dependency dependency = new Dependency();
826
827                dependency.setArtifactId( a.getArtifactId() );
828                dependency.setGroupId( a.getGroupId() );
829                dependency.setVersion( a.getVersion() );
830                dependency.setScope( a.getScope() );
831                dependency.setType( a.getType() );
832                dependency.setClassifier( a.getClassifier() );
833
834                list.add( dependency );
835            }
836        }
837        return list;
838    }
839
840    // ----------------------------------------------------------------------
841    // Delegate to the model
842    // ----------------------------------------------------------------------
843
844    public void setModelVersion( String pomVersion )
845    {
846        getModel().setModelVersion( pomVersion );
847    }
848
849    public String getModelVersion()
850    {
851        return getModel().getModelVersion();
852    }
853
854    public String getId()
855    {
856        return getModel().getId();
857    }
858
859    public void setGroupId( String groupId )
860    {
861        getModel().setGroupId( groupId );
862    }
863
864    public String getGroupId()
865    {
866        String groupId = getModel().getGroupId();
867
868        if ( ( groupId == null ) && ( getModel().getParent() != null ) )
869        {
870            groupId = getModel().getParent().getGroupId();
871        }
872
873        return groupId;
874    }
875
876    public void setArtifactId( String artifactId )
877    {
878        getModel().setArtifactId( artifactId );
879    }
880
881    public String getArtifactId()
882    {
883        return getModel().getArtifactId();
884    }
885
886    public void setName( String name )
887    {
888        getModel().setName( name );
889    }
890
891    public String getName()
892    {
893        // TODO: this should not be allowed to be null.
894        if ( getModel().getName() != null )
895        {
896            return getModel().getName();
897        }
898        else
899        {
900            return getArtifactId();
901        }
902    }
903
904    public void setVersion( String version )
905    {
906        getModel().setVersion( version );
907    }
908
909    public String getVersion()
910    {
911        String version = getModel().getVersion();
912
913        if ( ( version == null ) && ( getModel().getParent() != null ) )
914        {
915            version = getModel().getParent().getVersion();
916        }
917
918        return version;
919    }
920
921    public String getPackaging()
922    {
923        return getModel().getPackaging();
924    }
925
926    public void setPackaging( String packaging )
927    {
928        getModel().setPackaging( packaging );
929    }
930
931    public void setInceptionYear( String inceptionYear )
932    {
933        getModel().setInceptionYear( inceptionYear );
934    }
935
936    public String getInceptionYear()
937    {
938        return getModel().getInceptionYear();
939    }
940
941    public void setUrl( String url )
942    {
943        getModel().setUrl( url );
944    }
945
946    public String getUrl()
947    {
948        return getModel().getUrl();
949    }
950
951    public Prerequisites getPrerequisites()
952    {
953        return getModel().getPrerequisites();
954    }
955
956    public void setIssueManagement( IssueManagement issueManagement )
957    {
958        getModel().setIssueManagement( issueManagement );
959    }
960
961    public CiManagement getCiManagement()
962    {
963        return getModel().getCiManagement();
964    }
965
966    public void setCiManagement( CiManagement ciManagement )
967    {
968        getModel().setCiManagement( ciManagement );
969    }
970
971    public IssueManagement getIssueManagement()
972    {
973        return getModel().getIssueManagement();
974    }
975
976    public void setDistributionManagement( DistributionManagement distributionManagement )
977    {
978        getModel().setDistributionManagement( distributionManagement );
979    }
980
981    public DistributionManagement getDistributionManagement()
982    {
983        return getModel().getDistributionManagement();
984    }
985
986    public void setDescription( String description )
987    {
988        getModel().setDescription( description );
989    }
990
991    public String getDescription()
992    {
993        return getModel().getDescription();
994    }
995
996    public void setOrganization( Organization organization )
997    {
998        getModel().setOrganization( organization );
999    }
1000
1001    public Organization getOrganization()
1002    {
1003        return getModel().getOrganization();
1004    }
1005
1006    public void setScm( Scm scm )
1007    {
1008        getModel().setScm( scm );
1009    }
1010
1011    public Scm getScm()
1012    {
1013        return getModel().getScm();
1014    }
1015
1016    public void setMailingLists( List<MailingList> mailingLists )
1017    {
1018        getModel().setMailingLists( mailingLists );
1019    }
1020
1021    public List<MailingList> getMailingLists()
1022    {
1023        return getModel().getMailingLists();
1024    }
1025
1026    public void addMailingList( MailingList mailingList )
1027    {
1028        getModel().addMailingList( mailingList );
1029    }
1030
1031    public void setDevelopers( List<Developer> developers )
1032    {
1033        getModel().setDevelopers( developers );
1034    }
1035
1036    public List<Developer> getDevelopers()
1037    {
1038        return getModel().getDevelopers();
1039    }
1040
1041    public void addDeveloper( Developer developer )
1042    {
1043        getModel().addDeveloper( developer );
1044    }
1045
1046    public void setContributors( List<Contributor> contributors )
1047    {
1048        getModel().setContributors( contributors );
1049    }
1050
1051    public List<Contributor> getContributors()
1052    {
1053        return getModel().getContributors();
1054    }
1055
1056    public void addContributor( Contributor contributor )
1057    {
1058        getModel().addContributor( contributor );
1059    }
1060
1061    public void setBuild( Build build )
1062    {
1063        getModel().setBuild( build );
1064    }
1065
1066    public Build getBuild()
1067    {
1068        return getModelBuild();
1069    }
1070
1071    public List<Resource> getResources()
1072    {
1073        return getBuild().getResources();
1074    }
1075
1076    public List<Resource> getTestResources()
1077    {
1078        return getBuild().getTestResources();
1079    }
1080
1081    public void addResource( Resource resource )
1082    {
1083        getBuild().addResource( resource );
1084    }
1085
1086    public void addTestResource( Resource testResource )
1087    {
1088        getBuild().addTestResource( testResource );
1089    }
1090
1091    @Deprecated
1092    public void setReporting( Reporting reporting )
1093    {
1094        getModel().setReporting( reporting );
1095    }
1096
1097    @Deprecated
1098    public Reporting getReporting()
1099    {
1100        return getModel().getReporting();
1101    }
1102
1103    public void setLicenses( List<License> licenses )
1104    {
1105        getModel().setLicenses( licenses );
1106    }
1107
1108    public List<License> getLicenses()
1109    {
1110        return getModel().getLicenses();
1111    }
1112
1113    public void addLicense( License license )
1114    {
1115        getModel().addLicense( license );
1116    }
1117
1118    public void setArtifacts( Set<Artifact> artifacts )
1119    {
1120        this.artifacts = artifacts;
1121
1122        // flush the calculated artifactMap
1123        artifactMap = null;
1124    }
1125
1126    /**
1127     * All dependencies that this project has, including transitive ones. Contents are lazily
1128     * populated, so depending on what phases have run dependencies in some scopes won't be
1129     * included. eg. if only compile phase has run, dependencies with scope test won't be included.
1130     * 
1131     * @return {@link Set} &lt; {@link Artifact} >
1132     * @see #getDependencyArtifacts() to get only direct dependencies
1133     */
1134    public Set<Artifact> getArtifacts()
1135    {
1136        if ( artifacts == null )
1137        {
1138            if ( artifactFilter == null || resolvedArtifacts == null )
1139            {
1140                artifacts = new LinkedHashSet<Artifact>();
1141            }
1142            else
1143            {
1144                artifacts = new LinkedHashSet<Artifact>( resolvedArtifacts.size() * 2 );
1145                for ( Artifact artifact : resolvedArtifacts )
1146                {
1147                    if ( artifactFilter.include( artifact ) )
1148                    {
1149                        artifacts.add( artifact );
1150                    }
1151                }
1152            }
1153        }
1154        return artifacts;
1155    }
1156
1157    public Map<String, Artifact> getArtifactMap()
1158    {
1159        if ( artifactMap == null )
1160        {
1161            artifactMap = ArtifactUtils.artifactMapByVersionlessId( getArtifacts() );
1162        }
1163        return artifactMap;
1164    }
1165
1166    public void setPluginArtifacts( Set<Artifact> pluginArtifacts )
1167    {
1168        this.pluginArtifacts = pluginArtifacts;
1169
1170        this.pluginArtifactMap = null;
1171    }
1172
1173    public Set<Artifact> getPluginArtifacts()
1174    {
1175        if ( pluginArtifacts != null )
1176        {
1177            return pluginArtifacts;
1178        }
1179
1180        pluginArtifacts = new HashSet<Artifact>();
1181
1182        if ( repositorySystem != null )
1183        {
1184            for ( Plugin p : getBuildPlugins() )
1185            {
1186                Artifact artifact = repositorySystem.createPluginArtifact( p );
1187
1188                if ( artifact != null )
1189                {
1190                    pluginArtifacts.add( artifact );
1191                }
1192            }
1193        }
1194
1195        pluginArtifactMap = null;
1196
1197        return pluginArtifacts;
1198    }
1199
1200    public Map<String, Artifact> getPluginArtifactMap()
1201    {
1202        if ( pluginArtifactMap == null )
1203        {
1204            pluginArtifactMap = ArtifactUtils.artifactMapByVersionlessId( getPluginArtifacts() );
1205        }
1206
1207        return pluginArtifactMap;
1208    }
1209
1210    @Deprecated
1211    public void setReportArtifacts( Set<Artifact> reportArtifacts )
1212    {
1213        this.reportArtifacts = reportArtifacts;
1214
1215        reportArtifactMap = null;
1216    }
1217
1218    @Deprecated
1219    public Set<Artifact> getReportArtifacts()
1220    {
1221        if ( reportArtifacts != null )
1222        {
1223            return reportArtifacts;
1224        }
1225
1226        reportArtifacts = new HashSet<Artifact>();
1227
1228        if ( repositorySystem != null )
1229        {
1230            for ( ReportPlugin p : getReportPlugins() )
1231            {
1232                Plugin pp = new Plugin();
1233                pp.setGroupId( p.getGroupId() );
1234                pp.setArtifactId( p.getArtifactId() );
1235                pp.setVersion( p.getVersion() );
1236
1237                Artifact artifact = repositorySystem.createPluginArtifact( pp );
1238
1239                if ( artifact != null )
1240                {
1241                    reportArtifacts.add( artifact );
1242                }
1243            }
1244        }
1245
1246        reportArtifactMap = null;
1247
1248        return reportArtifacts;
1249    }
1250
1251    @Deprecated
1252    public Map<String, Artifact> getReportArtifactMap()
1253    {
1254        if ( reportArtifactMap == null )
1255        {
1256            reportArtifactMap = ArtifactUtils.artifactMapByVersionlessId( getReportArtifacts() );
1257        }
1258
1259        return reportArtifactMap;
1260    }
1261
1262    public void setExtensionArtifacts( Set<Artifact> extensionArtifacts )
1263    {
1264        this.extensionArtifacts = extensionArtifacts;
1265
1266        extensionArtifactMap = null;
1267    }
1268
1269    public Set<Artifact> getExtensionArtifacts()
1270    {
1271        if ( extensionArtifacts != null )
1272        {
1273            return extensionArtifacts;
1274        }
1275        extensionArtifacts = new HashSet<Artifact>();
1276        List<Extension> extensions = getBuildExtensions();
1277        if ( extensions != null )
1278        {
1279            for ( Extension ext : extensions )
1280            {
1281                String version;
1282                if ( StringUtils.isEmpty( ext.getVersion() ) )
1283                {
1284                    version = "RELEASE";
1285                }
1286                else
1287                {
1288                    version = ext.getVersion();
1289                }
1290
1291                Artifact artifact =
1292                    repositorySystem.createArtifact( ext.getGroupId(), ext.getArtifactId(), version, null, "jar" );
1293
1294                if ( artifact != null )
1295                {
1296                    extensionArtifacts.add( artifact );
1297                }
1298            }
1299        }
1300        extensionArtifactMap = null;
1301        return extensionArtifacts;
1302    }
1303
1304    public Map<String, Artifact> getExtensionArtifactMap()
1305    {
1306        if ( extensionArtifactMap == null )
1307        {
1308            extensionArtifactMap = ArtifactUtils.artifactMapByVersionlessId( getExtensionArtifacts() );
1309        }
1310
1311        return extensionArtifactMap;
1312    }
1313
1314    public void setParentArtifact( Artifact parentArtifact )
1315    {
1316        this.parentArtifact = parentArtifact;
1317    }
1318
1319    public Artifact getParentArtifact()
1320    {
1321        if ( parentArtifact == null && getParent() != null )
1322        {
1323            parentArtifact = repositorySystem.createProjectArtifact(
1324                getParent().getGroupId(), getParent().getArtifactId(), getParent().getVersion() );
1325
1326        }
1327        return parentArtifact;
1328    }
1329
1330    public List<Repository> getRepositories()
1331    {
1332        return getModel().getRepositories();
1333    }
1334
1335    // ----------------------------------------------------------------------
1336    // Plugins
1337    // ----------------------------------------------------------------------
1338
1339    @Deprecated
1340    public List<ReportPlugin> getReportPlugins()
1341    {
1342        if ( getModel().getReporting() == null )
1343        {
1344            return Collections.emptyList();
1345        }
1346        return getModel().getReporting().getPlugins();
1347
1348    }
1349
1350    public List<Plugin> getBuildPlugins()
1351    {
1352        if ( getModel().getBuild() == null )
1353        {
1354            return Collections.emptyList();
1355        }
1356        return getModel().getBuild().getPlugins();
1357    }
1358
1359    public List<String> getModules()
1360    {
1361        return getModel().getModules();
1362    }
1363
1364    public PluginManagement getPluginManagement()
1365    {
1366        PluginManagement pluginMgmt = null;
1367
1368        Build build = getModel().getBuild();
1369        if ( build != null )
1370        {
1371            pluginMgmt = build.getPluginManagement();
1372        }
1373
1374        return pluginMgmt;
1375    }
1376
1377    private Build getModelBuild()
1378    {
1379        Build build = getModel().getBuild();
1380
1381        if ( build == null )
1382        {
1383            build = new Build();
1384
1385            getModel().setBuild( build );
1386        }
1387
1388        return build;
1389    }
1390
1391    public void setRemoteArtifactRepositories( List<ArtifactRepository> remoteArtifactRepositories )
1392    {
1393        this.remoteArtifactRepositories = remoteArtifactRepositories;
1394        this.remoteProjectRepositories = RepositoryUtils.toRepos( getRemoteArtifactRepositories() );
1395    }
1396
1397    public List<ArtifactRepository> getRemoteArtifactRepositories()
1398    {
1399        if ( remoteArtifactRepositories == null )
1400        {
1401            remoteArtifactRepositories = new ArrayList<ArtifactRepository>();
1402        }
1403
1404        return remoteArtifactRepositories;
1405    }
1406
1407    public void setPluginArtifactRepositories( List<ArtifactRepository> pluginArtifactRepositories )
1408    {
1409        this.pluginArtifactRepositories = pluginArtifactRepositories;
1410        this.remotePluginRepositories = RepositoryUtils.toRepos( getPluginArtifactRepositories() );
1411    }
1412
1413    /**
1414     * @return a list of ArtifactRepository objects constructed from the Repository objects returned
1415     *         by getPluginRepositories.
1416     */
1417    public List<ArtifactRepository> getPluginArtifactRepositories()
1418    {
1419        if ( pluginArtifactRepositories == null )
1420        {
1421            pluginArtifactRepositories = new ArrayList<ArtifactRepository>();
1422        }
1423
1424        return pluginArtifactRepositories;
1425    }
1426
1427    public ArtifactRepository getDistributionManagementArtifactRepository()
1428    {
1429        return getArtifact().isSnapshot() && ( getSnapshotArtifactRepository() != null ) ? getSnapshotArtifactRepository() : getReleaseArtifactRepository();
1430    }
1431
1432    public List<Repository> getPluginRepositories()
1433    {
1434        return getModel().getPluginRepositories();
1435    }
1436
1437    public List<RemoteRepository> getRemoteProjectRepositories()
1438    {
1439        return remoteProjectRepositories;
1440    }
1441
1442    public List<RemoteRepository> getRemotePluginRepositories()
1443    {
1444        return remotePluginRepositories;
1445    }
1446
1447    public void setActiveProfiles( List<Profile> activeProfiles )
1448    {
1449        this.activeProfiles = activeProfiles;
1450    }
1451
1452    public List<Profile> getActiveProfiles()
1453    {
1454        return activeProfiles;
1455    }
1456
1457    public void setInjectedProfileIds( String source, List<String> injectedProfileIds )
1458    {
1459        if ( injectedProfileIds != null )
1460        {
1461            this.injectedProfileIds.put( source, new ArrayList<String>( injectedProfileIds ) );
1462        }
1463        else
1464        {
1465            this.injectedProfileIds.remove( source );
1466        }
1467    }
1468
1469    /**
1470     * Gets the identifiers of all profiles that contributed to this project's effective model. This includes active
1471     * profiles from the project's POM and all its parent POMs as well as from external sources like the {@code
1472     * settings.xml}. The profile identifiers are grouped by the identifier of their source, e.g. {@code
1473     * <groupId>:<artifactId>:<version>} for a POM profile or {@code external} for profiles from the {@code
1474     * settings.xml}.
1475     * 
1476     * @return The identifiers of all injected profiles, indexed by the source from which the profiles originated, never
1477     *         {@code null}.
1478     */
1479    public Map<String, List<String>> getInjectedProfileIds()
1480    {
1481        return this.injectedProfileIds;
1482    }
1483
1484    private String logStringForArtifactFile( Artifact a )
1485    {
1486        if ( a.getFile() != null )
1487        {
1488            return a.getFile().getAbsolutePath();
1489        }
1490        else
1491        {
1492            return "(no path)";
1493        }
1494    }
1495
1496    /**
1497     * Add or replace an artifact.
1498     * In spite of the 'throws' declaration on this API, this method has never thrown an exception since Maven 3.0.x.
1499     * Historically, it logged and ignored a second addition of the same g/a/v/c/t. Now it replaces the file for
1500     * the artifact, so that plugins (e.g. shade) can change the pathname of the file for a particular set of
1501     * coordinates.
1502     * @param artifact the artifact to add or replace.
1503     * @throws DuplicateArtifactAttachmentException
1504     */
1505    public void addAttachedArtifact( Artifact artifact )
1506        throws DuplicateArtifactAttachmentException
1507    {
1508        List<Artifact> attachedArtifacts = getAttachedArtifacts();
1509        for ( int ax = 0; ax < attachedArtifacts.size(); ax++ )
1510        {
1511            Artifact a = attachedArtifacts.get( ax );
1512            if ( a.equals( artifact ) )
1513            {
1514                if ( logger != null )
1515                {
1516                    logger.debug( String.format( "Replacing attached artifact %s. Old path %s, new path %s. ",
1517                                                 a,
1518                                                 logStringForArtifactFile( a ),
1519                                                 logStringForArtifactFile( artifact ) ) );
1520                }
1521                attachedArtifacts.set( ax, artifact );
1522                return;
1523            }
1524        }
1525
1526        getAttachedArtifacts().add( artifact );
1527    }
1528
1529    public List<Artifact> getAttachedArtifacts()
1530    {
1531        if ( attachedArtifacts == null )
1532        {
1533            attachedArtifacts = new ArrayList<Artifact>();
1534        }
1535        return attachedArtifacts;
1536    }
1537
1538    public Xpp3Dom getGoalConfiguration( String pluginGroupId, String pluginArtifactId, String executionId,
1539                                         String goalId )
1540    {
1541        Xpp3Dom dom = null;
1542
1543        if ( getBuildPlugins() != null )
1544        {
1545            for ( Plugin plugin : getBuildPlugins() )
1546            {
1547                if ( pluginGroupId.equals( plugin.getGroupId() ) && pluginArtifactId.equals( plugin.getArtifactId() ) )
1548                {
1549                    dom = (Xpp3Dom) plugin.getConfiguration();
1550
1551                    if ( executionId != null )
1552                    {
1553                        PluginExecution execution = plugin.getExecutionsAsMap().get( executionId );
1554                        if ( execution != null )
1555                        {
1556                            // NOTE: The PluginConfigurationExpander already merged the plugin-level config in
1557                            dom = (Xpp3Dom) execution.getConfiguration();
1558                        }
1559                    }
1560                    break;
1561                }
1562            }
1563        }
1564
1565        if ( dom != null )
1566        {
1567            // make a copy so the original in the POM doesn't get messed with
1568            dom = new Xpp3Dom( dom );
1569        }
1570
1571        return dom;
1572    }
1573
1574    @Deprecated
1575    public Xpp3Dom getReportConfiguration( String pluginGroupId, String pluginArtifactId, String reportSetId )
1576    {
1577        Xpp3Dom dom = null;
1578
1579        // ----------------------------------------------------------------------
1580        // I would like to be able to lookup the Mojo object using a key but
1581        // we have a limitation in modello that will be remedied shortly. So
1582        // for now I have to iterate through and see what we have.
1583        // ----------------------------------------------------------------------
1584
1585        if ( getReportPlugins() != null )
1586        {
1587            for ( ReportPlugin plugin : getReportPlugins() )
1588            {
1589                if ( pluginGroupId.equals( plugin.getGroupId() ) && pluginArtifactId.equals( plugin.getArtifactId() ) )
1590                {
1591                    dom = (Xpp3Dom) plugin.getConfiguration();
1592
1593                    if ( reportSetId != null )
1594                    {
1595                        ReportSet reportSet = plugin.getReportSetsAsMap().get( reportSetId );
1596                        if ( reportSet != null )
1597                        {
1598                            Xpp3Dom executionConfiguration = (Xpp3Dom) reportSet.getConfiguration();
1599                            if ( executionConfiguration != null )
1600                            {
1601                                Xpp3Dom newDom = new Xpp3Dom( executionConfiguration );
1602                                dom = Xpp3Dom.mergeXpp3Dom( newDom, dom );
1603                            }
1604                        }
1605                    }
1606                    break;
1607                }
1608            }
1609        }
1610
1611        if ( dom != null )
1612        {
1613            // make a copy so the original in the POM doesn't get messed with
1614            dom = new Xpp3Dom( dom );
1615        }
1616
1617        return dom;
1618    }
1619
1620    public MavenProject getExecutionProject()
1621    {
1622        return ( executionProject == null ? this : executionProject );
1623    }
1624
1625    public void setExecutionProject( MavenProject executionProject )
1626    {
1627        this.executionProject = executionProject;
1628    }
1629
1630    public List<MavenProject> getCollectedProjects()
1631    {
1632        return collectedProjects;
1633    }
1634
1635    public void setCollectedProjects( List<MavenProject> collectedProjects )
1636    {
1637        this.collectedProjects = collectedProjects;
1638    }
1639
1640    /**
1641     * Direct dependencies that this project has.
1642     * 
1643     * @return {@link Set} &lt; {@link Artifact} >
1644     * @see #getArtifacts() to get all transitive dependencies
1645     */
1646    public Set<Artifact> getDependencyArtifacts()
1647    {
1648        return dependencyArtifacts;
1649    }
1650
1651    public void setDependencyArtifacts( Set<Artifact> dependencyArtifacts )
1652    {
1653        this.dependencyArtifacts = dependencyArtifacts;
1654    }
1655
1656    public void setReleaseArtifactRepository( ArtifactRepository releaseArtifactRepository )
1657    {
1658        this.releaseArtifactRepository = releaseArtifactRepository;
1659    }
1660
1661    public void setSnapshotArtifactRepository( ArtifactRepository snapshotArtifactRepository )
1662    {
1663        this.snapshotArtifactRepository = snapshotArtifactRepository;
1664    }
1665
1666    public void setOriginalModel( Model originalModel )
1667    {
1668        this.originalModel = originalModel;
1669    }
1670
1671    public Model getOriginalModel()
1672    {
1673        return originalModel;
1674    }
1675
1676    public void setManagedVersionMap( Map<String, Artifact> map )
1677    {
1678        managedVersionMap = map;
1679    }
1680
1681    public Map<String, Artifact> getManagedVersionMap()
1682    {
1683        if ( managedVersionMap != null )
1684        {
1685            return managedVersionMap;
1686        }
1687
1688        Map<String, Artifact> map = null;
1689        if ( repositorySystem != null )
1690        {
1691
1692            List<Dependency> deps;
1693            DependencyManagement dependencyManagement = getDependencyManagement();
1694            if ( ( dependencyManagement != null ) && ( ( deps = dependencyManagement.getDependencies() ) != null ) && ( deps.size() > 0 ) )
1695            {
1696                map = new HashMap<String, Artifact>();
1697                for ( Dependency d : dependencyManagement.getDependencies() )
1698                {
1699                    Artifact artifact = repositorySystem.createDependencyArtifact( d );
1700
1701                    if ( artifact == null )
1702                    {
1703                        map = Collections.emptyMap();
1704                    }
1705
1706                    map.put( d.getManagementKey(), artifact );
1707                }
1708            }
1709            else
1710            {
1711                map = Collections.emptyMap();
1712            }
1713        }
1714        managedVersionMap = map;
1715        return managedVersionMap;
1716    }
1717
1718    @Override
1719    public boolean equals( Object other )
1720    {
1721        if ( other == this )
1722        {
1723            return true;
1724        }
1725        else if ( !( other instanceof MavenProject ) )
1726        {
1727            return false;
1728        }
1729
1730        MavenProject that = (MavenProject) other;
1731
1732        return eq( getArtifactId(), that.getArtifactId() )
1733            && eq( getGroupId(), that.getGroupId() )
1734            && eq( getVersion(), that.getVersion() );
1735    }
1736
1737    private static <T> boolean eq( T s1, T s2 )
1738    {
1739        return ( s1 != null ) ? s1.equals( s2 ) : s2 == null;
1740    }
1741
1742    @Override
1743    public int hashCode()
1744    {
1745        int hash = 17;
1746        hash = 31 * hash + getGroupId().hashCode();
1747        hash = 31 * hash + getArtifactId().hashCode();
1748        hash = 31 * hash + getVersion().hashCode();
1749        return hash;
1750    }
1751
1752    public List<Extension> getBuildExtensions()
1753    {
1754        Build build = getBuild();
1755        if ( ( build == null ) || ( build.getExtensions() == null ) )
1756        {
1757            return Collections.emptyList();
1758        }
1759        else
1760        {
1761            return build.getExtensions();
1762        }
1763    }
1764
1765    public void addProjectReference( MavenProject project )
1766    {
1767        projectReferences.put( getProjectReferenceId( project.getGroupId(), project.getArtifactId(), project.getVersion() ), project );
1768    }
1769
1770    /**
1771     * @deprecated Use MavenProjectHelper.attachArtifact(..) instead.
1772     */
1773    @Deprecated
1774    public void attachArtifact( String type, String classifier, File file )
1775    {
1776    }
1777
1778    public Properties getProperties()
1779    {
1780        return getModel().getProperties();
1781    }
1782
1783    public List<String> getFilters()
1784    {
1785        return getBuild().getFilters();
1786    }
1787
1788    public Map<String, MavenProject> getProjectReferences()
1789    {
1790        return projectReferences;
1791    }
1792
1793    public boolean isExecutionRoot()
1794    {
1795        return executionRoot;
1796    }
1797
1798    public void setExecutionRoot( boolean executionRoot )
1799    {
1800        this.executionRoot = executionRoot;
1801    }
1802
1803    public String getDefaultGoal()
1804    {
1805        return getBuild() != null ? getBuild().getDefaultGoal() : null;
1806    }
1807
1808    public Plugin getPlugin( String pluginKey )
1809    {
1810        return getBuild().getPluginsAsMap().get( pluginKey );
1811    }
1812
1813    /**
1814     * Default toString
1815     */
1816    @Override
1817    public String toString()
1818    {
1819        StringBuilder sb = new StringBuilder( 128 );
1820        sb.append( "MavenProject: " );
1821        sb.append( getGroupId() );
1822        sb.append( ":" );
1823        sb.append( getArtifactId() );
1824        sb.append( ":" );
1825        sb.append( getVersion() );
1826        sb.append( " @ " );
1827
1828        try
1829        {
1830            sb.append( getFile().getPath() );
1831        }
1832        catch ( NullPointerException e )
1833        {
1834            //don't log it.
1835        }
1836
1837        return sb.toString();
1838    }
1839
1840    /**
1841     * @deprecated Use {@link org.apache.maven.model.io.ModelWriter}.
1842     */
1843    @Deprecated
1844    public void writeModel( Writer writer )
1845        throws IOException
1846    {
1847        MavenXpp3Writer pomWriter = new MavenXpp3Writer();
1848        pomWriter.write( writer, getModel() );
1849    }
1850
1851    /**
1852     * @deprecated Use {@link org.apache.maven.model.io.ModelWriter}.
1853     */
1854    @Deprecated
1855    public void writeOriginalModel( Writer writer )
1856        throws IOException
1857    {
1858        MavenXpp3Writer pomWriter = new MavenXpp3Writer();
1859        pomWriter.write( writer, getOriginalModel() );
1860    }
1861
1862    /**
1863     * @throws CloneNotSupportedException
1864     * @since 2.0.9
1865     */
1866    @Override
1867    public MavenProject clone()
1868    {
1869        MavenProject clone;
1870        try
1871        {
1872            clone = (MavenProject) super.clone();
1873        }
1874        catch ( CloneNotSupportedException e )
1875        {
1876            throw new UnsupportedOperationException( e );
1877        }
1878
1879        clone.deepCopy( this );
1880
1881        return clone;
1882    }
1883
1884    protected void setModel( Model model )
1885    {
1886        this.model = model;
1887    }
1888
1889    protected void setAttachedArtifacts( List<Artifact> attachedArtifacts )
1890    {
1891        this.attachedArtifacts = attachedArtifacts;
1892    }
1893
1894    protected void setCompileSourceRoots( List<String> compileSourceRoots )
1895    {
1896        this.compileSourceRoots = compileSourceRoots;
1897    }
1898
1899    protected void setTestCompileSourceRoots( List<String> testCompileSourceRoots )
1900    {
1901        this.testCompileSourceRoots = testCompileSourceRoots;
1902    }
1903
1904    protected void setScriptSourceRoots( List<String> scriptSourceRoots )
1905    {
1906        this.scriptSourceRoots = scriptSourceRoots;
1907    }
1908
1909    protected ArtifactRepository getReleaseArtifactRepository()
1910    {
1911        if ( releaseArtifactRepository == null && getDistributionManagement() != null
1912            && getDistributionManagement().getRepository() != null )
1913        {
1914            checkProjectBuildingRequest();
1915            try
1916            {
1917                ArtifactRepository repo =
1918                    repositorySystem.buildArtifactRepository( getDistributionManagement().getRepository() );
1919                repositorySystem.injectProxy( projectBuilderConfiguration.getRepositorySession(), Arrays.asList( repo ) );
1920                repositorySystem.injectAuthentication( projectBuilderConfiguration.getRepositorySession(),
1921                                                       Arrays.asList( repo ) );
1922                setReleaseArtifactRepository( repo );
1923            }
1924            catch ( InvalidRepositoryException e )
1925            {
1926                throw new IllegalStateException( "Failed to create release distribution repository for " + getId(), e );
1927            }
1928        }
1929
1930        return releaseArtifactRepository;
1931    }
1932
1933    protected ArtifactRepository getSnapshotArtifactRepository()
1934    {
1935        if ( snapshotArtifactRepository == null && getDistributionManagement() != null
1936            && getDistributionManagement().getSnapshotRepository() != null )
1937        {
1938            checkProjectBuildingRequest();
1939            try
1940            {
1941                ArtifactRepository repo =
1942                    repositorySystem.buildArtifactRepository( getDistributionManagement().getSnapshotRepository() );
1943                repositorySystem.injectProxy( projectBuilderConfiguration.getRepositorySession(), Arrays.asList( repo ) );
1944                repositorySystem.injectAuthentication( projectBuilderConfiguration.getRepositorySession(),
1945                                                       Arrays.asList( repo ) );
1946                setSnapshotArtifactRepository( repo );
1947            }
1948            catch ( InvalidRepositoryException e )
1949            {
1950                throw new IllegalStateException( "Failed to create snapshot distribution repository for " + getId(), e );
1951            }
1952        }
1953
1954        return snapshotArtifactRepository;
1955    }
1956
1957    @Deprecated
1958    public Artifact replaceWithActiveArtifact( Artifact pluginArtifact )
1959    {
1960        return pluginArtifact;
1961    }
1962
1963    private void deepCopy( MavenProject project )
1964    {
1965        // disown the parent
1966
1967        // copy fields
1968        setFile( project.getFile() );
1969
1970        // don't need a deep copy, they don't get modified or added/removed to/from - but make them unmodifiable to be
1971        // sure!
1972        if ( project.getDependencyArtifacts() != null )
1973        {
1974            setDependencyArtifacts( Collections.unmodifiableSet( project.getDependencyArtifacts() ) );
1975        }
1976
1977        if ( project.getArtifacts() != null )
1978        {
1979            setArtifacts( Collections.unmodifiableSet( project.getArtifacts() ) );
1980        }
1981
1982        if ( project.getParentFile() != null )
1983        {
1984            parentFile = new File( project.getParentFile().getAbsolutePath() );
1985        }
1986
1987        if ( project.getPluginArtifacts() != null )
1988        {
1989            setPluginArtifacts( Collections.unmodifiableSet( project.getPluginArtifacts() ) );
1990        }
1991
1992        if ( project.getReportArtifacts() != null )
1993        {
1994            setReportArtifacts( Collections.unmodifiableSet( project.getReportArtifacts() ) );
1995        }
1996
1997        if ( project.getExtensionArtifacts() != null )
1998        {
1999            setExtensionArtifacts( Collections.unmodifiableSet( project.getExtensionArtifacts() ) );
2000        }
2001
2002        setParentArtifact( ( project.getParentArtifact() ) );
2003
2004        if ( project.getRemoteArtifactRepositories() != null )
2005        {
2006            setRemoteArtifactRepositories( Collections.unmodifiableList( project.getRemoteArtifactRepositories() ) );
2007        }
2008
2009        if ( project.getPluginArtifactRepositories() != null )
2010        {
2011            setPluginArtifactRepositories( ( Collections.unmodifiableList( project.getPluginArtifactRepositories() ) ) );
2012        }
2013
2014        if ( project.getActiveProfiles() != null )
2015        {
2016            setActiveProfiles( ( Collections.unmodifiableList( project.getActiveProfiles() ) ) );
2017        }
2018
2019        if ( project.getAttachedArtifacts() != null )
2020        {
2021            // clone properties modifyable by plugins in a forked lifecycle
2022            setAttachedArtifacts( new ArrayList<Artifact>( project.getAttachedArtifacts() ) );
2023        }
2024
2025        if ( project.getCompileSourceRoots() != null )
2026        {
2027            // clone source roots
2028            setCompileSourceRoots( ( new ArrayList<String>( project.getCompileSourceRoots() ) ) );
2029        }
2030
2031        if ( project.getTestCompileSourceRoots() != null )
2032        {
2033            setTestCompileSourceRoots( ( new ArrayList<String>( project.getTestCompileSourceRoots() ) ) );
2034        }
2035
2036        if ( project.getScriptSourceRoots() != null )
2037        {
2038            setScriptSourceRoots( ( new ArrayList<String>( project.getScriptSourceRoots() ) ) );
2039        }
2040
2041        if ( project.getModel() != null )
2042        {
2043            setModel( project.getModel().clone() );
2044        }
2045
2046        if ( project.getOriginalModel() != null )
2047        {
2048            setOriginalModel( project.getOriginalModel() );
2049        }
2050
2051        setExecutionRoot( project.isExecutionRoot() );
2052
2053        if ( project.getArtifact() != null )
2054        {
2055            setArtifact( ArtifactUtils.copyArtifact( project.getArtifact() ) );
2056        }
2057
2058        if ( project.getManagedVersionMap() != null )
2059        {
2060            setManagedVersionMap( new HashMap<String, Artifact>( project.getManagedVersionMap() ) );
2061        }
2062
2063        lifecyclePhases.addAll( project.lifecyclePhases );
2064    }
2065
2066    private void addArtifactPath( Artifact artifact, List<String> classpath )
2067    {
2068        File file = artifact.getFile();
2069        if ( file != null )
2070        {
2071            classpath.add( file.getPath() );
2072        }
2073    }
2074
2075    private static String getProjectReferenceId( String groupId, String artifactId, String version )
2076    {
2077        StringBuilder buffer = new StringBuilder( 128 );
2078        buffer.append( groupId ).append( ':' ).append( artifactId ).append( ':' ).append( version );
2079        return buffer.toString();
2080    }
2081
2082    /**
2083     * Sets the value of the context value of this project identified
2084     * by the given key. If the supplied value is <code>null</code>,
2085     * the context value is removed from this project.
2086     * 
2087     * Context values are intended to allow core extensions to associate
2088     * derived state with project instances. 
2089     */
2090    public void setContextValue( String key, Object value )
2091    {
2092        if ( context == null )
2093        {
2094            context = new HashMap<String, Object>();
2095        }
2096        if ( value != null )
2097        {
2098            context.put( key, value );
2099        }
2100        else
2101        {
2102            context.remove( key );
2103        }
2104    }
2105
2106    /**
2107     * Returns context value of this project associated with the given key 
2108     * or null if this project has no such value. 
2109     */
2110    public Object getContextValue( String key )
2111    {
2112        if ( context == null )
2113        {
2114            return null;
2115        }
2116        return context.get( key );
2117    }
2118
2119    /**
2120     * Sets the project's class realm. <strong>Warning:</strong> This is an internal utility method that is only public
2121     * for technical reasons, it is not part of the public API. In particular, this method can be changed or deleted
2122     * without prior notice and must not be used by plugins.
2123     * 
2124     * @param classRealm The class realm hosting the build extensions of this project, may be {@code null}.
2125     */
2126    public void setClassRealm( ClassRealm classRealm )
2127    {
2128        this.classRealm = classRealm;
2129    }
2130
2131    /**
2132     * Gets the project's class realm. This class realm hosts the build extensions of the project.
2133     * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
2134     * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
2135     * used by plugins.
2136     * 
2137     * @return The project's class realm or {@code null}.
2138     */
2139    public ClassRealm getClassRealm()
2140    {
2141        return classRealm;
2142    }
2143
2144    /**
2145     * Sets the artifact filter used to exclude shared extension artifacts from plugin realms. <strong>Warning:</strong>
2146     * This is an internal utility method that is only public for technical reasons, it is not part of the public API.
2147     * In particular, this method can be changed or deleted without prior notice and must not be used by plugins.
2148     * 
2149     * @param extensionDependencyFilter The dependency filter to apply to plugins, may be {@code null}.
2150     */
2151    public void setExtensionDependencyFilter( DependencyFilter extensionDependencyFilter )
2152    {
2153        this.extensionDependencyFilter = extensionDependencyFilter;
2154    }
2155
2156    /**
2157     * Gets the dependency filter used to exclude shared extension artifacts from plugin realms.
2158     * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
2159     * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
2160     * used by plugins.
2161     * 
2162     * @return The dependency filter or {@code null}.
2163     */
2164    public DependencyFilter getExtensionDependencyFilter()
2165    {
2166        return extensionDependencyFilter;
2167    }
2168
2169    /**
2170     * Sets the transitive dependency artifacts that have been resolved/collected for this project.
2171     * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
2172     * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
2173     * used by plugins.
2174     * 
2175     * @param artifacts The set of artifacts, may be {@code null}.
2176     */
2177    public void setResolvedArtifacts( Set<Artifact> artifacts )
2178    {
2179        this.resolvedArtifacts = ( artifacts != null ) ? artifacts : Collections.<Artifact> emptySet();
2180        this.artifacts = null;
2181        this.artifactMap = null;
2182    }
2183
2184    /**
2185     * Sets the scope filter to select the artifacts being exposed to the currently executed mojo.
2186     * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
2187     * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
2188     * used by plugins.
2189     * 
2190     * @param artifactFilter The artifact filter, may be {@code null} to exclude all artifacts.
2191     */
2192    public void setArtifactFilter( ArtifactFilter artifactFilter )
2193    {
2194        this.artifactFilter = artifactFilter;
2195        this.artifacts = null;
2196        this.artifactMap = null;
2197    }
2198
2199    /**
2200     * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
2201     * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
2202     * used by plugins.
2203     * 
2204     * @param phase The phase to check for, must not be {@code null}.
2205     * @return {@code true} if the phase has been seen.
2206     */
2207    public boolean hasLifecyclePhase( String phase )
2208    {
2209        return lifecyclePhases.contains( phase );
2210    }
2211
2212    /**
2213     * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
2214     * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
2215     * used by plugins.
2216     * 
2217     * @param lifecyclePhase The lifecycle phase to add, must not be {@code null}.
2218     */
2219    public void addLifecyclePhase( String lifecyclePhase )
2220    {
2221        lifecyclePhases.add( lifecyclePhase );
2222    }
2223
2224    /**
2225     * Gets the project building request from which this project instance was created. <strong>Warning:</strong> This is
2226     * an utility method that is meant to assist integrators of Maven, it must not be used by Maven plugins.
2227     * 
2228     * @return The project building request or {@code null}.
2229     * @since 2.1
2230     */
2231    public ProjectBuildingRequest getProjectBuildingRequest()
2232    {
2233        return projectBuilderConfiguration;
2234    }
2235
2236    /**
2237     * Sets the project building request from which this project instance was created. <strong>Warning:</strong> This is
2238     * an utility method that is meant to assist integrators of Maven, it must not be used by Maven plugins.
2239     * 
2240     * @param projectBuildingRequest The project building request, may be {@code null}.
2241     * @since 2.1
2242     */
2243    public void setProjectBuildingRequest( ProjectBuildingRequest projectBuildingRequest )
2244    {
2245        projectBuilderConfiguration = projectBuildingRequest;
2246    }
2247
2248    private void checkProjectBuildingRequest()
2249    {
2250        if ( projectBuilderConfiguration == null )
2251        {
2252            throw new IllegalStateException( "project building request missing" );
2253        }
2254    }
2255
2256}