View Javadoc

1   package org.apache.maven.project;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.FileNotFoundException;
24  import java.io.IOException;
25  import java.io.Reader;
26  import java.io.StringReader;
27  import java.net.URL;
28  import java.util.ArrayList;
29  import java.util.Collections;
30  import java.util.Date;
31  import java.util.HashMap;
32  import java.util.HashSet;
33  import java.util.Iterator;
34  import java.util.LinkedHashSet;
35  import java.util.LinkedList;
36  import java.util.List;
37  import java.util.Map;
38  import java.util.Set;
39  import java.util.TreeMap;
40  
41  import org.apache.maven.artifact.Artifact;
42  import org.apache.maven.artifact.ArtifactStatus;
43  import org.apache.maven.artifact.ArtifactUtils;
44  import org.apache.maven.artifact.InvalidRepositoryException;
45  import org.apache.maven.artifact.manager.WagonManager;
46  import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
47  import org.apache.maven.artifact.repository.ArtifactRepository;
48  import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
49  import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
50  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
51  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
52  import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
53  import org.apache.maven.artifact.resolver.ArtifactResolver;
54  import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter;
55  import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
56  import org.apache.maven.artifact.versioning.ManagedVersionMap;
57  import org.apache.maven.artifact.versioning.VersionRange;
58  import org.apache.maven.model.Build;
59  import org.apache.maven.model.Dependency;
60  import org.apache.maven.model.DependencyManagement;
61  import org.apache.maven.model.DistributionManagement;
62  import org.apache.maven.model.Exclusion;
63  import org.apache.maven.model.Extension;
64  import org.apache.maven.model.Model;
65  import org.apache.maven.model.Parent;
66  import org.apache.maven.model.Plugin;
67  import org.apache.maven.model.PluginExecution;
68  import org.apache.maven.model.PluginManagement;
69  import org.apache.maven.model.Profile;
70  import org.apache.maven.model.ReportPlugin;
71  import org.apache.maven.model.Repository;
72  import org.apache.maven.model.Resource;
73  import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
74  import org.apache.maven.profiles.DefaultProfileManager;
75  import org.apache.maven.profiles.MavenProfilesBuilder;
76  import org.apache.maven.profiles.ProfileManager;
77  import org.apache.maven.profiles.ProfilesConversionUtils;
78  import org.apache.maven.profiles.ProfilesRoot;
79  import org.apache.maven.profiles.activation.ProfileActivationException;
80  import org.apache.maven.project.artifact.InvalidDependencyVersionException;
81  import org.apache.maven.project.artifact.ProjectArtifactFactory;
82  import org.apache.maven.project.inheritance.ModelInheritanceAssembler;
83  import org.apache.maven.project.injection.ModelDefaultsInjector;
84  import org.apache.maven.project.injection.ProfileInjector;
85  import org.apache.maven.project.interpolation.ModelInterpolationException;
86  import org.apache.maven.project.interpolation.ModelInterpolator;
87  import org.apache.maven.project.path.PathTranslator;
88  import org.apache.maven.project.validation.ModelValidationResult;
89  import org.apache.maven.project.validation.ModelValidator;
90  import org.apache.maven.wagon.events.TransferListener;
91  import org.codehaus.plexus.PlexusConstants;
92  import org.codehaus.plexus.PlexusContainer;
93  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
94  import org.codehaus.plexus.context.Context;
95  import org.codehaus.plexus.context.ContextException;
96  import org.codehaus.plexus.logging.AbstractLogEnabled;
97  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
98  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
99  import org.codehaus.plexus.util.IOUtil;
100 import org.codehaus.plexus.util.ReaderFactory;
101 import org.codehaus.plexus.util.StringUtils;
102 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
103 
104 /*:apt
105 
106  -----
107  POM lifecycle
108  -----
109 
110 POM Lifecycle
111 
112  Order of operations when building a POM
113 
114  * inheritance
115  * path translation
116  * interpolation
117  * defaults injection
118 
119  Current processing is:
120 
121  * inheritance
122  * interpolation
123  * defaults injection
124  * path translation
125 
126  I'm not sure how this is working at all ... i think i have a case where this is failing but i need to
127  encapsulate as a test so i can fix it. Also need to think of the in working build directory versus looking
128  things up from the repository i.e buildFromSource vs buildFromRepository.
129 
130 Notes
131 
132  * when the model is read it may not have a groupId, as it must be inherited
133 
134  * the inheritance assembler must use models that are unadulterated!
135 
136 */
137 
138 /**
139  * @version $Id: DefaultMavenProjectBuilder.java 749997 2009-03-04 13:14:32Z brett $
140  */
141 public class DefaultMavenProjectBuilder
142     extends AbstractLogEnabled
143     implements MavenProjectBuilder, Initializable, Contextualizable
144 {
145     // TODO: remove
146     private PlexusContainer container;
147 
148     protected MavenProfilesBuilder profilesBuilder;
149 
150     protected ArtifactResolver artifactResolver;
151 
152     protected ArtifactMetadataSource artifactMetadataSource;
153 
154     private ProjectArtifactFactory artifactFactory;
155 
156     private ModelInheritanceAssembler modelInheritanceAssembler;
157 
158     private ProfileInjector profileInjector;
159 
160     private ModelValidator validator;
161 
162     private Map rawProjectCache = new HashMap();
163 
164     private Map processedProjectCache = new HashMap();
165 
166     // TODO: make it a component
167     private MavenXpp3Reader modelReader;
168 
169     private PathTranslator pathTranslator;
170 
171     private ModelDefaultsInjector modelDefaultsInjector;
172 
173     private ModelInterpolator modelInterpolator;
174 
175     private ArtifactRepositoryFactory artifactRepositoryFactory;
176 
177     // ----------------------------------------------------------------------
178     // I am making this available for use with a new method that takes a
179     // a monitor wagon monitor as a parameter so that tools can use the
180     // methods here and receive callbacks. MNG-1015
181     // ----------------------------------------------------------------------
182 
183     private WagonManager wagonManager;
184 
185     public static final String MAVEN_MODEL_VERSION = "4.0.0";
186 
187     public void initialize()
188     {
189         modelReader = new MavenXpp3Reader();
190     }
191 
192     // ----------------------------------------------------------------------
193     // MavenProjectBuilder Implementation
194     // ----------------------------------------------------------------------
195 
196     public MavenProject build( File pom,
197                                ProjectBuilderConfiguration config )
198         throws ProjectBuildingException
199     {
200         return buildFromSourceFileInternal( pom, config, true );
201     }
202 
203     public MavenProject build( File pom,
204                                ProjectBuilderConfiguration config,
205                                boolean checkDistributionManagementStatus )
206         throws ProjectBuildingException
207     {
208         return buildFromSourceFileInternal( pom, config, checkDistributionManagementStatus );
209     }
210 
211     public MavenProject build( File projectDescriptor,
212                                ArtifactRepository localRepository,
213                                ProfileManager profileManager )
214         throws ProjectBuildingException
215     {
216         ProjectBuilderConfiguration config = new DefaultProjectBuilderConfiguration().setLocalRepository( localRepository ).setGlobalProfileManager( profileManager );
217         return buildFromSourceFileInternal( projectDescriptor, config, true );
218     }
219 
220     public MavenProject build( File projectDescriptor,
221                                ArtifactRepository localRepository,
222                                ProfileManager profileManager,
223                                boolean checkDistributionManagementStatus )
224         throws ProjectBuildingException
225     {
226         ProjectBuilderConfiguration config = new DefaultProjectBuilderConfiguration().setLocalRepository( localRepository ).setGlobalProfileManager( profileManager );
227         return buildFromSourceFileInternal( projectDescriptor, config, checkDistributionManagementStatus );
228     }
229 
230     // jvz:note
231     // When asked for something from the repository are we getting it from the reactor? Yes, when using this call
232     // we are assuming that the reactor has been run and we have collected the projects required to satisfy it0042
233     // which means the projects in the reactor are required for finding classes in <project>/target/classes. Not
234     // sure this is ideal. I remove all caching from the builder and all reactor related ITs which assume
235     // access to simbling project resources failed.
236     public MavenProject buildFromRepository( Artifact artifact,
237                                              List remoteArtifactRepositories,
238                                              ArtifactRepository localRepository,
239                                              boolean allowStubModel )
240         throws ProjectBuildingException
241     {
242         String cacheKey = createCacheKey( artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion() );
243 
244         MavenProject project = (MavenProject) processedProjectCache.get( cacheKey );
245 
246         if ( project != null )
247         {
248             return project;
249         }
250 
251         Model model = findModelFromRepository( artifact, remoteArtifactRepositories, localRepository, allowStubModel );
252 
253         ProjectBuilderConfiguration config = new DefaultProjectBuilderConfiguration().setLocalRepository( localRepository );
254 
255         return buildInternal( "Artifact [" + artifact + "]", model, config, remoteArtifactRepositories,
256                               null, false );
257     }
258 
259     public MavenProject buildFromRepository( Artifact artifact,
260                                              List remoteArtifactRepositories,
261                                              ArtifactRepository localRepository )
262         throws ProjectBuildingException
263     {
264         return buildFromRepository( artifact, remoteArtifactRepositories, localRepository, true );
265     }
266 
267     // what is using this externally? jvz.
268     public MavenProject buildStandaloneSuperProject( ArtifactRepository localRepository )
269         throws ProjectBuildingException
270     {
271         //TODO mkleint - use the (Container, Properties) constructor to make system properties embeddable
272         ProfileManager profileManager = new DefaultProfileManager( container );
273 
274         return buildStandaloneSuperProject( new DefaultProjectBuilderConfiguration().setLocalRepository( localRepository )
275                                                                                     .setGlobalProfileManager( profileManager ) );
276     }
277 
278     public MavenProject buildStandaloneSuperProject( ArtifactRepository localRepository,
279                                                      ProfileManager profileManager )
280         throws ProjectBuildingException
281     {
282         return buildStandaloneSuperProject( new DefaultProjectBuilderConfiguration().setLocalRepository( localRepository )
283                                                                                     .setGlobalProfileManager( profileManager ) );
284     }
285 
286     public MavenProject buildStandaloneSuperProject( ProjectBuilderConfiguration config )
287         throws ProjectBuildingException
288     {
289         Model superModel = getSuperModel();
290 
291         superModel.setGroupId( STANDALONE_SUPERPOM_GROUPID );
292 
293         superModel.setArtifactId( STANDALONE_SUPERPOM_ARTIFACTID );
294 
295         superModel.setVersion( STANDALONE_SUPERPOM_VERSION );
296 
297 
298         List activeProfiles;
299 
300         ProfileManager profileManager = config.getGlobalProfileManager();
301 
302         if ( profileManager == null )
303         {
304             profileManager = new DefaultProfileManager( container );
305         }
306 
307         profileManager.addProfiles( superModel.getProfiles() );
308 
309         String projectId = safeVersionlessKey( STANDALONE_SUPERPOM_GROUPID, STANDALONE_SUPERPOM_ARTIFACTID );
310 
311         activeProfiles = injectActiveProfiles( profileManager, superModel );
312 
313         MavenProject project = new MavenProject( superModel );
314 
315         project.setManagedVersionMap(
316             createManagedVersionMap( projectId, superModel.getDependencyManagement(), null ) );
317 
318         project.setActiveProfiles( activeProfiles );
319 
320         project.setOriginalModel( superModel );
321 
322         try
323         {
324             project = processProjectLogic( "<Super-POM>", project, config, null, null, true, true );
325 
326             project.setExecutionRoot( true );
327 
328             return project;
329         }
330         catch ( ModelInterpolationException e )
331         {
332             throw new ProjectBuildingException( projectId, e.getMessage(), e );
333         }
334         catch ( InvalidRepositoryException e )
335         {
336             throw new ProjectBuildingException( projectId, e.getMessage(), e );
337         }
338     }
339 
340     public MavenProject buildWithDependencies( File projectDescriptor,
341                                                ArtifactRepository localRepository,
342                                                ProfileManager profileManager )
343         throws ProjectBuildingException, ArtifactResolutionException, ArtifactNotFoundException
344     {
345         return buildWithDependencies( projectDescriptor, localRepository, profileManager, null );
346     }
347 
348     // note:jvz This was added for the embedder.
349 
350     /** @todo move to metadatasource itself? */
351     public MavenProject buildWithDependencies( File projectDescriptor,
352                                                ArtifactRepository localRepository,
353                                                ProfileManager profileManager,
354                                                TransferListener transferListener )
355         throws ProjectBuildingException, ArtifactResolutionException, ArtifactNotFoundException
356     {
357         MavenProject project = build( projectDescriptor, localRepository, profileManager, false );
358 
359         // ----------------------------------------------------------------------
360         // Typically when the project builder is being used from maven proper
361         // the transitive dependencies will not be resolved here because this
362         // requires a lot of work when we may only be interested in running
363         // something simple like 'm2 clean'. So the artifact collector is used
364         // in the dependency resolution phase if it is required by any of the
365         // goals being executed. But when used as a component in another piece
366         // of code people may just want to build maven projects and have the
367         // dependencies resolved for whatever reason: this is why we keep
368         // this snippet of code here.
369         // ----------------------------------------------------------------------
370 
371         // TODO: such a call in MavenMetadataSource too - packaging not really the intention of type
372         Artifact projectArtifact = project.getArtifact();
373 
374         String projectId = safeVersionlessKey( project.getGroupId(), project.getArtifactId() );
375 
376         // Map managedVersions = createManagedVersionMap( projectId, project.getDependencyManagement() );
377         Map managedVersions = project.getManagedVersionMap();
378 
379         ensureMetadataSourceIsInitialized();
380 
381         try
382         {
383             project.setDependencyArtifacts( project.createArtifacts( artifactFactory, null, null ) );
384         }
385         catch ( InvalidDependencyVersionException e )
386         {
387             throw new ProjectBuildingException( projectId,
388                                                 "Unable to build project due to an invalid dependency version: " +
389                                                     e.getMessage(), e );
390         }
391 
392         if ( transferListener != null )
393         {
394             wagonManager.setDownloadMonitor( transferListener );
395         }
396 
397         ArtifactResolutionResult result = artifactResolver.resolveTransitively( project.getDependencyArtifacts(),
398                                                                                 projectArtifact, managedVersions,
399                                                                                 localRepository,
400                                                                                 project.getRemoteArtifactRepositories(),
401                                                                                 artifactMetadataSource );
402 
403         project.setArtifacts( result.getArtifacts() );
404 
405         return project;
406     }
407 
408     // ----------------------------------------------------------------------
409     //
410     // ----------------------------------------------------------------------
411 
412     private void ensureMetadataSourceIsInitialized()
413         throws ProjectBuildingException
414     {
415         if ( artifactMetadataSource == null )
416         {
417             try
418             {
419                 artifactMetadataSource = (ArtifactMetadataSource) container.lookup( ArtifactMetadataSource.ROLE );
420             }
421             catch ( ComponentLookupException e )
422             {
423                 throw new ProjectBuildingException( "all", "Cannot lookup metadata source for building the project.",
424                                                     e );
425             }
426         }
427     }
428 
429     private Map createManagedVersionMap( String projectId,
430                                          DependencyManagement dependencyManagement,
431                                          MavenProject parent )
432         throws ProjectBuildingException
433     {
434         Map map = null;
435         List deps;
436         if ( ( dependencyManagement != null ) && ( ( deps = dependencyManagement.getDependencies() ) != null ) &&
437             ( deps.size() > 0 ) )
438         {
439             map = new ManagedVersionMap( map );
440 
441             if ( getLogger().isDebugEnabled() )
442             {
443                 getLogger().debug( "Adding managed dependencies for " + projectId );
444             }
445 
446             for ( Iterator i = dependencyManagement.getDependencies().iterator(); i.hasNext(); )
447             {
448                 Dependency d = (Dependency) i.next();
449 
450                 try
451                 {
452                     VersionRange versionRange = VersionRange.createFromVersionSpec( d.getVersion() );
453 
454                     Artifact artifact = artifactFactory.createDependencyArtifact( d.getGroupId(), d.getArtifactId(),
455                                                                                   versionRange, d.getType(),
456                                                                                   d.getClassifier(), d.getScope(),
457                                                                                   d.isOptional() );
458                     if ( getLogger().isDebugEnabled() )
459                     {
460                         getLogger().debug( "  " + artifact );
461                     }
462 
463                     // If the dependencyManagement section listed exclusions,
464                     // add them to the managed artifacts here so that transitive
465                     // dependencies will be excluded if necessary.
466                     if ( ( null != d.getExclusions() ) && !d.getExclusions().isEmpty() )
467                     {
468                         List exclusions = new ArrayList();
469 
470                         Iterator exclItr = d.getExclusions().iterator();
471 
472                         while ( exclItr.hasNext() )
473                         {
474                             Exclusion e = (Exclusion) exclItr.next();
475                             exclusions.add( e.getGroupId() + ":" + e.getArtifactId() );
476                         }
477                         ExcludesArtifactFilter eaf = new ExcludesArtifactFilter( exclusions );
478                         artifact.setDependencyFilter( eaf );
479                     }
480                     else
481                     {
482                         artifact.setDependencyFilter( null );
483                     }
484                     map.put( d.getManagementKey(), artifact );
485                 }
486                 catch ( InvalidVersionSpecificationException e )
487                 {
488                     throw new ProjectBuildingException( projectId, "Unable to parse version '" + d.getVersion() +
489                         "' for dependency '" + d.getManagementKey() + "': " + e.getMessage(), e );
490                 }
491             }
492         }
493         else if ( map == null )
494         {
495             map = Collections.EMPTY_MAP;
496         }
497 
498         return map;
499     }
500 
501     private MavenProject buildFromSourceFileInternal( File projectDescriptor,
502                                                       ProjectBuilderConfiguration config,
503                                                       boolean checkDistributionManagementStatus )
504         throws ProjectBuildingException
505     {
506         Model model = readModel( "unknown", projectDescriptor, true );
507 
508         MavenProject project = buildInternal( projectDescriptor.getAbsolutePath(), model, config,
509                                               buildArtifactRepositories( getSuperModel() ), projectDescriptor,
510                                               true );
511 
512         if ( checkDistributionManagementStatus )
513         {
514             if ( ( project.getDistributionManagement() != null ) &&
515                 ( project.getDistributionManagement().getStatus() != null ) )
516             {
517                 String projectId = safeVersionlessKey( project.getGroupId(), project.getArtifactId() );
518 
519                 throw new ProjectBuildingException( projectId,
520                                                     "Invalid project file: distribution status must not be specified for a project outside of the repository" );
521             }
522         }
523 
524         return project;
525     }
526 
527     private Model findModelFromRepository( Artifact artifact,
528                                            List remoteArtifactRepositories,
529                                            ArtifactRepository localRepository,
530                                            boolean allowStubModel )
531         throws ProjectBuildingException
532     {
533         String projectId = safeVersionlessKey( artifact.getGroupId(), artifact.getArtifactId() );
534 
535         normalizeToArtifactRepositories( remoteArtifactRepositories, projectId );
536 
537         Artifact projectArtifact;
538 
539         // if the artifact is not a POM, we need to construct a POM artifact based on the artifact parameter given.
540         if ( "pom".equals( artifact.getType() ) )
541         {
542             projectArtifact = artifact;
543         }
544         else
545         {
546             getLogger().debug( "Attempting to build MavenProject instance for Artifact (" + artifact.getGroupId() + ":"
547                                   + artifact.getArtifactId() + ":" + artifact.getVersion() + ") of type: "
548                                   + artifact.getType() + "; constructing POM artifact instead." );
549 
550             projectArtifact = artifactFactory.createProjectArtifact( artifact.getGroupId(), artifact.getArtifactId(),
551                                                                      artifact.getVersion(), artifact.getScope() );
552         }
553 
554         Model model;
555 
556         try
557         {
558             artifactResolver.resolve( projectArtifact, remoteArtifactRepositories, localRepository );
559 
560             File file = projectArtifact.getFile();
561 
562             model = readModel( projectId, file, false );
563 
564             String downloadUrl = null;
565 
566             ArtifactStatus status = ArtifactStatus.NONE;
567 
568             DistributionManagement distributionManagement = model.getDistributionManagement();
569 
570             if ( distributionManagement != null )
571             {
572                 downloadUrl = distributionManagement.getDownloadUrl();
573 
574                 status = ArtifactStatus.valueOf( distributionManagement.getStatus() );
575             }
576 
577             checkStatusAndUpdate( projectArtifact, status, file, remoteArtifactRepositories, localRepository );
578 
579             // TODO: this is gross. Would like to give it the whole model, but maven-artifact shouldn't depend on that
580             // Can a maven-core implementation of the Artifact interface store it, and be used in the exceptions?
581             if ( downloadUrl != null )
582             {
583                 projectArtifact.setDownloadUrl( downloadUrl );
584             }
585             else
586             {
587                 projectArtifact.setDownloadUrl( model.getUrl() );
588             }
589         }
590         catch ( ArtifactResolutionException e )
591         {
592             throw new ProjectBuildingException( projectId, "Error getting POM for '" + projectId +
593                 "' from the repository: " + e.getMessage(), e );
594         }
595         catch ( ArtifactNotFoundException e )
596         {
597             if ( allowStubModel )
598             {
599                 getLogger().debug( "Artifact not found - using stub model: " + e.getMessage() );
600 
601                 model = createStubModel( projectArtifact );
602             }
603             else
604             {
605                 throw new ProjectBuildingException( projectId, "POM '" + projectId + "' not found in repository: " +
606                     e.getMessage(), e );
607             }
608         }
609 
610         return model;
611     }
612 
613     private List normalizeToArtifactRepositories( List remoteArtifactRepositories,
614                                                   String projectId )
615         throws ProjectBuildingException
616     {
617         List normalized = new ArrayList( remoteArtifactRepositories.size() );
618 
619         boolean normalizationNeeded = false;
620         for ( Iterator it = remoteArtifactRepositories.iterator(); it.hasNext(); )
621         {
622             Object item = it.next();
623 
624             if ( item instanceof ArtifactRepository )
625             {
626                 normalized.add( item );
627             }
628             else if ( item instanceof Repository )
629             {
630                 Repository repo = (Repository) item;
631                 try
632                 {
633                     item = ProjectUtils.buildArtifactRepository( repo, artifactRepositoryFactory, container );
634 
635                     normalized.add( item );
636                     normalizationNeeded = true;
637                 }
638                 catch ( InvalidRepositoryException e )
639                 {
640                     throw new ProjectBuildingException( projectId, "Error building artifact repository for id: " + repo.getId(), e );
641                 }
642             }
643             else
644             {
645                 throw new ProjectBuildingException( projectId, "Error building artifact repository from non-repository information item: " + item );
646             }
647         }
648 
649         if ( normalizationNeeded )
650         {
651             return normalized;
652         }
653         else
654         {
655             return remoteArtifactRepositories;
656         }
657     }
658 
659     private void checkStatusAndUpdate( Artifact projectArtifact,
660                                        ArtifactStatus status,
661                                        File file,
662                                        List remoteArtifactRepositories,
663                                        ArtifactRepository localRepository )
664         throws ArtifactNotFoundException
665     {
666         // TODO: configurable actions dependant on status
667         if ( !projectArtifact.isSnapshot() && ( status.compareTo( ArtifactStatus.DEPLOYED ) < 0 ) )
668         {
669             // use default policy (enabled, daily update, warn on bad checksum)
670             ArtifactRepositoryPolicy policy = new ArtifactRepositoryPolicy();
671             // TODO: re-enable [MNG-798/865]
672             policy.setUpdatePolicy( ArtifactRepositoryPolicy.UPDATE_POLICY_NEVER );
673 
674             if ( policy.checkOutOfDate( new Date( file.lastModified() ) ) )
675             {
676                 getLogger().info(
677                     projectArtifact.getArtifactId() + ": updating metadata due to status of '" + status + "'" );
678                 try
679                 {
680                     projectArtifact.setResolved( false );
681                     artifactResolver.resolveAlways( projectArtifact, remoteArtifactRepositories, localRepository );
682                 }
683                 catch ( ArtifactResolutionException e )
684                 {
685                     getLogger().warn( "Error updating POM - using existing version" );
686                     getLogger().debug( "Cause", e );
687                 }
688                 catch ( ArtifactNotFoundException e )
689                 {
690                     getLogger().warn( "Error updating POM - not found. Removing local copy." );
691                     getLogger().debug( "Cause", e );
692                     file.delete();
693                     throw e;
694                 }
695             }
696         }
697     }
698 
699     // jvz:note
700     // This is used when requested artifacts do not have an associated POM. This is for the case where we are
701     // using an m1 repo where the only thing required to be present are the JAR files.
702     private Model createStubModel( Artifact projectArtifact )
703     {
704         getLogger().debug( "Using defaults for missing POM " + projectArtifact );
705 
706         Model model = new Model();
707 
708         model.setModelVersion( "4.0.0" );
709 
710         model.setArtifactId( projectArtifact.getArtifactId() );
711 
712         model.setGroupId( projectArtifact.getGroupId() );
713 
714         model.setVersion( projectArtifact.getVersion() );
715 
716         // TODO: not correct in some instances
717         model.setPackaging( projectArtifact.getType() );
718 
719         model.setDistributionManagement( new DistributionManagement() );
720 
721         model.getDistributionManagement().setStatus( ArtifactStatus.GENERATED.toString() );
722 
723         return model;
724     }
725 
726     // jvz:note
727     // We've got a mixture of things going in the USD and from the repository, sometimes the descriptor
728     // is a real file and sometimes null which makes things confusing.
729     private MavenProject buildInternal( String pomLocation,
730                                         Model model,
731                                         ProjectBuilderConfiguration config,
732                                         List parentSearchRepositories,
733                                         File projectDescriptor,
734                                         boolean strict )
735         throws ProjectBuildingException
736     {
737         File projectDir = null;
738 
739         if ( projectDescriptor != null )
740         {
741             projectDir = projectDescriptor.getAbsoluteFile().getParentFile();
742         }
743 
744         Model superModel = getSuperModel();
745 
746         ProfileManager externalProfileManager = config.getGlobalProfileManager();
747         ProfileManager superProjectProfileManager;
748         if ( externalProfileManager != null )
749         {
750             superProjectProfileManager = new DefaultProfileManager(
751                                                                     container,
752                                                                     externalProfileManager.getRequestProperties() );
753         }
754         else
755         {
756             superProjectProfileManager = new DefaultProfileManager( container );
757         }
758 
759         List activeProfiles;
760 
761         superProjectProfileManager.addProfiles( superModel.getProfiles() );
762 
763         activeProfiles = injectActiveProfiles( superProjectProfileManager, superModel );
764 
765         MavenProject superProject = new MavenProject( superModel );
766 
767         superProject.setActiveProfiles( activeProfiles );
768 
769         //noinspection CollectionDeclaredAsConcreteClass
770         LinkedList lineage = new LinkedList();
771 
772         // TODO: the aRWR can get out of sync with project.model.repositories. We should do all the processing of
773         // profiles, etc on the models then recreate the aggregated sets at the end from the project repositories (they
774         // must still be created along the way so that parent poms can be discovered, however)
775         // Use a TreeSet to ensure ordering is retained
776         Set aggregatedRemoteWagonRepositories = new LinkedHashSet();
777 
778         String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
779 
780         List activeExternalProfiles;
781         try
782         {
783             if ( externalProfileManager != null )
784             {
785                 activeExternalProfiles = externalProfileManager.getActiveProfiles();
786             }
787             else
788             {
789                 activeExternalProfiles = Collections.EMPTY_LIST;
790             }
791         }
792         catch ( ProfileActivationException e )
793         {
794             throw new ProjectBuildingException( projectId, "Failed to calculate active external profiles.", e );
795         }
796 
797         for ( Iterator i = activeExternalProfiles.iterator(); i.hasNext(); )
798         {
799             Profile externalProfile = (Profile) i.next();
800 
801             for ( Iterator repoIterator = externalProfile.getRepositories().iterator(); repoIterator.hasNext(); )
802             {
803                 Repository mavenRepo = (Repository) repoIterator.next();
804 
805                 ArtifactRepository artifactRepo = null;
806                 try
807                 {
808                     artifactRepo =
809                         ProjectUtils.buildArtifactRepository( mavenRepo, artifactRepositoryFactory, container );
810                 }
811                 catch ( InvalidRepositoryException e )
812                 {
813                     throw new ProjectBuildingException( projectId, e.getMessage(), e );
814                 }
815 
816                 aggregatedRemoteWagonRepositories.add( artifactRepo );
817             }
818         }
819 
820         MavenProject project = null;
821         try
822         {
823             project = assembleLineage( model, lineage, config, projectDir, parentSearchRepositories,
824                                        aggregatedRemoteWagonRepositories, strict );
825         }
826         catch ( InvalidRepositoryException e )
827         {
828             throw new ProjectBuildingException( projectId, e.getMessage(), e );
829         }
830 
831         // we don't have to force the collision exception for superModel here, it's already been done in getSuperModel()
832         MavenProject previousProject = superProject;
833 
834         Model previous = superProject.getModel();
835 
836         for ( Iterator i = lineage.iterator(); i.hasNext(); )
837         {
838             MavenProject currentProject = (MavenProject) i.next();
839 
840             Model current = currentProject.getModel();
841 
842             String pathAdjustment = null;
843 
844             try
845             {
846                 pathAdjustment = previousProject.getModulePathAdjustment( currentProject );
847             }
848             catch ( IOException e )
849             {
850                 getLogger().debug( "Cannot determine whether " + currentProject.getId() + " is a module of " +
851                     previousProject.getId() + ". Reason: " + e.getMessage(), e );
852             }
853 
854             modelInheritanceAssembler.assembleModelInheritance( current, previous, pathAdjustment );
855 
856             previous = current;
857             previousProject = currentProject;
858         }
859 
860         // only add the super repository if it wasn't overridden by a profile or project
861         List repositories = new ArrayList( aggregatedRemoteWagonRepositories );
862 
863         List superRepositories = buildArtifactRepositories( superModel );
864 
865         for ( Iterator i = superRepositories.iterator(); i.hasNext(); )
866         {
867             ArtifactRepository repository = (ArtifactRepository) i.next();
868 
869             if ( !repositories.contains( repository ) )
870             {
871                 repositories.add( repository );
872             }
873         }
874 
875         // merge any duplicated plugin definitions together, using the first appearance as the dominant one.
876         ModelUtils.mergeDuplicatePluginDefinitions( project.getModel().getBuild() );
877 
878         try
879         {
880             project = processProjectLogic( pomLocation, project, config, projectDir, repositories, strict, false );
881         }
882         catch ( ModelInterpolationException e )
883         {
884             throw new InvalidProjectModelException( projectId, pomLocation, e.getMessage(), e );
885         }
886         catch ( InvalidRepositoryException e )
887         {
888             throw new InvalidProjectModelException( projectId, pomLocation, e.getMessage(), e );
889         }
890 
891         processedProjectCache.put(
892                                   createCacheKey( project.getGroupId(), project.getArtifactId(), project.getVersion() ), project );
893 
894           // jvz:note
895         // this only happens if we are building from a source file
896         if ( projectDescriptor != null )
897         {
898             Build build = project.getBuild();
899 
900             project.addCompileSourceRoot( build.getSourceDirectory() );
901 
902             project.addScriptSourceRoot( build.getScriptSourceDirectory() );
903 
904             project.addTestCompileSourceRoot( build.getTestSourceDirectory() );
905 
906             // Only track the file of a POM in the source tree
907             project.setFile( projectDescriptor );
908         }
909 
910 //        try
911 //        {
912 //            calculateConcreteState( project, config );
913 //        }
914 //        catch ( ModelInterpolationException e )
915 //        {
916 //            throw new InvalidProjectModelException( projectId, pomLocation, e.getMessage(), e );
917 //        }
918 
919         project.setManagedVersionMap( createManagedVersionMap( projectId,
920                                                                project.getDependencyManagement(),
921                                                                project.getParent() ) );
922 
923         return project;
924     }
925 
926     private String safeVersionlessKey( String groupId,
927                                        String artifactId )
928     {
929         String gid = groupId;
930 
931         if ( StringUtils.isEmpty( gid ) )
932         {
933             gid = "unknown";
934         }
935 
936         String aid = artifactId;
937 
938         if ( StringUtils.isEmpty( aid ) )
939         {
940             aid = "unknown";
941         }
942 
943         return ArtifactUtils.versionlessKey( gid, aid );
944     }
945 
946     private List buildArtifactRepositories( Model model )
947         throws ProjectBuildingException
948     {
949         try
950         {
951             return ProjectUtils.buildArtifactRepositories( model.getRepositories(), artifactRepositoryFactory,
952                                                            container );
953         }
954         catch ( InvalidRepositoryException e )
955         {
956             String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
957 
958             throw new ProjectBuildingException( projectId, e.getMessage(), e );
959         }
960     }
961 
962     /**
963      * @todo can this take in a model instead of a project and still be successful?
964      * @todo In fact, does project REALLY need a MavenProject as a parent? Couldn't it have just a wrapper around a
965      * model that supported parents which were also the wrapper so that inheritence was assembled. We don't really need
966      * the resolved source roots, etc for the parent - that occurs for the parent when it is constructed independently
967      * and projects are not cached or reused
968      */
969     private MavenProject processProjectLogic( String pomLocation,
970                                               MavenProject project,
971                                               ProjectBuilderConfiguration config,
972                                               File projectDir,
973                                               List remoteRepositories,
974                                               boolean strict,
975                                               boolean isSuperPom )
976         throws ProjectBuildingException, ModelInterpolationException, InvalidRepositoryException
977     {
978         Model model = project.getModel();
979 
980         List activeProfiles = project.getActiveProfiles();
981 
982         if ( activeProfiles == null )
983         {
984             activeProfiles = new ArrayList();
985         }
986 
987         ProfileManager profileMgr = config == null ? null : config.getGlobalProfileManager();
988 
989         List injectedProfiles = injectActiveProfiles( profileMgr, model );
990 
991         activeProfiles.addAll( injectedProfiles );
992         
993         // --------------------------------------------------------------------------------
994         
995         Build dynamicBuild = model.getBuild();
996 
997         model.setBuild( ModelUtils.cloneBuild( dynamicBuild ) );
998 
999         model = modelInterpolator.interpolate( model, projectDir, config, getLogger().isDebugEnabled() );
1000 
1001         mergeDeterministicBuildElements( model.getBuild(), dynamicBuild );
1002 
1003         model.setBuild( dynamicBuild );
1004         
1005         // MNG-3482: Make sure depMgmt is interpolated before merging.
1006         if ( !isSuperPom )
1007         {
1008             mergeManagedDependencies( model, config.getLocalRepository(), remoteRepositories );
1009         }
1010 
1011         // interpolation is before injection, because interpolation is off-limits in the injected variables
1012         modelDefaultsInjector.injectDefaults( model );
1013 
1014         MavenProject parentProject = project.getParent();
1015 
1016         Model originalModel = project.getOriginalModel();
1017 
1018         // We will return a different project object using the new model (hence the need to return a project, not just modify the parameter)
1019         project = new MavenProject( model, getLogger() );
1020 
1021         project.setOriginalModel( originalModel );
1022         
1023         project.setActiveProfiles( activeProfiles );
1024 
1025         // TODO: maybe not strictly correct, while we should enfore that packaging has a type handler of the same id, we don't
1026         Artifact projectArtifact = artifactFactory.create( project );
1027         
1028         project.setArtifact( projectArtifact );
1029         project.setProjectBuilderConfiguration( config );
1030 
1031         project.setPluginArtifactRepositories( ProjectUtils.buildArtifactRepositories( model.getPluginRepositories(),
1032                                                                                        artifactRepositoryFactory,
1033                                                                                        container ) );
1034 
1035         DistributionManagement dm = model.getDistributionManagement();
1036         if ( dm != null )
1037         {
1038             ArtifactRepository repo = ProjectUtils.buildDeploymentArtifactRepository( dm.getRepository(),
1039                                                                                       artifactRepositoryFactory,
1040                                                                                       container );
1041             project.setReleaseArtifactRepository( repo );
1042 
1043             if ( dm.getSnapshotRepository() != null )
1044             {
1045                 repo = ProjectUtils.buildDeploymentArtifactRepository( dm.getSnapshotRepository(),
1046                                                                        artifactRepositoryFactory, container );
1047                 project.setSnapshotArtifactRepository( repo );
1048             }
1049         }
1050 
1051         if ( parentProject != null )
1052         {
1053             String cacheKey = createCacheKey( parentProject.getGroupId(),
1054                                               parentProject.getArtifactId(),
1055                                               parentProject.getVersion() );
1056 
1057             MavenProject processedParent = (MavenProject) processedProjectCache.get( cacheKey );
1058             Artifact parentArtifact;
1059 
1060             // yeah, this null check might be a bit paranoid, but better safe than sorry...
1061             if ( processedParent != null )
1062             {
1063                 project.setParent( processedParent );
1064 
1065                 parentArtifact = processedParent.getArtifact();
1066             }
1067             else
1068             {
1069                 project.setParent( parentProject );
1070 
1071                 parentArtifact = artifactFactory.createParentArtifact( parentProject.getGroupId(),
1072                                                                                 parentProject.getArtifactId(),
1073                                                                                 parentProject.getVersion() );
1074             }
1075 
1076             project.setParentArtifact( parentArtifact );
1077         }
1078 
1079         // Must validate before artifact construction to make sure dependencies are good
1080         ModelValidationResult validationResult = validator.validate( model );
1081 
1082         String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
1083 
1084         if ( validationResult.getMessageCount() > 0 )
1085         {
1086             throw new InvalidProjectModelException( projectId, pomLocation, "Failed to validate POM",
1087                                                     validationResult );
1088         }
1089 
1090         project.setRemoteArtifactRepositories(
1091             ProjectUtils.buildArtifactRepositories( model.getRepositories(), artifactRepositoryFactory, container ) );
1092 
1093         // TODO: these aren't taking active project artifacts into consideration in the reactor
1094         project.setPluginArtifacts( createPluginArtifacts( projectId, project.getBuildPlugins() ) );
1095 
1096         project.setReportArtifacts( createReportArtifacts( projectId, project.getReportPlugins() ) );
1097 
1098         project.setExtensionArtifacts( createExtensionArtifacts( projectId, project.getBuildExtensions() ) );
1099         
1100         return project;
1101     }
1102 
1103     private void mergeDeterministicBuildElements( Build interpolatedBuild,
1104                                                   Build dynamicBuild )
1105     {
1106         mergeDeterministicPluginElements( interpolatedBuild.getPlugins(), dynamicBuild.getPlugins() );
1107 
1108         PluginManagement dPluginMgmt = dynamicBuild.getPluginManagement();
1109         PluginManagement iPluginMgmt = interpolatedBuild.getPluginManagement();
1110 
1111         if ( dPluginMgmt != null )
1112         {
1113             mergeDeterministicPluginElements( iPluginMgmt.getPlugins(), dPluginMgmt.getPlugins() );
1114         }
1115 
1116         if ( dynamicBuild.getExtensions() != null )
1117         {
1118             dynamicBuild.setExtensions( interpolatedBuild.getExtensions() );
1119         }
1120     }
1121 
1122     private void mergeDeterministicPluginElements( List iPlugins, List dPlugins )
1123     {
1124         if ( dPlugins != null )
1125         {
1126             for ( int i = 0; i < dPlugins.size(); i++ )
1127             {
1128                 Plugin dPlugin = (Plugin) dPlugins.get( i );
1129                 Plugin iPlugin = (Plugin) iPlugins.get( i );
1130 
1131                 dPlugin.setGroupId( iPlugin.getGroupId() );
1132                 dPlugin.setArtifactId( iPlugin.getArtifactId() );
1133                 dPlugin.setVersion( iPlugin.getVersion() );
1134                 
1135                 dPlugin.setDependencies( iPlugin.getDependencies() );
1136                 
1137                 List dExecutions = dPlugin.getExecutions();
1138                 if ( dExecutions != null )
1139                 {
1140                     List iExecutions = iPlugin.getExecutions();
1141                     
1142                     for ( int j = 0; j < dExecutions.size(); j++ )
1143                     {
1144                         PluginExecution dExec = (PluginExecution) dExecutions.get( j );
1145                         PluginExecution iExec = (PluginExecution) iExecutions.get( j );
1146                         
1147                         dExec.setId( iExec.getId() );
1148                     }
1149                 }
1150             }
1151         }
1152     }
1153 
1154     /**
1155      * @noinspection CollectionDeclaredAsConcreteClass
1156      * @todo We need to find an effective way to unit test parts of this method!
1157      * @todo Refactor this into smaller methods with discrete purposes.
1158      */
1159     private MavenProject assembleLineage( Model model,
1160                                           LinkedList lineage,
1161                                           ProjectBuilderConfiguration config,
1162                                           File projectDir,
1163                                           List parentSearchRepositories,
1164                                           Set aggregatedRemoteWagonRepositories,
1165                                           boolean strict )
1166         throws ProjectBuildingException, InvalidRepositoryException
1167     {
1168         Model originalModel = ModelUtils.cloneModel( model );
1169 
1170         ProfileManager externalProfileManager = config.getGlobalProfileManager();
1171         ProfileManager profileManager;
1172         if ( externalProfileManager != null )
1173         {
1174             profileManager = new DefaultProfileManager( container, externalProfileManager.getRequestProperties() );
1175         }
1176         else
1177         {
1178             //TODO mkleint - use the (Container, Properties constructor to make system properties embeddable
1179             profileManager = new DefaultProfileManager( container );
1180         }
1181 
1182         if ( externalProfileManager != null )
1183         {
1184             profileManager.explicitlyActivate( externalProfileManager.getExplicitlyActivatedIds() );
1185 
1186             profileManager.explicitlyDeactivate( externalProfileManager.getExplicitlyDeactivatedIds() );
1187         }
1188 
1189         List activeProfiles;
1190 
1191         try
1192         {
1193             profileManager.addProfiles( model.getProfiles() );
1194 
1195             loadProjectExternalProfiles( profileManager, projectDir );
1196 
1197             activeProfiles = injectActiveProfiles( profileManager, model );
1198         }
1199         catch ( ProfileActivationException e )
1200         {
1201             String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
1202 
1203             throw new ProjectBuildingException( projectId, "Failed to activate local (project-level) build profiles: " +
1204                 e.getMessage(), e );
1205         }
1206 
1207         if ( !model.getRepositories().isEmpty() )
1208         {
1209             List respositories = buildArtifactRepositories( model );
1210 
1211             for ( Iterator it = respositories.iterator(); it.hasNext(); )
1212             {
1213                 ArtifactRepository repository = (ArtifactRepository) it.next();
1214 
1215                 if ( !aggregatedRemoteWagonRepositories.contains( repository ) )
1216                 {
1217                     aggregatedRemoteWagonRepositories.add( repository );
1218                 }
1219             }
1220         }
1221 
1222         MavenProject project = new MavenProject( model, getLogger() );
1223 
1224         project.setActiveProfiles( activeProfiles );
1225         project.setOriginalModel( originalModel );
1226 
1227         lineage.addFirst( project );
1228 
1229         Parent parentModel = model.getParent();
1230 
1231         String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
1232 
1233         if ( parentModel != null )
1234         {
1235             if ( StringUtils.isEmpty( parentModel.getGroupId() ) )
1236             {
1237                 throw new ProjectBuildingException( projectId, "Missing groupId element from parent element" );
1238             }
1239             else if ( StringUtils.isEmpty( parentModel.getArtifactId() ) )
1240             {
1241                 throw new ProjectBuildingException( projectId, "Missing artifactId element from parent element" );
1242             }
1243             else if ( parentModel.getGroupId().equals( model.getGroupId() ) &&
1244                 parentModel.getArtifactId().equals( model.getArtifactId() ) )
1245             {
1246                 throw new ProjectBuildingException( projectId,
1247                                                     "Parent element is a duplicate of " + "the current project " );
1248             }
1249             else if ( StringUtils.isEmpty( parentModel.getVersion() ) )
1250             {
1251                 throw new ProjectBuildingException( projectId, "Missing version element from parent element" );
1252             }
1253 
1254             // the only way this will have a value is if we find the parent on disk...
1255             File parentDescriptor = null;
1256 
1257             model = null;
1258 
1259             String parentKey =
1260                 createCacheKey( parentModel.getGroupId(), parentModel.getArtifactId(), parentModel.getVersion() );
1261             MavenProject parentProject = (MavenProject) rawProjectCache.get( parentKey );
1262 
1263             if ( parentProject != null )
1264             {
1265                 model = ModelUtils.cloneModel( parentProject.getOriginalModel() );
1266 
1267                 parentDescriptor = parentProject.getFile();
1268             }
1269 
1270             String parentRelativePath = parentModel.getRelativePath();
1271 
1272             // if we can't find a cached model matching the parent spec, then let's try to look on disk using
1273             // <relativePath/>
1274             if ( ( model == null ) && ( projectDir != null ) && StringUtils.isNotEmpty( parentRelativePath ) )
1275             {
1276                 parentDescriptor = new File( projectDir, parentRelativePath );
1277 
1278                 if ( getLogger().isDebugEnabled() )
1279                 {
1280                     getLogger().debug( "Searching for parent-POM: " + parentModel.getId() + " of project: " +
1281                         project.getId() + " in relative path: " + parentRelativePath );
1282                 }
1283 
1284                 if ( parentDescriptor.isDirectory() )
1285                 {
1286                     if ( getLogger().isDebugEnabled() )
1287                     {
1288                         getLogger().debug( "Path specified in <relativePath/> (" + parentRelativePath +
1289                             ") is a directory. Searching for 'pom.xml' within this directory." );
1290                     }
1291 
1292                     parentDescriptor = new File( parentDescriptor, "pom.xml" );
1293 
1294                     if ( !parentDescriptor.exists() )
1295                     {
1296                         if ( getLogger().isDebugEnabled() )
1297                         {
1298                             getLogger().debug( "Parent-POM: " + parentModel.getId() + " for project: " +
1299                                 project.getId() + " cannot be loaded from relative path: " + parentDescriptor +
1300                                 "; path does not exist." );
1301                         }
1302                     }
1303                 }
1304 
1305                 if ( parentDescriptor != null )
1306                 {
1307                     try
1308                     {
1309                         parentDescriptor = parentDescriptor.getCanonicalFile();
1310                     }
1311                     catch ( IOException e )
1312                     {
1313                         getLogger().debug( "Failed to canonicalize potential parent POM: \'" + parentDescriptor + "\'",
1314                                            e );
1315 
1316                         parentDescriptor = null;
1317                     }
1318                 }
1319 
1320                 if ( ( parentDescriptor != null ) && parentDescriptor.exists() )
1321                 {
1322                     Model candidateParent = readModel( projectId, parentDescriptor, strict );
1323 
1324                     String candidateParentGroupId = candidateParent.getGroupId();
1325                     if ( ( candidateParentGroupId == null ) && ( candidateParent.getParent() != null ) )
1326                     {
1327                         candidateParentGroupId = candidateParent.getParent().getGroupId();
1328                     }
1329 
1330                     String candidateParentVersion = candidateParent.getVersion();
1331                     if ( ( candidateParentVersion == null ) && ( candidateParent.getParent() != null ) )
1332                     {
1333                         candidateParentVersion = candidateParent.getParent().getVersion();
1334                     }
1335 
1336                     if ( parentModel.getGroupId().equals( candidateParentGroupId ) &&
1337                         parentModel.getArtifactId().equals( candidateParent.getArtifactId() ) &&
1338                         parentModel.getVersion().equals( candidateParentVersion ) )
1339                     {
1340                         model = candidateParent;
1341 
1342                         getLogger().debug( "Using parent-POM from the project hierarchy at: \'" +
1343                             parentModel.getRelativePath() + "\' for project: " + project.getId() );
1344                     }
1345                     else
1346                     {
1347                         getLogger().debug( "Invalid parent-POM referenced by relative path '" +
1348                             parentModel.getRelativePath() + "' in parent specification in " + project.getId() + ":" +
1349                             "\n  Specified: " + parentModel.getId() + "\n  Found:     " + candidateParent.getId() );
1350                     }
1351                 }
1352                 else if ( getLogger().isDebugEnabled() )
1353                 {
1354                     getLogger().debug(
1355                         "Parent-POM: " + parentModel.getId() + " not found in relative path: " + parentRelativePath );
1356                 }
1357             }
1358 
1359             Artifact parentArtifact = null;
1360 
1361             // only resolve the parent model from the repository system if we didn't find it on disk...
1362             if ( model == null )
1363             {
1364                 // MNG-2302: parent's File was being populated incorrectly when parent is loaded from repo.
1365                 // keep this in line with other POMs loaded from the repository...the file should be null.
1366                 parentDescriptor = null;
1367 
1368                 //!! (**)
1369                 // ----------------------------------------------------------------------
1370                 // Do we have the necessary information to actually find the parent
1371                 // POMs here?? I don't think so ... Say only one remote repository is
1372                 // specified and that is ibiblio then this model that we just read doesn't
1373                 // have any repository information ... I think we might have to inherit
1374                 // as we go in order to do this.
1375                 // ----------------------------------------------------------------------
1376 
1377                 // we must add the repository this POM was found in too, by chance it may be located where the parent is
1378                 // we can't query the parent to ask where it is :)
1379                 List remoteRepositories = new ArrayList( aggregatedRemoteWagonRepositories );
1380                 remoteRepositories.addAll( parentSearchRepositories );
1381 
1382                 if ( getLogger().isDebugEnabled() )
1383                 {
1384                     getLogger().debug( "Retrieving parent-POM: " + parentModel.getId() + " for project: " +
1385                         project.getId() + " from the repository." );
1386                 }
1387 
1388                 parentArtifact = artifactFactory.createParentArtifact( parentModel.getGroupId(),
1389                                                                        parentModel.getArtifactId(),
1390                                                                        parentModel.getVersion() );
1391 
1392                 try
1393                 {
1394                     model = findModelFromRepository( parentArtifact, remoteRepositories, config.getLocalRepository(), false );
1395                 }
1396                 catch ( ProjectBuildingException e )
1397                 {
1398                     throw new ProjectBuildingException( project.getId(), "Cannot find parent: " + e.getProjectId() +
1399                         " for project: " + project.getId(), e );
1400                 }
1401             }
1402 
1403             if ( ( model != null ) && !"pom".equals( model.getPackaging() ) )
1404             {
1405                 throw new ProjectBuildingException( projectId, "Parent: " + model.getId() + " of project: " +
1406                     projectId + " has wrong packaging: " + model.getPackaging() + ". Must be 'pom'." );
1407             }
1408 
1409             File parentProjectDir = null;
1410             if ( parentDescriptor != null )
1411             {
1412                 parentProjectDir = parentDescriptor.getParentFile();
1413             }
1414 
1415             MavenProject parent = assembleLineage( model,
1416                                                    lineage,
1417                                                    config,
1418                                                    parentProjectDir,
1419                                                    parentSearchRepositories,
1420                                                    aggregatedRemoteWagonRepositories,
1421                                                    strict );
1422 
1423             parent.setFile( parentDescriptor );
1424 
1425             project.setParent( parent );
1426 
1427             project.setParentArtifact( parentArtifact );
1428         }
1429 
1430         rawProjectCache.put( createCacheKey( project.getGroupId(), project.getArtifactId(), project.getVersion() ), new MavenProject( project ) );
1431 
1432         return project;
1433     }
1434 
1435     private void mergeManagedDependencies(Model model, ArtifactRepository localRepository, List parentSearchRepositories)
1436         throws ProjectBuildingException
1437     {
1438         DependencyManagement modelDepMgmt = model.getDependencyManagement();
1439 
1440         if (modelDepMgmt != null)
1441         {
1442             Map depsMap = new TreeMap();
1443             Iterator iter = modelDepMgmt.getDependencies().iterator();
1444             boolean doInclude = false;
1445             while (iter.hasNext())
1446             {
1447                 Dependency dep = (Dependency) iter.next();
1448                 depsMap.put( dep.getManagementKey(), dep );
1449                 if ( dep.getType().equals( "pom" ) && Artifact.SCOPE_IMPORT.equals( dep.getScope() ) )
1450                 {
1451                     doInclude = true;
1452                 }
1453             }
1454             Map newDeps = new TreeMap(depsMap);
1455             iter = modelDepMgmt.getDependencies().iterator();
1456             if (doInclude)
1457             {
1458                 while (iter.hasNext())
1459                 {
1460                     Dependency dep = (Dependency)iter.next();
1461                     if ( dep.getType().equals( "pom" )
1462                          && Artifact.SCOPE_IMPORT.equals( dep.getScope() ) )
1463                     {
1464                         Artifact artifact = artifactFactory.createProjectArtifact( dep.getGroupId(), dep.getArtifactId(),
1465                                                                                   dep.getVersion(), dep.getScope() );
1466                         MavenProject project = buildFromRepository(artifact, parentSearchRepositories, localRepository, false);
1467 
1468                         DependencyManagement depMgmt = project.getDependencyManagement();
1469 
1470                         if (depMgmt != null)
1471                         {
1472                             if ( getLogger().isDebugEnabled() )
1473                             {
1474                                 getLogger().debug( "Importing managed dependencies for " + dep.toString() );
1475                             }
1476 
1477                             for ( Iterator it = depMgmt.getDependencies().iterator(); it.hasNext(); )
1478                             {
1479                                 Dependency includedDep = (Dependency) it.next();
1480                                 String key = includedDep.getManagementKey();
1481                                 if (!newDeps.containsKey(key))
1482                                 {
1483                                     newDeps.put( includedDep.getManagementKey(), includedDep );
1484                                 }
1485                             }
1486                             newDeps.remove(dep.getManagementKey());
1487                         }
1488                     }
1489                 }
1490                 List deps = new ArrayList(newDeps.values());
1491                 modelDepMgmt.setDependencies(deps);
1492             }
1493         }
1494     }
1495 
1496     private List injectActiveProfiles( ProfileManager profileManager,
1497                                        Model model )
1498         throws ProjectBuildingException
1499     {
1500         List activeProfiles;
1501 
1502         if ( profileManager != null )
1503         {
1504             try
1505             {
1506                 activeProfiles = profileManager.getActiveProfiles();
1507             }
1508             catch ( ProfileActivationException e )
1509             {
1510                 String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
1511 
1512                 throw new ProjectBuildingException( projectId, e.getMessage(), e );
1513             }
1514 
1515             for ( Iterator it = activeProfiles.iterator(); it.hasNext(); )
1516             {
1517                 Profile profile = (Profile) it.next();
1518 
1519                 profileInjector.inject( profile, model );
1520             }
1521         }
1522         else
1523         {
1524             activeProfiles = Collections.EMPTY_LIST;
1525         }
1526 
1527         return activeProfiles;
1528     }
1529 
1530     private void loadProjectExternalProfiles( ProfileManager profileManager,
1531                                               File projectDir )
1532         throws ProfileActivationException
1533     {
1534         if ( projectDir != null )
1535         {
1536             try
1537             {
1538                 ProfilesRoot root = profilesBuilder.buildProfiles( projectDir );
1539 
1540                 if ( root != null )
1541                 {
1542                     List active = root.getActiveProfiles();
1543 
1544                     if ( ( active != null ) && !active.isEmpty() )
1545                     {
1546                         profileManager.explicitlyActivate( root.getActiveProfiles() );
1547                     }
1548 
1549                     for ( Iterator it = root.getProfiles().iterator(); it.hasNext(); )
1550                     {
1551                         org.apache.maven.profiles.Profile rawProfile = (org.apache.maven.profiles.Profile) it.next();
1552 
1553                         Profile converted = ProfilesConversionUtils.convertFromProfileXmlProfile( rawProfile );
1554 
1555                         profileManager.addProfile( converted );
1556                     }
1557                 }
1558             }
1559             catch ( IOException e )
1560             {
1561                 throw new ProfileActivationException( "Cannot read profiles.xml resource from directory: " + projectDir,
1562                                                       e );
1563             }
1564             catch ( XmlPullParserException e )
1565             {
1566                 throw new ProfileActivationException(
1567                     "Cannot parse profiles.xml resource from directory: " + projectDir, e );
1568             }
1569         }
1570     }
1571 
1572     private Model readModel( String projectId,
1573                              File file,
1574                              boolean strict )
1575         throws ProjectBuildingException
1576     {
1577         Reader reader = null;
1578         try
1579         {
1580             reader = ReaderFactory.newXmlReader( file );
1581             return readModel( projectId, file.getAbsolutePath(), reader, strict );
1582         }
1583         catch ( FileNotFoundException e )
1584         {
1585             throw new ProjectBuildingException( projectId,
1586                                                 "Could not find the model file '" + file.getAbsolutePath() + "'.", e );
1587         }
1588         catch ( IOException e )
1589         {
1590             throw new ProjectBuildingException( projectId, "Failed to build model from file '" +
1591                 file.getAbsolutePath() + "'.\nError: \'" + e.getLocalizedMessage() + "\'", e );
1592         }
1593         finally
1594         {
1595             IOUtil.close( reader );
1596         }
1597     }
1598 
1599     private Model readModel( String projectId,
1600                              String pomLocation,
1601                              Reader reader,
1602                              boolean strict )
1603         throws IOException, InvalidProjectModelException
1604     {
1605         String modelSource = IOUtil.toString( reader );
1606 
1607         if ( modelSource.indexOf( "<modelVersion>" + MAVEN_MODEL_VERSION ) < 0 )
1608         {
1609             throw new InvalidProjectModelException( projectId, pomLocation, "Not a v" + MAVEN_MODEL_VERSION  + " POM." );
1610         }
1611 
1612         StringReader sReader = new StringReader( modelSource );
1613 
1614         try
1615         {
1616             return modelReader.read( sReader, strict );
1617         }
1618         catch ( XmlPullParserException e )
1619         {
1620             throw new InvalidProjectModelException( projectId, pomLocation,
1621                                                     "Parse error reading POM. Reason: " + e.getMessage(), e );
1622         }
1623     }
1624 
1625     private Model readModel( String projectId,
1626                              URL url,
1627                              boolean strict )
1628         throws ProjectBuildingException
1629     {
1630         Reader reader = null;
1631         try
1632         {
1633             reader = ReaderFactory.newXmlReader( url.openStream() );
1634             return readModel( projectId, url.toExternalForm(), reader, strict );
1635         }
1636         catch ( IOException e )
1637         {
1638             throw new ProjectBuildingException( projectId, "Failed build model from URL \'" + url.toExternalForm() +
1639                 "\'\nError: \'" + e.getLocalizedMessage() + "\'", e );
1640         }
1641         finally
1642         {
1643             IOUtil.close( reader );
1644         }
1645     }
1646 
1647     private static String createCacheKey( String groupId,
1648                                           String artifactId,
1649                                           String version )
1650     {
1651         return groupId + ":" + artifactId + ":" + version;
1652     }
1653 
1654     protected Set createPluginArtifacts( String projectId,
1655                                          List plugins )
1656         throws ProjectBuildingException
1657     {
1658         Set pluginArtifacts = new LinkedHashSet();
1659 
1660         for ( Iterator i = plugins.iterator(); i.hasNext(); )
1661         {
1662             Plugin p = (Plugin) i.next();
1663 
1664             String version;
1665             if ( StringUtils.isEmpty( p.getVersion() ) )
1666             {
1667                 version = "RELEASE";
1668             }
1669             else
1670             {
1671                 version = p.getVersion();
1672             }
1673 
1674             Artifact artifact;
1675             try
1676             {
1677                 artifact = artifactFactory.createPluginArtifact( p.getGroupId(), p.getArtifactId(),
1678                                                                  VersionRange.createFromVersionSpec( version ) );
1679             }
1680             catch ( InvalidVersionSpecificationException e )
1681             {
1682                 throw new ProjectBuildingException( projectId, "Unable to parse version '" + version +
1683                     "' for plugin '" + ArtifactUtils.versionlessKey( p.getGroupId(), p.getArtifactId() ) + "': " +
1684                     e.getMessage(), e );
1685             }
1686 
1687             if ( artifact != null )
1688             {
1689                 pluginArtifacts.add( artifact );
1690             }
1691         }
1692 
1693         return pluginArtifacts;
1694     }
1695 
1696     // TODO: share with createPluginArtifacts?
1697     protected Set createReportArtifacts( String projectId,
1698                                          List reports )
1699         throws ProjectBuildingException
1700     {
1701         Set pluginArtifacts = new LinkedHashSet();
1702 
1703         if ( reports != null )
1704         {
1705             for ( Iterator i = reports.iterator(); i.hasNext(); )
1706             {
1707                 ReportPlugin p = (ReportPlugin) i.next();
1708 
1709                 String version;
1710                 if ( StringUtils.isEmpty( p.getVersion() ) )
1711                 {
1712                     version = "RELEASE";
1713                 }
1714                 else
1715                 {
1716                     version = p.getVersion();
1717                 }
1718 
1719                 Artifact artifact;
1720                 try
1721                 {
1722                     artifact = artifactFactory.createPluginArtifact( p.getGroupId(), p.getArtifactId(),
1723                                                                      VersionRange.createFromVersionSpec( version ) );
1724                 }
1725                 catch ( InvalidVersionSpecificationException e )
1726                 {
1727                     throw new ProjectBuildingException( projectId, "Unable to parse version '" + version +
1728                         "' for report '" + ArtifactUtils.versionlessKey( p.getGroupId(), p.getArtifactId() ) + "': " +
1729                         e.getMessage(), e );
1730                 }
1731 
1732                 if ( artifact != null )
1733                 {
1734                     pluginArtifacts.add( artifact );
1735                 }
1736             }
1737         }
1738 
1739         return pluginArtifacts;
1740     }
1741 
1742     // TODO: share with createPluginArtifacts?
1743     protected Set createExtensionArtifacts( String projectId,
1744                                             List extensions )
1745         throws ProjectBuildingException
1746     {
1747         Set extensionArtifacts = new LinkedHashSet();
1748 
1749         if ( extensions != null )
1750         {
1751             for ( Iterator i = extensions.iterator(); i.hasNext(); )
1752             {
1753                 Extension ext = (Extension) i.next();
1754 
1755                 String version;
1756                 if ( StringUtils.isEmpty( ext.getVersion() ) )
1757                 {
1758                     version = "RELEASE";
1759                 }
1760                 else
1761                 {
1762                     version = ext.getVersion();
1763                 }
1764 
1765                 Artifact artifact;
1766                 try
1767                 {
1768                     VersionRange versionRange = VersionRange.createFromVersionSpec( version );
1769                     artifact =
1770                         artifactFactory.createExtensionArtifact( ext.getGroupId(), ext.getArtifactId(), versionRange );
1771                 }
1772                 catch ( InvalidVersionSpecificationException e )
1773                 {
1774                     throw new ProjectBuildingException( projectId, "Unable to parse version '" + version +
1775                         "' for extension '" + ArtifactUtils.versionlessKey( ext.getGroupId(), ext.getArtifactId() ) +
1776                         "': " + e.getMessage(), e );
1777                 }
1778 
1779                 if ( artifact != null )
1780                 {
1781                     extensionArtifacts.add( artifact );
1782                 }
1783             }
1784         }
1785 
1786         return extensionArtifacts;
1787     }
1788 
1789     // ----------------------------------------------------------------------
1790     //
1791     // ----------------------------------------------------------------------
1792 
1793     private Model getSuperModel()
1794         throws ProjectBuildingException
1795     {
1796         URL url = DefaultMavenProjectBuilder.class.getResource( "pom-" + MAVEN_MODEL_VERSION + ".xml" );
1797 
1798         String projectId = safeVersionlessKey( STANDALONE_SUPERPOM_GROUPID, STANDALONE_SUPERPOM_ARTIFACTID );
1799 
1800         return readModel( projectId, url, true );
1801     }
1802 
1803     public void contextualize( Context context )
1804         throws ContextException
1805     {
1806         container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
1807     }
1808 
1809     /**
1810      * {@inheritDoc}
1811      */
1812     public void calculateConcreteState( MavenProject project, ProjectBuilderConfiguration config )
1813         throws ModelInterpolationException
1814     {
1815         calculateConcreteStateInternal( project, config, true, new HashSet() );
1816     }
1817     
1818     /**
1819      * {@inheritDoc}
1820      */
1821     public void calculateConcreteState( MavenProject project, ProjectBuilderConfiguration config, boolean processProjectReferences )
1822         throws ModelInterpolationException
1823     {
1824         calculateConcreteStateInternal( project, config, processProjectReferences, ( processProjectReferences ? new HashSet() : null ) );
1825     }
1826     
1827     /*
1828      * NOTE: This is a code hotspot, PLEASE be careful about the performance of logic inside or
1829      * called from this method. 
1830      * 
1831      * NOTE: If processProjectReferences == false, processedProjects MUST NOT BE USED. It will be null.
1832      */
1833     private void calculateConcreteStateInternal( MavenProject project, ProjectBuilderConfiguration config, boolean processProjectReferences, Set processedProjects )
1834         throws ModelInterpolationException
1835     {
1836         if ( processProjectReferences )
1837         {
1838             processedProjects.add( project.getId() );
1839         }
1840         
1841         restoreDynamicStateInternal( project, config, processProjectReferences, processProjectReferences ? new HashSet( processedProjects ) : null );
1842         
1843         if ( !project.isConcrete() )
1844         {
1845             if ( project.getParent() != null )
1846             {
1847                 calculateConcreteStateInternal( project.getParent(), config, processProjectReferences, processedProjects );
1848             }
1849             
1850             Build build = project.getBuild();
1851             if ( build != null )
1852             {
1853                 initResourceMergeIds( build.getResources() );
1854                 initResourceMergeIds( build.getTestResources() );
1855             }
1856 
1857             // NOTE: Since interpolation makes a copy through serialization, we don't need this.
1858             // See note below.
1859             //
1860             // Model model = ModelUtils.cloneModel( project.getModel() );
1861 
1862             File basedir = project.getBasedir();
1863 
1864             // NOTE: If we ever get past serialization/deserialization for interpolation, we'll need to copy the model here!
1865             Model model = ModelUtils.cloneModel( project.getModel() );
1866             model = modelInterpolator.interpolate( model, project.getBasedir(), config, getLogger().isDebugEnabled() );
1867 
1868             List originalInterpolatedCompileSourceRoots = interpolateListOfStrings( project.getCompileSourceRoots(),
1869                                                                                model,
1870                                                                                project.getBasedir(),
1871                                                                                config,
1872                                                                                getLogger().isDebugEnabled() );
1873 
1874             project.preserveCompileSourceRoots( originalInterpolatedCompileSourceRoots );
1875 
1876             project.setCompileSourceRoots( originalInterpolatedCompileSourceRoots == null ? null
1877                             : translateListOfPaths( originalInterpolatedCompileSourceRoots, basedir ) );
1878 
1879             List originalInterpolatedTestCompileSourceRoots = interpolateListOfStrings( project.getTestCompileSourceRoots(),
1880                                                                                    model,
1881                                                                                    project.getBasedir(),
1882                                                                                    config,
1883                                                                                    getLogger().isDebugEnabled() );
1884 
1885             project.preserveTestCompileSourceRoots( originalInterpolatedTestCompileSourceRoots );
1886             project.setTestCompileSourceRoots( originalInterpolatedTestCompileSourceRoots == null ? null
1887                             : translateListOfPaths( originalInterpolatedTestCompileSourceRoots, basedir ) );
1888 
1889             List originalInterpolatedScriptSourceRoots = interpolateListOfStrings( project.getScriptSourceRoots(),
1890                                                                               model,
1891                                                                               project.getBasedir(),
1892                                                                               config,
1893                                                                               getLogger().isDebugEnabled() );
1894 
1895             project.preserveScriptSourceRoots( originalInterpolatedScriptSourceRoots );
1896             
1897             // TODO: MNG-3731
1898             project.setScriptSourceRoots( originalInterpolatedScriptSourceRoots );
1899 //            project.setScriptSourceRoots( originalInterpolatedScriptSourceRoots == null ? null
1900 //                            : translateListOfPaths( originalInterpolatedScriptSourceRoots, basedir ) );
1901 
1902             if ( basedir != null )
1903             {
1904                 pathTranslator.alignToBaseDirectory( model, basedir );
1905             }
1906 
1907             project.preserveBuild( ModelUtils.cloneBuild( model.getBuild() ) );
1908             project.preserveProperties();
1909             project.preserveBasedir();
1910             project.setBuild( model.getBuild() );
1911             
1912             if ( project.getExecutionProject() != null )
1913             {
1914                 calculateConcreteStateInternal( project.getExecutionProject(), config, processProjectReferences, processedProjects );
1915             }
1916             
1917             project.setConcrete( true );
1918         }
1919 
1920         if ( processProjectReferences )
1921         {
1922             calculateConcreteProjectReferences( project, config, processedProjects );
1923         }
1924     }
1925 
1926     private void initResourceMergeIds( List resources )
1927     {
1928         if ( resources != null )
1929         {
1930             for ( Iterator it = resources.iterator(); it.hasNext(); )
1931             {
1932                 Resource resource = (Resource) it.next();
1933 
1934                 resource.initMergeId();
1935             }
1936         }
1937     }
1938 
1939     private void calculateConcreteProjectReferences( MavenProject project,
1940                                                      ProjectBuilderConfiguration config,
1941                                                      Set processedProjects )
1942         throws ModelInterpolationException
1943     {
1944         Map projectRefs = project.getProjectReferences();
1945 
1946         if ( projectRefs != null )
1947         {
1948             for ( Iterator it = projectRefs.values().iterator(); it.hasNext(); )
1949             {
1950                 MavenProject reference = (MavenProject) it.next();
1951                 if ( !processedProjects.contains( reference.getId() ) )
1952                 {
1953                     calculateConcreteStateInternal( reference, config, true, processedProjects );
1954                 }
1955             }
1956         }
1957     }
1958 
1959     private List translateListOfPaths( List paths, File basedir )
1960     {
1961         if ( paths == null )
1962         {
1963             return null;
1964         }
1965         else if ( basedir == null )
1966         {
1967             return paths;
1968         }
1969 
1970         List result = new ArrayList( paths.size() );
1971         for ( Iterator it = paths.iterator(); it.hasNext(); )
1972         {
1973             String path = (String) it.next();
1974 
1975             String aligned = pathTranslator.alignToBaseDirectory( path, basedir );
1976 
1977             result.add( aligned );
1978         }
1979 
1980         return result;
1981     }
1982 
1983     /**
1984      * {@inheritDoc}
1985      */
1986     public void restoreDynamicState( MavenProject project, ProjectBuilderConfiguration config )
1987         throws ModelInterpolationException
1988     {
1989         restoreDynamicStateInternal( project, config, true, new HashSet() );
1990     }
1991     
1992     /**
1993      * {@inheritDoc}
1994      */
1995     public void restoreDynamicState( MavenProject project, ProjectBuilderConfiguration config, boolean processProjectReferences )
1996         throws ModelInterpolationException
1997     {
1998         restoreDynamicStateInternal( project, config, processProjectReferences, ( processProjectReferences ? new HashSet() : null ) );
1999     }
2000     
2001     /*
2002      * NOTE: This is a code hotspot, PLEASE be careful about the performance of logic inside or
2003      * called from this method. 
2004      * 
2005      * NOTE: If processProjectReferences == false, processedProjects MUST NOT BE USED. It will be null.
2006      */
2007     private void restoreDynamicStateInternal( MavenProject project, ProjectBuilderConfiguration config, boolean processProjectReferences, Set processedProjects )
2008         throws ModelInterpolationException
2009     {
2010         if ( processProjectReferences )
2011         {
2012             processedProjects.add( project.getId() );
2013         }
2014         
2015         if ( project.isConcrete() && projectWasChanged( project ) )
2016         {
2017             if ( project.getParent() != null )
2018             {
2019                 restoreDynamicStateInternal( project.getParent(), config, processProjectReferences, processedProjects );
2020             }
2021             
2022             restoreBuildRoots( project, config, getLogger().isDebugEnabled() );
2023             restoreModelBuildSection( project, config, getLogger().isDebugEnabled() );
2024             
2025             if ( project.getExecutionProject() != null )
2026             {
2027                 restoreDynamicStateInternal( project.getExecutionProject(), config, processProjectReferences, processedProjects );
2028             }
2029             
2030             project.setConcrete( false );
2031         }
2032 
2033         if ( processProjectReferences )
2034         {
2035             restoreDynamicProjectReferences( project, config, processedProjects );
2036         }
2037     }
2038 
2039     private boolean projectWasChanged( MavenProject project )
2040     {
2041         if ( !objectEquals( project.getBasedir(), project.getPreservedBasedir() ) )
2042         {
2043             return true;
2044         }
2045         
2046         if ( !objectEquals( project.getProperties(), project.getPreservedProperties() ) )
2047         {
2048             return true;
2049         }
2050         
2051         Build oBuild = project.getOriginalInterpolatedBuild();
2052         Build build = project.getBuild();
2053         
2054         if ( !objectEquals( oBuild.getDirectory(), build.getDirectory() ) )
2055         {
2056             return true;
2057         }
2058         
2059         if ( !objectEquals( oBuild.getOutputDirectory(), build.getOutputDirectory() ) )
2060         {
2061             return true;
2062         }
2063         
2064         if ( !objectEquals( oBuild.getSourceDirectory(), build.getSourceDirectory() ) )
2065         {
2066             return true;
2067         }
2068         
2069         if ( !objectEquals( oBuild.getTestSourceDirectory(), build.getTestSourceDirectory() ) )
2070         {
2071             return true;
2072         }
2073         
2074         if ( !objectEquals( oBuild.getScriptSourceDirectory(), build.getScriptSourceDirectory() ) )
2075         {
2076             return true;
2077         }
2078         
2079         return false;
2080     }
2081 
2082     private boolean objectEquals( Object obj1, Object obj2 )
2083     {
2084         return obj1 == null ? obj2 == null : obj2 != null && ( obj1 == obj2 || obj1.equals( obj2 ) );
2085     }
2086 
2087     private void propagateNewPlugins( MavenProject project )
2088     {
2089         Build changedBuild = project.getBuild();
2090         Build dynamicBuild = project.getDynamicBuild();
2091         
2092         if ( changedBuild == null || dynamicBuild == null )
2093         {
2094             return;
2095         }
2096         
2097         List changedPlugins = changedBuild.getPlugins();
2098         List dynamicPlugins = dynamicBuild.getPlugins();
2099         
2100         if ( changedPlugins != null && dynamicPlugins != null && changedPlugins.size() != dynamicPlugins.size() )
2101         {
2102             changedPlugins.removeAll( dynamicPlugins );
2103             if ( !changedPlugins.isEmpty() )
2104             {
2105                 for ( Iterator it = changedPlugins.iterator(); it.hasNext(); )
2106                 {
2107                     Plugin plugin = (Plugin) it.next();
2108                     
2109                     dynamicBuild.addPlugin( plugin );
2110                 }
2111             }
2112         }
2113         
2114         dynamicBuild.flushPluginMap();
2115     }
2116 
2117     private void restoreDynamicProjectReferences( MavenProject project,
2118                                                   ProjectBuilderConfiguration config,
2119                                                   Set processedProjects )
2120         throws ModelInterpolationException
2121     {
2122         Map projectRefs = project.getProjectReferences();
2123         if ( projectRefs != null )
2124         {
2125             for ( Iterator it = projectRefs.values().iterator(); it.hasNext(); )
2126             {
2127                 MavenProject projectRef = (MavenProject) it.next();
2128                 if ( !processedProjects.contains( projectRef.getId() ) )
2129                 {
2130                     restoreDynamicStateInternal( projectRef, config, true, processedProjects );
2131                 }
2132             }
2133         }
2134     }
2135 
2136     private void restoreBuildRoots( MavenProject project,
2137                                     ProjectBuilderConfiguration config,
2138                                     boolean debugMessages )
2139         throws ModelInterpolationException
2140     {
2141         project.setCompileSourceRoots( restoreListOfStrings( project.getDynamicCompileSourceRoots(),
2142                                                              project.getOriginalInterpolatedCompileSourceRoots(),
2143                                                              project.getCompileSourceRoots(),
2144                                                              project,
2145                                                              config,
2146                                                              debugMessages ) );
2147 
2148         project.setTestCompileSourceRoots( restoreListOfStrings( project.getDynamicTestCompileSourceRoots(),
2149                                                                  project.getOriginalInterpolatedTestCompileSourceRoots(),
2150                                                                  project.getTestCompileSourceRoots(),
2151                                                                  project,
2152                                                                  config,
2153                                                                  debugMessages ) );
2154 
2155         project.setScriptSourceRoots( restoreListOfStrings( project.getDynamicScriptSourceRoots(),
2156                                                             project.getOriginalInterpolatedScriptSourceRoots(),
2157                                                             project.getScriptSourceRoots(),
2158                                                             project,
2159                                                             config,
2160                                                             debugMessages ) );
2161 
2162         project.clearRestorableRoots();
2163     }
2164 
2165     private void restoreModelBuildSection( MavenProject project,
2166                                            ProjectBuilderConfiguration config,
2167                                            boolean debugMessages )
2168         throws ModelInterpolationException
2169     {
2170         Build changedBuild = project.getBuild();
2171         Build dynamicBuild = project.getDynamicBuild();
2172         Build originalInterpolatedBuild = project.getOriginalInterpolatedBuild();
2173 
2174         dynamicBuild.setResources( restoreResources( dynamicBuild.getResources(),
2175                                                          originalInterpolatedBuild.getResources(),
2176                                                          changedBuild.getResources(),
2177                                                          project,
2178                                                          config,
2179                                                          debugMessages ) );
2180 
2181         dynamicBuild.setTestResources( restoreResources( dynamicBuild.getTestResources(),
2182                                                          originalInterpolatedBuild.getTestResources(),
2183                                                          changedBuild.getTestResources(),
2184                                                          project,
2185                                                          config,
2186                                                          debugMessages ) );
2187 
2188         dynamicBuild.setFilters( restoreListOfStrings( dynamicBuild.getFilters(),
2189                                                            originalInterpolatedBuild.getFilters(),
2190                                                            changedBuild.getFilters(),
2191                                                            project,
2192                                                            config,
2193                                                            debugMessages ) );
2194 
2195         dynamicBuild.setFinalName( restoreString( dynamicBuild.getFinalName(),
2196                                                   originalInterpolatedBuild.getFinalName(),
2197                                                   changedBuild.getFinalName(),
2198                                                   project,
2199                                                   config,
2200                                                   debugMessages ) );
2201 
2202         dynamicBuild.setDefaultGoal( restoreString( dynamicBuild.getDefaultGoal(),
2203                                                   originalInterpolatedBuild.getDefaultGoal(),
2204                                                   changedBuild.getDefaultGoal(),
2205                                                   project,
2206                                                   config,
2207                                                   debugMessages ) );
2208 
2209         dynamicBuild.setSourceDirectory( restoreString( dynamicBuild.getSourceDirectory(),
2210                                                             originalInterpolatedBuild.getSourceDirectory(),
2211                                                             changedBuild.getSourceDirectory(),
2212                                                             project,
2213                                                             config,
2214                                                             debugMessages ) );
2215 
2216         dynamicBuild.setTestSourceDirectory( restoreString( dynamicBuild.getTestSourceDirectory(),
2217                                                                 originalInterpolatedBuild.getTestSourceDirectory(),
2218                                                                 changedBuild.getTestSourceDirectory(),
2219                                                                 project,
2220                                                                 config,
2221                                                                 debugMessages ) );
2222 
2223         dynamicBuild.setScriptSourceDirectory( restoreString( dynamicBuild.getScriptSourceDirectory(),
2224                                                                   originalInterpolatedBuild.getScriptSourceDirectory(),
2225                                                                   changedBuild.getScriptSourceDirectory(),
2226                                                                   project,
2227                                                                   config,
2228                                                                   debugMessages ) );
2229 
2230         dynamicBuild.setOutputDirectory( restoreString( dynamicBuild.getOutputDirectory(),
2231                                                             originalInterpolatedBuild.getOutputDirectory(),
2232                                                             changedBuild.getOutputDirectory(),
2233                                                             project,
2234                                                             config,
2235                                                             debugMessages ) );
2236 
2237         dynamicBuild.setTestOutputDirectory( restoreString( dynamicBuild.getTestOutputDirectory(),
2238                                                                 originalInterpolatedBuild.getTestOutputDirectory(),
2239                                                                 changedBuild.getTestOutputDirectory(),
2240                                                                 project,
2241                                                                 config,
2242                                                                 debugMessages ) );
2243 
2244         dynamicBuild.setDirectory( restoreString( dynamicBuild.getDirectory(),
2245                                                       originalInterpolatedBuild.getDirectory(),
2246                                                       changedBuild.getDirectory(),
2247                                                       project,
2248                                                       config,
2249                                                       debugMessages ) );
2250 
2251         propagateNewPlugins( project );
2252         
2253         project.setBuild( dynamicBuild );
2254 
2255         project.clearRestorableBuild();
2256     }
2257 
2258     private List interpolateListOfStrings( List originalStrings,
2259                                            Model model,
2260                                            File projectDir,
2261                                            ProjectBuilderConfiguration config,
2262                                            boolean debugMessages )
2263         throws ModelInterpolationException
2264     {
2265         if ( originalStrings == null )
2266         {
2267             return null;
2268         }
2269 
2270         List result = new ArrayList();
2271 
2272         for ( Iterator it = originalStrings.iterator(); it.hasNext(); )
2273         {
2274             String original = (String) it.next();
2275             String interpolated = modelInterpolator.interpolate( original, model, projectDir, config, debugMessages );
2276 
2277             result.add( interpolated );
2278         }
2279 
2280         return result;
2281     }
2282 
2283     private String restoreString( String originalString,
2284                                       String originalInterpolatedString,
2285                                       String changedString,
2286                                       MavenProject project,
2287                                       ProjectBuilderConfiguration config,
2288                                       boolean debugMessages )
2289         throws ModelInterpolationException
2290     {
2291         if ( originalString == null )
2292         {
2293             return changedString;
2294         }
2295         else if ( changedString == null )
2296         {
2297             return originalString;
2298         }
2299 
2300         Model model = project.getModel();
2301 
2302         String relativeChangedString;
2303         if ( project.getBasedir() != null )
2304         {
2305             relativeChangedString = pathTranslator.unalignFromBaseDirectory( changedString, project.getBasedir() );
2306         }
2307         else
2308         {
2309             relativeChangedString = changedString;
2310         }
2311 
2312         String interpolatedOriginal = modelInterpolator.interpolate( originalString,
2313                                                                      model,
2314                                                                      project.getBasedir(),
2315                                                                      config,
2316                                                                      debugMessages );
2317         
2318         interpolatedOriginal = pathTranslator.unalignFromBaseDirectory( interpolatedOriginal, project.getBasedir() );
2319 
2320         String interpolatedOriginal2 = modelInterpolator.interpolate( originalInterpolatedString,
2321                                                                       model,
2322                                                                       project.getBasedir(),
2323                                                                       config,
2324                                                                       debugMessages );
2325         
2326         interpolatedOriginal2 = pathTranslator.alignToBaseDirectory( interpolatedOriginal2, project.getBasedir() );
2327 
2328         String interpolatedChanged = modelInterpolator.interpolate( changedString,
2329                                                                     model,
2330                                                                     project.getBasedir(),
2331                                                                     config,
2332                                                                     debugMessages );
2333         
2334         interpolatedChanged = pathTranslator.alignToBaseDirectory( interpolatedChanged, project.getBasedir() );
2335 
2336         String relativeInterpolatedChanged = modelInterpolator.interpolate( relativeChangedString,
2337                                                                             model,
2338                                                                             project.getBasedir(),
2339                                                                             config,
2340                                                                             debugMessages );
2341 
2342         if ( interpolatedOriginal.equals( interpolatedChanged ) || interpolatedOriginal2.equals( interpolatedChanged ) )
2343         {
2344             return originalString;
2345         }
2346         else if ( interpolatedOriginal.equals( relativeInterpolatedChanged )
2347             || interpolatedOriginal2.equals( relativeInterpolatedChanged ) )
2348         {
2349             return originalString;
2350         }
2351 
2352         return relativeChangedString;
2353     }
2354 
2355     private List restoreListOfStrings( List originalStrings,
2356                                            List originalInterpolatedStrings,
2357                                            List changedStrings,
2358                                            MavenProject project,
2359                                            ProjectBuilderConfiguration config,
2360                                            boolean debugMessages )
2361         throws ModelInterpolationException
2362     {
2363         if ( originalStrings == null )
2364         {
2365             return changedStrings;
2366         }
2367         else if ( changedStrings == null )
2368         {
2369             return originalStrings;
2370         }
2371 
2372         List result = new ArrayList();
2373 
2374         Map orig = new HashMap();
2375         for ( int idx = 0; idx < originalStrings.size(); idx++ )
2376         {
2377             String[] permutations = new String[2];
2378 
2379             permutations[0] = pathTranslator.alignToBaseDirectory( (String) originalInterpolatedStrings.get( idx ), project.getBasedir() );
2380             permutations[1] = (String) originalStrings.get( idx );
2381 
2382             orig.put( permutations[0], permutations );
2383         }
2384 
2385         for ( Iterator it = changedStrings.iterator(); it.hasNext(); )
2386         {
2387             String changedString = (String) it.next();
2388             String relativeChangedString;
2389             if ( project.getBasedir() != null )
2390             {
2391                 relativeChangedString = pathTranslator.unalignFromBaseDirectory( changedString, project.getBasedir() );
2392             }
2393             else
2394             {
2395                 relativeChangedString = changedString;
2396             }
2397 
2398             String interpolated = modelInterpolator.interpolate( changedString,
2399                                                                  project.getModel(),
2400                                                                  project.getBasedir(),
2401                                                                  config,
2402                                                                  debugMessages );
2403             
2404             interpolated = pathTranslator.alignToBaseDirectory( interpolated, project.getBasedir() );
2405 
2406             String relativeInterpolated = modelInterpolator.interpolate( relativeChangedString,
2407                                                                          project.getModel(),
2408                                                                          project.getBasedir(),
2409                                                                          config,
2410                                                                          debugMessages );
2411             
2412             String[] original = (String[]) orig.get( interpolated );
2413             if ( original == null )
2414             {
2415                 original = (String[]) orig.get( relativeInterpolated );
2416             }
2417 
2418             if ( original == null )
2419             {
2420                 result.add( relativeChangedString );
2421             }
2422             else
2423             {
2424                 result.add( original[1] );
2425             }
2426         }
2427 
2428         return result;
2429     }
2430 
2431     private List restoreResources( List originalResources,
2432                                        List originalInterpolatedResources,
2433                                        List changedResources,
2434                                        MavenProject project,
2435                                        ProjectBuilderConfiguration config,
2436                                        boolean debugMessages )
2437         throws ModelInterpolationException
2438     {
2439         if ( originalResources == null || changedResources == null )
2440         {
2441             return originalResources;
2442         }
2443 
2444         List result = new ArrayList();
2445 
2446         Map originalResourcesByMergeId = new HashMap();
2447         for ( int idx = 0; idx < originalResources.size(); idx++ )
2448         {
2449             Resource[] permutations = new Resource[2];
2450 
2451             permutations[0] = (Resource) originalInterpolatedResources.get( idx );
2452             permutations[1] = (Resource) originalResources.get( idx );
2453 
2454             originalResourcesByMergeId.put( permutations[0].getMergeId(), permutations );
2455         }
2456 
2457         for ( Iterator it = changedResources.iterator(); it.hasNext(); )
2458         {
2459             Resource resource = (Resource) it.next();
2460             String mergeId = resource.getMergeId();
2461             if ( mergeId == null || !originalResourcesByMergeId.containsKey( mergeId ) )
2462             {
2463                 result.add( resource );
2464             }
2465             else
2466             {
2467                 Resource originalInterpolatedResource = ( (Resource[]) originalResourcesByMergeId.get( mergeId ) )[0];
2468                 Resource originalResource = ( (Resource[]) originalResourcesByMergeId.get( mergeId ) )[1];
2469 
2470                 String dir = modelInterpolator.interpolate( resource.getDirectory(), project.getModel(), project.getBasedir(), config, getLogger().isDebugEnabled() );
2471                 String oDir = originalInterpolatedResource.getDirectory();
2472 
2473                 if ( !dir.equals( oDir ) )
2474                 {
2475                     originalResource.setDirectory( pathTranslator.unalignFromBaseDirectory( dir, project.getBasedir() ) );
2476                 }
2477 
2478                 if ( resource.getTargetPath() != null )
2479                 {
2480                     String target = modelInterpolator.interpolate( resource.getTargetPath(), project.getModel(), project.getBasedir(), config, getLogger().isDebugEnabled() );
2481 
2482                     String oTarget = originalInterpolatedResource.getTargetPath();
2483 
2484                     if ( !target.equals( oTarget ) )
2485                     {
2486                         originalResource.setTargetPath( pathTranslator.unalignFromBaseDirectory( target, project.getBasedir() ) );
2487                     }
2488                 }
2489 
2490                 originalResource.setFiltering( resource.isFiltering() );
2491 
2492                 originalResource.setExcludes( collectRestoredListOfPatterns( resource.getExcludes(),
2493                                                                              originalResource.getExcludes(),
2494                                                                              originalInterpolatedResource.getExcludes() ) );
2495 
2496                 originalResource.setIncludes( collectRestoredListOfPatterns( resource.getIncludes(),
2497                                                                              originalResource.getIncludes(),
2498                                                                              originalInterpolatedResource.getIncludes() ) );
2499 
2500                 result.add( originalResource );
2501             }
2502         }
2503 
2504         return result;
2505     }
2506 
2507     private List collectRestoredListOfPatterns( List patterns,
2508                                                         List originalPatterns,
2509                                                         List originalInterpolatedPatterns )
2510     {
2511         LinkedHashSet collectedPatterns = new LinkedHashSet();
2512 
2513         collectedPatterns.addAll( originalPatterns );
2514 
2515         for ( Iterator it = patterns.iterator(); it.hasNext(); )
2516         {
2517             String pattern = (String) it.next();
2518             if ( !originalInterpolatedPatterns.contains( pattern ) )
2519             {
2520                 collectedPatterns.add( pattern );
2521             }
2522         }
2523 
2524         return collectedPatterns.isEmpty() ? Collections.EMPTY_LIST
2525                         : new ArrayList( collectedPatterns );
2526     }
2527 
2528 }