o Centralized class realm creation

git-svn-id: https://svn.apache.org/repos/asf/maven/components/trunk@799936 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Benjamin Bentmann 2009-08-01 21:54:18 +00:00
parent 287a715954
commit 2ecdadb186
4 changed files with 305 additions and 73 deletions

View File

@ -0,0 +1,52 @@
package org.apache.maven.classrealm;
/*
* 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.model.Model;
import org.apache.maven.model.Plugin;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
/**
* Manages the class realms used by Maven. <strong>Warning:</strong> This is an internal utility interface that is only
* public for technical reasons, it is not part of the public API. In particular, this interface can be changed or
* deleted without prior notice.
*
* @author Benjamin Bentmann
*/
public interface ClassRealmManager
{
/**
* Creates a new class realm for the specified project and its build extensions.
*
* @param model The model of the project for which to create a realm, must not be {@code null}.
* @return The new project realm, never {@code null}.
*/
ClassRealm createProjectRealm( Model model );
/**
* Creates a new class realm for the specified plugin.
*
* @param plugin The plugin for which to create a realm, must not be {@code null}.
* @return The new plugin realm, never {@code null}.
*/
ClassRealm createPluginRealm( Plugin plugin );
}

View File

@ -0,0 +1,238 @@
package org.apache.maven.classrealm;
/*
* 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.Random;
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.model.Model;
import org.apache.maven.model.Plugin;
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.classworlds.realm.NoSuchRealmException;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.Logger;
/**
* Manages the class realms used by Maven. <strong>Warning:</strong> This is an internal utility class that is only
* public for technical reasons, it is not part of the public API. In particular, this interface can be changed or
* deleted without prior notice.
*
* @author Benjamin Bentmann
*/
@Component( role = ClassRealmManager.class )
public class DefaultClassRealmManager
implements ClassRealmManager
{
@Requirement
private Logger logger;
@Requirement
protected PlexusContainer container;
private ClassWorld getClassWorld()
{
return ( (MutablePlexusContainer) container ).getClassWorld();
}
private ClassRealm createRealm( String baseRealmId )
{
ClassWorld world = getClassWorld();
String realmId = baseRealmId;
Random random = new Random();
synchronized ( world )
{
ClassRealm classRealm;
while ( true )
{
try
{
classRealm = world.newRealm( realmId );
if ( logger.isDebugEnabled() )
{
logger.debug( "Created new class realm " + realmId );
}
break;
}
catch ( DuplicateRealmException e )
{
realmId = baseRealmId + '-' + random.nextInt();
}
}
classRealm.setParentRealm( getApiRealm() );
importXpp3Dom( classRealm );
return classRealm;
}
}
/**
* Gets the class realm that holds the Maven API classes that we intend to share with plugins and extensions. The
* API realm is basically a subset of the core realm and hides internal utility/implementation classes from
* plugins/extensions.
*
* @return The class realm for the Maven API, never {@code null}.
*/
private ClassRealm getApiRealm()
{
return container.getContainerRealm();
// TODO: MNG-4273, currently non-functional because the core artifact filter wipes out transitive plugin dependencies
// like plexus-utils, too. We need to filter the result set of the plugin artifacts, not the graph.
//
// ClassWorld world = getClassWorld();
//
// String realmId = "maven.api";
//
// ClassRealm apiRealm;
//
// synchronized ( world )
// {
// apiRealm = world.getClassRealm( realmId );
//
// if ( apiRealm == null )
// {
// try
// {
// apiRealm = world.newRealm( realmId );
// }
// catch ( DuplicateRealmException e )
// {
// throw new IllegalStateException( "Failed to create API realm " + realmId, e );
// }
//
// String coreRealmId = container.getContainerRealm().getId();
// try
// {
// // components.xml
// apiRealm.importFrom( coreRealmId, "META-INF/plexus" );
//
// // maven-*
// apiRealm.importFrom( coreRealmId, "org.apache.maven." );
//
// // plexus-classworlds
// apiRealm.importFrom( coreRealmId, "org.codehaus.plexus.classworlds" );
//
// // plexus-container, plexus-component-annotations
// apiRealm.importFrom( coreRealmId, "org.codehaus.plexus.component" );
// apiRealm.importFrom( coreRealmId, "org.codehaus.plexus.configuration" );
// apiRealm.importFrom( coreRealmId, "org.codehaus.plexus.container" );
// apiRealm.importFrom( coreRealmId, "org.codehaus.plexus.context" );
// apiRealm.importFrom( coreRealmId, "org.codehaus.plexus.lifecycle" );
// apiRealm.importFrom( coreRealmId, "org.codehaus.plexus.logging" );
// apiRealm.importFrom( coreRealmId, "org.codehaus.plexus.personality" );
// apiRealm.importFrom( coreRealmId, "org.codehaus.plexus.ComponentRegistry" );
// apiRealm.importFrom( coreRealmId, "org.codehaus.plexus.ContainerConfiguration" );
// apiRealm.importFrom( coreRealmId, "org.codehaus.plexus.DefaultComponentRegistry" );
// apiRealm.importFrom( coreRealmId, "org.codehaus.plexus.DefaultContainerConfiguration" );
// apiRealm.importFrom( coreRealmId, "org.codehaus.plexus.DefaultPlexusContainer" );
// apiRealm.importFrom( coreRealmId, "org.codehaus.plexus.DuplicateChildContainerException" );
// apiRealm.importFrom( coreRealmId, "org.codehaus.plexus.MutablePlexusContainer" );
// apiRealm.importFrom( coreRealmId, "org.codehaus.plexus.PlexusConstants" );
// apiRealm.importFrom( coreRealmId, "org.codehaus.plexus.PlexusContainer" );
// apiRealm.importFrom( coreRealmId, "org.codehaus.plexus.PlexusContainerException" );
// }
// catch ( NoSuchRealmException e )
// {
// throw new IllegalStateException( e );
// }
//
// try
// {
// container.discoverComponents( apiRealm );
// }
// catch ( Exception e )
// {
// throw new IllegalStateException( "Failed to discover components in API realm " + realmId, e );
// }
// }
// }
//
// return apiRealm;
}
/**
* Imports Xpp3Dom and associated types into the specified realm. Unlike the other archives that constitute the API
* realm, plexus-utils is not excluded from the plugin/project realm, yet we must ensure this class is loaded from
* the API realm and not from the plugin/project realm.
*
* @param importingRealm The realm into which to import Xpp3Dom, must not be {@code null}.
*/
private void importXpp3Dom( ClassRealm importingRealm )
{
String coreRealmId = container.getContainerRealm().getId();
try
{
importingRealm.importFrom( coreRealmId, "org.codehaus.plexus.util.xml.Xpp3Dom" );
importingRealm.importFrom( coreRealmId, "org.codehaus.plexus.util.xml.pull.XmlPullParser" );
importingRealm.importFrom( coreRealmId, "org.codehaus.plexus.util.xml.pull.XmlPullParserException" );
importingRealm.importFrom( coreRealmId, "org.codehaus.plexus.util.xml.pull.XmlSerializer" );
}
catch ( NoSuchRealmException e )
{
throw new IllegalStateException( e );
}
}
public ClassRealm createProjectRealm( Model model )
{
if ( model == null )
{
throw new IllegalArgumentException( "model missing" );
}
return createRealm( getKey( model ) );
}
private String getKey( Model model )
{
return "project>" + model.getGroupId() + ":" + model.getArtifactId() + ":" + model.getVersion();
}
public ClassRealm createPluginRealm( Plugin plugin )
{
if ( plugin == null )
{
throw new IllegalArgumentException( "plugin missing" );
}
return createRealm( getKey( plugin ) );
}
private String getKey( Plugin plugin )
{
String version = ArtifactUtils.toSnapshotVersion( plugin.getVersion() );
return "plugin>" + plugin.getGroupId() + ":" + plugin.getArtifactId() + ":" + version;
}
}

View File

@ -41,6 +41,7 @@ import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.artifact.resolver.ResolutionErrorHandler;
import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
import org.apache.maven.classrealm.ClassRealmManager;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Plugin;
@ -51,12 +52,8 @@ import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
import org.apache.maven.project.DuplicateArtifactAttachmentException;
import org.apache.maven.project.MavenProject;
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.classworlds.realm.NoSuchRealmException;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.component.composition.CycleDetectedInComponentGraphException;
@ -91,6 +88,9 @@ public class DefaultPluginManager
@Requirement
protected PlexusContainer container;
@Requirement
private ClassRealmManager classRealmManager;
@Requirement
protected ArtifactFilterManager coreArtifactFilterManager;
@ -450,45 +450,8 @@ public class DefaultPluginManager
* Creates ClassRealm with unique id for the given plugin
*/
private ClassRealm createPluginRealm( Plugin plugin )
throws PluginManagerException
{
ClassWorld world = ((MutablePlexusContainer) container).getClassWorld();
String baseRealmId = constructPluginKey( plugin );
String realmId = baseRealmId;
synchronized ( world )
{
for ( int i = 0; i < 100; i++ )
{
try
{
ClassRealm pluginRealm = world.newRealm( realmId );
pluginRealm.setParentRealm( container.getContainerRealm() );
String coreRealmId = container.getContainerRealm().getId();
try
{
pluginRealm.importFrom( coreRealmId, "org.codehaus.plexus.util.xml.Xpp3Dom" );
pluginRealm.importFrom( coreRealmId, "org.codehaus.plexus.util.xml.pull.XmlPullParser" );
pluginRealm.importFrom( coreRealmId, "org.codehaus.plexus.util.xml.pull.XmlPullParserException" );
pluginRealm.importFrom( coreRealmId, "org.codehaus.plexus.util.xml.pull.XmlSerializer" );
}
catch ( NoSuchRealmException e )
{
throw new IllegalStateException( e );
}
return pluginRealm;
}
catch ( DuplicateRealmException e )
{
realmId = baseRealmId + "-" + i;
}
}
}
throw new PluginManagerException( plugin, "Could not create ClassRealm for plugin " + baseRealmId, (Throwable) null );
return classRealmManager.createPluginRealm( plugin );
}
private Mojo getConfiguredMojo( MavenSession session, MavenProject project, MojoExecution mojoExecution, ClassRealm pluginRealm )

View File

@ -33,6 +33,7 @@ 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.classrealm.ClassRealmManager;
import org.apache.maven.model.Build;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Extension;
@ -40,17 +41,16 @@ 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.
* Assists the project builder. <strong>Warning:</strong> This is an internal utility class that is only public for
* technical reasons, it is not part of the public API. In particular, this interface can be changed or deleted without
* prior notice.
*
* @author Benjamin Bentmann
*/
@ -65,6 +65,9 @@ public class DefaultProjectBuildingHelper
@Requirement
private PlexusContainer container;
@Requirement
private ClassRealmManager classRealmManager;
@Requirement
private RepositorySystem repositorySystem;
@ -125,32 +128,7 @@ public class DefaultProjectBuildingHelper
return projectRealm;
}
String realmId = model.getGroupId() + ':' + model.getArtifactId() + ':' + model.getVersion();
if ( logger.isDebugEnabled() )
{
logger.debug( "Creating project realm " + realmId );
}
ClassWorld world = ( (MutablePlexusContainer) container ).getClassWorld();
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 );
}
}
}
projectRealm = classRealmManager.createProjectRealm( model );
for ( Extension extension : build.getExtensions() )
{
@ -180,7 +158,8 @@ public class DefaultProjectBuildingHelper
}
catch ( Exception e )
{
throw new IllegalStateException( "Failed to discover components in project realm " + realmId, e );
throw new IllegalStateException( "Failed to discover components in project realm " + projectRealm.getId(),
e );
}
return projectRealm;