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