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