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 org.apache.maven.artifact.Artifact;
23  import org.apache.maven.artifact.ArtifactStatus;
24  import org.apache.maven.artifact.ArtifactUtils;
25  import org.apache.maven.artifact.InvalidRepositoryException;
26  import org.apache.maven.artifact.manager.WagonManager;
27  import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
28  import org.apache.maven.artifact.repository.ArtifactRepository;
29  import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
30  import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
31  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
32  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
33  import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
34  import org.apache.maven.artifact.resolver.ArtifactResolver;
35  import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter;
36  import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
37  import org.apache.maven.artifact.versioning.ManagedVersionMap;
38  import org.apache.maven.artifact.versioning.VersionRange;
39  import org.apache.maven.model.Build;
40  import org.apache.maven.model.Dependency;
41  import org.apache.maven.model.DependencyManagement;
42  import org.apache.maven.model.DistributionManagement;
43  import org.apache.maven.model.Exclusion;
44  import org.apache.maven.model.Extension;
45  import org.apache.maven.model.Model;
46  import org.apache.maven.model.Parent;
47  import org.apache.maven.model.Plugin;
48  import org.apache.maven.model.PluginExecution;
49  import org.apache.maven.model.PluginManagement;
50  import org.apache.maven.model.Profile;
51  import org.apache.maven.model.ReportPlugin;
52  import org.apache.maven.model.Repository;
53  import org.apache.maven.model.Resource;
54  import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
55  import org.apache.maven.profiles.DefaultProfileManager;
56  import org.apache.maven.profiles.MavenProfilesBuilder;
57  import org.apache.maven.profiles.ProfileManager;
58  import org.apache.maven.profiles.ProfilesConversionUtils;
59  import org.apache.maven.profiles.ProfilesRoot;
60  import org.apache.maven.profiles.activation.ProfileActivationException;
61  import org.apache.maven.project.artifact.InvalidDependencyVersionException;
62  import org.apache.maven.project.artifact.ProjectArtifactFactory;
63  import org.apache.maven.project.inheritance.ModelInheritanceAssembler;
64  import org.apache.maven.project.injection.ModelDefaultsInjector;
65  import org.apache.maven.project.injection.ProfileInjector;
66  import org.apache.maven.project.interpolation.ModelInterpolationException;
67  import org.apache.maven.project.interpolation.ModelInterpolator;
68  import org.apache.maven.project.path.PathTranslator;
69  import org.apache.maven.project.validation.ModelValidationResult;
70  import org.apache.maven.project.validation.ModelValidator;
71  import org.apache.maven.wagon.events.TransferListener;
72  import org.codehaus.plexus.PlexusConstants;
73  import org.codehaus.plexus.PlexusContainer;
74  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
75  import org.codehaus.plexus.context.Context;
76  import org.codehaus.plexus.context.ContextException;
77  import org.codehaus.plexus.logging.AbstractLogEnabled;
78  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
79  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
80  import org.codehaus.plexus.util.IOUtil;
81  import org.codehaus.plexus.util.ReaderFactory;
82  import org.codehaus.plexus.util.StringUtils;
83  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
84  
85  import java.io.File;
86  import java.io.FileNotFoundException;
87  import java.io.IOException;
88  import java.io.Reader;
89  import java.io.StringReader;
90  import java.net.URL;
91  import java.util.ArrayList;
92  import java.util.Collections;
93  import java.util.Date;
94  import java.util.HashMap;
95  import java.util.HashSet;
96  import java.util.Iterator;
97  import java.util.LinkedHashSet;
98  import java.util.LinkedList;
99  import java.util.List;
100 import java.util.Map;
101 import java.util.Set;
102 import java.util.TreeMap;
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 788791 2009-06-26 17:55:26Z jdcasey $
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, projectDescriptor, 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         project.setManagedVersionMap( createManagedVersionMap( projectId,
911                                                                project.getDependencyManagement(),
912                                                                project.getParent() ) );
913 
914         return project;
915     }
916 
917     private String safeVersionlessKey( String groupId,
918                                        String artifactId )
919     {
920         String gid = groupId;
921 
922         if ( StringUtils.isEmpty( gid ) )
923         {
924             gid = "unknown";
925         }
926 
927         String aid = artifactId;
928 
929         if ( StringUtils.isEmpty( aid ) )
930         {
931             aid = "unknown";
932         }
933 
934         return ArtifactUtils.versionlessKey( gid, aid );
935     }
936 
937     private List buildArtifactRepositories( Model model )
938         throws ProjectBuildingException
939     {
940         try
941         {
942             return ProjectUtils.buildArtifactRepositories( model.getRepositories(), artifactRepositoryFactory,
943                                                            container );
944         }
945         catch ( InvalidRepositoryException e )
946         {
947             String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
948 
949             throw new ProjectBuildingException( projectId, e.getMessage(), e );
950         }
951     }
952 
953     /**
954      * @todo can this take in a model instead of a project and still be successful?
955      * @todo In fact, does project REALLY need a MavenProject as a parent? Couldn't it have just a wrapper around a
956      * model that supported parents which were also the wrapper so that inheritence was assembled. We don't really need
957      * the resolved source roots, etc for the parent - that occurs for the parent when it is constructed independently
958      * and projects are not cached or reused
959      */
960     private MavenProject processProjectLogic( String pomLocation,
961                                               MavenProject project,
962                                               ProjectBuilderConfiguration config,
963                                               File projectDir,
964                                               List remoteRepositories,
965                                               boolean strict,
966                                               boolean isSuperPom )
967         throws ProjectBuildingException, ModelInterpolationException, InvalidRepositoryException
968     {
969         Model model = project.getModel();
970 
971         List activeProfiles = project.getActiveProfiles();
972 
973         if ( activeProfiles == null )
974         {
975             activeProfiles = new ArrayList();
976         }
977 
978         ProfileManager profileMgr = config == null ? null : config.getGlobalProfileManager();
979 
980         List injectedProfiles = injectActiveProfiles( profileMgr, model );
981 
982         activeProfiles.addAll( injectedProfiles );
983         
984         // --------------------------------------------------------------------------------
985         
986         Build dynamicBuild = model.getBuild();
987 
988         model.setBuild( ModelUtils.cloneBuild( dynamicBuild ) );
989 
990         model = modelInterpolator.interpolate( model, projectDir, config, getLogger().isDebugEnabled() );
991 
992         mergeDeterministicBuildElements( model.getBuild(), dynamicBuild );
993 
994         model.setBuild( dynamicBuild );
995         
996         // MNG-3482: Make sure depMgmt is interpolated before merging.
997         if ( !isSuperPom )
998         {
999             mergeManagedDependencies( model, config.getLocalRepository(), remoteRepositories );
1000         }
1001 
1002         // interpolation is before injection, because interpolation is off-limits in the injected variables
1003         modelDefaultsInjector.injectDefaults( model );
1004 
1005         MavenProject parentProject = project.getParent();
1006 
1007         Model originalModel = project.getOriginalModel();
1008 
1009         // We will return a different project object using the new model (hence the need to return a project, not just modify the parameter)
1010         project = new MavenProject( model, getLogger() );
1011 
1012         project.setOriginalModel( originalModel );
1013         
1014         project.setActiveProfiles( activeProfiles );
1015 
1016         // TODO: maybe not strictly correct, while we should enfore that packaging has a type handler of the same id, we don't
1017         Artifact projectArtifact = artifactFactory.create( project );
1018         
1019         project.setArtifact( projectArtifact );
1020         project.setProjectBuilderConfiguration( config );
1021 
1022         project.setPluginArtifactRepositories( ProjectUtils.buildArtifactRepositories( model.getPluginRepositories(),
1023                                                                                        artifactRepositoryFactory,
1024                                                                                        container ) );
1025 
1026         DistributionManagement dm = model.getDistributionManagement();
1027         if ( dm != null )
1028         {
1029             ArtifactRepository repo = ProjectUtils.buildDeploymentArtifactRepository( dm.getRepository(),
1030                                                                                       artifactRepositoryFactory,
1031                                                                                       container );
1032             project.setReleaseArtifactRepository( repo );
1033 
1034             if ( dm.getSnapshotRepository() != null )
1035             {
1036                 repo = ProjectUtils.buildDeploymentArtifactRepository( dm.getSnapshotRepository(),
1037                                                                        artifactRepositoryFactory, container );
1038                 project.setSnapshotArtifactRepository( repo );
1039             }
1040         }
1041 
1042         if ( parentProject != null )
1043         {
1044             String cacheKey = createCacheKey( parentProject.getGroupId(),
1045                                               parentProject.getArtifactId(),
1046                                               parentProject.getVersion() );
1047 
1048             MavenProject processedParent = (MavenProject) processedProjectCache.get( cacheKey );
1049             Artifact parentArtifact;
1050 
1051             // yeah, this null check might be a bit paranoid, but better safe than sorry...
1052             if ( processedParent != null )
1053             {
1054                 project.setParent( processedParent );
1055 
1056                 parentArtifact = processedParent.getArtifact();
1057             }
1058             else
1059             {
1060                 project.setParent( parentProject );
1061 
1062                 parentArtifact = artifactFactory.createParentArtifact( parentProject.getGroupId(),
1063                                                                                 parentProject.getArtifactId(),
1064                                                                                 parentProject.getVersion() );
1065             }
1066 
1067             project.setParentArtifact( parentArtifact );
1068         }
1069 
1070         // Must validate before artifact construction to make sure dependencies are good
1071         ModelValidationResult validationResult = validator.validate( model );
1072 
1073         String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
1074 
1075         if ( validationResult.getMessageCount() > 0 )
1076         {
1077             throw new InvalidProjectModelException( projectId, pomLocation, "Failed to validate POM",
1078                                                     validationResult );
1079         }
1080 
1081         project.setRemoteArtifactRepositories(
1082             ProjectUtils.buildArtifactRepositories( model.getRepositories(), artifactRepositoryFactory, container ) );
1083 
1084         // TODO: these aren't taking active project artifacts into consideration in the reactor
1085         project.setPluginArtifacts( createPluginArtifacts( projectId, project.getBuildPlugins() ) );
1086 
1087         project.setReportArtifacts( createReportArtifacts( projectId, project.getReportPlugins() ) );
1088 
1089         project.setExtensionArtifacts( createExtensionArtifacts( projectId, project.getBuildExtensions() ) );
1090         
1091         return project;
1092     }
1093 
1094     private void mergeDeterministicBuildElements( Build interpolatedBuild,
1095                                                   Build dynamicBuild )
1096     {
1097         mergeDeterministicPluginElements( interpolatedBuild.getPlugins(), dynamicBuild.getPlugins() );
1098 
1099         PluginManagement dPluginMgmt = dynamicBuild.getPluginManagement();
1100         PluginManagement iPluginMgmt = interpolatedBuild.getPluginManagement();
1101 
1102         if ( dPluginMgmt != null )
1103         {
1104             mergeDeterministicPluginElements( iPluginMgmt.getPlugins(), dPluginMgmt.getPlugins() );
1105         }
1106 
1107         if ( dynamicBuild.getExtensions() != null )
1108         {
1109             dynamicBuild.setExtensions( interpolatedBuild.getExtensions() );
1110         }
1111     }
1112 
1113     private void mergeDeterministicPluginElements( List iPlugins, List dPlugins )
1114     {
1115         if ( dPlugins != null )
1116         {
1117             for ( int i = 0; i < dPlugins.size(); i++ )
1118             {
1119                 Plugin dPlugin = (Plugin) dPlugins.get( i );
1120                 Plugin iPlugin = (Plugin) iPlugins.get( i );
1121 
1122                 dPlugin.setGroupId( iPlugin.getGroupId() );
1123                 dPlugin.setArtifactId( iPlugin.getArtifactId() );
1124                 dPlugin.setVersion( iPlugin.getVersion() );
1125                 
1126                 dPlugin.setDependencies( iPlugin.getDependencies() );
1127                 
1128                 List dExecutions = dPlugin.getExecutions();
1129                 if ( dExecutions != null )
1130                 {
1131                     List iExecutions = iPlugin.getExecutions();
1132                     
1133                     for ( int j = 0; j < dExecutions.size(); j++ )
1134                     {
1135                         PluginExecution dExec = (PluginExecution) dExecutions.get( j );
1136                         PluginExecution iExec = (PluginExecution) iExecutions.get( j );
1137                         
1138                         dExec.setId( iExec.getId() );
1139                     }
1140                 }
1141             }
1142         }
1143     }
1144 
1145     /**
1146      * @noinspection CollectionDeclaredAsConcreteClass
1147      * @todo We need to find an effective way to unit test parts of this method!
1148      * @todo Refactor this into smaller methods with discrete purposes.
1149      */
1150     private MavenProject assembleLineage( Model model,
1151                                           LinkedList lineage,
1152                                           ProjectBuilderConfiguration config,
1153                                           File projectDescriptor,
1154                                           List parentSearchRepositories,
1155                                           Set aggregatedRemoteWagonRepositories,
1156                                           boolean strict )
1157         throws ProjectBuildingException, InvalidRepositoryException
1158     {
1159         Model originalModel = ModelUtils.cloneModel( model );
1160 
1161         File projectDir = null;
1162         if ( projectDescriptor != null )
1163         {
1164             projectDir = projectDescriptor.getAbsoluteFile().getParentFile();
1165         }
1166 
1167         ProfileManager externalProfileManager = config.getGlobalProfileManager();
1168         ProfileManager profileManager;
1169         if ( externalProfileManager != null )
1170         {
1171             profileManager = new DefaultProfileManager( container, externalProfileManager.getRequestProperties() );
1172         }
1173         else
1174         {
1175             //TODO mkleint - use the (Container, Properties constructor to make system properties embeddable
1176             profileManager = new DefaultProfileManager( container );
1177         }
1178 
1179         if ( externalProfileManager != null )
1180         {
1181             profileManager.explicitlyActivate( externalProfileManager.getExplicitlyActivatedIds() );
1182 
1183             profileManager.explicitlyDeactivate( externalProfileManager.getExplicitlyDeactivatedIds() );
1184         }
1185 
1186         List activeProfiles;
1187 
1188         try
1189         {
1190             profileManager.addProfiles( model.getProfiles() );
1191 
1192             loadProjectExternalProfiles( profileManager, projectDir );
1193 
1194             activeProfiles = injectActiveProfiles( profileManager, model );
1195         }
1196         catch ( ProfileActivationException e )
1197         {
1198             String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
1199 
1200             throw new ProjectBuildingException( projectId, "Failed to activate local (project-level) build profiles: " +
1201                 e.getMessage(), e );
1202         }
1203 
1204         if ( !model.getRepositories().isEmpty() )
1205         {
1206             List respositories = buildArtifactRepositories( model );
1207 
1208             for ( Iterator it = respositories.iterator(); it.hasNext(); )
1209             {
1210                 ArtifactRepository repository = (ArtifactRepository) it.next();
1211 
1212                 if ( !aggregatedRemoteWagonRepositories.contains( repository ) )
1213                 {
1214                     aggregatedRemoteWagonRepositories.add( repository );
1215                 }
1216             }
1217         }
1218 
1219         MavenProject project = new MavenProject( model, getLogger() );
1220 
1221         project.setFile( projectDescriptor );
1222         project.setActiveProfiles( activeProfiles );
1223         project.setOriginalModel( originalModel );
1224 
1225         lineage.addFirst( project );
1226 
1227         Parent parentModel = model.getParent();
1228 
1229         String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
1230 
1231         if ( parentModel != null )
1232         {
1233             if ( StringUtils.isEmpty( parentModel.getGroupId() ) )
1234             {
1235                 throw new ProjectBuildingException( projectId, "Missing groupId element from parent element" );
1236             }
1237             else if ( StringUtils.isEmpty( parentModel.getArtifactId() ) )
1238             {
1239                 throw new ProjectBuildingException( projectId, "Missing artifactId element from parent element" );
1240             }
1241             else if ( parentModel.getGroupId().equals( model.getGroupId() ) &&
1242                 parentModel.getArtifactId().equals( model.getArtifactId() ) )
1243             {
1244                 throw new ProjectBuildingException( projectId,
1245                                                     "Parent element is a duplicate of " + "the current project " );
1246             }
1247             else if ( StringUtils.isEmpty( parentModel.getVersion() ) )
1248             {
1249                 throw new ProjectBuildingException( projectId, "Missing version element from parent element" );
1250             }
1251 
1252             // the only way this will have a value is if we find the parent on disk...
1253             File parentDescriptor = null;
1254 
1255             model = null;
1256 
1257             String parentKey =
1258                 createCacheKey( parentModel.getGroupId(), parentModel.getArtifactId(), parentModel.getVersion() );
1259             MavenProject parentProject = (MavenProject) rawProjectCache.get( parentKey );
1260 
1261             if ( parentProject != null )
1262             {
1263                 model = ModelUtils.cloneModel( parentProject.getOriginalModel() );
1264 
1265                 parentDescriptor = parentProject.getFile();
1266             }
1267 
1268             String parentRelativePath = parentModel.getRelativePath();
1269 
1270             // if we can't find a cached model matching the parent spec, then let's try to look on disk using
1271             // <relativePath/>
1272             if ( ( model == null ) && ( projectDir != null ) && StringUtils.isNotEmpty( parentRelativePath ) )
1273             {
1274                 parentDescriptor = new File( projectDir, parentRelativePath );
1275 
1276                 if ( getLogger().isDebugEnabled() )
1277                 {
1278                     getLogger().debug( "Searching for parent-POM: " + parentModel.getId() + " of project: " +
1279                         project.getId() + " in relative path: " + parentRelativePath );
1280                 }
1281 
1282                 if ( parentDescriptor.isDirectory() )
1283                 {
1284                     if ( getLogger().isDebugEnabled() )
1285                     {
1286                         getLogger().debug( "Path specified in <relativePath/> (" + parentRelativePath +
1287                             ") is a directory. Searching for 'pom.xml' within this directory." );
1288                     }
1289 
1290                     parentDescriptor = new File( parentDescriptor, "pom.xml" );
1291 
1292                     if ( !parentDescriptor.exists() )
1293                     {
1294                         if ( getLogger().isDebugEnabled() )
1295                         {
1296                             getLogger().debug( "Parent-POM: " + parentModel.getId() + " for project: " +
1297                                 project.getId() + " cannot be loaded from relative path: " + parentDescriptor +
1298                                 "; path does not exist." );
1299                         }
1300                     }
1301                 }
1302 
1303                 if ( parentDescriptor != null )
1304                 {
1305                     try
1306                     {
1307                         parentDescriptor = parentDescriptor.getCanonicalFile();
1308                     }
1309                     catch ( IOException e )
1310                     {
1311                         getLogger().debug( "Failed to canonicalize potential parent POM: \'" + parentDescriptor + "\'",
1312                                            e );
1313 
1314                         parentDescriptor = null;
1315                     }
1316                 }
1317 
1318                 if ( ( parentDescriptor != null ) && parentDescriptor.exists() )
1319                 {
1320                     Model candidateParent = readModel( projectId, parentDescriptor, strict );
1321 
1322                     String candidateParentGroupId = candidateParent.getGroupId();
1323                     if ( ( candidateParentGroupId == null ) && ( candidateParent.getParent() != null ) )
1324                     {
1325                         candidateParentGroupId = candidateParent.getParent().getGroupId();
1326                     }
1327 
1328                     String candidateParentVersion = candidateParent.getVersion();
1329                     if ( ( candidateParentVersion == null ) && ( candidateParent.getParent() != null ) )
1330                     {
1331                         candidateParentVersion = candidateParent.getParent().getVersion();
1332                     }
1333 
1334                     if ( parentModel.getGroupId().equals( candidateParentGroupId ) &&
1335                         parentModel.getArtifactId().equals( candidateParent.getArtifactId() ) &&
1336                         parentModel.getVersion().equals( candidateParentVersion ) )
1337                     {
1338                         model = candidateParent;
1339 
1340                         getLogger().debug( "Using parent-POM from the project hierarchy at: \'" +
1341                             parentModel.getRelativePath() + "\' for project: " + project.getId() );
1342                     }
1343                     else
1344                     {
1345                         getLogger().debug( "Invalid parent-POM referenced by relative path '" +
1346                             parentModel.getRelativePath() + "' in parent specification in " + project.getId() + ":" +
1347                             "\n  Specified: " + parentModel.getId() + "\n  Found:     " + candidateParent.getId() );
1348                     }
1349                 }
1350                 else if ( getLogger().isDebugEnabled() )
1351                 {
1352                     getLogger().debug(
1353                         "Parent-POM: " + parentModel.getId() + " not found in relative path: " + parentRelativePath );
1354                 }
1355             }
1356 
1357             Artifact parentArtifact = null;
1358 
1359             // only resolve the parent model from the repository system if we didn't find it on disk...
1360             if ( model == null )
1361             {
1362                 // MNG-2302: parent's File was being populated incorrectly when parent is loaded from repo.
1363                 // keep this in line with other POMs loaded from the repository...the file should be null.
1364                 parentDescriptor = null;
1365 
1366                 //!! (**)
1367                 // ----------------------------------------------------------------------
1368                 // Do we have the necessary information to actually find the parent
1369                 // POMs here?? I don't think so ... Say only one remote repository is
1370                 // specified and that is ibiblio then this model that we just read doesn't
1371                 // have any repository information ... I think we might have to inherit
1372                 // as we go in order to do this.
1373                 // ----------------------------------------------------------------------
1374 
1375                 // we must add the repository this POM was found in too, by chance it may be located where the parent is
1376                 // we can't query the parent to ask where it is :)
1377                 List remoteRepositories = new ArrayList( aggregatedRemoteWagonRepositories );
1378                 remoteRepositories.addAll( parentSearchRepositories );
1379 
1380                 if ( getLogger().isDebugEnabled() )
1381                 {
1382                     getLogger().debug( "Retrieving parent-POM: " + parentModel.getId() + " for project: " +
1383                         project.getId() + " from the repository." );
1384                 }
1385 
1386                 parentArtifact = artifactFactory.createParentArtifact( parentModel.getGroupId(),
1387                                                                        parentModel.getArtifactId(),
1388                                                                        parentModel.getVersion() );
1389 
1390                 try
1391                 {
1392                     model = findModelFromRepository( parentArtifact, remoteRepositories, config.getLocalRepository(), false );
1393                 }
1394                 catch ( ProjectBuildingException e )
1395                 {
1396                     throw new ProjectBuildingException( project.getId(), "Cannot find parent: " + e.getProjectId() +
1397                         " for project: " + project.getId(), e );
1398                 }
1399             }
1400 
1401             if ( ( model != null ) && !"pom".equals( model.getPackaging() ) )
1402             {
1403                 throw new ProjectBuildingException( projectId, "Parent: " + model.getId() + " of project: " +
1404                     projectId + " has wrong packaging: " + model.getPackaging() + ". Must be 'pom'." );
1405             }
1406 
1407             MavenProject parent = assembleLineage( model,
1408                                                    lineage,
1409                                                    config,
1410                                                    parentDescriptor,
1411                                                    parentSearchRepositories,
1412                                                    aggregatedRemoteWagonRepositories,
1413                                                    strict );
1414 
1415             project.setParent( parent );
1416 
1417             project.setParentArtifact( parentArtifact );
1418         }
1419 
1420         rawProjectCache.put( createCacheKey( project.getGroupId(), project.getArtifactId(), project.getVersion() ), new MavenProject( project ) );
1421 
1422         return project;
1423     }
1424 
1425     private void mergeManagedDependencies(Model model, ArtifactRepository localRepository, List parentSearchRepositories)
1426         throws ProjectBuildingException
1427     {
1428         DependencyManagement modelDepMgmt = model.getDependencyManagement();
1429 
1430         if (modelDepMgmt != null)
1431         {
1432             Map depsMap = new TreeMap();
1433             Iterator iter = modelDepMgmt.getDependencies().iterator();
1434             boolean doInclude = false;
1435             while (iter.hasNext())
1436             {
1437                 Dependency dep = (Dependency) iter.next();
1438                 depsMap.put( dep.getManagementKey(), dep );
1439                 if ( dep.getType().equals( "pom" ) && Artifact.SCOPE_IMPORT.equals( dep.getScope() ) )
1440                 {
1441                     doInclude = true;
1442                 }
1443             }
1444             Map newDeps = new TreeMap(depsMap);
1445             iter = modelDepMgmt.getDependencies().iterator();
1446             if (doInclude)
1447             {
1448                 while (iter.hasNext())
1449                 {
1450                     Dependency dep = (Dependency)iter.next();
1451                     if ( dep.getType().equals( "pom" )
1452                          && Artifact.SCOPE_IMPORT.equals( dep.getScope() ) )
1453                     {
1454                         Artifact artifact = artifactFactory.createProjectArtifact( dep.getGroupId(), dep.getArtifactId(),
1455                                                                                   dep.getVersion(), dep.getScope() );
1456                         MavenProject project = buildFromRepository(artifact, parentSearchRepositories, localRepository, false);
1457 
1458                         DependencyManagement depMgmt = project.getDependencyManagement();
1459 
1460                         if (depMgmt != null)
1461                         {
1462                             if ( getLogger().isDebugEnabled() )
1463                             {
1464                                 getLogger().debug( "Importing managed dependencies for " + dep.toString() );
1465                             }
1466 
1467                             for ( Iterator it = depMgmt.getDependencies().iterator(); it.hasNext(); )
1468                             {
1469                                 Dependency includedDep = (Dependency) it.next();
1470                                 String key = includedDep.getManagementKey();
1471                                 if (!newDeps.containsKey(key))
1472                                 {
1473                                     newDeps.put( includedDep.getManagementKey(), includedDep );
1474                                 }
1475                             }
1476                             newDeps.remove(dep.getManagementKey());
1477                         }
1478                     }
1479                 }
1480                 List deps = new ArrayList(newDeps.values());
1481                 modelDepMgmt.setDependencies(deps);
1482             }
1483         }
1484     }
1485 
1486     private List injectActiveProfiles( ProfileManager profileManager,
1487                                        Model model )
1488         throws ProjectBuildingException
1489     {
1490         List activeProfiles;
1491 
1492         if ( profileManager != null )
1493         {
1494             try
1495             {
1496                 activeProfiles = profileManager.getActiveProfiles();
1497             }
1498             catch ( ProfileActivationException e )
1499             {
1500                 String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
1501 
1502                 throw new ProjectBuildingException( projectId, e.getMessage(), e );
1503             }
1504 
1505             for ( Iterator it = activeProfiles.iterator(); it.hasNext(); )
1506             {
1507                 Profile profile = (Profile) it.next();
1508 
1509                 profileInjector.inject( profile, model );
1510             }
1511         }
1512         else
1513         {
1514             activeProfiles = Collections.EMPTY_LIST;
1515         }
1516 
1517         return activeProfiles;
1518     }
1519 
1520     private void loadProjectExternalProfiles( ProfileManager profileManager,
1521                                               File projectDir )
1522         throws ProfileActivationException
1523     {
1524         if ( projectDir != null )
1525         {
1526             try
1527             {
1528                 ProfilesRoot root = profilesBuilder.buildProfiles( projectDir );
1529 
1530                 if ( root != null )
1531                 {
1532                     List active = root.getActiveProfiles();
1533 
1534                     if ( ( active != null ) && !active.isEmpty() )
1535                     {
1536                         profileManager.explicitlyActivate( root.getActiveProfiles() );
1537                     }
1538 
1539                     for ( Iterator it = root.getProfiles().iterator(); it.hasNext(); )
1540                     {
1541                         org.apache.maven.profiles.Profile rawProfile = (org.apache.maven.profiles.Profile) it.next();
1542 
1543                         Profile converted = ProfilesConversionUtils.convertFromProfileXmlProfile( rawProfile );
1544 
1545                         profileManager.addProfile( converted );
1546                     }
1547                 }
1548             }
1549             catch ( IOException e )
1550             {
1551                 throw new ProfileActivationException( "Cannot read profiles.xml resource from directory: " + projectDir,
1552                                                       e );
1553             }
1554             catch ( XmlPullParserException e )
1555             {
1556                 throw new ProfileActivationException(
1557                     "Cannot parse profiles.xml resource from directory: " + projectDir, e );
1558             }
1559         }
1560     }
1561 
1562     private Model readModel( String projectId,
1563                              File file,
1564                              boolean strict )
1565         throws ProjectBuildingException
1566     {
1567         Reader reader = null;
1568         try
1569         {
1570             reader = ReaderFactory.newXmlReader( file );
1571             return readModel( projectId, file.getAbsolutePath(), reader, strict );
1572         }
1573         catch ( FileNotFoundException e )
1574         {
1575             throw new ProjectBuildingException( projectId,
1576                                                 "Could not find the model file '" + file.getAbsolutePath() + "'.", e );
1577         }
1578         catch ( IOException e )
1579         {
1580             throw new ProjectBuildingException( projectId, "Failed to build model from file '" +
1581                 file.getAbsolutePath() + "'.\nError: \'" + e.getLocalizedMessage() + "\'", e );
1582         }
1583         finally
1584         {
1585             IOUtil.close( reader );
1586         }
1587     }
1588 
1589     private Model readModel( String projectId,
1590                              String pomLocation,
1591                              Reader reader,
1592                              boolean strict )
1593         throws IOException, InvalidProjectModelException
1594     {
1595         String modelSource = IOUtil.toString( reader );
1596 
1597         if ( modelSource.indexOf( "<modelVersion>" + MAVEN_MODEL_VERSION ) < 0 )
1598         {
1599             throw new InvalidProjectModelException( projectId, pomLocation, "Not a v" + MAVEN_MODEL_VERSION  + " POM." );
1600         }
1601 
1602         StringReader sReader = new StringReader( modelSource );
1603 
1604         try
1605         {
1606             return modelReader.read( sReader, strict );
1607         }
1608         catch ( XmlPullParserException e )
1609         {
1610             throw new InvalidProjectModelException( projectId, pomLocation,
1611                                                     "Parse error reading POM. Reason: " + e.getMessage(), e );
1612         }
1613     }
1614 
1615     private Model readModel( String projectId,
1616                              URL url,
1617                              boolean strict )
1618         throws ProjectBuildingException
1619     {
1620         Reader reader = null;
1621         try
1622         {
1623             reader = ReaderFactory.newXmlReader( url.openStream() );
1624             return readModel( projectId, url.toExternalForm(), reader, strict );
1625         }
1626         catch ( IOException e )
1627         {
1628             throw new ProjectBuildingException( projectId, "Failed build model from URL \'" + url.toExternalForm() +
1629                 "\'\nError: \'" + e.getLocalizedMessage() + "\'", e );
1630         }
1631         finally
1632         {
1633             IOUtil.close( reader );
1634         }
1635     }
1636 
1637     private static String createCacheKey( String groupId,
1638                                           String artifactId,
1639                                           String version )
1640     {
1641         return groupId + ":" + artifactId + ":" + version;
1642     }
1643 
1644     protected Set createPluginArtifacts( String projectId,
1645                                          List plugins )
1646         throws ProjectBuildingException
1647     {
1648         Set pluginArtifacts = new LinkedHashSet();
1649 
1650         for ( Iterator i = plugins.iterator(); i.hasNext(); )
1651         {
1652             Plugin p = (Plugin) i.next();
1653 
1654             String version;
1655             if ( StringUtils.isEmpty( p.getVersion() ) )
1656             {
1657                 version = "RELEASE";
1658             }
1659             else
1660             {
1661                 version = p.getVersion();
1662             }
1663 
1664             Artifact artifact;
1665             try
1666             {
1667                 artifact = artifactFactory.createPluginArtifact( p.getGroupId(), p.getArtifactId(),
1668                                                                  VersionRange.createFromVersionSpec( version ) );
1669             }
1670             catch ( InvalidVersionSpecificationException e )
1671             {
1672                 throw new ProjectBuildingException( projectId, "Unable to parse version '" + version +
1673                     "' for plugin '" + ArtifactUtils.versionlessKey( p.getGroupId(), p.getArtifactId() ) + "': " +
1674                     e.getMessage(), e );
1675             }
1676 
1677             if ( artifact != null )
1678             {
1679                 pluginArtifacts.add( artifact );
1680             }
1681         }
1682 
1683         return pluginArtifacts;
1684     }
1685 
1686     // TODO: share with createPluginArtifacts?
1687     protected Set createReportArtifacts( String projectId,
1688                                          List reports )
1689         throws ProjectBuildingException
1690     {
1691         Set pluginArtifacts = new LinkedHashSet();
1692 
1693         if ( reports != null )
1694         {
1695             for ( Iterator i = reports.iterator(); i.hasNext(); )
1696             {
1697                 ReportPlugin p = (ReportPlugin) i.next();
1698 
1699                 String version;
1700                 if ( StringUtils.isEmpty( p.getVersion() ) )
1701                 {
1702                     version = "RELEASE";
1703                 }
1704                 else
1705                 {
1706                     version = p.getVersion();
1707                 }
1708 
1709                 Artifact artifact;
1710                 try
1711                 {
1712                     artifact = artifactFactory.createPluginArtifact( p.getGroupId(), p.getArtifactId(),
1713                                                                      VersionRange.createFromVersionSpec( version ) );
1714                 }
1715                 catch ( InvalidVersionSpecificationException e )
1716                 {
1717                     throw new ProjectBuildingException( projectId, "Unable to parse version '" + version +
1718                         "' for report '" + ArtifactUtils.versionlessKey( p.getGroupId(), p.getArtifactId() ) + "': " +
1719                         e.getMessage(), e );
1720                 }
1721 
1722                 if ( artifact != null )
1723                 {
1724                     pluginArtifacts.add( artifact );
1725                 }
1726             }
1727         }
1728 
1729         return pluginArtifacts;
1730     }
1731 
1732     // TODO: share with createPluginArtifacts?
1733     protected Set createExtensionArtifacts( String projectId,
1734                                             List extensions )
1735         throws ProjectBuildingException
1736     {
1737         Set extensionArtifacts = new LinkedHashSet();
1738 
1739         if ( extensions != null )
1740         {
1741             for ( Iterator i = extensions.iterator(); i.hasNext(); )
1742             {
1743                 Extension ext = (Extension) i.next();
1744 
1745                 String version;
1746                 if ( StringUtils.isEmpty( ext.getVersion() ) )
1747                 {
1748                     version = "RELEASE";
1749                 }
1750                 else
1751                 {
1752                     version = ext.getVersion();
1753                 }
1754 
1755                 Artifact artifact;
1756                 try
1757                 {
1758                     VersionRange versionRange = VersionRange.createFromVersionSpec( version );
1759                     artifact =
1760                         artifactFactory.createExtensionArtifact( ext.getGroupId(), ext.getArtifactId(), versionRange );
1761                 }
1762                 catch ( InvalidVersionSpecificationException e )
1763                 {
1764                     throw new ProjectBuildingException( projectId, "Unable to parse version '" + version +
1765                         "' for extension '" + ArtifactUtils.versionlessKey( ext.getGroupId(), ext.getArtifactId() ) +
1766                         "': " + e.getMessage(), e );
1767                 }
1768 
1769                 if ( artifact != null )
1770                 {
1771                     extensionArtifacts.add( artifact );
1772                 }
1773             }
1774         }
1775 
1776         return extensionArtifacts;
1777     }
1778 
1779     // ----------------------------------------------------------------------
1780     //
1781     // ----------------------------------------------------------------------
1782 
1783     private Model getSuperModel()
1784         throws ProjectBuildingException
1785     {
1786         URL url = DefaultMavenProjectBuilder.class.getResource( "pom-" + MAVEN_MODEL_VERSION + ".xml" );
1787 
1788         String projectId = safeVersionlessKey( STANDALONE_SUPERPOM_GROUPID, STANDALONE_SUPERPOM_ARTIFACTID );
1789 
1790         return readModel( projectId, url, true );
1791     }
1792 
1793     public void contextualize( Context context )
1794         throws ContextException
1795     {
1796         container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
1797     }
1798 
1799     /**
1800      * {@inheritDoc}
1801      */
1802     public void calculateConcreteState( MavenProject project, ProjectBuilderConfiguration config )
1803         throws ModelInterpolationException
1804     {
1805         calculateConcreteStateInternal( project, config, true, new HashSet() );
1806     }
1807     
1808     /**
1809      * {@inheritDoc}
1810      */
1811     public void calculateConcreteState( MavenProject project, ProjectBuilderConfiguration config, boolean processProjectReferences )
1812         throws ModelInterpolationException
1813     {
1814         calculateConcreteStateInternal( project, config, processProjectReferences, ( processProjectReferences ? new HashSet() : null ) );
1815     }
1816     
1817     /*
1818      * NOTE: This is a code hotspot, PLEASE be careful about the performance of logic inside or
1819      * called from this method. 
1820      * 
1821      * NOTE: If processProjectReferences == false, processedProjects MUST NOT BE USED. It will be null.
1822      */
1823     private void calculateConcreteStateInternal( MavenProject project, ProjectBuilderConfiguration config, boolean processProjectReferences, Set processedProjects )
1824         throws ModelInterpolationException
1825     {
1826         if ( processProjectReferences )
1827         {
1828             processedProjects.add( project.getId() );
1829         }
1830         
1831         restoreDynamicStateInternal( project, config, processProjectReferences, processProjectReferences ? new HashSet( processedProjects ) : null );
1832         
1833         if ( !project.isConcrete() )
1834         {
1835             if ( project.getParent() != null )
1836             {
1837                 calculateConcreteStateInternal( project.getParent(), config, processProjectReferences, processedProjects );
1838             }
1839             
1840             Build build = project.getBuild();
1841             if ( build != null )
1842             {
1843                 initResourceMergeIds( build.getResources() );
1844                 initResourceMergeIds( build.getTestResources() );
1845             }
1846 
1847             // NOTE: Since interpolation makes a copy through serialization, we don't need this.
1848             // See note below.
1849             //
1850             // Model model = ModelUtils.cloneModel( project.getModel() );
1851 
1852             File basedir = project.getBasedir();
1853 
1854             // NOTE: If we ever get past serialization/deserialization for interpolation, we'll need to copy the model here!
1855             Model model = ModelUtils.cloneModel( project.getModel() );
1856             model = modelInterpolator.interpolate( model, project.getBasedir(), config, getLogger().isDebugEnabled() );
1857 
1858             List originalInterpolatedCompileSourceRoots = interpolateListOfStrings( project.getCompileSourceRoots(),
1859                                                                                model,
1860                                                                                project.getBasedir(),
1861                                                                                config,
1862                                                                                getLogger().isDebugEnabled() );
1863 
1864             project.preserveCompileSourceRoots( originalInterpolatedCompileSourceRoots );
1865 
1866             project.setCompileSourceRoots( originalInterpolatedCompileSourceRoots == null ? null
1867                             : translateListOfPaths( originalInterpolatedCompileSourceRoots, basedir ) );
1868 
1869             List originalInterpolatedTestCompileSourceRoots = interpolateListOfStrings( project.getTestCompileSourceRoots(),
1870                                                                                    model,
1871                                                                                    project.getBasedir(),
1872                                                                                    config,
1873                                                                                    getLogger().isDebugEnabled() );
1874 
1875             project.preserveTestCompileSourceRoots( originalInterpolatedTestCompileSourceRoots );
1876             project.setTestCompileSourceRoots( originalInterpolatedTestCompileSourceRoots == null ? null
1877                             : translateListOfPaths( originalInterpolatedTestCompileSourceRoots, basedir ) );
1878 
1879             List originalInterpolatedScriptSourceRoots = interpolateListOfStrings( project.getScriptSourceRoots(),
1880                                                                               model,
1881                                                                               project.getBasedir(),
1882                                                                               config,
1883                                                                               getLogger().isDebugEnabled() );
1884 
1885             project.preserveScriptSourceRoots( originalInterpolatedScriptSourceRoots );
1886             
1887             // TODO: MNG-3731
1888             project.setScriptSourceRoots( originalInterpolatedScriptSourceRoots );
1889 //            project.setScriptSourceRoots( originalInterpolatedScriptSourceRoots == null ? null
1890 //                            : translateListOfPaths( originalInterpolatedScriptSourceRoots, basedir ) );
1891 
1892             if ( basedir != null )
1893             {
1894                 pathTranslator.alignToBaseDirectory( model, basedir );
1895             }
1896 
1897             project.preserveBuild( ModelUtils.cloneBuild( model.getBuild() ) );
1898             project.preserveProperties();
1899             project.preserveBasedir();
1900             project.setBuild( model.getBuild() );
1901             
1902             if ( project.getExecutionProject() != null )
1903             {
1904                 calculateConcreteStateInternal( project.getExecutionProject(), config, processProjectReferences, processedProjects );
1905             }
1906             
1907             project.setConcrete( true );
1908         }
1909 
1910         if ( processProjectReferences )
1911         {
1912             calculateConcreteProjectReferences( project, config, processedProjects );
1913         }
1914     }
1915 
1916     private void initResourceMergeIds( List resources )
1917     {
1918         if ( resources != null )
1919         {
1920             for ( Iterator it = resources.iterator(); it.hasNext(); )
1921             {
1922                 Resource resource = (Resource) it.next();
1923 
1924                 resource.initMergeId();
1925             }
1926         }
1927     }
1928 
1929     private void calculateConcreteProjectReferences( MavenProject project,
1930                                                      ProjectBuilderConfiguration config,
1931                                                      Set processedProjects )
1932         throws ModelInterpolationException
1933     {
1934         Map projectRefs = project.getProjectReferences();
1935 
1936         if ( projectRefs != null )
1937         {
1938             for ( Iterator it = projectRefs.values().iterator(); it.hasNext(); )
1939             {
1940                 MavenProject reference = (MavenProject) it.next();
1941                 if ( !processedProjects.contains( reference.getId() ) )
1942                 {
1943                     calculateConcreteStateInternal( reference, config, true, processedProjects );
1944                 }
1945             }
1946         }
1947     }
1948 
1949     private List translateListOfPaths( List paths, File basedir )
1950     {
1951         if ( paths == null )
1952         {
1953             return null;
1954         }
1955         else if ( basedir == null )
1956         {
1957             return paths;
1958         }
1959 
1960         List result = new ArrayList( paths.size() );
1961         for ( Iterator it = paths.iterator(); it.hasNext(); )
1962         {
1963             String path = (String) it.next();
1964 
1965             String aligned = pathTranslator.alignToBaseDirectory( path, basedir );
1966 
1967             result.add( aligned );
1968         }
1969 
1970         return result;
1971     }
1972 
1973     /**
1974      * {@inheritDoc}
1975      */
1976     public void restoreDynamicState( MavenProject project, ProjectBuilderConfiguration config )
1977         throws ModelInterpolationException
1978     {
1979         restoreDynamicStateInternal( project, config, true, new HashSet() );
1980     }
1981     
1982     /**
1983      * {@inheritDoc}
1984      */
1985     public void restoreDynamicState( MavenProject project, ProjectBuilderConfiguration config, boolean processProjectReferences )
1986         throws ModelInterpolationException
1987     {
1988         restoreDynamicStateInternal( project, config, processProjectReferences, ( processProjectReferences ? new HashSet() : null ) );
1989     }
1990     
1991     /*
1992      * NOTE: This is a code hotspot, PLEASE be careful about the performance of logic inside or
1993      * called from this method. 
1994      * 
1995      * NOTE: If processProjectReferences == false, processedProjects MUST NOT BE USED. It will be null.
1996      */
1997     private void restoreDynamicStateInternal( MavenProject project, ProjectBuilderConfiguration config, boolean processProjectReferences, Set processedProjects )
1998         throws ModelInterpolationException
1999     {
2000         if ( processProjectReferences )
2001         {
2002             processedProjects.add( project.getId() );
2003         }
2004         
2005         if ( project.isConcrete() && projectWasChanged( project ) )
2006         {
2007             if ( project.getParent() != null )
2008             {
2009                 restoreDynamicStateInternal( project.getParent(), config, processProjectReferences, processedProjects );
2010             }
2011             
2012             restoreBuildRoots( project, config, getLogger().isDebugEnabled() );
2013             restoreModelBuildSection( project, config, getLogger().isDebugEnabled() );
2014             
2015             if ( project.getExecutionProject() != null )
2016             {
2017                 restoreDynamicStateInternal( project.getExecutionProject(), config, processProjectReferences, processedProjects );
2018             }
2019             
2020             project.setConcrete( false );
2021         }
2022 
2023         if ( processProjectReferences )
2024         {
2025             restoreDynamicProjectReferences( project, config, processedProjects );
2026         }
2027     }
2028 
2029     private boolean projectWasChanged( MavenProject project )
2030     {
2031         if ( !objectEquals( project.getBasedir(), project.getPreservedBasedir() ) )
2032         {
2033             return true;
2034         }
2035         
2036         if ( !objectEquals( project.getProperties(), project.getPreservedProperties() ) )
2037         {
2038             return true;
2039         }
2040         
2041         Build oBuild = project.getOriginalInterpolatedBuild();
2042         Build build = project.getBuild();
2043         
2044         if ( !objectEquals( oBuild.getDirectory(), build.getDirectory() ) )
2045         {
2046             return true;
2047         }
2048         
2049         if ( !objectEquals( oBuild.getOutputDirectory(), build.getOutputDirectory() ) )
2050         {
2051             return true;
2052         }
2053         
2054         if ( !objectEquals( oBuild.getSourceDirectory(), build.getSourceDirectory() ) )
2055         {
2056             return true;
2057         }
2058         
2059         if ( !objectEquals( oBuild.getTestSourceDirectory(), build.getTestSourceDirectory() ) )
2060         {
2061             return true;
2062         }
2063         
2064         if ( !objectEquals( oBuild.getScriptSourceDirectory(), build.getScriptSourceDirectory() ) )
2065         {
2066             return true;
2067         }
2068         
2069         return false;
2070     }
2071 
2072     private boolean objectEquals( Object obj1, Object obj2 )
2073     {
2074         return obj1 == null ? obj2 == null : obj2 != null && ( obj1 == obj2 || obj1.equals( obj2 ) );
2075     }
2076 
2077     private void propagateNewPlugins( MavenProject project )
2078     {
2079         Build changedBuild = project.getBuild();
2080         Build dynamicBuild = project.getDynamicBuild();
2081         
2082         if ( changedBuild == null || dynamicBuild == null )
2083         {
2084             return;
2085         }
2086         
2087         List changedPlugins = changedBuild.getPlugins();
2088         List dynamicPlugins = dynamicBuild.getPlugins();
2089         
2090         if ( changedPlugins != null && dynamicPlugins != null && changedPlugins.size() != dynamicPlugins.size() )
2091         {
2092             changedPlugins.removeAll( dynamicPlugins );
2093             if ( !changedPlugins.isEmpty() )
2094             {
2095                 for ( Iterator it = changedPlugins.iterator(); it.hasNext(); )
2096                 {
2097                     Plugin plugin = (Plugin) it.next();
2098                     
2099                     dynamicBuild.addPlugin( plugin );
2100                 }
2101             }
2102         }
2103         
2104         dynamicBuild.flushPluginMap();
2105     }
2106 
2107     private void restoreDynamicProjectReferences( MavenProject project,
2108                                                   ProjectBuilderConfiguration config,
2109                                                   Set processedProjects )
2110         throws ModelInterpolationException
2111     {
2112         Map projectRefs = project.getProjectReferences();
2113         if ( projectRefs != null )
2114         {
2115             for ( Iterator it = projectRefs.values().iterator(); it.hasNext(); )
2116             {
2117                 MavenProject projectRef = (MavenProject) it.next();
2118                 if ( !processedProjects.contains( projectRef.getId() ) )
2119                 {
2120                     restoreDynamicStateInternal( projectRef, config, true, processedProjects );
2121                 }
2122             }
2123         }
2124     }
2125 
2126     private void restoreBuildRoots( MavenProject project,
2127                                     ProjectBuilderConfiguration config,
2128                                     boolean debugMessages )
2129         throws ModelInterpolationException
2130     {
2131         project.setCompileSourceRoots( restoreListOfStrings( project.getDynamicCompileSourceRoots(),
2132                                                              project.getOriginalInterpolatedCompileSourceRoots(),
2133                                                              project.getCompileSourceRoots(),
2134                                                              project,
2135                                                              config,
2136                                                              debugMessages ) );
2137 
2138         project.setTestCompileSourceRoots( restoreListOfStrings( project.getDynamicTestCompileSourceRoots(),
2139                                                                  project.getOriginalInterpolatedTestCompileSourceRoots(),
2140                                                                  project.getTestCompileSourceRoots(),
2141                                                                  project,
2142                                                                  config,
2143                                                                  debugMessages ) );
2144 
2145         project.setScriptSourceRoots( restoreListOfStrings( project.getDynamicScriptSourceRoots(),
2146                                                             project.getOriginalInterpolatedScriptSourceRoots(),
2147                                                             project.getScriptSourceRoots(),
2148                                                             project,
2149                                                             config,
2150                                                             debugMessages ) );
2151 
2152         project.clearRestorableRoots();
2153     }
2154 
2155     private void restoreModelBuildSection( MavenProject project,
2156                                            ProjectBuilderConfiguration config,
2157                                            boolean debugMessages )
2158         throws ModelInterpolationException
2159     {
2160         Build changedBuild = project.getBuild();
2161         Build dynamicBuild = project.getDynamicBuild();
2162         Build originalInterpolatedBuild = project.getOriginalInterpolatedBuild();
2163 
2164         dynamicBuild.setResources( restoreResources( dynamicBuild.getResources(),
2165                                                          originalInterpolatedBuild.getResources(),
2166                                                          changedBuild.getResources(),
2167                                                          project,
2168                                                          config,
2169                                                          debugMessages ) );
2170 
2171         dynamicBuild.setTestResources( restoreResources( dynamicBuild.getTestResources(),
2172                                                          originalInterpolatedBuild.getTestResources(),
2173                                                          changedBuild.getTestResources(),
2174                                                          project,
2175                                                          config,
2176                                                          debugMessages ) );
2177 
2178         dynamicBuild.setFilters( restoreListOfStrings( dynamicBuild.getFilters(),
2179                                                            originalInterpolatedBuild.getFilters(),
2180                                                            changedBuild.getFilters(),
2181                                                            project,
2182                                                            config,
2183                                                            debugMessages ) );
2184 
2185         dynamicBuild.setFinalName( restoreString( dynamicBuild.getFinalName(),
2186                                                   originalInterpolatedBuild.getFinalName(),
2187                                                   changedBuild.getFinalName(),
2188                                                   project,
2189                                                   config,
2190                                                   debugMessages ) );
2191 
2192         dynamicBuild.setDefaultGoal( restoreString( dynamicBuild.getDefaultGoal(),
2193                                                   originalInterpolatedBuild.getDefaultGoal(),
2194                                                   changedBuild.getDefaultGoal(),
2195                                                   project,
2196                                                   config,
2197                                                   debugMessages ) );
2198 
2199         dynamicBuild.setSourceDirectory( restoreString( dynamicBuild.getSourceDirectory(),
2200                                                             originalInterpolatedBuild.getSourceDirectory(),
2201                                                             changedBuild.getSourceDirectory(),
2202                                                             project,
2203                                                             config,
2204                                                             debugMessages ) );
2205 
2206         dynamicBuild.setTestSourceDirectory( restoreString( dynamicBuild.getTestSourceDirectory(),
2207                                                                 originalInterpolatedBuild.getTestSourceDirectory(),
2208                                                                 changedBuild.getTestSourceDirectory(),
2209                                                                 project,
2210                                                                 config,
2211                                                                 debugMessages ) );
2212 
2213         dynamicBuild.setScriptSourceDirectory( restoreString( dynamicBuild.getScriptSourceDirectory(),
2214                                                                   originalInterpolatedBuild.getScriptSourceDirectory(),
2215                                                                   changedBuild.getScriptSourceDirectory(),
2216                                                                   project,
2217                                                                   config,
2218                                                                   debugMessages ) );
2219 
2220         dynamicBuild.setOutputDirectory( restoreString( dynamicBuild.getOutputDirectory(),
2221                                                             originalInterpolatedBuild.getOutputDirectory(),
2222                                                             changedBuild.getOutputDirectory(),
2223                                                             project,
2224                                                             config,
2225                                                             debugMessages ) );
2226 
2227         dynamicBuild.setTestOutputDirectory( restoreString( dynamicBuild.getTestOutputDirectory(),
2228                                                                 originalInterpolatedBuild.getTestOutputDirectory(),
2229                                                                 changedBuild.getTestOutputDirectory(),
2230                                                                 project,
2231                                                                 config,
2232                                                                 debugMessages ) );
2233 
2234         dynamicBuild.setDirectory( restoreString( dynamicBuild.getDirectory(),
2235                                                       originalInterpolatedBuild.getDirectory(),
2236                                                       changedBuild.getDirectory(),
2237                                                       project,
2238                                                       config,
2239                                                       debugMessages ) );
2240 
2241         propagateNewPlugins( project );
2242         
2243         project.setBuild( dynamicBuild );
2244 
2245         project.clearRestorableBuild();
2246     }
2247 
2248     private List interpolateListOfStrings( List originalStrings,
2249                                            Model model,
2250                                            File projectDir,
2251                                            ProjectBuilderConfiguration config,
2252                                            boolean debugMessages )
2253         throws ModelInterpolationException
2254     {
2255         if ( originalStrings == null )
2256         {
2257             return null;
2258         }
2259 
2260         List result = new ArrayList();
2261 
2262         for ( Iterator it = originalStrings.iterator(); it.hasNext(); )
2263         {
2264             String original = (String) it.next();
2265             String interpolated = modelInterpolator.interpolate( original, model, projectDir, config, debugMessages );
2266 
2267             result.add( interpolated );
2268         }
2269 
2270         return result;
2271     }
2272 
2273     private String restoreString( String originalString,
2274                                       String originalInterpolatedString,
2275                                       String changedString,
2276                                       MavenProject project,
2277                                       ProjectBuilderConfiguration config,
2278                                       boolean debugMessages )
2279         throws ModelInterpolationException
2280     {
2281         if ( originalString == null )
2282         {
2283             return changedString;
2284         }
2285         else if ( changedString == null )
2286         {
2287             return originalString;
2288         }
2289 
2290         Model model = project.getModel();
2291 
2292         String relativeChangedString;
2293         if ( project.getBasedir() != null )
2294         {
2295             relativeChangedString = pathTranslator.unalignFromBaseDirectory( changedString, project.getBasedir() );
2296         }
2297         else
2298         {
2299             relativeChangedString = changedString;
2300         }
2301 
2302         String interpolatedOriginal = modelInterpolator.interpolate( originalString,
2303                                                                      model,
2304                                                                      project.getBasedir(),
2305                                                                      config,
2306                                                                      debugMessages );
2307         
2308         interpolatedOriginal = pathTranslator.unalignFromBaseDirectory( interpolatedOriginal, project.getBasedir() );
2309 
2310         String interpolatedOriginal2 = modelInterpolator.interpolate( originalInterpolatedString,
2311                                                                       model,
2312                                                                       project.getBasedir(),
2313                                                                       config,
2314                                                                       debugMessages );
2315         
2316         interpolatedOriginal2 = pathTranslator.alignToBaseDirectory( interpolatedOriginal2, project.getBasedir() );
2317 
2318         String interpolatedChanged = modelInterpolator.interpolate( changedString,
2319                                                                     model,
2320                                                                     project.getBasedir(),
2321                                                                     config,
2322                                                                     debugMessages );
2323         
2324         interpolatedChanged = pathTranslator.alignToBaseDirectory( interpolatedChanged, project.getBasedir() );
2325 
2326         String relativeInterpolatedChanged = modelInterpolator.interpolate( relativeChangedString,
2327                                                                             model,
2328                                                                             project.getBasedir(),
2329                                                                             config,
2330                                                                             debugMessages );
2331 
2332         if ( interpolatedOriginal.equals( interpolatedChanged ) || interpolatedOriginal2.equals( interpolatedChanged ) )
2333         {
2334             return originalString;
2335         }
2336         else if ( interpolatedOriginal.equals( relativeInterpolatedChanged )
2337             || interpolatedOriginal2.equals( relativeInterpolatedChanged ) )
2338         {
2339             return originalString;
2340         }
2341 
2342         return relativeChangedString;
2343     }
2344 
2345     private List restoreListOfStrings( List originalStrings,
2346                                            List originalInterpolatedStrings,
2347                                            List changedStrings,
2348                                            MavenProject project,
2349                                            ProjectBuilderConfiguration config,
2350                                            boolean debugMessages )
2351         throws ModelInterpolationException
2352     {
2353         if ( originalStrings == null )
2354         {
2355             return changedStrings;
2356         }
2357         else if ( changedStrings == null )
2358         {
2359             return originalStrings;
2360         }
2361 
2362         List result = new ArrayList();
2363 
2364         Map orig = new HashMap();
2365         for ( int idx = 0; idx < originalStrings.size(); idx++ )
2366         {
2367             String[] permutations = new String[2];
2368 
2369             permutations[0] = pathTranslator.alignToBaseDirectory( (String) originalInterpolatedStrings.get( idx ), project.getBasedir() );
2370             permutations[1] = (String) originalStrings.get( idx );
2371 
2372             orig.put( permutations[0], permutations );
2373         }
2374 
2375         for ( Iterator it = changedStrings.iterator(); it.hasNext(); )
2376         {
2377             String changedString = (String) it.next();
2378             String relativeChangedString;
2379             if ( project.getBasedir() != null )
2380             {
2381                 relativeChangedString = pathTranslator.unalignFromBaseDirectory( changedString, project.getBasedir() );
2382             }
2383             else
2384             {
2385                 relativeChangedString = changedString;
2386             }
2387 
2388             String interpolated = modelInterpolator.interpolate( changedString,
2389                                                                  project.getModel(),
2390                                                                  project.getBasedir(),
2391                                                                  config,
2392                                                                  debugMessages );
2393             
2394             interpolated = pathTranslator.alignToBaseDirectory( interpolated, project.getBasedir() );
2395 
2396             String relativeInterpolated = modelInterpolator.interpolate( relativeChangedString,
2397                                                                          project.getModel(),
2398                                                                          project.getBasedir(),
2399                                                                          config,
2400                                                                          debugMessages );
2401             
2402             String[] original = (String[]) orig.get( interpolated );
2403             if ( original == null )
2404             {
2405                 original = (String[]) orig.get( relativeInterpolated );
2406             }
2407 
2408             if ( original == null )
2409             {
2410                 result.add( relativeChangedString );
2411             }
2412             else
2413             {
2414                 result.add( original[1] );
2415             }
2416         }
2417 
2418         return result;
2419     }
2420 
2421     private List restoreResources( List originalResources,
2422                                        List originalInterpolatedResources,
2423                                        List changedResources,
2424                                        MavenProject project,
2425                                        ProjectBuilderConfiguration config,
2426                                        boolean debugMessages )
2427         throws ModelInterpolationException
2428     {
2429         if ( originalResources == null || changedResources == null )
2430         {
2431             return originalResources;
2432         }
2433 
2434         List result = new ArrayList();
2435 
2436         Map originalResourcesByMergeId = new HashMap();
2437         for ( int idx = 0; idx < originalResources.size(); idx++ )
2438         {
2439             Resource[] permutations = new Resource[2];
2440 
2441             permutations[0] = (Resource) originalInterpolatedResources.get( idx );
2442             permutations[1] = (Resource) originalResources.get( idx );
2443 
2444             originalResourcesByMergeId.put( permutations[0].getMergeId(), permutations );
2445         }
2446 
2447         for ( Iterator it = changedResources.iterator(); it.hasNext(); )
2448         {
2449             Resource resource = (Resource) it.next();
2450             String mergeId = resource.getMergeId();
2451             if ( mergeId == null || !originalResourcesByMergeId.containsKey( mergeId ) )
2452             {
2453                 result.add( resource );
2454             }
2455             else
2456             {
2457                 Resource originalInterpolatedResource = ( (Resource[]) originalResourcesByMergeId.get( mergeId ) )[0];
2458                 Resource originalResource = ( (Resource[]) originalResourcesByMergeId.get( mergeId ) )[1];
2459 
2460                 String dir = modelInterpolator.interpolate( resource.getDirectory(), project.getModel(), project.getBasedir(), config, getLogger().isDebugEnabled() );
2461                 String oDir = originalInterpolatedResource.getDirectory();
2462 
2463                 if ( !dir.equals( oDir ) )
2464                 {
2465                     originalResource.setDirectory( pathTranslator.unalignFromBaseDirectory( dir, project.getBasedir() ) );
2466                 }
2467 
2468                 if ( resource.getTargetPath() != null )
2469                 {
2470                     String target = modelInterpolator.interpolate( resource.getTargetPath(), project.getModel(), project.getBasedir(), config, getLogger().isDebugEnabled() );
2471 
2472                     String oTarget = originalInterpolatedResource.getTargetPath();
2473 
2474                     if ( !target.equals( oTarget ) )
2475                     {
2476                         originalResource.setTargetPath( pathTranslator.unalignFromBaseDirectory( target, project.getBasedir() ) );
2477                     }
2478                 }
2479 
2480                 originalResource.setFiltering( resource.isFiltering() );
2481 
2482                 originalResource.setExcludes( collectRestoredListOfPatterns( resource.getExcludes(),
2483                                                                              originalResource.getExcludes(),
2484                                                                              originalInterpolatedResource.getExcludes() ) );
2485 
2486                 originalResource.setIncludes( collectRestoredListOfPatterns( resource.getIncludes(),
2487                                                                              originalResource.getIncludes(),
2488                                                                              originalInterpolatedResource.getIncludes() ) );
2489 
2490                 result.add( originalResource );
2491             }
2492         }
2493 
2494         return result;
2495     }
2496 
2497     private List collectRestoredListOfPatterns( List patterns,
2498                                                         List originalPatterns,
2499                                                         List originalInterpolatedPatterns )
2500     {
2501         LinkedHashSet collectedPatterns = new LinkedHashSet();
2502 
2503         collectedPatterns.addAll( originalPatterns );
2504 
2505         for ( Iterator it = patterns.iterator(); it.hasNext(); )
2506         {
2507             String pattern = (String) it.next();
2508             if ( !originalInterpolatedPatterns.contains( pattern ) )
2509             {
2510                 collectedPatterns.add( pattern );
2511             }
2512         }
2513 
2514         return collectedPatterns.isEmpty() ? Collections.EMPTY_LIST
2515                         : new ArrayList( collectedPatterns );
2516     }
2517 
2518 }