blob: c8f24e34f4995250867263f1732797bf5c96094c [file] [log] [blame]
package org.apache.maven.project;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.ArtifactStatus;
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.artifact.InvalidRepositoryException;
import org.apache.maven.artifact.manager.WagonManager;
import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter;
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
import org.apache.maven.artifact.versioning.ManagedVersionMap;
import org.apache.maven.artifact.versioning.VersionRange;
import org.apache.maven.model.Build;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.DependencyManagement;
import org.apache.maven.model.DistributionManagement;
import org.apache.maven.model.Exclusion;
import org.apache.maven.model.Extension;
import org.apache.maven.model.Model;
import org.apache.maven.model.Parent;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginExecution;
import org.apache.maven.model.PluginManagement;
import org.apache.maven.model.Profile;
import org.apache.maven.model.ReportPlugin;
import org.apache.maven.model.Repository;
import org.apache.maven.model.Resource;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.profiles.DefaultProfileManager;
import org.apache.maven.profiles.MavenProfilesBuilder;
import org.apache.maven.profiles.ProfileManager;
import org.apache.maven.profiles.ProfilesConversionUtils;
import org.apache.maven.profiles.ProfilesRoot;
import org.apache.maven.profiles.activation.ProfileActivationException;
import org.apache.maven.project.artifact.InvalidDependencyVersionException;
import org.apache.maven.project.artifact.ProjectArtifactFactory;
import org.apache.maven.project.inheritance.ModelInheritanceAssembler;
import org.apache.maven.project.injection.ModelDefaultsInjector;
import org.apache.maven.project.injection.ProfileInjector;
import org.apache.maven.project.interpolation.ModelInterpolationException;
import org.apache.maven.project.interpolation.ModelInterpolator;
import org.apache.maven.project.path.PathTranslator;
import org.apache.maven.project.validation.ModelValidationResult;
import org.apache.maven.project.validation.ModelValidator;
import org.apache.maven.wagon.events.TransferListener;
import org.codehaus.plexus.PlexusConstants;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.context.Context;
import org.codehaus.plexus.context.ContextException;
import org.codehaus.plexus.logging.AbstractLogEnabled;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/*:apt
-----
POM lifecycle
-----
POM Lifecycle
Order of operations when building a POM
* inheritance
* path translation
* interpolation
* defaults injection
Current processing is:
* inheritance
* interpolation
* defaults injection
* path translation
I'm not sure how this is working at all ... i think i have a case where this is failing but i need to
encapsulate as a test so i can fix it. Also need to think of the in working build directory versus looking
things up from the repository i.e buildFromSource vs buildFromRepository.
Notes
* when the model is read it may not have a groupId, as it must be inherited
* the inheritance assembler must use models that are unadulterated!
*/
/**
* @version $Id$
*/
public class DefaultMavenProjectBuilder
extends AbstractLogEnabled
implements MavenProjectBuilder, Initializable, Contextualizable
{
// TODO: remove
private PlexusContainer container;
protected MavenProfilesBuilder profilesBuilder;
protected ArtifactResolver artifactResolver;
protected ArtifactMetadataSource artifactMetadataSource;
private ProjectArtifactFactory artifactFactory;
private ModelInheritanceAssembler modelInheritanceAssembler;
private ProfileInjector profileInjector;
private ModelValidator validator;
private Map rawProjectCache = new HashMap();
private Map processedProjectCache = new HashMap();
// TODO: make it a component
private MavenXpp3Reader modelReader;
private PathTranslator pathTranslator;
private ModelDefaultsInjector modelDefaultsInjector;
private ModelInterpolator modelInterpolator;
private ArtifactRepositoryFactory artifactRepositoryFactory;
// ----------------------------------------------------------------------
// I am making this available for use with a new method that takes a
// a monitor wagon monitor as a parameter so that tools can use the
// methods here and receive callbacks. MNG-1015
// ----------------------------------------------------------------------
private WagonManager wagonManager;
public static final String MAVEN_MODEL_VERSION = "4.0.0";
public void initialize()
{
modelReader = new MavenXpp3Reader();
}
// ----------------------------------------------------------------------
// MavenProjectBuilder Implementation
// ----------------------------------------------------------------------
public MavenProject build( File pom,
ProjectBuilderConfiguration config )
throws ProjectBuildingException
{
return buildFromSourceFileInternal( pom, config, true );
}
public MavenProject build( File pom,
ProjectBuilderConfiguration config,
boolean checkDistributionManagementStatus )
throws ProjectBuildingException
{
return buildFromSourceFileInternal( pom, config, checkDistributionManagementStatus );
}
public MavenProject build( File projectDescriptor,
ArtifactRepository localRepository,
ProfileManager profileManager )
throws ProjectBuildingException
{
ProjectBuilderConfiguration config = new DefaultProjectBuilderConfiguration().setLocalRepository( localRepository ).setGlobalProfileManager( profileManager );
return buildFromSourceFileInternal( projectDescriptor, config, true );
}
public MavenProject build( File projectDescriptor,
ArtifactRepository localRepository,
ProfileManager profileManager,
boolean checkDistributionManagementStatus )
throws ProjectBuildingException
{
ProjectBuilderConfiguration config = new DefaultProjectBuilderConfiguration().setLocalRepository( localRepository ).setGlobalProfileManager( profileManager );
return buildFromSourceFileInternal( projectDescriptor, config, checkDistributionManagementStatus );
}
// jvz:note
// When asked for something from the repository are we getting it from the reactor? Yes, when using this call
// we are assuming that the reactor has been run and we have collected the projects required to satisfy it0042
// which means the projects in the reactor are required for finding classes in <project>/target/classes. Not
// sure this is ideal. I remove all caching from the builder and all reactor related ITs which assume
// access to simbling project resources failed.
public MavenProject buildFromRepository( Artifact artifact,
List remoteArtifactRepositories,
ArtifactRepository localRepository,
boolean allowStubModel )
throws ProjectBuildingException
{
ProjectBuilderConfiguration config = new DefaultProjectBuilderConfiguration().setLocalRepository( localRepository );
return buildFromRepository( artifact, remoteArtifactRepositories, config, allowStubModel );
}
public MavenProject buildFromRepository( Artifact artifact,
List remoteArtifactRepositories,
ProjectBuilderConfiguration config,
boolean allowStubModel )
throws ProjectBuildingException
{
String cacheKey = createCacheKey( artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion() );
MavenProject project = (MavenProject) processedProjectCache.get( cacheKey );
if ( project != null )
{
return project;
}
Model model = findModelFromRepository( artifact, remoteArtifactRepositories, config, allowStubModel );
return buildInternal( "Artifact [" + artifact + "]", model, config, remoteArtifactRepositories,
null, false );
}
public MavenProject buildFromRepository( Artifact artifact,
List remoteArtifactRepositories,
ArtifactRepository localRepository )
throws ProjectBuildingException
{
return buildFromRepository( artifact, remoteArtifactRepositories, localRepository, true );
}
// what is using this externally? jvz.
public MavenProject buildStandaloneSuperProject( ArtifactRepository localRepository )
throws ProjectBuildingException
{
//TODO mkleint - use the (Container, Properties) constructor to make system properties embeddable
ProfileManager profileManager = new DefaultProfileManager( container );
return buildStandaloneSuperProject( new DefaultProjectBuilderConfiguration().setLocalRepository( localRepository )
.setGlobalProfileManager( profileManager ) );
}
public MavenProject buildStandaloneSuperProject( ArtifactRepository localRepository,
ProfileManager profileManager )
throws ProjectBuildingException
{
return buildStandaloneSuperProject( new DefaultProjectBuilderConfiguration().setLocalRepository( localRepository )
.setGlobalProfileManager( profileManager ) );
}
public MavenProject buildStandaloneSuperProject( ProjectBuilderConfiguration config )
throws ProjectBuildingException
{
Model superModel = getSuperModel();
superModel.setGroupId( STANDALONE_SUPERPOM_GROUPID );
superModel.setArtifactId( STANDALONE_SUPERPOM_ARTIFACTID );
superModel.setVersion( STANDALONE_SUPERPOM_VERSION );
List activeProfiles;
ProfileManager profileManager = config.getGlobalProfileManager();
if ( profileManager == null )
{
profileManager = new DefaultProfileManager( container );
}
profileManager.addProfiles( superModel.getProfiles() );
String projectId = safeVersionlessKey( STANDALONE_SUPERPOM_GROUPID, STANDALONE_SUPERPOM_ARTIFACTID );
activeProfiles = injectActiveProfiles( profileManager, superModel );
MavenProject project = new MavenProject( superModel );
project.setManagedVersionMap(
createManagedVersionMap( projectId, superModel.getDependencyManagement(), null ) );
project.setActiveProfiles( activeProfiles );
project.setOriginalModel( superModel );
try
{
project = processProjectLogic( "<Super-POM>", project, config, null, null, true, true );
project.setExecutionRoot( true );
return project;
}
catch ( ModelInterpolationException e )
{
throw new ProjectBuildingException( projectId, e.getMessage(), e );
}
catch ( InvalidRepositoryException e )
{
throw new ProjectBuildingException( projectId, e.getMessage(), e );
}
}
public MavenProject buildWithDependencies( File projectDescriptor,
ArtifactRepository localRepository,
ProfileManager profileManager )
throws ProjectBuildingException, ArtifactResolutionException, ArtifactNotFoundException
{
return buildWithDependencies( projectDescriptor, localRepository, profileManager, null );
}
// note:jvz This was added for the embedder.
/** @todo move to metadatasource itself? */
public MavenProject buildWithDependencies( File projectDescriptor,
ArtifactRepository localRepository,
ProfileManager profileManager,
TransferListener transferListener )
throws ProjectBuildingException, ArtifactResolutionException, ArtifactNotFoundException
{
MavenProject project = build( projectDescriptor, localRepository, profileManager, false );
// ----------------------------------------------------------------------
// Typically when the project builder is being used from maven proper
// the transitive dependencies will not be resolved here because this
// requires a lot of work when we may only be interested in running
// something simple like 'm2 clean'. So the artifact collector is used
// in the dependency resolution phase if it is required by any of the
// goals being executed. But when used as a component in another piece
// of code people may just want to build maven projects and have the
// dependencies resolved for whatever reason: this is why we keep
// this snippet of code here.
// ----------------------------------------------------------------------
// TODO: such a call in MavenMetadataSource too - packaging not really the intention of type
Artifact projectArtifact = project.getArtifact();
String projectId = safeVersionlessKey( project.getGroupId(), project.getArtifactId() );
// Map managedVersions = createManagedVersionMap( projectId, project.getDependencyManagement() );
Map managedVersions = project.getManagedVersionMap();
ensureMetadataSourceIsInitialized();
try
{
project.setDependencyArtifacts( project.createArtifacts( artifactFactory, null, null ) );
}
catch ( InvalidDependencyVersionException e )
{
throw new ProjectBuildingException( projectId,
"Unable to build project due to an invalid dependency version: " +
e.getMessage(), e );
}
if ( transferListener != null )
{
wagonManager.setDownloadMonitor( transferListener );
}
ArtifactResolutionResult result = artifactResolver.resolveTransitively( project.getDependencyArtifacts(),
projectArtifact, managedVersions,
localRepository,
project.getRemoteArtifactRepositories(),
artifactMetadataSource );
project.setArtifacts( result.getArtifacts() );
return project;
}
// ----------------------------------------------------------------------
//
// ----------------------------------------------------------------------
private void ensureMetadataSourceIsInitialized()
throws ProjectBuildingException
{
if ( artifactMetadataSource == null )
{
try
{
artifactMetadataSource = (ArtifactMetadataSource) container.lookup( ArtifactMetadataSource.ROLE );
}
catch ( ComponentLookupException e )
{
throw new ProjectBuildingException( "all", "Cannot lookup metadata source for building the project.",
e );
}
}
}
private Map createManagedVersionMap( String projectId,
DependencyManagement dependencyManagement,
MavenProject parent )
throws ProjectBuildingException
{
Map map = null;
List deps;
if ( ( dependencyManagement != null ) && ( ( deps = dependencyManagement.getDependencies() ) != null ) &&
( deps.size() > 0 ) )
{
map = new ManagedVersionMap( map );
if ( getLogger().isDebugEnabled() )
{
getLogger().debug( "Adding managed dependencies for " + projectId );
}
for ( Iterator i = dependencyManagement.getDependencies().iterator(); i.hasNext(); )
{
Dependency d = (Dependency) i.next();
try
{
VersionRange versionRange = VersionRange.createFromVersionSpec( d.getVersion() );
Artifact artifact = artifactFactory.createDependencyArtifact( d.getGroupId(), d.getArtifactId(),
versionRange, d.getType(),
d.getClassifier(), d.getScope(),
d.isOptional() );
if ( getLogger().isDebugEnabled() )
{
getLogger().debug( " " + artifact );
}
// If the dependencyManagement section listed exclusions,
// add them to the managed artifacts here so that transitive
// dependencies will be excluded if necessary.
if ( ( null != d.getExclusions() ) && !d.getExclusions().isEmpty() )
{
List exclusions = new ArrayList();
Iterator exclItr = d.getExclusions().iterator();
while ( exclItr.hasNext() )
{
Exclusion e = (Exclusion) exclItr.next();
exclusions.add( e.getGroupId() + ":" + e.getArtifactId() );
}
ExcludesArtifactFilter eaf = new ExcludesArtifactFilter( exclusions );
artifact.setDependencyFilter( eaf );
}
else
{
artifact.setDependencyFilter( null );
}
map.put( d.getManagementKey(), artifact );
}
catch ( InvalidVersionSpecificationException e )
{
throw new ProjectBuildingException( projectId, "Unable to parse version '" + d.getVersion() +
"' for dependency '" + d.getManagementKey() + "': " + e.getMessage(), e );
}
}
}
else if ( map == null )
{
map = Collections.EMPTY_MAP;
}
return map;
}
private MavenProject buildFromSourceFileInternal( File projectDescriptor,
ProjectBuilderConfiguration config,
boolean checkDistributionManagementStatus )
throws ProjectBuildingException
{
Model model = readModel( "unknown", projectDescriptor, true );
MavenProject project = buildInternal( projectDescriptor.getAbsolutePath(), model, config,
buildArtifactRepositories( getSuperModel() ), projectDescriptor,
true );
if ( checkDistributionManagementStatus )
{
if ( ( project.getDistributionManagement() != null ) &&
( project.getDistributionManagement().getStatus() != null ) )
{
String projectId = safeVersionlessKey( project.getGroupId(), project.getArtifactId() );
throw new ProjectBuildingException( projectId,
"Invalid project file: distribution status must not be specified for a project outside of the repository" );
}
}
return project;
}
private Model findModelFromRepository( Artifact artifact,
List remoteArtifactRepositories,
ProjectBuilderConfiguration config,
boolean allowStubModel )
throws ProjectBuildingException
{
String projectId = safeVersionlessKey( artifact.getGroupId(), artifact.getArtifactId() );
normalizeToArtifactRepositories( remoteArtifactRepositories, projectId );
Artifact projectArtifact;
// if the artifact is not a POM, we need to construct a POM artifact based on the artifact parameter given.
if ( "pom".equals( artifact.getType() ) )
{
projectArtifact = artifact;
}
else
{
getLogger().debug( "Attempting to build MavenProject instance for Artifact (" + artifact.getGroupId() + ":"
+ artifact.getArtifactId() + ":" + artifact.getVersion() + ") of type: "
+ artifact.getType() + "; constructing POM artifact instead." );
projectArtifact = artifactFactory.createProjectArtifact( artifact.getGroupId(), artifact.getArtifactId(),
artifact.getVersion(), artifact.getScope() );
}
Model model;
try
{
artifactResolver.resolve( projectArtifact, remoteArtifactRepositories, config.getLocalRepository() );
File file = projectArtifact.getFile();
model = readModel( projectId, file, false );
String downloadUrl = null;
ArtifactStatus status = ArtifactStatus.NONE;
DistributionManagement distributionManagement = model.getDistributionManagement();
if ( distributionManagement != null )
{
downloadUrl = distributionManagement.getDownloadUrl();
status = ArtifactStatus.valueOf( distributionManagement.getStatus() );
}
checkStatusAndUpdate( projectArtifact, status, file, remoteArtifactRepositories, config.getLocalRepository() );
// TODO: this is gross. Would like to give it the whole model, but maven-artifact shouldn't depend on that
// Can a maven-core implementation of the Artifact interface store it, and be used in the exceptions?
if ( downloadUrl != null )
{
projectArtifact.setDownloadUrl( downloadUrl );
}
else
{
projectArtifact.setDownloadUrl( model.getUrl() );
}
}
catch ( ArtifactResolutionException e )
{
throw new ProjectBuildingException( projectId, "Error getting POM for '" + projectId +
"' from the repository: " + e.getMessage(), e );
}
catch ( ArtifactNotFoundException e )
{
if ( allowStubModel )
{
getLogger().debug( "Artifact not found - using stub model: " + e.getMessage() );
model = createStubModel( projectArtifact );
}
else
{
throw new ProjectBuildingException( projectId, "POM '" + projectId + "' not found in repository: " +
e.getMessage(), e );
}
}
return model;
}
private List normalizeToArtifactRepositories( List remoteArtifactRepositories,
String projectId )
throws ProjectBuildingException
{
List normalized = new ArrayList( remoteArtifactRepositories.size() );
boolean normalizationNeeded = false;
for ( Iterator it = remoteArtifactRepositories.iterator(); it.hasNext(); )
{
Object item = it.next();
if ( item instanceof ArtifactRepository )
{
normalized.add( item );
}
else if ( item instanceof Repository )
{
Repository repo = (Repository) item;
try
{
item = ProjectUtils.buildArtifactRepository( repo, artifactRepositoryFactory, container );
normalized.add( item );
normalizationNeeded = true;
}
catch ( InvalidRepositoryException e )
{
throw new ProjectBuildingException( projectId, "Error building artifact repository for id: " + repo.getId(), e );
}
}
else
{
throw new ProjectBuildingException( projectId, "Error building artifact repository from non-repository information item: " + item );
}
}
if ( normalizationNeeded )
{
return normalized;
}
else
{
return remoteArtifactRepositories;
}
}
private void checkStatusAndUpdate( Artifact projectArtifact,
ArtifactStatus status,
File file,
List remoteArtifactRepositories,
ArtifactRepository localRepository )
throws ArtifactNotFoundException
{
// TODO: configurable actions dependant on status
if ( !projectArtifact.isSnapshot() && ( status.compareTo( ArtifactStatus.DEPLOYED ) < 0 ) )
{
// use default policy (enabled, daily update, warn on bad checksum)
ArtifactRepositoryPolicy policy = new ArtifactRepositoryPolicy();
// TODO: re-enable [MNG-798/865]
policy.setUpdatePolicy( ArtifactRepositoryPolicy.UPDATE_POLICY_NEVER );
if ( policy.checkOutOfDate( new Date( file.lastModified() ) ) )
{
getLogger().info(
projectArtifact.getArtifactId() + ": updating metadata due to status of '" + status + "'" );
try
{
projectArtifact.setResolved( false );
artifactResolver.resolveAlways( projectArtifact, remoteArtifactRepositories, localRepository );
}
catch ( ArtifactResolutionException e )
{
getLogger().warn( "Error updating POM - using existing version" );
getLogger().debug( "Cause", e );
}
catch ( ArtifactNotFoundException e )
{
getLogger().warn( "Error updating POM - not found. Removing local copy." );
getLogger().debug( "Cause", e );
file.delete();
throw e;
}
}
}
}
// jvz:note
// This is used when requested artifacts do not have an associated POM. This is for the case where we are
// using an m1 repo where the only thing required to be present are the JAR files.
private Model createStubModel( Artifact projectArtifact )
{
getLogger().debug( "Using defaults for missing POM " + projectArtifact );
Model model = new Model();
model.setModelVersion( "4.0.0" );
model.setArtifactId( projectArtifact.getArtifactId() );
model.setGroupId( projectArtifact.getGroupId() );
model.setVersion( projectArtifact.getVersion() );
// TODO: not correct in some instances
model.setPackaging( projectArtifact.getType() );
model.setDistributionManagement( new DistributionManagement() );
model.getDistributionManagement().setStatus( ArtifactStatus.GENERATED.toString() );
return model;
}
// jvz:note
// We've got a mixture of things going in the USD and from the repository, sometimes the descriptor
// is a real file and sometimes null which makes things confusing.
private MavenProject buildInternal( String pomLocation,
Model model,
ProjectBuilderConfiguration config,
List parentSearchRepositories,
File projectDescriptor,
boolean strict )
throws ProjectBuildingException
{
File projectDir = null;
if ( projectDescriptor != null )
{
projectDir = projectDescriptor.getAbsoluteFile().getParentFile();
}
Model superModel = getSuperModel();
ProfileManager externalProfileManager = config.getGlobalProfileManager();
ProfileManager superProjectProfileManager;
if ( externalProfileManager != null )
{
superProjectProfileManager = new DefaultProfileManager(
container,
externalProfileManager.getRequestProperties() );
}
else
{
superProjectProfileManager = new DefaultProfileManager( container );
}
List activeProfiles;
superProjectProfileManager.addProfiles( superModel.getProfiles() );
activeProfiles = injectActiveProfiles( superProjectProfileManager, superModel );
MavenProject superProject = new MavenProject( superModel );
superProject.setActiveProfiles( activeProfiles );
//noinspection CollectionDeclaredAsConcreteClass
LinkedList lineage = new LinkedList();
// TODO: the aRWR can get out of sync with project.model.repositories. We should do all the processing of
// profiles, etc on the models then recreate the aggregated sets at the end from the project repositories (they
// must still be created along the way so that parent poms can be discovered, however)
// Use a TreeSet to ensure ordering is retained
Set aggregatedRemoteWagonRepositories = new LinkedHashSet();
String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
List activeExternalProfiles;
try
{
if ( externalProfileManager != null )
{
activeExternalProfiles = externalProfileManager.getActiveProfiles();
}
else
{
activeExternalProfiles = Collections.EMPTY_LIST;
}
}
catch ( ProfileActivationException e )
{
throw new ProjectBuildingException( projectId, "Failed to calculate active external profiles.", e );
}
for ( Iterator i = activeExternalProfiles.iterator(); i.hasNext(); )
{
Profile externalProfile = (Profile) i.next();
for ( Iterator repoIterator = externalProfile.getRepositories().iterator(); repoIterator.hasNext(); )
{
Repository mavenRepo = (Repository) repoIterator.next();
ArtifactRepository artifactRepo = null;
try
{
artifactRepo =
ProjectUtils.buildArtifactRepository( mavenRepo, artifactRepositoryFactory, container );
}
catch ( InvalidRepositoryException e )
{
throw new ProjectBuildingException( projectId, e.getMessage(), e );
}
aggregatedRemoteWagonRepositories.add( artifactRepo );
}
}
MavenProject project = null;
try
{
project = assembleLineage( model, lineage, config, projectDescriptor, parentSearchRepositories,
aggregatedRemoteWagonRepositories, strict );
}
catch ( InvalidRepositoryException e )
{
throw new ProjectBuildingException( projectId, e.getMessage(), e );
}
// we don't have to force the collision exception for superModel here, it's already been done in getSuperModel()
MavenProject previousProject = superProject;
Model previous = superProject.getModel();
for ( Iterator i = lineage.iterator(); i.hasNext(); )
{
MavenProject currentProject = (MavenProject) i.next();
Model current = currentProject.getModel();
String pathAdjustment = null;
try
{
pathAdjustment = previousProject.getModulePathAdjustment( currentProject );
}
catch ( IOException e )
{
getLogger().debug( "Cannot determine whether " + currentProject.getId() + " is a module of " +
previousProject.getId() + ". Reason: " + e.getMessage(), e );
}
modelInheritanceAssembler.assembleModelInheritance( current, previous, pathAdjustment );
previous = current;
previousProject = currentProject;
}
// only add the super repository if it wasn't overridden by a profile or project
List repositories = new ArrayList( aggregatedRemoteWagonRepositories );
repositories.addAll( parentSearchRepositories );
List superRepositories = buildArtifactRepositories( superModel );
for ( Iterator i = superRepositories.iterator(); i.hasNext(); )
{
ArtifactRepository repository = (ArtifactRepository) i.next();
if ( !repositories.contains( repository ) )
{
repositories.add( repository );
}
}
// merge any duplicated plugin definitions together, using the first appearance as the dominant one.
ModelUtils.mergeDuplicatePluginDefinitions( project.getModel().getBuild() );
try
{
project = processProjectLogic( pomLocation, project, config, projectDir, repositories, strict, false );
}
catch ( ModelInterpolationException e )
{
throw new InvalidProjectModelException( projectId, pomLocation, e.getMessage(), e );
}
catch ( InvalidRepositoryException e )
{
throw new InvalidProjectModelException( projectId, pomLocation, e.getMessage(), e );
}
processedProjectCache.put(
createCacheKey( project.getGroupId(), project.getArtifactId(), project.getVersion() ), project );
// jvz:note
// this only happens if we are building from a source file
if ( projectDescriptor != null )
{
Build build = project.getBuild();
project.addCompileSourceRoot( build.getSourceDirectory() );
project.addScriptSourceRoot( build.getScriptSourceDirectory() );
project.addTestCompileSourceRoot( build.getTestSourceDirectory() );
// Only track the file of a POM in the source tree
project.setFile( projectDescriptor );
}
project.setManagedVersionMap( createManagedVersionMap( projectId,
project.getDependencyManagement(),
project.getParent() ) );
return project;
}
private String safeVersionlessKey( String groupId,
String artifactId )
{
String gid = groupId;
if ( StringUtils.isEmpty( gid ) )
{
gid = "unknown";
}
String aid = artifactId;
if ( StringUtils.isEmpty( aid ) )
{
aid = "unknown";
}
return ArtifactUtils.versionlessKey( gid, aid );
}
private List buildArtifactRepositories( Model model )
throws ProjectBuildingException
{
try
{
return ProjectUtils.buildArtifactRepositories( model.getRepositories(), artifactRepositoryFactory,
container );
}
catch ( InvalidRepositoryException e )
{
String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
throw new ProjectBuildingException( projectId, e.getMessage(), e );
}
}
/**
* @todo can this take in a model instead of a project and still be successful?
* @todo In fact, does project REALLY need a MavenProject as a parent? Couldn't it have just a wrapper around a
* model that supported parents which were also the wrapper so that inheritence was assembled. We don't really need
* the resolved source roots, etc for the parent - that occurs for the parent when it is constructed independently
* and projects are not cached or reused
*/
private MavenProject processProjectLogic( String pomLocation,
MavenProject project,
ProjectBuilderConfiguration config,
File projectDir,
List remoteRepositories,
boolean strict,
boolean isSuperPom )
throws ProjectBuildingException, ModelInterpolationException, InvalidRepositoryException
{
Model model = project.getModel();
List activeProfiles = project.getActiveProfiles();
if ( activeProfiles == null )
{
activeProfiles = new ArrayList();
}
ProfileManager profileMgr = config == null ? null : config.getGlobalProfileManager();
List injectedProfiles = injectActiveProfiles( profileMgr, model );
activeProfiles.addAll( injectedProfiles );
// --------------------------------------------------------------------------------
Build dynamicBuild = model.getBuild();
model.setBuild( ModelUtils.cloneBuild( dynamicBuild ) );
model = modelInterpolator.interpolate( model, projectDir, config, getLogger().isDebugEnabled() );
mergeDeterministicBuildElements( model.getBuild(), dynamicBuild );
model.setBuild( dynamicBuild );
// MNG-3482: Make sure depMgmt is interpolated before merging.
if ( !isSuperPom )
{
mergeManagedDependencies( model, config, remoteRepositories );
}
// interpolation is before injection, because interpolation is off-limits in the injected variables
modelDefaultsInjector.injectDefaults( model );
MavenProject parentProject = project.getParent();
Model originalModel = project.getOriginalModel();
// We will return a different project object using the new model (hence the need to return a project, not just modify the parameter)
project = new MavenProject( model, getLogger() );
project.setOriginalModel( originalModel );
project.setActiveProfiles( activeProfiles );
// TODO: maybe not strictly correct, while we should enfore that packaging has a type handler of the same id, we don't
Artifact projectArtifact = artifactFactory.create( project );
project.setArtifact( projectArtifact );
project.setProjectBuilderConfiguration( config );
project.setPluginArtifactRepositories( ProjectUtils.buildArtifactRepositories( model.getPluginRepositories(),
artifactRepositoryFactory,
container ) );
DistributionManagement dm = model.getDistributionManagement();
if ( dm != null )
{
ArtifactRepository repo = ProjectUtils.buildDeploymentArtifactRepository( dm.getRepository(),
artifactRepositoryFactory,
container );
project.setReleaseArtifactRepository( repo );
if ( dm.getSnapshotRepository() != null )
{
repo = ProjectUtils.buildDeploymentArtifactRepository( dm.getSnapshotRepository(),
artifactRepositoryFactory, container );
project.setSnapshotArtifactRepository( repo );
}
}
if ( parentProject != null )
{
String cacheKey = createCacheKey( parentProject.getGroupId(),
parentProject.getArtifactId(),
parentProject.getVersion() );
MavenProject processedParent = (MavenProject) processedProjectCache.get( cacheKey );
Artifact parentArtifact;
// yeah, this null check might be a bit paranoid, but better safe than sorry...
if ( processedParent != null )
{
project.setParent( processedParent );
parentArtifact = processedParent.getArtifact();
}
else
{
project.setParent( parentProject );
parentArtifact = artifactFactory.createParentArtifact( parentProject.getGroupId(),
parentProject.getArtifactId(),
parentProject.getVersion() );
}
project.setParentArtifact( parentArtifact );
}
// Must validate before artifact construction to make sure dependencies are good
ModelValidationResult validationResult = validator.validate( model );
String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
if ( validationResult.getMessageCount() > 0 )
{
throw new InvalidProjectModelException( projectId, pomLocation, "Failed to validate POM",
validationResult );
}
project.setRemoteArtifactRepositories(
ProjectUtils.buildArtifactRepositories( model.getRepositories(), artifactRepositoryFactory, container ) );
// TODO: these aren't taking active project artifacts into consideration in the reactor
project.setPluginArtifacts( createPluginArtifacts( projectId, project.getBuildPlugins() ) );
project.setReportArtifacts( createReportArtifacts( projectId, project.getReportPlugins() ) );
project.setExtensionArtifacts( createExtensionArtifacts( projectId, project.getBuildExtensions() ) );
return project;
}
private void mergeDeterministicBuildElements( Build interpolatedBuild,
Build dynamicBuild )
{
mergeDeterministicPluginElements( interpolatedBuild.getPlugins(), dynamicBuild.getPlugins() );
PluginManagement dPluginMgmt = dynamicBuild.getPluginManagement();
PluginManagement iPluginMgmt = interpolatedBuild.getPluginManagement();
if ( dPluginMgmt != null )
{
mergeDeterministicPluginElements( iPluginMgmt.getPlugins(), dPluginMgmt.getPlugins() );
}
if ( dynamicBuild.getExtensions() != null )
{
dynamicBuild.setExtensions( interpolatedBuild.getExtensions() );
}
}
private void mergeDeterministicPluginElements( List iPlugins, List dPlugins )
{
if ( dPlugins != null )
{
for ( int i = 0; i < dPlugins.size(); i++ )
{
Plugin dPlugin = (Plugin) dPlugins.get( i );
Plugin iPlugin = (Plugin) iPlugins.get( i );
dPlugin.setGroupId( iPlugin.getGroupId() );
dPlugin.setArtifactId( iPlugin.getArtifactId() );
dPlugin.setVersion( iPlugin.getVersion() );
dPlugin.setDependencies( iPlugin.getDependencies() );
List dExecutions = dPlugin.getExecutions();
if ( dExecutions != null )
{
List iExecutions = iPlugin.getExecutions();
for ( int j = 0; j < dExecutions.size(); j++ )
{
PluginExecution dExec = (PluginExecution) dExecutions.get( j );
PluginExecution iExec = (PluginExecution) iExecutions.get( j );
dExec.setId( iExec.getId() );
}
}
}
}
}
/**
* @noinspection CollectionDeclaredAsConcreteClass
* @todo We need to find an effective way to unit test parts of this method!
* @todo Refactor this into smaller methods with discrete purposes.
*/
private MavenProject assembleLineage( Model model,
LinkedList lineage,
ProjectBuilderConfiguration config,
File projectDescriptor,
List parentSearchRepositories,
Set aggregatedRemoteWagonRepositories,
boolean strict )
throws ProjectBuildingException, InvalidRepositoryException
{
Model originalModel = ModelUtils.cloneModel( model );
File projectDir = null;
if ( projectDescriptor != null )
{
projectDir = projectDescriptor.getAbsoluteFile().getParentFile();
}
ProfileManager externalProfileManager = config.getGlobalProfileManager();
ProfileManager profileManager;
if ( externalProfileManager != null )
{
profileManager = new DefaultProfileManager( container, externalProfileManager.getRequestProperties() );
}
else
{
//TODO mkleint - use the (Container, Properties constructor to make system properties embeddable
profileManager = new DefaultProfileManager( container );
}
if ( externalProfileManager != null )
{
profileManager.explicitlyActivate( externalProfileManager.getExplicitlyActivatedIds() );
profileManager.explicitlyDeactivate( externalProfileManager.getExplicitlyDeactivatedIds() );
}
List activeProfiles;
try
{
profileManager.addProfiles( model.getProfiles() );
loadProjectExternalProfiles( profileManager, projectDir );
activeProfiles = injectActiveProfiles( profileManager, model );
}
catch ( ProfileActivationException e )
{
String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
throw new ProjectBuildingException( projectId, "Failed to activate local (project-level) build profiles: " +
e.getMessage(), e );
}
if ( !model.getRepositories().isEmpty() )
{
List respositories = buildArtifactRepositories( model );
for ( Iterator it = respositories.iterator(); it.hasNext(); )
{
ArtifactRepository repository = (ArtifactRepository) it.next();
if ( !aggregatedRemoteWagonRepositories.contains( repository ) )
{
aggregatedRemoteWagonRepositories.add( repository );
}
}
}
MavenProject project = new MavenProject( model, getLogger() );
project.setFile( projectDescriptor );
project.setActiveProfiles( activeProfiles );
project.setOriginalModel( originalModel );
lineage.addFirst( project );
Parent parentModel = model.getParent();
String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
if ( parentModel != null )
{
if ( StringUtils.isEmpty( parentModel.getGroupId() ) )
{
throw new ProjectBuildingException( projectId, "Missing groupId element from parent element" );
}
else if ( StringUtils.isEmpty( parentModel.getArtifactId() ) )
{
throw new ProjectBuildingException( projectId, "Missing artifactId element from parent element" );
}
else if ( parentModel.getGroupId().equals( model.getGroupId() ) &&
parentModel.getArtifactId().equals( model.getArtifactId() ) )
{
throw new ProjectBuildingException( projectId,
"Parent element is a duplicate of " + "the current project " );
}
else if ( StringUtils.isEmpty( parentModel.getVersion() ) )
{
throw new ProjectBuildingException( projectId, "Missing version element from parent element" );
}
// the only way this will have a value is if we find the parent on disk...
File parentDescriptor = null;
model = null;
String parentKey =
createCacheKey( parentModel.getGroupId(), parentModel.getArtifactId(), parentModel.getVersion() );
MavenProject parentProject = (MavenProject) rawProjectCache.get( parentKey );
if ( parentProject != null )
{
model = ModelUtils.cloneModel( parentProject.getOriginalModel() );
parentDescriptor = parentProject.getFile();
}
String parentRelativePath = parentModel.getRelativePath();
// if we can't find a cached model matching the parent spec, then let's try to look on disk using
// <relativePath/>
if ( ( model == null ) && ( projectDir != null ) && StringUtils.isNotEmpty( parentRelativePath ) )
{
parentDescriptor = new File( projectDir, parentRelativePath );
if ( getLogger().isDebugEnabled() )
{
getLogger().debug( "Searching for parent-POM: " + parentModel.getId() + " of project: " +
project.getId() + " in relative path: " + parentRelativePath );
}
if ( parentDescriptor.isDirectory() )
{
if ( getLogger().isDebugEnabled() )
{
getLogger().debug( "Path specified in <relativePath/> (" + parentRelativePath +
") is a directory. Searching for 'pom.xml' within this directory." );
}
parentDescriptor = new File( parentDescriptor, "pom.xml" );
if ( !parentDescriptor.exists() )
{
if ( getLogger().isDebugEnabled() )
{
getLogger().debug( "Parent-POM: " + parentModel.getId() + " for project: " +
project.getId() + " cannot be loaded from relative path: " + parentDescriptor +
"; path does not exist." );
}
}
}
if ( parentDescriptor != null )
{
try
{
parentDescriptor = parentDescriptor.getCanonicalFile();
}
catch ( IOException e )
{
getLogger().debug( "Failed to canonicalize potential parent POM: \'" + parentDescriptor + "\'",
e );
parentDescriptor = null;
}
}
if ( ( parentDescriptor != null ) && parentDescriptor.exists() )
{
Model candidateParent = readModel( projectId, parentDescriptor, strict );
String candidateParentGroupId = candidateParent.getGroupId();
if ( ( candidateParentGroupId == null ) && ( candidateParent.getParent() != null ) )
{
candidateParentGroupId = candidateParent.getParent().getGroupId();
}
String candidateParentVersion = candidateParent.getVersion();
if ( ( candidateParentVersion == null ) && ( candidateParent.getParent() != null ) )
{
candidateParentVersion = candidateParent.getParent().getVersion();
}
if ( parentModel.getGroupId().equals( candidateParentGroupId ) &&
parentModel.getArtifactId().equals( candidateParent.getArtifactId() ) &&
parentModel.getVersion().equals( candidateParentVersion ) )
{
model = candidateParent;
getLogger().debug( "Using parent-POM from the project hierarchy at: \'" +
parentModel.getRelativePath() + "\' for project: " + project.getId() );
}
else
{
getLogger().debug( "Invalid parent-POM referenced by relative path '" +
parentModel.getRelativePath() + "' in parent specification in " + project.getId() + ":" +
"\n Specified: " + parentModel.getId() + "\n Found: " + candidateParent.getId() );
}
}
else if ( getLogger().isDebugEnabled() )
{
getLogger().debug(
"Parent-POM: " + parentModel.getId() + " not found in relative path: " + parentRelativePath );
}
}
Artifact parentArtifact = null;
// only resolve the parent model from the repository system if we didn't find it on disk...
if ( model == null )
{
// MNG-2302: parent's File was being populated incorrectly when parent is loaded from repo.
// keep this in line with other POMs loaded from the repository...the file should be null.
parentDescriptor = null;
//!! (**)
// ----------------------------------------------------------------------
// Do we have the necessary information to actually find the parent
// POMs here?? I don't think so ... Say only one remote repository is
// specified and that is ibiblio then this model that we just read doesn't
// have any repository information ... I think we might have to inherit
// as we go in order to do this.
// ----------------------------------------------------------------------
// we must add the repository this POM was found in too, by chance it may be located where the parent is
// we can't query the parent to ask where it is :)
List remoteRepositories = new ArrayList( aggregatedRemoteWagonRepositories );
remoteRepositories.addAll( parentSearchRepositories );
if ( getLogger().isDebugEnabled() )
{
getLogger().debug( "Retrieving parent-POM: " + parentModel.getId() + " for project: " +
project.getId() + " from the repository." );
}
parentArtifact = artifactFactory.createParentArtifact( parentModel.getGroupId(),
parentModel.getArtifactId(),
parentModel.getVersion() );
try
{
model = findModelFromRepository( parentArtifact, remoteRepositories, config, false );
}
catch ( ProjectBuildingException e )
{
throw new ProjectBuildingException( project.getId(), "Cannot find parent: " + e.getProjectId() +
" for project: " + project.getId(), e );
}
}
if ( ( model != null ) && !"pom".equals( model.getPackaging() ) )
{
throw new ProjectBuildingException( projectId, "Parent: " + model.getId() + " of project: " +
projectId + " has wrong packaging: " + model.getPackaging() + ". Must be 'pom'." );
}
MavenProject parent = assembleLineage( model,
lineage,
config,
parentDescriptor,
parentSearchRepositories,
aggregatedRemoteWagonRepositories,
strict );
project.setParent( parent );
project.setParentArtifact( parentArtifact );
}
rawProjectCache.put( createCacheKey( project.getGroupId(), project.getArtifactId(), project.getVersion() ), new MavenProject( project ) );
return project;
}
private void mergeManagedDependencies(Model model, ProjectBuilderConfiguration config, List parentSearchRepositories)
throws ProjectBuildingException
{
DependencyManagement modelDepMgmt = model.getDependencyManagement();
if (modelDepMgmt != null)
{
Map depsMap = new TreeMap();
Iterator iter = modelDepMgmt.getDependencies().iterator();
boolean doInclude = false;
while (iter.hasNext())
{
Dependency dep = (Dependency) iter.next();
depsMap.put( dep.getManagementKey(), dep );
if ( dep.getType().equals( "pom" ) && Artifact.SCOPE_IMPORT.equals( dep.getScope() ) )
{
doInclude = true;
}
}
Map newDeps = new TreeMap(depsMap);
iter = modelDepMgmt.getDependencies().iterator();
if (doInclude)
{
while (iter.hasNext())
{
Dependency dep = (Dependency)iter.next();
if ( dep.getType().equals( "pom" )
&& Artifact.SCOPE_IMPORT.equals( dep.getScope() ) )
{
Artifact artifact = artifactFactory.createProjectArtifact( dep.getGroupId(), dep.getArtifactId(),
dep.getVersion(), dep.getScope() );
MavenProject project = buildFromRepository(artifact, parentSearchRepositories, config, false);
DependencyManagement depMgmt = project.getDependencyManagement();
if (depMgmt != null)
{
if ( getLogger().isDebugEnabled() )
{
getLogger().debug( "Importing managed dependencies for " + dep.toString() );
}
for ( Iterator it = depMgmt.getDependencies().iterator(); it.hasNext(); )
{
Dependency includedDep = (Dependency) it.next();
String key = includedDep.getManagementKey();
if (!newDeps.containsKey(key))
{
newDeps.put( includedDep.getManagementKey(), includedDep );
}
}
newDeps.remove(dep.getManagementKey());
}
}
}
List deps = new ArrayList(newDeps.values());
modelDepMgmt.setDependencies(deps);
}
}
}
private List injectActiveProfiles( ProfileManager profileManager,
Model model )
throws ProjectBuildingException
{
List activeProfiles;
if ( profileManager != null )
{
try
{
activeProfiles = profileManager.getActiveProfiles();
}
catch ( ProfileActivationException e )
{
String projectId = safeVersionlessKey( model.getGroupId(), model.getArtifactId() );
throw new ProjectBuildingException( projectId, e.getMessage(), e );
}
for ( Iterator it = activeProfiles.iterator(); it.hasNext(); )
{
Profile profile = (Profile) it.next();
profileInjector.inject( profile, model );
}
}
else
{
activeProfiles = Collections.EMPTY_LIST;
}
return activeProfiles;
}
private void loadProjectExternalProfiles( ProfileManager profileManager,
File projectDir )
throws ProfileActivationException
{
if ( projectDir != null )
{
try
{
ProfilesRoot root = profilesBuilder.buildProfiles( projectDir );
if ( root != null )
{
List active = root.getActiveProfiles();
if ( ( active != null ) && !active.isEmpty() )
{
profileManager.explicitlyActivate( root.getActiveProfiles() );
}
for ( Iterator it = root.getProfiles().iterator(); it.hasNext(); )
{
org.apache.maven.profiles.Profile rawProfile = (org.apache.maven.profiles.Profile) it.next();
Profile converted = ProfilesConversionUtils.convertFromProfileXmlProfile( rawProfile );
profileManager.addProfile( converted );
}
}
}
catch ( IOException e )
{
throw new ProfileActivationException( "Cannot read profiles.xml resource from directory: " + projectDir,
e );
}
catch ( XmlPullParserException e )
{
throw new ProfileActivationException(
"Cannot parse profiles.xml resource from directory: " + projectDir, e );
}
}
}
private Model readModel( String projectId,
File file,
boolean strict )
throws ProjectBuildingException
{
Reader reader = null;
try
{
reader = ReaderFactory.newXmlReader( file );
return readModel( projectId, file.getAbsolutePath(), reader, strict );
}
catch ( FileNotFoundException e )
{
throw new ProjectBuildingException( projectId,
"Could not find the model file '" + file.getAbsolutePath() + "'.", e );
}
catch ( IOException e )
{
throw new ProjectBuildingException( projectId, "Failed to build model from file '" +
file.getAbsolutePath() + "'.\nError: \'" + e.getLocalizedMessage() + "\'", e );
}
finally
{
IOUtil.close( reader );
}
}
private Model readModel( String projectId,
String pomLocation,
Reader reader,
boolean strict )
throws IOException, InvalidProjectModelException
{
String modelSource = IOUtil.toString( reader );
if ( modelSource.indexOf( "<modelVersion>" + MAVEN_MODEL_VERSION ) < 0 )
{
throw new InvalidProjectModelException( projectId, pomLocation, "Not a v" + MAVEN_MODEL_VERSION + " POM." );
}
StringReader sReader = new StringReader( modelSource );
try
{
return modelReader.read( sReader, strict );
}
catch ( XmlPullParserException e )
{
throw new InvalidProjectModelException( projectId, pomLocation,
"Parse error reading POM. Reason: " + e.getMessage(), e );
}
}
private Model readModel( String projectId,
URL url,
boolean strict )
throws ProjectBuildingException
{
Reader reader = null;
try
{
reader = ReaderFactory.newXmlReader( url.openStream() );
return readModel( projectId, url.toExternalForm(), reader, strict );
}
catch ( IOException e )
{
throw new ProjectBuildingException( projectId, "Failed build model from URL \'" + url.toExternalForm() +
"\'\nError: \'" + e.getLocalizedMessage() + "\'", e );
}
finally
{
IOUtil.close( reader );
}
}
private static String createCacheKey( String groupId,
String artifactId,
String version )
{
return groupId + ":" + artifactId + ":" + version;
}
protected Set createPluginArtifacts( String projectId,
List plugins )
throws ProjectBuildingException
{
Set pluginArtifacts = new LinkedHashSet();
for ( Iterator i = plugins.iterator(); i.hasNext(); )
{
Plugin p = (Plugin) i.next();
String version;
if ( StringUtils.isEmpty( p.getVersion() ) )
{
version = "RELEASE";
}
else
{
version = p.getVersion();
}
Artifact artifact;
try
{
artifact = artifactFactory.createPluginArtifact( p.getGroupId(), p.getArtifactId(),
VersionRange.createFromVersionSpec( version ) );
}
catch ( InvalidVersionSpecificationException e )
{
throw new ProjectBuildingException( projectId, "Unable to parse version '" + version +
"' for plugin '" + ArtifactUtils.versionlessKey( p.getGroupId(), p.getArtifactId() ) + "': " +
e.getMessage(), e );
}
if ( artifact != null )
{
pluginArtifacts.add( artifact );
}
}
return pluginArtifacts;
}
// TODO: share with createPluginArtifacts?
protected Set createReportArtifacts( String projectId,
List reports )
throws ProjectBuildingException
{
Set pluginArtifacts = new LinkedHashSet();
if ( reports != null )
{
for ( Iterator i = reports.iterator(); i.hasNext(); )
{
ReportPlugin p = (ReportPlugin) i.next();
String version;
if ( StringUtils.isEmpty( p.getVersion() ) )
{
version = "RELEASE";
}
else
{
version = p.getVersion();
}
Artifact artifact;
try
{
artifact = artifactFactory.createPluginArtifact( p.getGroupId(), p.getArtifactId(),
VersionRange.createFromVersionSpec( version ) );
}
catch ( InvalidVersionSpecificationException e )
{
throw new ProjectBuildingException( projectId, "Unable to parse version '" + version +
"' for report '" + ArtifactUtils.versionlessKey( p.getGroupId(), p.getArtifactId() ) + "': " +
e.getMessage(), e );
}
if ( artifact != null )
{
pluginArtifacts.add( artifact );
}
}
}
return pluginArtifacts;
}
// TODO: share with createPluginArtifacts?
protected Set createExtensionArtifacts( String projectId,
List extensions )
throws ProjectBuildingException
{
Set extensionArtifacts = new LinkedHashSet();
if ( extensions != null )
{
for ( Iterator i = extensions.iterator(); i.hasNext(); )
{
Extension ext = (Extension) i.next();
String version;
if ( StringUtils.isEmpty( ext.getVersion() ) )
{
version = "RELEASE";
}
else
{
version = ext.getVersion();
}
Artifact artifact;
try
{
VersionRange versionRange = VersionRange.createFromVersionSpec( version );
artifact =
artifactFactory.createExtensionArtifact( ext.getGroupId(), ext.getArtifactId(), versionRange );
}
catch ( InvalidVersionSpecificationException e )
{
throw new ProjectBuildingException( projectId, "Unable to parse version '" + version +
"' for extension '" + ArtifactUtils.versionlessKey( ext.getGroupId(), ext.getArtifactId() ) +
"': " + e.getMessage(), e );
}
if ( artifact != null )
{
extensionArtifacts.add( artifact );
}
}
}
return extensionArtifacts;
}
// ----------------------------------------------------------------------
//
// ----------------------------------------------------------------------
private Model getSuperModel()
throws ProjectBuildingException
{
URL url = DefaultMavenProjectBuilder.class.getResource( "pom-" + MAVEN_MODEL_VERSION + ".xml" );
String projectId = safeVersionlessKey( STANDALONE_SUPERPOM_GROUPID, STANDALONE_SUPERPOM_ARTIFACTID );
return readModel( projectId, url, true );
}
public void contextualize( Context context )
throws ContextException
{
container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
}
/**
* {@inheritDoc}
*/
public void calculateConcreteState( MavenProject project, ProjectBuilderConfiguration config )
throws ModelInterpolationException
{
calculateConcreteStateInternal( project, config, true, new HashSet() );
}
/**
* {@inheritDoc}
*/
public void calculateConcreteState( MavenProject project, ProjectBuilderConfiguration config, boolean processProjectReferences )
throws ModelInterpolationException
{
calculateConcreteStateInternal( project, config, processProjectReferences, ( processProjectReferences ? new HashSet() : null ) );
}
/*
* NOTE: This is a code hotspot, PLEASE be careful about the performance of logic inside or
* called from this method.
*
* NOTE: If processProjectReferences == false, processedProjects MUST NOT BE USED. It will be null.
*/
private void calculateConcreteStateInternal( MavenProject project, ProjectBuilderConfiguration config, boolean processProjectReferences, Set processedProjects )
throws ModelInterpolationException
{
if ( processProjectReferences )
{
processedProjects.add( project.getId() );
}
restoreDynamicStateInternal( project, config, processProjectReferences, processProjectReferences ? new HashSet( processedProjects ) : null );
if ( !project.isConcrete() )
{
if ( project.getParent() != null )
{
calculateConcreteStateInternal( project.getParent(), config, processProjectReferences, processedProjects );
}
Build build = project.getBuild();
if ( build != null )
{
initResourceMergeIds( build.getResources() );
initResourceMergeIds( build.getTestResources() );
}
// NOTE: Since interpolation makes a copy through serialization, we don't need this.
// See note below.
//
// Model model = ModelUtils.cloneModel( project.getModel() );
File basedir = project.getBasedir();
// NOTE: If we ever get past serialization/deserialization for interpolation, we'll need to copy the model here!
Model model = ModelUtils.cloneModel( project.getModel() );
model = modelInterpolator.interpolate( model, project.getBasedir(), config, getLogger().isDebugEnabled() );
List originalInterpolatedCompileSourceRoots = interpolateListOfStrings( project.getCompileSourceRoots(),
model,
project.getBasedir(),
config,
getLogger().isDebugEnabled() );
project.preserveCompileSourceRoots( originalInterpolatedCompileSourceRoots );
project.setCompileSourceRoots( originalInterpolatedCompileSourceRoots == null ? null
: translateListOfPaths( originalInterpolatedCompileSourceRoots, basedir ) );
List originalInterpolatedTestCompileSourceRoots = interpolateListOfStrings( project.getTestCompileSourceRoots(),
model,
project.getBasedir(),
config,
getLogger().isDebugEnabled() );
project.preserveTestCompileSourceRoots( originalInterpolatedTestCompileSourceRoots );
project.setTestCompileSourceRoots( originalInterpolatedTestCompileSourceRoots == null ? null
: translateListOfPaths( originalInterpolatedTestCompileSourceRoots, basedir ) );
List originalInterpolatedScriptSourceRoots = interpolateListOfStrings( project.getScriptSourceRoots(),
model,
project.getBasedir(),
config,
getLogger().isDebugEnabled() );
project.preserveScriptSourceRoots( originalInterpolatedScriptSourceRoots );
// TODO: MNG-3731
project.setScriptSourceRoots( originalInterpolatedScriptSourceRoots );
// project.setScriptSourceRoots( originalInterpolatedScriptSourceRoots == null ? null
// : translateListOfPaths( originalInterpolatedScriptSourceRoots, basedir ) );
if ( basedir != null )
{
pathTranslator.alignToBaseDirectory( model, basedir );
}
project.preserveBuild( ModelUtils.cloneBuild( model.getBuild() ) );
project.preserveProperties();
project.preserveBasedir();
project.setBuild( model.getBuild() );
if ( project.getExecutionProject() != null )
{
calculateConcreteStateInternal( project.getExecutionProject(), config, processProjectReferences, processedProjects );
}
project.setConcrete( true );
}
if ( processProjectReferences )
{
calculateConcreteProjectReferences( project, config, processedProjects );
}
}
private void initResourceMergeIds( List resources )
{
if ( resources != null )
{
for ( Iterator it = resources.iterator(); it.hasNext(); )
{
Resource resource = (Resource) it.next();
resource.initMergeId();
}
}
}
private void calculateConcreteProjectReferences( MavenProject project,
ProjectBuilderConfiguration config,
Set processedProjects )
throws ModelInterpolationException
{
Map projectRefs = project.getProjectReferences();
if ( projectRefs != null )
{
for ( Iterator it = projectRefs.values().iterator(); it.hasNext(); )
{
MavenProject reference = (MavenProject) it.next();
if ( !processedProjects.contains( reference.getId() ) )
{
calculateConcreteStateInternal( reference, config, true, processedProjects );
}
}
}
}
private List translateListOfPaths( List paths, File basedir )
{
if ( paths == null )
{
return null;
}
else if ( basedir == null )
{
return paths;
}
List result = new ArrayList( paths.size() );
for ( Iterator it = paths.iterator(); it.hasNext(); )
{
String path = (String) it.next();
String aligned = pathTranslator.alignToBaseDirectory( path, basedir );
result.add( aligned );
}
return result;
}
/**
* {@inheritDoc}
*/
public void restoreDynamicState( MavenProject project, ProjectBuilderConfiguration config )
throws ModelInterpolationException
{
restoreDynamicStateInternal( project, config, true, new HashSet() );
}
/**
* {@inheritDoc}
*/
public void restoreDynamicState( MavenProject project, ProjectBuilderConfiguration config, boolean processProjectReferences )
throws ModelInterpolationException
{
restoreDynamicStateInternal( project, config, processProjectReferences, ( processProjectReferences ? new HashSet() : null ) );
}
/*
* NOTE: This is a code hotspot, PLEASE be careful about the performance of logic inside or
* called from this method.
*
* NOTE: If processProjectReferences == false, processedProjects MUST NOT BE USED. It will be null.
*/
private void restoreDynamicStateInternal( MavenProject project, ProjectBuilderConfiguration config, boolean processProjectReferences, Set processedProjects )
throws ModelInterpolationException
{
if ( processProjectReferences )
{
processedProjects.add( project.getId() );
}
if ( project.isConcrete() && projectWasChanged( project ) )
{
if ( project.getParent() != null )
{
restoreDynamicStateInternal( project.getParent(), config, processProjectReferences, processedProjects );
}
restoreBuildRoots( project, config, getLogger().isDebugEnabled() );
restoreModelBuildSection( project, config, getLogger().isDebugEnabled() );
if ( project.getExecutionProject() != null )
{
restoreDynamicStateInternal( project.getExecutionProject(), config, processProjectReferences, processedProjects );
}
project.setConcrete( false );
}
if ( processProjectReferences )
{
restoreDynamicProjectReferences( project, config, processedProjects );
}
}
private boolean projectWasChanged( MavenProject project )
{
if ( !objectEquals( project.getBasedir(), project.getPreservedBasedir() ) )
{
return true;
}
if ( !objectEquals( project.getProperties(), project.getPreservedProperties() ) )
{
return true;
}
Build oBuild = project.getOriginalInterpolatedBuild();
Build build = project.getBuild();
if ( !objectEquals( oBuild.getDirectory(), build.getDirectory() ) )
{
return true;
}
if ( !objectEquals( oBuild.getOutputDirectory(), build.getOutputDirectory() ) )
{
return true;
}
if ( !objectEquals( oBuild.getSourceDirectory(), build.getSourceDirectory() ) )
{
return true;
}
if ( !objectEquals( oBuild.getTestSourceDirectory(), build.getTestSourceDirectory() ) )
{
return true;
}
if ( !objectEquals( oBuild.getScriptSourceDirectory(), build.getScriptSourceDirectory() ) )
{
return true;
}
return false;
}
private boolean objectEquals( Object obj1, Object obj2 )
{
return obj1 == null ? obj2 == null : obj2 != null && ( obj1 == obj2 || obj1.equals( obj2 ) );
}
private void propagateNewPlugins( MavenProject project )
{
Build changedBuild = project.getBuild();
Build dynamicBuild = project.getDynamicBuild();
if ( changedBuild == null || dynamicBuild == null )
{
return;
}
List changedPlugins = changedBuild.getPlugins();
List dynamicPlugins = dynamicBuild.getPlugins();
if ( changedPlugins != null && dynamicPlugins != null && changedPlugins.size() != dynamicPlugins.size() )
{
changedPlugins.removeAll( dynamicPlugins );
if ( !changedPlugins.isEmpty() )
{
for ( Iterator it = changedPlugins.iterator(); it.hasNext(); )
{
Plugin plugin = (Plugin) it.next();
dynamicBuild.addPlugin( plugin );
}
}
}
dynamicBuild.flushPluginMap();
}
private void restoreDynamicProjectReferences( MavenProject project,
ProjectBuilderConfiguration config,
Set processedProjects )
throws ModelInterpolationException
{
Map projectRefs = project.getProjectReferences();
if ( projectRefs != null )
{
for ( Iterator it = projectRefs.values().iterator(); it.hasNext(); )
{
MavenProject projectRef = (MavenProject) it.next();
if ( !processedProjects.contains( projectRef.getId() ) )
{
restoreDynamicStateInternal( projectRef, config, true, processedProjects );
}
}
}
}
private void restoreBuildRoots( MavenProject project,
ProjectBuilderConfiguration config,
boolean debugMessages )
throws ModelInterpolationException
{
project.setCompileSourceRoots( restoreListOfStrings( project.getDynamicCompileSourceRoots(),
project.getOriginalInterpolatedCompileSourceRoots(),
project.getCompileSourceRoots(),
project,
config,
debugMessages ) );
project.setTestCompileSourceRoots( restoreListOfStrings( project.getDynamicTestCompileSourceRoots(),
project.getOriginalInterpolatedTestCompileSourceRoots(),
project.getTestCompileSourceRoots(),
project,
config,
debugMessages ) );
project.setScriptSourceRoots( restoreListOfStrings( project.getDynamicScriptSourceRoots(),
project.getOriginalInterpolatedScriptSourceRoots(),
project.getScriptSourceRoots(),
project,
config,
debugMessages ) );
project.clearRestorableRoots();
}
private void restoreModelBuildSection( MavenProject project,
ProjectBuilderConfiguration config,
boolean debugMessages )
throws ModelInterpolationException
{
Build changedBuild = project.getBuild();
Build dynamicBuild = project.getDynamicBuild();
Build originalInterpolatedBuild = project.getOriginalInterpolatedBuild();
dynamicBuild.setResources( restoreResources( dynamicBuild.getResources(),
originalInterpolatedBuild.getResources(),
changedBuild.getResources(),
project,
config,
debugMessages ) );
dynamicBuild.setTestResources( restoreResources( dynamicBuild.getTestResources(),
originalInterpolatedBuild.getTestResources(),
changedBuild.getTestResources(),
project,
config,
debugMessages ) );
dynamicBuild.setFilters( restoreListOfStrings( dynamicBuild.getFilters(),
originalInterpolatedBuild.getFilters(),
changedBuild.getFilters(),
project,
config,
debugMessages ) );
dynamicBuild.setFinalName( restoreString( dynamicBuild.getFinalName(),
originalInterpolatedBuild.getFinalName(),
changedBuild.getFinalName(),
project,
config,
debugMessages ) );
dynamicBuild.setDefaultGoal( restoreString( dynamicBuild.getDefaultGoal(),
originalInterpolatedBuild.getDefaultGoal(),
changedBuild.getDefaultGoal(),
project,
config,
debugMessages ) );
dynamicBuild.setSourceDirectory( restoreString( dynamicBuild.getSourceDirectory(),
originalInterpolatedBuild.getSourceDirectory(),
changedBuild.getSourceDirectory(),
project,
config,
debugMessages ) );
dynamicBuild.setTestSourceDirectory( restoreString( dynamicBuild.getTestSourceDirectory(),
originalInterpolatedBuild.getTestSourceDirectory(),
changedBuild.getTestSourceDirectory(),
project,
config,
debugMessages ) );
dynamicBuild.setScriptSourceDirectory( restoreString( dynamicBuild.getScriptSourceDirectory(),
originalInterpolatedBuild.getScriptSourceDirectory(),
changedBuild.getScriptSourceDirectory(),
project,
config,
debugMessages ) );
dynamicBuild.setOutputDirectory( restoreString( dynamicBuild.getOutputDirectory(),
originalInterpolatedBuild.getOutputDirectory(),
changedBuild.getOutputDirectory(),
project,
config,
debugMessages ) );
dynamicBuild.setTestOutputDirectory( restoreString( dynamicBuild.getTestOutputDirectory(),
originalInterpolatedBuild.getTestOutputDirectory(),
changedBuild.getTestOutputDirectory(),
project,
config,
debugMessages ) );
dynamicBuild.setDirectory( restoreString( dynamicBuild.getDirectory(),
originalInterpolatedBuild.getDirectory(),
changedBuild.getDirectory(),
project,
config,
debugMessages ) );
propagateNewPlugins( project );
project.setBuild( dynamicBuild );
project.clearRestorableBuild();
}
private List interpolateListOfStrings( List originalStrings,
Model model,
File projectDir,
ProjectBuilderConfiguration config,
boolean debugMessages )
throws ModelInterpolationException
{
if ( originalStrings == null )
{
return null;
}
List result = new ArrayList();
for ( Iterator it = originalStrings.iterator(); it.hasNext(); )
{
String original = (String) it.next();
String interpolated = modelInterpolator.interpolate( original, model, projectDir, config, debugMessages );
result.add( interpolated );
}
return result;
}
private String restoreString( String originalString,
String originalInterpolatedString,
String changedString,
MavenProject project,
ProjectBuilderConfiguration config,
boolean debugMessages )
throws ModelInterpolationException
{
if ( originalString == null )
{
return changedString;
}
else if ( changedString == null )
{
return originalString;
}
Model model = project.getModel();
String relativeChangedString;
if ( project.getBasedir() != null )
{
relativeChangedString = pathTranslator.unalignFromBaseDirectory( changedString, project.getBasedir() );
}
else
{
relativeChangedString = changedString;
}
String interpolatedOriginal = modelInterpolator.interpolate( originalString,
model,
project.getBasedir(),
config,
debugMessages );
interpolatedOriginal = pathTranslator.unalignFromBaseDirectory( interpolatedOriginal, project.getBasedir() );
String interpolatedOriginal2 = modelInterpolator.interpolate( originalInterpolatedString,
model,
project.getBasedir(),
config,
debugMessages );
interpolatedOriginal2 = pathTranslator.alignToBaseDirectory( interpolatedOriginal2, project.getBasedir() );
String interpolatedChanged = modelInterpolator.interpolate( changedString,
model,
project.getBasedir(),
config,
debugMessages );
interpolatedChanged = pathTranslator.alignToBaseDirectory( interpolatedChanged, project.getBasedir() );
String relativeInterpolatedChanged = modelInterpolator.interpolate( relativeChangedString,
model,
project.getBasedir(),
config,
debugMessages );
if ( interpolatedOriginal.equals( interpolatedChanged ) || interpolatedOriginal2.equals( interpolatedChanged ) )
{
return originalString;
}
else if ( interpolatedOriginal.equals( relativeInterpolatedChanged )
|| interpolatedOriginal2.equals( relativeInterpolatedChanged ) )
{
return originalString;
}
return relativeChangedString;
}
private List restoreListOfStrings( List originalStrings,
List originalInterpolatedStrings,
List changedStrings,
MavenProject project,
ProjectBuilderConfiguration config,
boolean debugMessages )
throws ModelInterpolationException
{
if ( originalStrings == null )
{
return changedStrings;
}
else if ( changedStrings == null )
{
return originalStrings;
}
List result = new ArrayList();
Map orig = new HashMap();
for ( int idx = 0; idx < originalStrings.size(); idx++ )
{
String[] permutations = new String[2];
permutations[0] = pathTranslator.alignToBaseDirectory( (String) originalInterpolatedStrings.get( idx ), project.getBasedir() );
permutations[1] = (String) originalStrings.get( idx );
orig.put( permutations[0], permutations );
}
for ( Iterator it = changedStrings.iterator(); it.hasNext(); )
{
String changedString = (String) it.next();
String relativeChangedString;
if ( project.getBasedir() != null )
{
relativeChangedString = pathTranslator.unalignFromBaseDirectory( changedString, project.getBasedir() );
}
else
{
relativeChangedString = changedString;
}
String interpolated = modelInterpolator.interpolate( changedString,
project.getModel(),
project.getBasedir(),
config,
debugMessages );
interpolated = pathTranslator.alignToBaseDirectory( interpolated, project.getBasedir() );
String relativeInterpolated = modelInterpolator.interpolate( relativeChangedString,
project.getModel(),
project.getBasedir(),
config,
debugMessages );
String[] original = (String[]) orig.get( interpolated );
if ( original == null )
{
original = (String[]) orig.get( relativeInterpolated );
}
if ( original == null )
{
result.add( relativeChangedString );
}
else
{
result.add( original[1] );
}
}
return result;
}
private List restoreResources( List originalResources,
List originalInterpolatedResources,
List changedResources,
MavenProject project,
ProjectBuilderConfiguration config,
boolean debugMessages )
throws ModelInterpolationException
{
if ( originalResources == null || changedResources == null )
{
return originalResources;
}
List result = new ArrayList();
Map originalResourcesByMergeId = new HashMap();
for ( int idx = 0; idx < originalResources.size(); idx++ )
{
Resource[] permutations = new Resource[2];
permutations[0] = (Resource) originalInterpolatedResources.get( idx );
permutations[1] = (Resource) originalResources.get( idx );
originalResourcesByMergeId.put( permutations[0].getMergeId(), permutations );
}
for ( Iterator it = changedResources.iterator(); it.hasNext(); )
{
Resource resource = (Resource) it.next();
String mergeId = resource.getMergeId();
if ( mergeId == null || !originalResourcesByMergeId.containsKey( mergeId ) )
{
result.add( resource );
}
else
{
Resource originalInterpolatedResource = ( (Resource[]) originalResourcesByMergeId.get( mergeId ) )[0];
Resource originalResource = ( (Resource[]) originalResourcesByMergeId.get( mergeId ) )[1];
String dir = modelInterpolator.interpolate( resource.getDirectory(), project.getModel(), project.getBasedir(), config, getLogger().isDebugEnabled() );
String oDir = originalInterpolatedResource.getDirectory();
if ( !dir.equals( oDir ) )
{
originalResource.setDirectory( pathTranslator.unalignFromBaseDirectory( dir, project.getBasedir() ) );
}
if ( resource.getTargetPath() != null )
{
String target = modelInterpolator.interpolate( resource.getTargetPath(), project.getModel(), project.getBasedir(), config, getLogger().isDebugEnabled() );
String oTarget = originalInterpolatedResource.getTargetPath();
if ( !target.equals( oTarget ) )
{
originalResource.setTargetPath( pathTranslator.unalignFromBaseDirectory( target, project.getBasedir() ) );
}
}
originalResource.setFiltering( resource.isFiltering() );
originalResource.setExcludes( collectRestoredListOfPatterns( resource.getExcludes(),
originalResource.getExcludes(),
originalInterpolatedResource.getExcludes() ) );
originalResource.setIncludes( collectRestoredListOfPatterns( resource.getIncludes(),
originalResource.getIncludes(),
originalInterpolatedResource.getIncludes() ) );
result.add( originalResource );
}
}
return result;
}
private List collectRestoredListOfPatterns( List patterns,
List originalPatterns,
List originalInterpolatedPatterns )
{
LinkedHashSet collectedPatterns = new LinkedHashSet();
collectedPatterns.addAll( originalPatterns );
for ( Iterator it = patterns.iterator(); it.hasNext(); )
{
String pattern = (String) it.next();
if ( !originalInterpolatedPatterns.contains( pattern ) )
{
collectedPatterns.add( pattern );
}
}
return collectedPatterns.isEmpty() ? Collections.EMPTY_LIST
: new ArrayList( collectedPatterns );
}
}