View Javadoc

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