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