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.factory.ArtifactFactory;
27  import org.apache.maven.artifact.manager.WagonManager;
28  import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
29  import org.apache.maven.artifact.repository.ArtifactRepository;
30  import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
31  import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
32  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
33  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
34  import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
35  import org.apache.maven.artifact.resolver.ArtifactResolver;
36  import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter;
37  import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
38  import org.apache.maven.artifact.versioning.ManagedVersionMap;
39  import org.apache.maven.artifact.versioning.VersionRange;
40  import org.apache.maven.model.Build;
41  import org.apache.maven.model.Dependency;
42  import org.apache.maven.model.DependencyManagement;
43  import org.apache.maven.model.DistributionManagement;
44  import org.apache.maven.model.Exclusion;
45  import org.apache.maven.model.Extension;
46  import org.apache.maven.model.Model;
47  import org.apache.maven.model.Parent;
48  import org.apache.maven.model.Plugin;
49  import org.apache.maven.model.Profile;
50  import org.apache.maven.model.ReportPlugin;
51  import org.apache.maven.model.Repository;
52  import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
53  import org.apache.maven.profiles.DefaultProfileManager;
54  import org.apache.maven.profiles.MavenProfilesBuilder;
55  import org.apache.maven.profiles.ProfileManager;
56  import org.apache.maven.profiles.ProfilesConversionUtils;
57  import org.apache.maven.profiles.ProfilesRoot;
58  import org.apache.maven.profiles.activation.ProfileActivationException;
59  import org.apache.maven.project.artifact.InvalidDependencyVersionException;
60  import org.apache.maven.project.inheritance.ModelInheritanceAssembler;
61  import org.apache.maven.project.injection.ModelDefaultsInjector;
62  import org.apache.maven.project.injection.ProfileInjector;
63  import org.apache.maven.project.interpolation.ModelInterpolationException;
64  import org.apache.maven.project.interpolation.ModelInterpolator;
65  import org.apache.maven.project.path.PathTranslator;
66  import org.apache.maven.project.validation.ModelValidationResult;
67  import org.apache.maven.project.validation.ModelValidator;
68  import org.apache.maven.wagon.events.TransferListener;
69  import org.codehaus.plexus.PlexusConstants;
70  import org.codehaus.plexus.PlexusContainer;
71  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
72  import org.codehaus.plexus.context.Context;
73  import org.codehaus.plexus.context.ContextException;
74  import org.codehaus.plexus.logging.AbstractLogEnabled;
75  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
76  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
77  import org.codehaus.plexus.util.IOUtil;
78  import org.codehaus.plexus.util.ReaderFactory;
79  import org.codehaus.plexus.util.StringUtils;
80  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
81  
82  import java.io.File;
83  import java.io.FileNotFoundException;
84  import java.io.IOException;
85  import java.io.Reader;
86  import java.io.StringReader;
87  import java.net.URL;
88  import java.util.ArrayList;
89  import java.util.Collections;
90  import java.util.Date;
91  import java.util.HashMap;
92  import java.util.Iterator;
93  import java.util.LinkedHashSet;
94  import java.util.LinkedList;
95  import java.util.List;
96  import java.util.Map;
97  import java.util.Properties;
98  import java.util.Set;
99  import java.util.TreeMap;
100 
101 /*:apt
102 
103  -----
104  POM lifecycle
105  -----
106 
107 POM Lifecycle
108 
109  Order of operations when building a POM
110 
111  * inheritance
112  * path translation
113  * interpolation
114  * defaults injection
115 
116  Current processing is:
117 
118  * inheritance
119  * interpolation
120  * defaults injection
121  * path translation
122 
123  I'm not sure how this is working at all ... i think i have a case where this is failing but i need to
124  encapsulate as a test so i can fix it. Also need to think of the in working build directory versus looking
125  things up from the repository i.e buildFromSource vs buildFromRepository.
126 
127 Notes
128 
129  * when the model is read it may not have a groupId, as it must be inherited
130 
131  * the inheritance assembler must use models that are unadulterated!
132 
133 */
134 
135 /**
136  * @version $Id: DefaultMavenProjectBuilder.java 763811 2009-04-09 21:26:37Z bentmann $
137  */
138 public class DefaultMavenProjectBuilder
139     extends AbstractLogEnabled
140     implements MavenProjectBuilder, Initializable, Contextualizable
141 {
142     // TODO: remove
143     private PlexusContainer container;
144 
145     protected MavenProfilesBuilder profilesBuilder;
146 
147     protected ArtifactResolver artifactResolver;
148 
149     protected ArtifactMetadataSource artifactMetadataSource;
150 
151     private ArtifactFactory artifactFactory;
152 
153     private ModelInheritanceAssembler modelInheritanceAssembler;
154 
155     private ProfileInjector profileInjector;
156 
157     private ModelValidator validator;
158 
159     private Map rawProjectCache = new HashMap();
160 
161     private Map processedProjectCache = new HashMap();
162 
163     // TODO: make it a component
164     private MavenXpp3Reader modelReader;
165 
166     private PathTranslator pathTranslator;
167 
168     private ModelDefaultsInjector modelDefaultsInjector;
169 
170     private ModelInterpolator modelInterpolator;
171 
172     private ArtifactRepositoryFactory artifactRepositoryFactory;
173 
174     // ----------------------------------------------------------------------
175     // I am making this available for use with a new method that takes a
176     // a monitor wagon monitor as a parameter so that tools can use the
177     // methods here and receive callbacks. MNG-1015
178     // ----------------------------------------------------------------------
179 
180     private WagonManager wagonManager;
181 
182     public static final String MAVEN_MODEL_VERSION = "4.0.0";
183 
184     public void initialize()
185     {
186         modelReader = new MavenXpp3Reader();
187     }
188 
189     // ----------------------------------------------------------------------
190     // MavenProjectBuilder Implementation
191     // ----------------------------------------------------------------------
192 
193     public MavenProject build( File pom,
194                                ProjectBuilderConfiguration config )
195         throws ProjectBuildingException
196     {
197         return buildFromSourceFileInternal( pom, config, true );
198     }
199 
200     public MavenProject build( File pom,
201                                ProjectBuilderConfiguration config,
202                                boolean checkDistributionManagementStatus )
203         throws ProjectBuildingException
204     {
205         return buildFromSourceFileInternal( pom, config, checkDistributionManagementStatus );
206     }
207 
208     public MavenProject build( File projectDescriptor,
209                                ArtifactRepository localRepository,
210                                ProfileManager profileManager )
211         throws ProjectBuildingException
212     {
213         ProjectBuilderConfiguration config = new DefaultProjectBuilderConfiguration().setLocalRepository( localRepository ).setGlobalProfileManager( profileManager );
214         return buildFromSourceFileInternal( projectDescriptor, config, true );
215     }
216 
217     public MavenProject build( File projectDescriptor,
218                                ArtifactRepository localRepository,
219                                ProfileManager profileManager,
220                                boolean checkDistributionManagementStatus )
221         throws ProjectBuildingException
222     {
223         ProjectBuilderConfiguration config = new DefaultProjectBuilderConfiguration().setLocalRepository( localRepository ).setGlobalProfileManager( profileManager );
224         return buildFromSourceFileInternal( projectDescriptor, config, checkDistributionManagementStatus );
225     }
226 
227     // jvz:note
228     // When asked for something from the repository are we getting it from the reactor? Yes, when using this call
229     // we are assuming that the reactor has been run and we have collected the projects required to satisfy it0042
230     // which means the projects in the reactor are required for finding classes in <project>/target/classes. Not
231     // sure this is ideal. I remove all caching from the builder and all reactor related ITs which assume
232     // access to simbling project resources failed.
233     public MavenProject buildFromRepository( Artifact artifact,
234                                              List remoteArtifactRepositories,
235                                              ArtifactRepository localRepository,
236                                              boolean allowStubModel )
237         throws ProjectBuildingException
238     {
239         String cacheKey = createCacheKey( artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion() );
240 
241         MavenProject project = (MavenProject) processedProjectCache.get( cacheKey );
242 
243         if ( project != null )
244         {
245             return project;
246         }
247 
248         Model model = findModelFromRepository( artifact, remoteArtifactRepositories, localRepository, allowStubModel );
249 
250         ProjectBuilderConfiguration config = new DefaultProjectBuilderConfiguration().setLocalRepository( localRepository );
251 
252         return buildInternal( "Artifact [" + artifact + "]", model, config, remoteArtifactRepositories,
253                               null, false );
254     }
255 
256     public MavenProject buildFromRepository( Artifact artifact,
257                                              List remoteArtifactRepositories,
258                                              ArtifactRepository localRepository )
259         throws ProjectBuildingException
260     {
261         return buildFromRepository( artifact, remoteArtifactRepositories, localRepository, true );
262     }
263 
264     // what is using this externally? jvz.
265     public MavenProject buildStandaloneSuperProject( ArtifactRepository localRepository )
266         throws ProjectBuildingException
267     {
268         //TODO mkleint - use the (Container, Properties) constructor to make system properties embeddable
269         ProfileManager profileManager = new DefaultProfileManager( container );
270 
271         return buildStandaloneSuperProject( new DefaultProjectBuilderConfiguration().setLocalRepository( localRepository )
272                                                                                     .setGlobalProfileManager( profileManager ) );
273     }
274 
275     public MavenProject buildStandaloneSuperProject( ArtifactRepository localRepository,
276                                                      ProfileManager profileManager )
277         throws ProjectBuildingException
278     {
279         return buildStandaloneSuperProject( new DefaultProjectBuilderConfiguration().setLocalRepository( localRepository )
280                                                                                     .setGlobalProfileManager( profileManager ) );
281     }
282 
283     public MavenProject buildStandaloneSuperProject( ProjectBuilderConfiguration config )
284         throws ProjectBuildingException
285     {
286         Model superModel = getSuperModel();
287 
288         superModel.setGroupId( STANDALONE_SUPERPOM_GROUPID );
289 
290         superModel.setArtifactId( STANDALONE_SUPERPOM_ARTIFACTID );
291 
292         superModel.setVersion( STANDALONE_SUPERPOM_VERSION );
293 
294 
295         List activeProfiles;
296 
297         ProfileManager profileManager = config.getGlobalProfileManager();
298 
299         if ( profileManager == null )
300         {
301             profileManager = new DefaultProfileManager( container );
302         }
303 
304         profileManager.addProfiles( superModel.getProfiles() );
305 
306         String projectId = safeVersionlessKey( STANDALONE_SUPERPOM_GROUPID, STANDALONE_SUPERPOM_ARTIFACTID );
307 
308         activeProfiles = injectActiveProfiles( profileManager, superModel );
309 
310         MavenProject project = new MavenProject( superModel );
311 
312         project.setManagedVersionMap(
313             createManagedVersionMap( projectId, superModel.getDependencyManagement(), null ) );
314 
315         project.setActiveProfiles( activeProfiles );
316 
317         project.setOriginalModel( superModel );
318 
319         try
320         {
321             project = processProjectLogic( "<Super-POM>", project, config, null, null, true, true );
322 
323             project.setExecutionRoot( true );
324 
325             return project;
326         }
327         catch ( ModelInterpolationException e )
328         {
329             throw new ProjectBuildingException( projectId, e.getMessage(), e );
330         }
331         catch ( InvalidRepositoryException e )
332         {
333             throw new ProjectBuildingException( projectId, e.getMessage(), e );
334         }
335     }
336 
337     public MavenProject buildWithDependencies( File projectDescriptor,
338                                                ArtifactRepository localRepository,
339                                                ProfileManager profileManager )
340         throws ProjectBuildingException, ArtifactResolutionException, ArtifactNotFoundException
341     {
342         return buildWithDependencies( projectDescriptor, localRepository, profileManager, null );
343     }
344 
345     // note:jvz This was added for the embedder.
346 
347     /** @todo move to metadatasource itself? */
348     public MavenProject buildWithDependencies( File projectDescriptor,
349                                                ArtifactRepository localRepository,
350                                                ProfileManager profileManager,
351                                                TransferListener transferListener )
352         throws ProjectBuildingException, ArtifactResolutionException, ArtifactNotFoundException
353     {
354         MavenProject project = build( projectDescriptor, localRepository, profileManager, false );
355 
356         // ----------------------------------------------------------------------
357         // Typically when the project builder is being used from maven proper
358         // the transitive dependencies will not be resolved here because this
359         // requires a lot of work when we may only be interested in running
360         // something simple like 'm2 clean'. So the artifact collector is used
361         // in the dependency resolution phase if it is required by any of the
362         // goals being executed. But when used as a component in another piece
363         // of code people may just want to build maven projects and have the
364         // dependencies resolved for whatever reason: this is why we keep
365         // this snippet of code here.
366         // ----------------------------------------------------------------------
367 
368         // TODO: such a call in MavenMetadataSource too - packaging not really the intention of type
369         Artifact projectArtifact = project.getArtifact();
370 
371         String projectId = safeVersionlessKey( project.getGroupId(), project.getArtifactId() );
372 
373         // Map managedVersions = createManagedVersionMap( projectId, project.getDependencyManagement() );
374         Map managedVersions = project.getManagedVersionMap();
375 
376         ensureMetadataSourceIsInitialized();
377 
378         try
379         {
380             project.setDependencyArtifacts( project.createArtifacts( artifactFactory, null, null ) );
381         }
382         catch ( InvalidDependencyVersionException e )
383         {
384             throw new ProjectBuildingException( projectId,
385                                                 "Unable to build project due to an invalid dependency version: " +
386                                                     e.getMessage(), e );
387         }
388 
389         if ( transferListener != null )
390         {
391             wagonManager.setDownloadMonitor( transferListener );
392         }
393 
394         ArtifactResolutionResult result = artifactResolver.resolveTransitively( project.getDependencyArtifacts(),
395                                                                                 projectArtifact, managedVersions,
396                                                                                 localRepository,
397                                                                                 project.getRemoteArtifactRepositories(),
398                                                                                 artifactMetadataSource );
399 
400         project.setArtifacts( result.getArtifacts() );
401 
402         return project;
403     }
404 
405     // ----------------------------------------------------------------------
406     //
407     // ----------------------------------------------------------------------
408 
409     private void ensureMetadataSourceIsInitialized()
410         throws ProjectBuildingException
411     {
412         if ( artifactMetadataSource == null )
413         {
414             try
415             {
416                 artifactMetadataSource = (ArtifactMetadataSource) container.lookup( ArtifactMetadataSource.ROLE );
417             }
418             catch ( ComponentLookupException e )
419             {
420                 throw new ProjectBuildingException( "all", "Cannot lookup metadata source for building the project.",
421                                                     e );
422             }
423         }
424     }
425 
426     private Map createManagedVersionMap( String projectId,
427                                          DependencyManagement dependencyManagement,
428                                          MavenProject parent )
429         throws ProjectBuildingException
430     {
431         Map map = null;
432         List deps;
433         if ( ( dependencyManagement != null ) && ( ( deps = dependencyManagement.getDependencies() ) != null ) &&
434             ( deps.size() > 0 ) )
435         {
436             map = new ManagedVersionMap( map );
437 
438             if ( getLogger().isDebugEnabled() )
439             {
440                 getLogger().debug( "Adding managed dependencies for " + projectId );
441             }
442 
443             for ( Iterator i = dependencyManagement.getDependencies().iterator(); i.hasNext(); )
444             {
445                 Dependency d = (Dependency) i.next();
446 
447                 try
448                 {
449                     VersionRange versionRange = VersionRange.createFromVersionSpec( d.getVersion() );
450 
451                     Artifact artifact = artifactFactory.createDependencyArtifact( d.getGroupId(), d.getArtifactId(),
452                                                                                   versionRange, d.getType(),
453                                                                                   d.getClassifier(), d.getScope(),
454                                                                                   d.isOptional() );
455                     if ( getLogger().isDebugEnabled() )
456                     {
457                         getLogger().debug( "  " + artifact );
458                     }
459 
460                     // If the dependencyManagement section listed exclusions,
461                     // add them to the managed artifacts here so that transitive
462                     // dependencies will be excluded if necessary.
463                     if ( ( null != d.getExclusions() ) && !d.getExclusions().isEmpty() )
464                     {
465                         List exclusions = new ArrayList();
466 
467                         Iterator exclItr = d.getExclusions().iterator();
468 
469                         while ( exclItr.hasNext() )
470                         {
471                             Exclusion e = (Exclusion) exclItr.next();
472                             exclusions.add( e.getGroupId() + ":" + e.getArtifactId() );
473                         }
474                         ExcludesArtifactFilter eaf = new ExcludesArtifactFilter( exclusions );
475                         artifact.setDependencyFilter( eaf );
476                     }
477                     else
478                     {
479                         artifact.setDependencyFilter( null );
480                     }
481                     map.put( d.getManagementKey(), artifact );
482                 }
483                 catch ( InvalidVersionSpecificationException e )
484                 {
485                     throw new ProjectBuildingException( projectId, "Unable to parse version '" + d.getVersion() +
486                         "' for dependency '" + d.getManagementKey() + "': " + e.getMessage(), e );
487                 }
488             }
489         }
490         else if ( map == null )
491         {
492             map = Collections.EMPTY_MAP;
493         }
494 
495         return map;
496     }
497 
498     private MavenProject buildFromSourceFileInternal( File projectDescriptor,
499                                                       ProjectBuilderConfiguration config,
500                                                       boolean checkDistributionManagementStatus )
501         throws ProjectBuildingException
502     {
503         Model model = readModel( "unknown", projectDescriptor, true );
504 
505         MavenProject project = buildInternal( projectDescriptor.getAbsolutePath(), model, config,
506                                               buildArtifactRepositories( getSuperModel() ), projectDescriptor,
507                                               true );
508 
509         if ( checkDistributionManagementStatus )
510         {
511             if ( ( project.getDistributionManagement() != null ) &&
512                 ( project.getDistributionManagement().getStatus() != null ) )
513             {
514                 String projectId = safeVersionlessKey( project.getGroupId(), project.getArtifactId() );
515 
516                 throw new ProjectBuildingException( projectId,
517                                                     "Invalid project file: distribution status must not be specified for a project outside of the repository" );
518             }
519         }
520 
521         return project;
522     }
523 
524     private Model findModelFromRepository( Artifact artifact,
525                                            List remoteArtifactRepositories,
526                                            ArtifactRepository localRepository,
527                                            boolean allowStubModel )
528         throws ProjectBuildingException
529     {
530         String projectId = safeVersionlessKey( artifact.getGroupId(), artifact.getArtifactId() );
531 
532         normalizeToArtifactRepositories( remoteArtifactRepositories, projectId );
533 
534         Artifact projectArtifact;
535 
536         // if the artifact is not a POM, we need to construct a POM artifact based on the artifact parameter given.
537         if ( "pom".equals( artifact.getType() ) )
538         {
539             projectArtifact = artifact;
540         }
541         else
542         {
543             getLogger().warn( "Attempting to build MavenProject instance for Artifact (" + artifact.getGroupId() + ":"
544                                   + artifact.getArtifactId() + ":" + artifact.getVersion() + ") of type: "
545                                   + artifact.getType() + "; constructing POM artifact instead." );
546 
547             projectArtifact = artifactFactory.createProjectArtifact( artifact.getGroupId(), artifact.getArtifactId(),
548                                                                      artifact.getVersion(), artifact.getScope() );
549         }
550 
551         Model model;
552 
553         try
554         {
555             artifactResolver.resolve( projectArtifact, remoteArtifactRepositories, localRepository );
556 
557             File file = projectArtifact.getFile();
558 
559             model = readModel( projectId, file, false );
560 
561             String downloadUrl = null;
562 
563             ArtifactStatus status = ArtifactStatus.NONE;
564 
565             DistributionManagement distributionManagement = model.getDistributionManagement();
566 
567             if ( distributionManagement != null )
568             {
569                 downloadUrl = distributionManagement.getDownloadUrl();
570 
571                 status = ArtifactStatus.valueOf( distributionManagement.getStatus() );
572             }
573 
574             checkStatusAndUpdate( projectArtifact, status, file, remoteArtifactRepositories, localRepository );
575 
576             // TODO: this is gross. Would like to give it the whole model, but maven-artifact shouldn't depend on that
577             // Can a maven-core implementation of the Artifact interface store it, and be used in the exceptions?
578             if ( downloadUrl != null )
579             {
580                 projectArtifact.setDownloadUrl( downloadUrl );
581             }
582             else
583             {
584                 projectArtifact.setDownloadUrl( model.getUrl() );
585             }
586         }
587         catch ( ArtifactResolutionException e )
588         {
589             throw new ProjectBuildingException( projectId, "Error getting POM for '" + projectId +
590                 "' from the repository: " + e.getMessage(), e );
591         }
592         catch ( ArtifactNotFoundException e )
593         {
594             if ( allowStubModel )
595             {
596                 getLogger().debug( "Artifact not found - using stub model: " + e.getMessage() );
597 
598                 model = createStubModel( projectArtifact );
599             }
600             else
601             {
602                 throw new ProjectBuildingException( projectId, "POM '" + projectId + "' not found in repository: " +
603                     e.getMessage(), e );
604             }
605         }
606 
607         return model;
608     }
609 
610     private List normalizeToArtifactRepositories( List remoteArtifactRepositories,
611                                                   String projectId )
612         throws ProjectBuildingException
613     {
614         List normalized = new ArrayList( remoteArtifactRepositories.size() );
615 
616         boolean normalizationNeeded = false;
617         for ( Iterator it = remoteArtifactRepositories.iterator(); it.hasNext(); )
618         {
619             Object item = it.next();
620 
621             if ( item instanceof ArtifactRepository )
622             {
623                 normalized.add( item );
624             }
625             else if ( item instanceof Repository )
626             {
627                 Repository repo = (Repository) item;
628                 try
629                 {
630                     item = ProjectUtils.buildArtifactRepository( repo, artifactRepositoryFactory, container );
631 
632                     normalized.add( item );
633                     normalizationNeeded = true;
634                 }
635                 catch ( InvalidRepositoryException e )
636                 {
637                     throw new ProjectBuildingException( projectId, "Error building artifact repository for id: " + repo.getId(), e );
638                 }
639             }
640             else
641             {
642                 throw new ProjectBuildingException( projectId, "Error building artifact repository from non-repository information item: " + item );
643             }
644         }
645 
646         if ( normalizationNeeded )
647         {
648             return normalized;
649         }
650         else
651         {
652             return remoteArtifactRepositories;
653         }
654     }
655 
656     private void checkStatusAndUpdate( Artifact projectArtifact,
657                                        ArtifactStatus status,
658                                        File file,
659                                        List remoteArtifactRepositories,
660                                        ArtifactRepository localRepository )
661         throws ArtifactNotFoundException
662     {
663         // TODO: configurable actions dependant on status
664         if ( !projectArtifact.isSnapshot() && ( status.compareTo( ArtifactStatus.DEPLOYED ) < 0 ) )
665         {
666             // use default policy (enabled, daily update, warn on bad checksum)
667             ArtifactRepositoryPolicy policy = new ArtifactRepositoryPolicy();
668             // TODO: re-enable [MNG-798/865]
669             policy.setUpdatePolicy( ArtifactRepositoryPolicy.UPDATE_POLICY_NEVER );
670 
671             if ( policy.checkOutOfDate( new Date( file.lastModified() ) ) )
672             {
673                 getLogger().info(
674                     projectArtifact.getArtifactId() + ": updating metadata due to status of '" + status + "'" );
675                 try
676                 {
677                     projectArtifact.setResolved( false );
678                     artifactResolver.resolveAlways( projectArtifact, remoteArtifactRepositories, localRepository );
679                 }
680                 catch ( ArtifactResolutionException e )
681                 {
682                     getLogger().warn( "Error updating POM - using existing version" );
683                     getLogger().debug( "Cause", e );
684                 }
685                 catch ( ArtifactNotFoundException e )
686                 {
687                     getLogger().warn( "Error updating POM - not found. Removing local copy." );
688                     getLogger().debug( "Cause", e );
689                     file.delete();
690                     throw e;
691                 }
692             }
693         }
694     }
695 
696     // jvz:note
697     // This is used when requested artifacts do not have an associated POM. This is for the case where we are
698     // using an m1 repo where the only thing required to be present are the JAR files.
699     private Model createStubModel( Artifact projectArtifact )
700     {
701         getLogger().debug( "Using defaults for missing POM " + projectArtifact );
702 
703         Model model = new Model();
704 
705         model.setModelVersion( "4.0.0" );
706 
707         model.setArtifactId( projectArtifact.getArtifactId() );
708 
709         model.setGroupId( projectArtifact.getGroupId() );
710 
711         model.setVersion( projectArtifact.getVersion() );
712 
713         // TODO: not correct in some instances
714         model.setPackaging( projectArtifact.getType() );
715 
716         model.setDistributionManagement( new DistributionManagement() );
717 
718         model.getDistributionManagement().setStatus( ArtifactStatus.GENERATED.toString() );
719 
720         return model;
721     }
722 
723     // jvz:note
724     // We've got a mixture of things going in the USD and from the repository, sometimes the descriptor
725     // is a real file and sometimes null which makes things confusing.
726     private MavenProject buildInternal( String pomLocation,
727                                         Model model,
728                                         ProjectBuilderConfiguration config,
729                                         List parentSearchRepositories,
730                                         File projectDescriptor,
731                                         boolean strict )
732         throws ProjectBuildingException
733     {
734         File projectDir = null;
735 
736         if ( projectDescriptor != null )
737         {
738             projectDir = projectDescriptor.getAbsoluteFile().getParentFile();
739         }
740 
741         Model superModel = getSuperModel();
742 
743         ProfileManager externalProfileManager = config.getGlobalProfileManager();
744         ProfileManager superProjectProfileManager;
745         if ( externalProfileManager != null )
746         {
747             superProjectProfileManager = new DefaultProfileManager(
748                                                                     container,
749                                                                     externalProfileManager.getRequestProperties() );
750         }
751         else
752         {
753             superProjectProfileManager = new DefaultProfileManager( container );
754         }
755 
756         List activeProfiles;
757 
758         superProjectProfileManager.addProfiles( superModel.getProfiles() );
759 
760         activeProfiles = injectActiveProfiles( superProjectProfileManager, superModel );
761 
762         MavenProject superProject = new MavenProject( superModel );
763 
764         superProject.setActiveProfiles( activeProfiles );
765 
766         //noinspection CollectionDeclaredAsConcreteClass
767         LinkedList lineage = new LinkedList();
768 
769         // TODO: the aRWR can get out of sync with project.model.repositories. We should do all the processing of
770         // profiles, etc on the models then recreate the aggregated sets at the end from the project repositories (they
771         // must still be created along the way so that parent poms can be discovered, however)
772         // Use a TreeSet to ensure ordering is retained
773         Set aggregatedRemoteWagonRepositories = new LinkedHashSet();
774 
775         String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
776 
777         List activeExternalProfiles;
778         try
779         {
780             if ( externalProfileManager != null )
781             {
782                 activeExternalProfiles = externalProfileManager.getActiveProfiles();
783             }
784             else
785             {
786                 activeExternalProfiles = Collections.EMPTY_LIST;
787             }
788         }
789         catch ( ProfileActivationException e )
790         {
791             throw new ProjectBuildingException( projectId, "Failed to calculate active external profiles.", e );
792         }
793 
794         for ( Iterator i = activeExternalProfiles.iterator(); i.hasNext(); )
795         {
796             Profile externalProfile = (Profile) i.next();
797 
798             for ( Iterator repoIterator = externalProfile.getRepositories().iterator(); repoIterator.hasNext(); )
799             {
800                 Repository mavenRepo = (Repository) repoIterator.next();
801 
802                 ArtifactRepository artifactRepo = null;
803                 try
804                 {
805                     artifactRepo =
806                         ProjectUtils.buildArtifactRepository( mavenRepo, artifactRepositoryFactory, container );
807                 }
808                 catch ( InvalidRepositoryException e )
809                 {
810                     throw new ProjectBuildingException( projectId, e.getMessage(), e );
811                 }
812 
813                 aggregatedRemoteWagonRepositories.add( artifactRepo );
814             }
815         }
816 
817         MavenProject project = null;
818         try
819         {
820             project = assembleLineage( model, lineage, config, projectDescriptor, parentSearchRepositories,
821                                        aggregatedRemoteWagonRepositories, strict );
822         }
823         catch ( InvalidRepositoryException e )
824         {
825             throw new ProjectBuildingException( projectId, e.getMessage(), e );
826         }
827 
828         // we don't have to force the collision exception for superModel here, it's already been done in getSuperModel()
829         MavenProject previousProject = superProject;
830 
831         Model previous = superProject.getModel();
832 
833         for ( Iterator i = lineage.iterator(); i.hasNext(); )
834         {
835             MavenProject currentProject = (MavenProject) i.next();
836 
837             Model current = currentProject.getModel();
838 
839             String pathAdjustment = null;
840 
841             try
842             {
843                 pathAdjustment = previousProject.getModulePathAdjustment( currentProject );
844             }
845             catch ( IOException e )
846             {
847                 getLogger().debug( "Cannot determine whether " + currentProject.getId() + " is a module of " +
848                     previousProject.getId() + ". Reason: " + e.getMessage(), e );
849             }
850 
851             modelInheritanceAssembler.assembleModelInheritance( current, previous, pathAdjustment );
852 
853             previous = current;
854             previousProject = currentProject;
855         }
856 
857         // only add the super repository if it wasn't overridden by a profile or project
858         List repositories = new ArrayList( aggregatedRemoteWagonRepositories );
859 
860         List superRepositories = buildArtifactRepositories( superModel );
861 
862         for ( Iterator i = superRepositories.iterator(); i.hasNext(); )
863         {
864             ArtifactRepository repository = (ArtifactRepository) i.next();
865 
866             if ( !repositories.contains( repository ) )
867             {
868                 repositories.add( repository );
869             }
870         }
871 
872         // merge any duplicated plugin definitions together, using the first appearance as the dominant one.
873         ModelUtils.mergeDuplicatePluginDefinitions( project.getModel().getBuild() );
874 
875         try
876         {
877             project = processProjectLogic( pomLocation, project, config, projectDir, repositories, strict, false );
878         }
879         catch ( ModelInterpolationException e )
880         {
881             throw new InvalidProjectModelException( projectId, pomLocation, e.getMessage(), e );
882         }
883         catch ( InvalidRepositoryException e )
884         {
885             throw new InvalidProjectModelException( projectId, pomLocation, e.getMessage(), e );
886         }
887 
888         processedProjectCache.put(
889                                   createCacheKey( project.getGroupId(), project.getArtifactId(), project.getVersion() ), project );
890 
891           // jvz:note
892         // this only happens if we are building from a source file
893         if ( projectDescriptor != null )
894         {
895             // Only translate the base directory for files in the source tree
896             pathTranslator.alignToBaseDirectory( project.getModel(),
897                                                  projectDir );
898 
899             Build build = project.getBuild();
900 
901             project.addCompileSourceRoot( build.getSourceDirectory() );
902 
903             project.addScriptSourceRoot( build.getScriptSourceDirectory() );
904 
905             project.addTestCompileSourceRoot( build.getTestSourceDirectory() );
906 
907             // Only track the file of a POM in the source tree
908             project.setFile( projectDescriptor );
909         }
910 
911         project.setManagedVersionMap( createManagedVersionMap( projectId,
912                                                                project.getDependencyManagement(),
913                                                                project.getParent() ) );
914 
915         return project;
916     }
917 
918     private String safeVersionlessKey( String groupId,
919                                        String artifactId )
920     {
921         String gid = groupId;
922 
923         if ( StringUtils.isEmpty( gid ) )
924         {
925             gid = "unknown";
926         }
927 
928         String aid = artifactId;
929 
930         if ( StringUtils.isEmpty( aid ) )
931         {
932             aid = "unknown";
933         }
934 
935         return ArtifactUtils.versionlessKey( gid, aid );
936     }
937 
938     private List buildArtifactRepositories( Model model )
939         throws ProjectBuildingException
940     {
941         try
942         {
943             return ProjectUtils.buildArtifactRepositories( model.getRepositories(), artifactRepositoryFactory,
944                                                            container );
945         }
946         catch ( InvalidRepositoryException e )
947         {
948             String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
949 
950             throw new ProjectBuildingException( projectId, e.getMessage(), e );
951         }
952     }
953 
954     /**
955      * @todo can this take in a model instead of a project and still be successful?
956      * @todo In fact, does project REALLY need a MavenProject as a parent? Couldn't it have just a wrapper around a
957      * model that supported parents which were also the wrapper so that inheritence was assembled. We don't really need
958      * the resolved source roots, etc for the parent - that occurs for the parent when it is constructed independently
959      * and projects are not cached or reused
960      */
961     private MavenProject processProjectLogic( String pomLocation,
962                                               MavenProject project,
963                                               ProjectBuilderConfiguration config,
964                                               File projectDir,
965                                               List remoteRepositories,
966                                               boolean strict,
967                                               boolean isSuperPom )
968         throws ProjectBuildingException, ModelInterpolationException, InvalidRepositoryException
969     {
970         Model model = project.getModel();
971 
972         List activeProfiles = project.getActiveProfiles();
973 
974         if ( activeProfiles == null )
975         {
976             activeProfiles = new ArrayList();
977         }
978 
979         ProfileManager profileMgr = config == null ? null : config.getGlobalProfileManager();
980 
981         List injectedProfiles = injectActiveProfiles( profileMgr, model );
982 
983         activeProfiles.addAll( injectedProfiles );
984 
985         // We don't need all the project methods that are added over those in the model, but we do need basedir
986         Map context = new HashMap();
987 
988         // --------------------------------------------------------------------------------
989         
990         Build build = model.getBuild();
991 
992         if ( projectDir != null )
993         {
994             context.put( "basedir", projectDir.getAbsolutePath() );
995 
996             // MNG-1927, MNG-2124, MNG-3355:
997             // If the build section is present and the project directory is non-null, we should make
998             // sure interpolation of the directories below uses translated paths.
999             // Afterward, we'll double back and translate any paths that weren't covered during interpolation via the
1000             // code below...
1001             context.put( "build.directory", pathTranslator.alignToBaseDirectory( build.getDirectory(), projectDir ) );
1002             context.put( "build.outputDirectory", pathTranslator.alignToBaseDirectory( build.getOutputDirectory(), projectDir ) );
1003             context.put( "build.testOutputDirectory", pathTranslator.alignToBaseDirectory( build.getTestOutputDirectory(), projectDir ) );
1004             context.put( "build.sourceDirectory", pathTranslator.alignToBaseDirectory( build.getSourceDirectory(), projectDir ) );
1005             context.put( "build.testSourceDirectory", pathTranslator.alignToBaseDirectory( build.getTestSourceDirectory(), projectDir ) );
1006         }
1007 
1008         if ( !isSuperPom )
1009         {
1010             Properties userProps = config.getUserProperties();
1011             if ( userProps != null )
1012             {
1013                 context.putAll( userProps );
1014             }
1015         }
1016 
1017         model = modelInterpolator.interpolate( model, context, strict );
1018 
1019         // second pass allows ${user.home} to work, if it needs to.
1020         // [MNG-2339] ensure the system properties are still interpolated for backwards compat, but the model values must win
1021         if ( config.getExecutionProperties() != null && !config.getExecutionProperties().isEmpty() )
1022         {
1023             context.putAll( config.getExecutionProperties() );
1024         }
1025 
1026         model = modelInterpolator.interpolate( model, context, strict );
1027 
1028         // MNG-3482: Make sure depMgmt is interpolated before merging.
1029         if ( !isSuperPom )
1030         {
1031             mergeManagedDependencies( model, config.getLocalRepository(), remoteRepositories );
1032         }
1033 
1034         // interpolation is before injection, because interpolation is off-limits in the injected variables
1035         modelDefaultsInjector.injectDefaults( model );
1036 
1037         MavenProject parentProject = project.getParent();
1038 
1039         Model originalModel = project.getOriginalModel();
1040 
1041         // We will return a different project object using the new model (hence the need to return a project, not just modify the parameter)
1042         project = new MavenProject( model );
1043 
1044         project.setOriginalModel( originalModel );
1045 
1046         project.setActiveProfiles( activeProfiles );
1047 
1048         // TODO: maybe not strictly correct, while we should enfore that packaging has a type handler of the same id, we don't
1049         Artifact projectArtifact = artifactFactory.createBuildArtifact( project.getGroupId(), project.getArtifactId(),
1050                                                                         project.getVersion(), project.getPackaging() );
1051 
1052         project.setArtifact( projectArtifact );
1053 
1054         project.setPluginArtifactRepositories( ProjectUtils.buildArtifactRepositories( model.getPluginRepositories(),
1055                                                                                        artifactRepositoryFactory,
1056                                                                                        container ) );
1057 
1058         DistributionManagement dm = model.getDistributionManagement();
1059         if ( dm != null )
1060         {
1061             ArtifactRepository repo = ProjectUtils.buildDeploymentArtifactRepository( dm.getRepository(),
1062                                                                                       artifactRepositoryFactory,
1063                                                                                       container );
1064             project.setReleaseArtifactRepository( repo );
1065 
1066             if ( dm.getSnapshotRepository() != null )
1067             {
1068                 repo = ProjectUtils.buildDeploymentArtifactRepository( dm.getSnapshotRepository(),
1069                                                                        artifactRepositoryFactory, container );
1070                 project.setSnapshotArtifactRepository( repo );
1071             }
1072         }
1073 
1074         if ( parentProject != null )
1075         {
1076             String cacheKey = createCacheKey( parentProject.getGroupId(),
1077                                               parentProject.getArtifactId(),
1078                                               parentProject.getVersion() );
1079 
1080             MavenProject processedParent = (MavenProject) processedProjectCache.get( cacheKey );
1081             Artifact parentArtifact;
1082 
1083             // yeah, this null check might be a bit paranoid, but better safe than sorry...
1084             if ( processedParent != null )
1085             {
1086                 project.setParent( processedParent );
1087 
1088                 parentArtifact = processedParent.getArtifact();
1089             }
1090             else
1091             {
1092                 project.setParent( parentProject );
1093 
1094                 parentArtifact = artifactFactory.createParentArtifact( parentProject.getGroupId(),
1095                                                                                 parentProject.getArtifactId(),
1096                                                                                 parentProject.getVersion() );
1097             }
1098 
1099             project.setParentArtifact( parentArtifact );
1100         }
1101 
1102         // Must validate before artifact construction to make sure dependencies are good
1103         ModelValidationResult validationResult = validator.validate( model );
1104 
1105         String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
1106 
1107         if ( validationResult.getMessageCount() > 0 )
1108         {
1109             throw new InvalidProjectModelException( projectId, pomLocation, "Failed to validate POM",
1110                                                     validationResult );
1111         }
1112 
1113         project.setRemoteArtifactRepositories(
1114             ProjectUtils.buildArtifactRepositories( model.getRepositories(), artifactRepositoryFactory, container ) );
1115 
1116         // TODO: these aren't taking active project artifacts into consideration in the reactor
1117         project.setPluginArtifacts( createPluginArtifacts( projectId, project.getBuildPlugins() ) );
1118 
1119         project.setReportArtifacts( createReportArtifacts( projectId, project.getReportPlugins() ) );
1120 
1121         project.setExtensionArtifacts( createExtensionArtifacts( projectId, project.getBuildExtensions() ) );
1122 
1123         return project;
1124     }
1125 
1126     /**
1127      * @noinspection CollectionDeclaredAsConcreteClass
1128      * @todo We need to find an effective way to unit test parts of this method!
1129      * @todo Refactor this into smaller methods with discrete purposes.
1130      */
1131     private MavenProject assembleLineage( Model model,
1132                                           LinkedList lineage,
1133                                           ProjectBuilderConfiguration config,
1134                                           File projectDescriptor,
1135                                           List parentSearchRepositories,
1136                                           Set aggregatedRemoteWagonRepositories,
1137                                           boolean strict )
1138         throws ProjectBuildingException, InvalidRepositoryException
1139     {
1140         Model originalModel = ModelUtils.cloneModel( model );
1141 
1142         File projectDir = null;
1143         if ( projectDescriptor != null )
1144         {
1145             projectDir = projectDescriptor.getAbsoluteFile().getParentFile();
1146         }
1147 
1148         ProfileManager externalProfileManager = config.getGlobalProfileManager();
1149         ProfileManager profileManager;
1150         if ( externalProfileManager != null )
1151         {
1152             profileManager = new DefaultProfileManager( container, externalProfileManager.getRequestProperties() );
1153         }
1154         else
1155         {
1156             //TODO mkleint - use the (Container, Properties constructor to make system properties embeddable
1157             profileManager = new DefaultProfileManager( container );
1158         }
1159 
1160         if ( externalProfileManager != null )
1161         {
1162             profileManager.explicitlyActivate( externalProfileManager.getExplicitlyActivatedIds() );
1163 
1164             profileManager.explicitlyDeactivate( externalProfileManager.getExplicitlyDeactivatedIds() );
1165         }
1166 
1167         List activeProfiles;
1168 
1169         try
1170         {
1171             profileManager.addProfiles( model.getProfiles() );
1172 
1173             loadProjectExternalProfiles( profileManager, projectDir );
1174 
1175             activeProfiles = injectActiveProfiles( profileManager, model );
1176         }
1177         catch ( ProfileActivationException e )
1178         {
1179             String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
1180 
1181             throw new ProjectBuildingException( projectId, "Failed to activate local (project-level) build profiles: " +
1182                 e.getMessage(), e );
1183         }
1184 
1185         if ( !model.getRepositories().isEmpty() )
1186         {
1187             List respositories = buildArtifactRepositories( model );
1188 
1189             for ( Iterator it = respositories.iterator(); it.hasNext(); )
1190             {
1191                 ArtifactRepository repository = (ArtifactRepository) it.next();
1192 
1193                 if ( !aggregatedRemoteWagonRepositories.contains( repository ) )
1194                 {
1195                     aggregatedRemoteWagonRepositories.add( repository );
1196                 }
1197             }
1198         }
1199 
1200         MavenProject project = new MavenProject( model );
1201 
1202         project.setFile( projectDescriptor );
1203         project.setActiveProfiles( activeProfiles );
1204         project.setOriginalModel( originalModel );
1205 
1206         lineage.addFirst( project );
1207 
1208         Parent parentModel = model.getParent();
1209 
1210         String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
1211 
1212         if ( parentModel != null )
1213         {
1214             if ( StringUtils.isEmpty( parentModel.getGroupId() ) )
1215             {
1216                 throw new ProjectBuildingException( projectId, "Missing groupId element from parent element" );
1217             }
1218             else if ( StringUtils.isEmpty( parentModel.getArtifactId() ) )
1219             {
1220                 throw new ProjectBuildingException( projectId, "Missing artifactId element from parent element" );
1221             }
1222             else if ( parentModel.getGroupId().equals( model.getGroupId() ) &&
1223                 parentModel.getArtifactId().equals( model.getArtifactId() ) )
1224             {
1225                 throw new ProjectBuildingException( projectId,
1226                                                     "Parent element is a duplicate of " + "the current project " );
1227             }
1228             else if ( StringUtils.isEmpty( parentModel.getVersion() ) )
1229             {
1230                 throw new ProjectBuildingException( projectId, "Missing version element from parent element" );
1231             }
1232 
1233             // the only way this will have a value is if we find the parent on disk...
1234             File parentDescriptor = null;
1235 
1236             model = null;
1237 
1238             String parentKey =
1239                 createCacheKey( parentModel.getGroupId(), parentModel.getArtifactId(), parentModel.getVersion() );
1240             MavenProject parentProject = (MavenProject) rawProjectCache.get( parentKey );
1241 
1242             if ( parentProject != null )
1243             {
1244                 model = ModelUtils.cloneModel( parentProject.getOriginalModel() );
1245 
1246                 parentDescriptor = parentProject.getFile();
1247             }
1248 
1249             String parentRelativePath = parentModel.getRelativePath();
1250 
1251             // if we can't find a cached model matching the parent spec, then let's try to look on disk using
1252             // <relativePath/>
1253             if ( ( model == null ) && ( projectDir != null ) && StringUtils.isNotEmpty( parentRelativePath ) )
1254             {
1255                 parentDescriptor = new File( projectDir, parentRelativePath );
1256 
1257                 if ( getLogger().isDebugEnabled() )
1258                 {
1259                     getLogger().debug( "Searching for parent-POM: " + parentModel.getId() + " of project: " +
1260                         project.getId() + " in relative path: " + parentRelativePath );
1261                 }
1262 
1263                 if ( parentDescriptor.isDirectory() )
1264                 {
1265                     if ( getLogger().isDebugEnabled() )
1266                     {
1267                         getLogger().debug( "Path specified in <relativePath/> (" + parentRelativePath +
1268                             ") is a directory. Searching for 'pom.xml' within this directory." );
1269                     }
1270 
1271                     parentDescriptor = new File( parentDescriptor, "pom.xml" );
1272 
1273                     if ( !parentDescriptor.exists() )
1274                     {
1275                         if ( getLogger().isDebugEnabled() )
1276                         {
1277                             getLogger().debug( "Parent-POM: " + parentModel.getId() + " for project: " +
1278                                 project.getId() + " cannot be loaded from relative path: " + parentDescriptor +
1279                                 "; path does not exist." );
1280                         }
1281                     }
1282                 }
1283 
1284                 if ( parentDescriptor != null )
1285                 {
1286                     try
1287                     {
1288                         parentDescriptor = parentDescriptor.getCanonicalFile();
1289                     }
1290                     catch ( IOException e )
1291                     {
1292                         getLogger().debug( "Failed to canonicalize potential parent POM: \'" + parentDescriptor + "\'",
1293                                            e );
1294 
1295                         parentDescriptor = null;
1296                     }
1297                 }
1298 
1299                 if ( ( parentDescriptor != null ) && parentDescriptor.exists() )
1300                 {
1301                     Model candidateParent = readModel( projectId, parentDescriptor, strict );
1302 
1303                     String candidateParentGroupId = candidateParent.getGroupId();
1304                     if ( ( candidateParentGroupId == null ) && ( candidateParent.getParent() != null ) )
1305                     {
1306                         candidateParentGroupId = candidateParent.getParent().getGroupId();
1307                     }
1308 
1309                     String candidateParentVersion = candidateParent.getVersion();
1310                     if ( ( candidateParentVersion == null ) && ( candidateParent.getParent() != null ) )
1311                     {
1312                         candidateParentVersion = candidateParent.getParent().getVersion();
1313                     }
1314 
1315                     if ( parentModel.getGroupId().equals( candidateParentGroupId ) &&
1316                         parentModel.getArtifactId().equals( candidateParent.getArtifactId() ) &&
1317                         parentModel.getVersion().equals( candidateParentVersion ) )
1318                     {
1319                         model = candidateParent;
1320 
1321                         getLogger().debug( "Using parent-POM from the project hierarchy at: \'" +
1322                             parentModel.getRelativePath() + "\' for project: " + project.getId() );
1323                     }
1324                     else
1325                     {
1326                         getLogger().debug( "Invalid parent-POM referenced by relative path '" +
1327                             parentModel.getRelativePath() + "' in parent specification in " + project.getId() + ":" +
1328                             "\n  Specified: " + parentModel.getId() + "\n  Found:     " + candidateParent.getId() );
1329                     }
1330                 }
1331                 else if ( getLogger().isDebugEnabled() )
1332                 {
1333                     getLogger().debug(
1334                         "Parent-POM: " + parentModel.getId() + " not found in relative path: " + parentRelativePath );
1335                 }
1336             }
1337 
1338             Artifact parentArtifact = null;
1339 
1340             // only resolve the parent model from the repository system if we didn't find it on disk...
1341             if ( model == null )
1342             {
1343                 // MNG-2302: parent's File was being populated incorrectly when parent is loaded from repo.
1344                 // keep this in line with other POMs loaded from the repository...the file should be null.
1345                 parentDescriptor = null;
1346 
1347                 //!! (**)
1348                 // ----------------------------------------------------------------------
1349                 // Do we have the necessary information to actually find the parent
1350                 // POMs here?? I don't think so ... Say only one remote repository is
1351                 // specified and that is ibiblio then this model that we just read doesn't
1352                 // have any repository information ... I think we might have to inherit
1353                 // as we go in order to do this.
1354                 // ----------------------------------------------------------------------
1355 
1356                 // we must add the repository this POM was found in too, by chance it may be located where the parent is
1357                 // we can't query the parent to ask where it is :)
1358                 List remoteRepositories = new ArrayList( aggregatedRemoteWagonRepositories );
1359                 remoteRepositories.addAll( parentSearchRepositories );
1360 
1361                 if ( getLogger().isDebugEnabled() )
1362                 {
1363                     getLogger().debug( "Retrieving parent-POM: " + parentModel.getId() + " for project: " +
1364                         project.getId() + " from the repository." );
1365                 }
1366 
1367                 parentArtifact = artifactFactory.createParentArtifact( parentModel.getGroupId(),
1368                                                                        parentModel.getArtifactId(),
1369                                                                        parentModel.getVersion() );
1370 
1371                 try
1372                 {
1373                     model = findModelFromRepository( parentArtifact, remoteRepositories, config.getLocalRepository(), false );
1374                 }
1375                 catch ( ProjectBuildingException e )
1376                 {
1377                     throw new ProjectBuildingException( project.getId(), "Cannot find parent: " + e.getProjectId() +
1378                         " for project: " + project.getId(), e );
1379                 }
1380             }
1381 
1382             if ( ( model != null ) && !"pom".equals( model.getPackaging() ) )
1383             {
1384                 throw new ProjectBuildingException( projectId, "Parent: " + model.getId() + " of project: " +
1385                     projectId + " has wrong packaging: " + model.getPackaging() + ". Must be 'pom'." );
1386             }
1387 
1388             MavenProject parent = assembleLineage( model,
1389                                                    lineage,
1390                                                    config,
1391                                                    parentDescriptor,
1392                                                    parentSearchRepositories,
1393                                                    aggregatedRemoteWagonRepositories,
1394                                                    strict );
1395 
1396             project.setParent( parent );
1397 
1398             project.setParentArtifact( parentArtifact );
1399         }
1400 
1401         rawProjectCache.put( createCacheKey( project.getGroupId(), project.getArtifactId(), project.getVersion() ), new MavenProject( project ) );
1402 
1403         return project;
1404     }
1405 
1406     private void mergeManagedDependencies(Model model, ArtifactRepository localRepository, List parentSearchRepositories)
1407         throws ProjectBuildingException
1408     {
1409         DependencyManagement modelDepMgmt = model.getDependencyManagement();
1410 
1411         if (modelDepMgmt != null)
1412         {
1413             Map depsMap = new TreeMap();
1414             Iterator iter = modelDepMgmt.getDependencies().iterator();
1415             boolean doInclude = false;
1416             while (iter.hasNext())
1417             {
1418                 Dependency dep = (Dependency) iter.next();
1419                 depsMap.put( dep.getManagementKey(), dep );
1420                 if ( dep.getType().equals( "pom" ) && Artifact.SCOPE_IMPORT.equals( dep.getScope() ) )
1421                 {
1422                     doInclude = true;
1423                 }
1424             }
1425             Map newDeps = new TreeMap(depsMap);
1426             iter = modelDepMgmt.getDependencies().iterator();
1427             if (doInclude)
1428             {
1429                 while (iter.hasNext())
1430                 {
1431                     Dependency dep = (Dependency)iter.next();
1432                     if ( dep.getType().equals( "pom" )
1433                          && Artifact.SCOPE_IMPORT.equals( dep.getScope() ) )
1434                     {
1435                         Artifact artifact = artifactFactory.createProjectArtifact( dep.getGroupId(), dep.getArtifactId(),
1436                                                                                   dep.getVersion(), dep.getScope() );
1437                         MavenProject project = buildFromRepository(artifact, parentSearchRepositories, localRepository, false);
1438 
1439                         DependencyManagement depMgmt = project.getDependencyManagement();
1440 
1441                         if (depMgmt != null)
1442                         {
1443                             if ( getLogger().isDebugEnabled() )
1444                             {
1445                                 getLogger().debug( "Importing managed dependencies for " + dep.toString() );
1446                             }
1447 
1448                             for ( Iterator it = depMgmt.getDependencies().iterator(); it.hasNext(); )
1449                             {
1450                                 Dependency includedDep = (Dependency) it.next();
1451                                 String key = includedDep.getManagementKey();
1452                                 if (!newDeps.containsKey(key))
1453                                 {
1454                                     newDeps.put( includedDep.getManagementKey(), includedDep );
1455                                 }
1456                             }
1457                             newDeps.remove(dep.getManagementKey());
1458                         }
1459                     }
1460                 }
1461                 List deps = new ArrayList(newDeps.values());
1462                 modelDepMgmt.setDependencies(deps);
1463             }
1464         }
1465     }
1466 
1467     private List injectActiveProfiles( ProfileManager profileManager,
1468                                        Model model )
1469         throws ProjectBuildingException
1470     {
1471         List activeProfiles;
1472 
1473         if ( profileManager != null )
1474         {
1475             try
1476             {
1477                 activeProfiles = profileManager.getActiveProfiles();
1478             }
1479             catch ( ProfileActivationException e )
1480             {
1481                 String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
1482 
1483                 throw new ProjectBuildingException( projectId, e.getMessage(), e );
1484             }
1485 
1486             for ( Iterator it = activeProfiles.iterator(); it.hasNext(); )
1487             {
1488                 Profile profile = (Profile) it.next();
1489 
1490                 profileInjector.inject( profile, model );
1491             }
1492         }
1493         else
1494         {
1495             activeProfiles = Collections.EMPTY_LIST;
1496         }
1497 
1498         return activeProfiles;
1499     }
1500 
1501     private void loadProjectExternalProfiles( ProfileManager profileManager,
1502                                               File projectDir )
1503         throws ProfileActivationException
1504     {
1505         if ( projectDir != null )
1506         {
1507             try
1508             {
1509                 ProfilesRoot root = profilesBuilder.buildProfiles( projectDir );
1510 
1511                 if ( root != null )
1512                 {
1513                     List active = root.getActiveProfiles();
1514 
1515                     if ( ( active != null ) && !active.isEmpty() )
1516                     {
1517                         profileManager.explicitlyActivate( root.getActiveProfiles() );
1518                     }
1519 
1520                     for ( Iterator it = root.getProfiles().iterator(); it.hasNext(); )
1521                     {
1522                         org.apache.maven.profiles.Profile rawProfile = (org.apache.maven.profiles.Profile) it.next();
1523 
1524                         Profile converted = ProfilesConversionUtils.convertFromProfileXmlProfile( rawProfile );
1525 
1526                         profileManager.addProfile( converted );
1527                     }
1528                 }
1529             }
1530             catch ( IOException e )
1531             {
1532                 throw new ProfileActivationException( "Cannot read profiles.xml resource from directory: " + projectDir,
1533                                                       e );
1534             }
1535             catch ( XmlPullParserException e )
1536             {
1537                 throw new ProfileActivationException(
1538                     "Cannot parse profiles.xml resource from directory: " + projectDir, e );
1539             }
1540         }
1541     }
1542 
1543     private Model readModel( String projectId,
1544                              File file,
1545                              boolean strict )
1546         throws ProjectBuildingException
1547     {
1548         Reader reader = null;
1549         try
1550         {
1551             reader = ReaderFactory.newXmlReader( file );
1552             return readModel( projectId, file.getAbsolutePath(), reader, strict );
1553         }
1554         catch ( FileNotFoundException e )
1555         {
1556             throw new ProjectBuildingException( projectId,
1557                                                 "Could not find the model file '" + file.getAbsolutePath() + "'.", e );
1558         }
1559         catch ( IOException e )
1560         {
1561             throw new ProjectBuildingException( projectId, "Failed to build model from file '" +
1562                 file.getAbsolutePath() + "'.\nError: \'" + e.getLocalizedMessage() + "\'", e );
1563         }
1564         finally
1565         {
1566             IOUtil.close( reader );
1567         }
1568     }
1569 
1570     private Model readModel( String projectId,
1571                              String pomLocation,
1572                              Reader reader,
1573                              boolean strict )
1574         throws IOException, InvalidProjectModelException
1575     {
1576         String modelSource = IOUtil.toString( reader );
1577 
1578         if ( modelSource.indexOf( "<modelVersion>" + MAVEN_MODEL_VERSION ) < 0 )
1579         {
1580             throw new InvalidProjectModelException( projectId, pomLocation, "Not a v" + MAVEN_MODEL_VERSION  + " POM." );
1581         }
1582 
1583         StringReader sReader = new StringReader( modelSource );
1584 
1585         try
1586         {
1587             return modelReader.read( sReader, strict );
1588         }
1589         catch ( XmlPullParserException e )
1590         {
1591             throw new InvalidProjectModelException( projectId, pomLocation,
1592                                                     "Parse error reading POM. Reason: " + e.getMessage(), e );
1593         }
1594     }
1595 
1596     private Model readModel( String projectId,
1597                              URL url,
1598                              boolean strict )
1599         throws ProjectBuildingException
1600     {
1601         Reader reader = null;
1602         try
1603         {
1604             reader = ReaderFactory.newXmlReader( url.openStream() );
1605             return readModel( projectId, url.toExternalForm(), reader, strict );
1606         }
1607         catch ( IOException e )
1608         {
1609             throw new ProjectBuildingException( projectId, "Failed build model from URL \'" + url.toExternalForm() +
1610                 "\'\nError: \'" + e.getLocalizedMessage() + "\'", e );
1611         }
1612         finally
1613         {
1614             IOUtil.close( reader );
1615         }
1616     }
1617 
1618     private static String createCacheKey( String groupId,
1619                                           String artifactId,
1620                                           String version )
1621     {
1622         return groupId + ":" + artifactId + ":" + version;
1623     }
1624 
1625     protected Set createPluginArtifacts( String projectId,
1626                                          List plugins )
1627         throws ProjectBuildingException
1628     {
1629         Set pluginArtifacts = new LinkedHashSet();
1630 
1631         for ( Iterator i = plugins.iterator(); i.hasNext(); )
1632         {
1633             Plugin p = (Plugin) i.next();
1634 
1635             String version;
1636             if ( StringUtils.isEmpty( p.getVersion() ) )
1637             {
1638                 version = "RELEASE";
1639             }
1640             else
1641             {
1642                 version = p.getVersion();
1643             }
1644 
1645             Artifact artifact;
1646             try
1647             {
1648                 artifact = artifactFactory.createPluginArtifact( p.getGroupId(), p.getArtifactId(),
1649                                                                  VersionRange.createFromVersionSpec( version ) );
1650             }
1651             catch ( InvalidVersionSpecificationException e )
1652             {
1653                 throw new ProjectBuildingException( projectId, "Unable to parse version '" + version +
1654                     "' for plugin '" + ArtifactUtils.versionlessKey( p.getGroupId(), p.getArtifactId() ) + "': " +
1655                     e.getMessage(), e );
1656             }
1657 
1658             if ( artifact != null )
1659             {
1660                 pluginArtifacts.add( artifact );
1661             }
1662         }
1663 
1664         return pluginArtifacts;
1665     }
1666 
1667     // TODO: share with createPluginArtifacts?
1668     protected Set createReportArtifacts( String projectId,
1669                                          List reports )
1670         throws ProjectBuildingException
1671     {
1672         Set pluginArtifacts = new LinkedHashSet();
1673 
1674         if ( reports != null )
1675         {
1676             for ( Iterator i = reports.iterator(); i.hasNext(); )
1677             {
1678                 ReportPlugin p = (ReportPlugin) i.next();
1679 
1680                 String version;
1681                 if ( StringUtils.isEmpty( p.getVersion() ) )
1682                 {
1683                     version = "RELEASE";
1684                 }
1685                 else
1686                 {
1687                     version = p.getVersion();
1688                 }
1689 
1690                 Artifact artifact;
1691                 try
1692                 {
1693                     artifact = artifactFactory.createPluginArtifact( p.getGroupId(), p.getArtifactId(),
1694                                                                      VersionRange.createFromVersionSpec( version ) );
1695                 }
1696                 catch ( InvalidVersionSpecificationException e )
1697                 {
1698                     throw new ProjectBuildingException( projectId, "Unable to parse version '" + version +
1699                         "' for report '" + ArtifactUtils.versionlessKey( p.getGroupId(), p.getArtifactId() ) + "': " +
1700                         e.getMessage(), e );
1701                 }
1702 
1703                 if ( artifact != null )
1704                 {
1705                     pluginArtifacts.add( artifact );
1706                 }
1707             }
1708         }
1709 
1710         return pluginArtifacts;
1711     }
1712 
1713     // TODO: share with createPluginArtifacts?
1714     protected Set createExtensionArtifacts( String projectId,
1715                                             List extensions )
1716         throws ProjectBuildingException
1717     {
1718         Set extensionArtifacts = new LinkedHashSet();
1719 
1720         if ( extensions != null )
1721         {
1722             for ( Iterator i = extensions.iterator(); i.hasNext(); )
1723             {
1724                 Extension ext = (Extension) i.next();
1725 
1726                 String version;
1727                 if ( StringUtils.isEmpty( ext.getVersion() ) )
1728                 {
1729                     version = "RELEASE";
1730                 }
1731                 else
1732                 {
1733                     version = ext.getVersion();
1734                 }
1735 
1736                 Artifact artifact;
1737                 try
1738                 {
1739                     VersionRange versionRange = VersionRange.createFromVersionSpec( version );
1740                     artifact =
1741                         artifactFactory.createExtensionArtifact( ext.getGroupId(), ext.getArtifactId(), versionRange );
1742                 }
1743                 catch ( InvalidVersionSpecificationException e )
1744                 {
1745                     throw new ProjectBuildingException( projectId, "Unable to parse version '" + version +
1746                         "' for extension '" + ArtifactUtils.versionlessKey( ext.getGroupId(), ext.getArtifactId() ) +
1747                         "': " + e.getMessage(), e );
1748                 }
1749 
1750                 if ( artifact != null )
1751                 {
1752                     extensionArtifacts.add( artifact );
1753                 }
1754             }
1755         }
1756 
1757         return extensionArtifacts;
1758     }
1759 
1760     // ----------------------------------------------------------------------
1761     //
1762     // ----------------------------------------------------------------------
1763 
1764     private Model getSuperModel()
1765         throws ProjectBuildingException
1766     {
1767         URL url = DefaultMavenProjectBuilder.class.getResource( "pom-" + MAVEN_MODEL_VERSION + ".xml" );
1768 
1769         String projectId = safeVersionlessKey( STANDALONE_SUPERPOM_GROUPID, STANDALONE_SUPERPOM_ARTIFACTID );
1770 
1771         return readModel( projectId, url, true );
1772     }
1773 
1774     public void contextualize( Context context )
1775         throws ContextException
1776     {
1777         container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
1778     }
1779 
1780 }