o Introduced project realm to host build extensions

git-svn-id: https://svn.apache.org/repos/asf/maven/components/trunk@793844 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Benjamin Bentmann 2009-07-14 10:44:44 +00:00
parent faa082995e
commit 2caa6b5112
7 changed files with 534 additions and 99 deletions

View File

@ -0,0 +1,109 @@
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 java.util.List;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.model.Model;
import org.apache.maven.model.building.AbstractModelBuildingListener;
import org.apache.maven.model.building.ModelBuildingEvent;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
/**
* Processes events from the model builder.
*
* @author Benjamin Bentmann
*/
class DefaultModelBuildingListener
extends AbstractModelBuildingListener
{
private ProjectBuildingHelper projectBuildingHelper;
private ProjectBuildingRequest projectBuildingRequest;
private ClassRealm projectRealm;
private List<ArtifactRepository> remoteRepositories;
private List<ArtifactRepository> pluginRepositories;
public DefaultModelBuildingListener( ProjectBuildingHelper projectBuildingHelper,
ProjectBuildingRequest projectBuildingRequest )
{
if ( projectBuildingHelper == null )
{
throw new IllegalArgumentException( "project realm manager missing" );
}
this.projectBuildingHelper = projectBuildingHelper;
if ( projectBuildingRequest == null )
{
throw new IllegalArgumentException( "project building request missing" );
}
this.projectBuildingRequest = projectBuildingRequest;
}
public ClassRealm getProjectRealm()
{
return projectRealm;
}
public List<ArtifactRepository> getRemoteRepositories()
{
return remoteRepositories;
}
public List<ArtifactRepository> getPluginRepositories()
{
return pluginRepositories;
}
@Override
public void buildExtensionsAssembled( ModelBuildingEvent event )
throws Exception
{
Model model = event.getModel();
remoteRepositories = projectBuildingRequest.getRemoteRepositories();
remoteRepositories =
projectBuildingHelper.createArtifactRepositories( model.getRepositories(), remoteRepositories );
pluginRepositories = projectBuildingRequest.getPluginArtifactRepositories();
pluginRepositories =
projectBuildingHelper.createArtifactRepositories( model.getPluginRepositories(), pluginRepositories );
if ( event.getRequest().isProcessPlugins() )
{
projectRealm =
projectBuildingHelper.createProjectRealm( model, projectBuildingRequest.getLocalRepository(),
pluginRepositories );
/*
* Update the context class loader so that the container will search the project realm when the model
* builder injects the lifecycle bindings from the packaging next. The class loader is reset by the project
* builder when the project is fully assembled.
*/
Thread.currentThread().setContextClassLoader( projectRealm );
}
}
}

View File

@ -17,6 +17,7 @@ package org.apache.maven.project;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.Artifact;
@ -60,6 +61,9 @@ public class DefaultProjectBuilder
@Requirement @Requirement
private ModelBuilder modelBuilder; private ModelBuilder modelBuilder;
@Requirement
private ProjectBuildingHelper projectBuildingHelper;
@Requirement @Requirement
private LifecycleExecutor lifecycle; private LifecycleExecutor lifecycle;
@ -86,81 +90,98 @@ public class DefaultProjectBuilder
{ {
ModelBuildingRequest request = getModelBuildingRequest( configuration ); ModelBuildingRequest request = getModelBuildingRequest( configuration );
ModelBuildingResult result; DefaultModelBuildingListener listener = new DefaultModelBuildingListener( projectBuildingHelper, configuration );
try request.setModelBuildingListeners( Arrays.asList( listener ) );
{
if ( localProject )
{
result = modelBuilder.build( pomFile, request );
}
else
{
result = modelBuilder.build( new FileModelSource( pomFile ), request );
}
}
catch ( ModelBuildingException e )
{
throw new ProjectBuildingException( "[unknown]", "Failed to build project for " + pomFile, pomFile, e );
}
if ( localProject && !result.getProblems().isEmpty() && logger.isWarnEnabled() ) ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
{
logger.warn( "" );
logger.warn( "One or more problems were encountered while building the effective model:" );
for ( ModelProblem problem : result.getProblems() )
{
logger.warn( problem.getMessage() );
}
logger.warn( "" );
logger.warn( "It is highly recommended to fix these problems"
+ " because they threaten the stability of your build." );
logger.warn( "" );
logger.warn( "For this reason, future Maven versions will no"
+ " longer support building such malformed projects." );
logger.warn( "" );
}
Model model = result.getEffectiveModel();
File parentPomFile = result.getRawModel( result.getModelIds().get( 1 ) ).getPomFile();
MavenProject project = fromModelToMavenProject( model, parentPomFile, configuration, model.getPomFile() );
project.setOriginalModel( result.getRawModel() );
try try
{ {
if ( configuration.isProcessPlugins() ) ModelBuildingResult result;
try
{ {
lifecycle.populateDefaultConfigurationForPlugins( model.getBuild().getPlugins(), configuration.getLocalRepository(), project.getPluginArtifactRepositories() ); if ( localProject )
{
result = modelBuilder.build( pomFile, request );
}
else
{
result = modelBuilder.build( new FileModelSource( pomFile ), request );
}
} }
catch ( ModelBuildingException e )
{
throw new ProjectBuildingException( "[unknown]", "Failed to build project for " + pomFile, pomFile, e );
}
if ( localProject && !result.getProblems().isEmpty() && logger.isWarnEnabled() )
{
logger.warn( "" );
logger.warn( "One or more problems were encountered while building the project's effective model:" );
for ( ModelProblem problem : result.getProblems() )
{
logger.warn( problem.getMessage() );
}
logger.warn( "" );
logger.warn( "It is highly recommended to fix these problems"
+ " because they threaten the stability of your build." );
logger.warn( "" );
logger.warn( "For this reason, future Maven versions will no"
+ " longer support building such malformed projects." );
logger.warn( "" );
}
Model model = result.getEffectiveModel();
File parentPomFile = result.getRawModel( result.getModelIds().get( 1 ) ).getPomFile();
MavenProject project = fromModelToMavenProject( model, parentPomFile, configuration, model.getPomFile() );
project.setOriginalModel( result.getRawModel() );
project.setRemoteArtifactRepositories( listener.getRemoteRepositories() );
project.setPluginArtifactRepositories( listener.getPluginRepositories() );
try
{
if ( configuration.isProcessPlugins() )
{
lifecycle.populateDefaultConfigurationForPlugins( model.getBuild().getPlugins(),
configuration.getLocalRepository(),
project.getPluginArtifactRepositories() );
}
}
catch ( LifecycleExecutionException e )
{
throw new ProjectBuildingException( project.getId(), e.getMessage(), e );
}
Build build = project.getBuild();
// NOTE: setting this script-source root before path translation, because
// the plugin tools compose basedir and scriptSourceRoot into a single file.
project.addScriptSourceRoot( build.getScriptSourceDirectory() );
project.addCompileSourceRoot( build.getSourceDirectory() );
project.addTestCompileSourceRoot( build.getTestSourceDirectory() );
project.setFile( pomFile );
List<Profile> activeProfiles = new ArrayList<Profile>();
activeProfiles.addAll( result.getActivePomProfiles( result.getModelIds().get( 0 ) ) );
activeProfiles.addAll( result.getActiveExternalProfiles() );
project.setActiveProfiles( activeProfiles );
project.setInjectedProfileIds( "external", getProfileIds( result.getActiveExternalProfiles() ) );
for ( String modelId : result.getModelIds() )
{
project.setInjectedProfileIds( modelId, getProfileIds( result.getActivePomProfiles( modelId ) ) );
}
return project;
} }
catch ( LifecycleExecutionException e ) finally
{ {
throw new ProjectBuildingException( "", e.getMessage(), e ); Thread.currentThread().setContextClassLoader( oldContextClassLoader );
} }
Build build = project.getBuild();
// NOTE: setting this script-source root before path translation, because
// the plugin tools compose basedir and scriptSourceRoot into a single file.
project.addScriptSourceRoot( build.getScriptSourceDirectory() );
project.addCompileSourceRoot( build.getSourceDirectory() );
project.addTestCompileSourceRoot( build.getTestSourceDirectory() );
project.setFile( pomFile );
List<Profile> activeProfiles = new ArrayList<Profile>();
activeProfiles.addAll( result.getActivePomProfiles( result.getModelIds().get( 0 ) ) );
activeProfiles.addAll( result.getActiveExternalProfiles() );
project.setActiveProfiles( activeProfiles );
project.setInjectedProfileIds( "external", getProfileIds( result.getActiveExternalProfiles() ) );
for ( String modelId : result.getModelIds() )
{
project.setInjectedProfileIds( modelId, getProfileIds( result.getActivePomProfiles( modelId ) ) );
}
return project;
} }
private List<String> getProfileIds( List<Profile> profiles ) private List<String> getProfileIds( List<Profile> profiles )
@ -182,6 +203,7 @@ public class DefaultProjectBuilder
configuration.getRemoteRepositories() ); configuration.getRemoteRepositories() );
ModelBuildingRequest request = new DefaultModelBuildingRequest(); ModelBuildingRequest request = new DefaultModelBuildingRequest();
request.setValidationLevel( configuration.getValidationLevel() ); request.setValidationLevel( configuration.getValidationLevel() );
request.setProcessPlugins( configuration.isProcessPlugins() ); request.setProcessPlugins( configuration.isProcessPlugins() );
request.setProfiles( configuration.getProfiles() ); request.setProfiles( configuration.getProfiles() );

View File

@ -0,0 +1,214 @@
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 java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;
import org.apache.maven.ArtifactFilterManager;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.InvalidRepositoryException;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.artifact.resolver.ResolutionErrorHandler;
import org.apache.maven.model.Build;
import org.apache.maven.model.Extension;
import org.apache.maven.model.Model;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.Repository;
import org.apache.maven.repository.RepositorySystem;
import org.codehaus.plexus.MutablePlexusContainer;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.classworlds.ClassWorld;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
import org.codehaus.plexus.classworlds.realm.DuplicateRealmException;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.Logger;
/**
* Assists the project builder.
*
* @author Benjamin Bentmann
*/
@Component( role = ProjectBuildingHelper.class )
public class DefaultProjectBuildingHelper
implements ProjectBuildingHelper
{
@Requirement
private Logger logger;
@Requirement
private PlexusContainer container;
@Requirement
private RepositorySystem repositorySystem;
@Requirement
private ResolutionErrorHandler resolutionErrorHandler;
@Requirement
private ArtifactFilterManager artifactFilterManager;
public List<ArtifactRepository> createArtifactRepositories( List<Repository> pomRepositories,
List<ArtifactRepository> externalRepositories )
throws InvalidRepositoryException
{
List<ArtifactRepository> artifactRepositories = new ArrayList<ArtifactRepository>();
for ( Repository repository : pomRepositories )
{
artifactRepositories.add( repositorySystem.buildArtifactRepository( repository ) );
}
artifactRepositories = repositorySystem.getMirrors( artifactRepositories );
if ( externalRepositories != null )
{
artifactRepositories.addAll( externalRepositories );
}
artifactRepositories = repositorySystem.getEffectiveRepositories( artifactRepositories );
return artifactRepositories;
}
public ClassRealm createProjectRealm( Model model, ArtifactRepository localRepository,
List<ArtifactRepository> remoteRepositories )
throws ArtifactResolutionException
{
Build build = model.getBuild();
if ( build == null )
{
return null;
}
List<Plugin> extensionPlugins = new ArrayList<Plugin>();
for ( Plugin plugin : build.getPlugins() )
{
if ( plugin.isExtensions() )
{
extensionPlugins.add( plugin );
}
}
if ( build.getExtensions().isEmpty() && extensionPlugins.isEmpty() )
{
return null;
}
String realmId = model.getGroupId() + ':' + model.getArtifactId() + ':' + model.getVersion();
if ( logger.isDebugEnabled() )
{
logger.debug( "Creating project realm " + realmId );
}
ClassWorld world = ( (MutablePlexusContainer) container ).getClassWorld();
ClassRealm projectRealm;
synchronized ( world )
{
projectRealm = world.getClassRealm( realmId );
if ( projectRealm == null )
{
try
{
projectRealm = world.newRealm( realmId );
projectRealm.setParentRealm( container.getContainerRealm() );
}
catch ( DuplicateRealmException e )
{
throw new IllegalStateException( "Failed to create project realm " + realmId, e );
}
}
}
for ( Extension extension : build.getExtensions() )
{
Artifact artifact =
repositorySystem.createArtifact( extension.getGroupId(), extension.getArtifactId(),
extension.getVersion(), "jar" );
populateRealm( projectRealm, artifact, localRepository, remoteRepositories );
}
for ( Plugin plugin : extensionPlugins )
{
Artifact artifact = repositorySystem.createPluginArtifact( plugin );
populateRealm( projectRealm, artifact, localRepository, remoteRepositories );
}
try
{
container.discoverComponents( projectRealm );
}
catch ( Exception e )
{
throw new IllegalStateException( "Failed to discover components in project realm " + realmId, e );
}
return projectRealm;
}
private void populateRealm( ClassRealm realm, Artifact artifact, ArtifactRepository localRepository,
List<ArtifactRepository> remoteRepositories )
throws ArtifactResolutionException
{
ArtifactResolutionRequest request = new ArtifactResolutionRequest();
request.setArtifact( artifact );
request.setResolveTransitively( true );
request.setFilter( artifactFilterManager.getCoreArtifactFilter() );
request.setLocalRepository( localRepository );
request.setRemoteRepostories( remoteRepositories );
ArtifactResolutionResult result = repositorySystem.resolve( request );
resolutionErrorHandler.throwErrors( request, result );
for ( Artifact resultArtifact : result.getArtifacts() )
{
if ( logger.isDebugEnabled() )
{
logger.debug( " " + resultArtifact.getFile() );
}
try
{
realm.addURL( resultArtifact.getFile().toURI().toURL() );
}
catch ( MalformedURLException e )
{
throw new IllegalStateException( "Failed to populate project realm " + realm.getId() + " with "
+ artifact.getFile(), e );
}
}
}
}

View File

@ -239,13 +239,6 @@ public class MavenProject
this.projectBuilderConfiguration = projectBuilderConfiguration; this.projectBuilderConfiguration = projectBuilderConfiguration;
this.repositorySystem = repositorySystem; this.repositorySystem = repositorySystem;
originalModel = model; originalModel = model;
remoteArtifactRepositories = projectBuilderConfiguration.getRemoteRepositories();
remoteArtifactRepositories = createArtifactRepositories( model.getRepositories(), remoteArtifactRepositories );
pluginArtifactRepositories = projectBuilderConfiguration.getPluginArtifactRepositories();
pluginArtifactRepositories =
createArtifactRepositories( model.getPluginRepositories(), pluginArtifactRepositories );
} }
//TODO: need to integrate the effective scope and refactor it out of the MMS //TODO: need to integrate the effective scope and refactor it out of the MMS
@ -269,35 +262,6 @@ public class MavenProject
return artifacts; return artifacts;
} }
private List<ArtifactRepository> createArtifactRepositories( List<Repository> pomRepositories,
List<ArtifactRepository> externalRepositories )
{
List<ArtifactRepository> artifactRepositories = new ArrayList<ArtifactRepository>();
for ( Repository repository : pomRepositories )
{
try
{
artifactRepositories.add( repositorySystem.buildArtifactRepository( repository ) );
}
catch ( InvalidRepositoryException e )
{
}
}
artifactRepositories = repositorySystem.getMirrors( artifactRepositories );
if ( externalRepositories != null )
{
artifactRepositories.addAll( externalRepositories );
}
artifactRepositories = repositorySystem.getEffectiveRepositories( artifactRepositories );
return artifactRepositories;
}
// TODO: Find a way to use <relativePath/> here...it's tricky, because the moduleProject // TODO: Find a way to use <relativePath/> here...it's tricky, because the moduleProject
// usually doesn't have a file associated with it yet. // usually doesn't have a file associated with it yet.
public String getModulePathAdjustment( MavenProject moduleProject ) public String getModulePathAdjustment( MavenProject moduleProject )

View File

@ -0,0 +1,65 @@
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 java.util.List;
import org.apache.maven.artifact.InvalidRepositoryException;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.model.Model;
import org.apache.maven.model.Repository;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
/**
* Assists the project builder.
*
* @author Benjamin Bentmann
*/
public interface ProjectBuildingHelper
{
/**
* Creates the effective artifact repositories from the specified POM repositories.
*
* @param pomRepositories The POM repositories to create the artifact repositories from, must not be {@code null}.
* @param externalRepositories The external (and already mirrored) repositories to merge into the result list, may
* be {@code null}.
* @return The effective artifact repositories, never {@code null}.
* @throws InvalidRepositoryException
*/
List<ArtifactRepository> createArtifactRepositories( List<Repository> pomRepositories,
List<ArtifactRepository> externalRepositories )
throws InvalidRepositoryException;
/**
* Creates the project realm that hosts the build extensions of the specified model.
*
* @param model The model to create the project realm for, must not be {@code null}
* @param localRepository The local repository to use for artifact resolution, must not be {@code null}.
* @param remoteRepositories The remote repositories to use for artifact resolution, must not be {@code null}.
* @return The project realm or {@code null} if no build extensions are present.
* @throws ArtifactResolutionException If any build extension could not be resolved.
*/
ClassRealm createProjectRealm( Model model, ArtifactRepository localRepository,
List<ArtifactRepository> remoteRepositories )
throws ArtifactResolutionException;
}

View File

@ -0,0 +1,57 @@
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 java.util.ArrayList;
import java.util.List;
import org.apache.maven.artifact.InvalidRepositoryException;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.model.Model;
import org.apache.maven.model.Repository;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
import org.codehaus.plexus.component.annotations.Component;
/**
* A stub implementation to bypass artifact resolution from repositories.
*
* @author Benjamin Bentmann
*/
@Component( role = ProjectBuildingHelper.class )
public class EmptyProjectBuildingHelper
implements ProjectBuildingHelper
{
public List<ArtifactRepository> createArtifactRepositories( List<Repository> pomRepositories,
List<ArtifactRepository> externalRepositories )
throws InvalidRepositoryException
{
return new ArrayList<ArtifactRepository>();
}
public ClassRealm createProjectRealm( Model model, ArtifactRepository localRepository,
List<ArtifactRepository> remoteRepositories )
throws ArtifactResolutionException
{
return null;
}
}

View File

@ -5,5 +5,9 @@
<role>org.apache.maven.lifecycle.LifecycleExecutor</role> <role>org.apache.maven.lifecycle.LifecycleExecutor</role>
<implementation>org.apache.maven.project.EmptyLifecycleExecutor</implementation> <implementation>org.apache.maven.project.EmptyLifecycleExecutor</implementation>
</component> </component>
<component>
<role>org.apache.maven.project.ProjectBuildingHelper</role>
<implementation>org.apache.maven.project.EmptyProjectBuildingHelper</implementation>
</component>
</components> </components>
</plexus> </plexus>