[MNG-4541] Extend class realm manager delegate to allow conditional behavior

git-svn-id: https://svn.apache.org/repos/asf/maven/maven-3/trunk@901852 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Benjamin Bentmann 2010-01-21 21:01:19 +00:00
parent a789d4c288
commit b6c016a84e
9 changed files with 431 additions and 135 deletions

View File

@ -0,0 +1,70 @@
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.io.File;
import org.apache.maven.artifact.Artifact;
/**
* @author Benjamin Bentmann
*/
class ArtifactClassRealmConstituent
implements ClassRealmConstituent
{
private final Artifact artifact;
public ArtifactClassRealmConstituent( Artifact artifact )
{
this.artifact = artifact;
}
public String getGroupId()
{
return artifact.getGroupId();
}
public String getArtifactId()
{
return artifact.getArtifactId();
}
public String getType()
{
return artifact.getType();
}
public String getClassifier()
{
return artifact.hasClassifier() ? artifact.getClassifier() : "";
}
public String getVersion()
{
return artifact.getBaseVersion();
}
public File getFile()
{
return artifact.getFile();
}
}

View File

@ -0,0 +1,74 @@
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.io.File;
/**
* Describes a constituent of a class realm.
*
* @author Benjamin Bentmann
*/
public interface ClassRealmConstituent
{
/**
* Gets the group id of the constituent's artifact.
*
* @return The group id, never {@code null}.
*/
String getGroupId();
/**
* Gets the artifact id of the constituent's artifact.
*
* @return The artifact id, never {@code null}.
*/
String getArtifactId();
/**
* Gets the type of the constituent's artifact.
*
* @return The type, never {@code null}.
*/
String getType();
/**
* Gets the classifier of the constituent's artifact.
*
* @return The classifier or an empty string, never {@code null}.
*/
String getClassifier();
/**
* Gets the version of the constituent's artifact.
*
* @return The version, never {@code null}.
*/
String getVersion();
/**
* Gets the file of the constituent's artifact.
*
* @return The file, never {@code null}.
*/
File getFile();
}

View File

@ -21,6 +21,7 @@
import java.util.List;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.model.Model;
import org.apache.maven.model.Plugin;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
@ -46,17 +47,21 @@ 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}.
* @param artifacts The artifacts to add to the class realm, may be {@code null}. Unresolved artifacts (i.e. with a
* missing file) will automatically be excluded from the realm.
* @return The new project realm, never {@code null}.
*/
ClassRealm createProjectRealm( Model model );
ClassRealm createProjectRealm( Model model, List<Artifact> artifacts );
/**
* Creates a new class realm for the specified build extension.
*
* @param plugin The extension plugin for which to create a realm, must not be {@code null}.
* @param artifacts The artifacts to add to the class realm, may be {@code null}. Unresolved artifacts (i.e. with a
* missing file) will automatically be excluded from the realm.
* @return The new extension realm, never {@code null}.
*/
ClassRealm createExtensionRealm( Plugin extension );
ClassRealm createExtensionRealm( Plugin extension, List<Artifact> artifacts );
/**
* Creates a new class realm for the specified plugin.
@ -64,8 +69,10 @@ public interface ClassRealmManager
* @param plugin The plugin for which to create a realm, must not be {@code null}.
* @param parent The parent realm for the new realm, may be {@code null} to use the Maven core realm.
* @param imports The packages/types to import from the parent realm, may be {@code null}.
* @param artifacts The artifacts to add to the class realm, may be {@code null}. Unresolved artifacts (i.e. with a
* missing file) will automatically be excluded from the realm.
* @return The new plugin realm, never {@code null}.
*/
ClassRealm createPluginRealm( Plugin plugin, ClassLoader parent, List<String> imports );
ClassRealm createPluginRealm( Plugin plugin, ClassLoader parent, List<String> imports, List<Artifact> artifacts );
}

View File

@ -30,5 +30,7 @@
*/
public interface ClassRealmManagerDelegate
{
void setupRealm( ClassRealm classRealm );
void setupRealm( ClassRealm classRealm, ClassRealmRequest request );
}

View File

@ -0,0 +1,65 @@
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.List;
/**
* Describes the requirements for a new class realm.
*
* @author Benjamin Bentmann
*/
public interface ClassRealmRequest
{
enum RealmType
{
Project, Extension, Plugin,
}
/**
* Gets the type of the class realm.
*
* @return The type of the class realm, never {@code null}.
*/
RealmType getType();
/**
* Gets the parent class realm (if any).
*
* @return The parent class realm or {@code null} if using the Maven core realm as parent.
*/
ClassLoader getParent();
/**
* Gets the packages/types to import from the parent realm
*
* @return The modifiable list of packages/types to import from the parent realm, never {@code null}.
*/
List<String> getImports();
/**
* Gets the constituents for the class realm.
*
* @return The modifiable list of constituents for the class realm, never {@code null}.
*/
List<ClassRealmConstituent> getConstituents();
}

View File

@ -19,11 +19,18 @@
* under the License.
*/
import java.io.File;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.classrealm.ClassRealmRequest.RealmType;
import org.apache.maven.model.Model;
import org.apache.maven.model.Plugin;
import org.codehaus.plexus.MutablePlexusContainer;
@ -35,6 +42,7 @@
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.util.StringUtils;
/**
* Manages the class realms used by Maven. <strong>Warning:</strong> This is an internal utility class that is only
@ -63,21 +71,52 @@ private ClassWorld getClassWorld()
* Creates a new class realm with the specified parent and imports.
*
* @param baseRealmId The base id to use for the new realm, must not be {@code null}.
* @param type The type of the class realm, must not be {@code null}.
* @param parent The parent realm for the new realm, may be {@code null} to use the Maven core realm.
* @param imports The packages/types to import from the parent realm, may be {@code null}.
* @param artifacts The artifacts to add to the realm, may be {@code null}. Unresolved artifacts (i.e. with a
* missing file) will automatically be excluded from the realm.
* @return The created class realm, never {@code null}.
*/
private ClassRealm createRealm( String baseRealmId, ClassLoader parent, List<String> imports, boolean importXpp3Dom )
private ClassRealm createRealm( String baseRealmId, RealmType type, ClassLoader parent, List<String> imports,
boolean importXpp3Dom, List<Artifact> artifacts )
{
Set<String> artifactIds = new HashSet<String>();
List<ClassRealmConstituent> constituents = new ArrayList<ClassRealmConstituent>();
if ( artifacts != null )
{
for ( Artifact artifact : artifacts )
{
artifactIds.add( artifact.getId() );
if ( artifact.getFile() != null )
{
constituents.add( new ArtifactClassRealmConstituent( artifact ) );
}
}
}
if ( imports != null )
{
imports = new ArrayList<String>( imports );
}
else
{
imports = new ArrayList<String>();
}
ClassRealmRequest request = new DefaultClassRealmRequest( type, parent, imports, constituents );
ClassRealm classRealm;
ClassWorld world = getClassWorld();
String realmId = baseRealmId;
Random random = new Random();
synchronized ( world )
{
ClassRealm classRealm;
String realmId = baseRealmId;
Random random = new Random();
while ( true )
{
@ -97,39 +136,84 @@ private ClassRealm createRealm( String baseRealmId, ClassLoader parent, List<Str
realmId = baseRealmId + '-' + random.nextInt();
}
}
if ( parent != null )
{
classRealm.setParentClassLoader( parent );
}
else
{
classRealm.setParentRealm( getCoreRealm() );
importMavenApi( classRealm );
}
if ( importXpp3Dom )
{
importXpp3Dom( classRealm );
}
if ( imports != null && !imports.isEmpty() )
{
ClassLoader importedRealm = classRealm.getParentClassLoader();
for ( String imp : imports )
{
classRealm.importFrom( importedRealm, imp );
}
}
for ( ClassRealmManagerDelegate delegate : getDelegates() )
{
delegate.setupRealm( classRealm );
}
return classRealm;
}
if ( parent != null )
{
classRealm.setParentClassLoader( parent );
}
else
{
classRealm.setParentRealm( getCoreRealm() );
importMavenApi( classRealm );
}
for ( ClassRealmManagerDelegate delegate : getDelegates() )
{
delegate.setupRealm( classRealm, request );
}
if ( importXpp3Dom )
{
importXpp3Dom( classRealm );
}
if ( !imports.isEmpty() )
{
ClassLoader importedRealm = classRealm.getParentClassLoader();
if ( logger.isDebugEnabled() )
{
logger.debug( "Importing packages into class realm " + classRealm.getId() );
}
for ( String imp : imports )
{
if ( logger.isDebugEnabled() )
{
logger.debug( " Imported: " + imp );
}
classRealm.importFrom( importedRealm, imp );
}
}
if ( logger.isDebugEnabled() )
{
logger.debug( "Populating class realm " + classRealm.getId() );
}
for ( ClassRealmConstituent constituent : constituents )
{
File file = constituent.getFile();
String id = getId( constituent );
artifactIds.remove( id );
if ( logger.isDebugEnabled() )
{
logger.debug( " Included: " + id );
}
try
{
classRealm.addURL( file.toURI().toURL() );
}
catch ( MalformedURLException e )
{
// Not going to happen
}
}
if ( logger.isDebugEnabled() )
{
for ( String id : artifactIds )
{
logger.debug( " Excluded: " + id );
}
}
return classRealm;
}
/**
@ -190,48 +274,56 @@ public ClassRealm getCoreRealm()
return container.getContainerRealm();
}
public ClassRealm createProjectRealm( Model model )
public ClassRealm createProjectRealm( Model model, List<Artifact> artifacts )
{
if ( model == null )
{
throw new IllegalArgumentException( "model missing" );
}
return createRealm( getKey( model ), null, null, false );
return createRealm( getKey( model ), RealmType.Project, null, null, false, artifacts );
}
private String getKey( Model model )
private static String getKey( Model model )
{
return "project>" + model.getGroupId() + ":" + model.getArtifactId() + ":" + model.getVersion();
}
public ClassRealm createExtensionRealm( Plugin plugin )
public ClassRealm createExtensionRealm( Plugin plugin, List<Artifact> artifacts )
{
if ( plugin == null )
{
throw new IllegalArgumentException( "extension plugin missing" );
}
return createRealm( getKey( plugin, true ), null, null, true );
return createRealm( getKey( plugin, true ), RealmType.Extension, null, null, true, artifacts );
}
public ClassRealm createPluginRealm( Plugin plugin, ClassLoader parent, List<String> imports )
public ClassRealm createPluginRealm( Plugin plugin, ClassLoader parent, List<String> imports,
List<Artifact> artifacts )
{
if ( plugin == null )
{
throw new IllegalArgumentException( "plugin missing" );
}
return createRealm( getKey( plugin, false ), parent, imports, true );
return createRealm( getKey( plugin, false ), RealmType.Plugin, parent, imports, true, artifacts );
}
private String getKey( Plugin plugin, boolean extension )
private static String getKey( Plugin plugin, boolean extension )
{
String version = ArtifactUtils.toSnapshotVersion( plugin.getVersion() );
return ( extension ? "extension>" : "plugin>" ) + plugin.getGroupId() + ":" + plugin.getArtifactId() + ":"
+ version;
}
private static String getId( ClassRealmConstituent constituent )
{
return constituent.getGroupId() + ':' + constituent.getArtifactId() + ':' + constituent.getType()
+ ( StringUtils.isNotEmpty( constituent.getClassifier() ) ? ':' + constituent.getClassifier() : "" ) + ':'
+ constituent.getVersion();
}
private List<ClassRealmManagerDelegate> getDelegates()
{
try

View File

@ -0,0 +1,68 @@
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.List;
/**
* @author Benjamin Bentmann
*/
class DefaultClassRealmRequest
implements ClassRealmRequest
{
private final RealmType type;
private final ClassLoader parent;
private final List<String> imports;
private final List<ClassRealmConstituent> constituents;
public DefaultClassRealmRequest( RealmType type, ClassLoader parent, List<String> imports,
List<ClassRealmConstituent> constituents )
{
this.type = type;
this.parent = parent;
this.imports = imports;
this.constituents = constituents;
}
public RealmType getType()
{
return type;
}
public ClassLoader getParent()
{
return parent;
}
public List<String> getImports()
{
return imports;
}
public List<ClassRealmConstituent> getConstituents()
{
return constituents;
}
}

View File

@ -27,7 +27,6 @@
import java.io.InputStream;
import java.io.PrintStream;
import java.io.Reader;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
@ -360,12 +359,7 @@ else if ( filter != null )
List<Artifact> pluginArtifacts = resolvePluginArtifacts( plugin, pluginArtifact, request, dependencyFilter );
ClassRealm pluginRealm = classRealmManager.createPluginRealm( plugin, parent, imports );
if ( logger.isDebugEnabled() )
{
logger.debug( "Populating plugin realm for " + plugin.getId() );
}
ClassRealm pluginRealm = classRealmManager.createPluginRealm( plugin, parent, imports, pluginArtifacts );
List<Artifact> exposedPluginArtifacts = new ArrayList<Artifact>();
@ -373,28 +367,7 @@ else if ( filter != null )
{
if ( artifact.getFile() != null )
{
if ( logger.isDebugEnabled() )
{
logger.debug( " Included: " + artifact.getId() );
}
exposedPluginArtifacts.add( artifact );
try
{
pluginRealm.addURL( artifact.getFile().toURI().toURL() );
}
catch ( MalformedURLException e )
{
// Not going to happen
}
}
else
{
if ( logger.isDebugEnabled() )
{
logger.debug( " Excluded: " + artifact.getId() );
}
}
}

View File

@ -20,7 +20,6 @@
*/
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@ -229,39 +228,7 @@ public synchronized ProjectRealmCache.CacheRecord createProjectRealm( MavenProje
}
else
{
extensionRealm = classRealmManager.createExtensionRealm( plugin );
if ( logger.isDebugEnabled() )
{
logger.debug( "Populating extension realm for " + plugin.getId() );
}
for ( Artifact artifact : artifacts )
{
if ( artifact.getFile() != null )
{
if ( logger.isDebugEnabled() )
{
logger.debug( " Included: " + artifact.getId() );
}
try
{
extensionRealm.addURL( artifact.getFile().toURI().toURL() );
}
catch ( MalformedURLException e )
{
// Not going to happen
}
}
else
{
if ( logger.isDebugEnabled() )
{
logger.debug( " Excluded: " + artifact.getId() );
}
}
}
extensionRealm = classRealmManager.createExtensionRealm( plugin, artifacts );
try
{
@ -323,29 +290,7 @@ public synchronized ProjectRealmCache.CacheRecord createProjectRealm( MavenProje
if ( record == null )
{
projectRealm = classRealmManager.createProjectRealm( model );
if ( logger.isDebugEnabled() )
{
logger.debug( "Populating project realm for " + model.getId() );
}
for ( Artifact publicArtifact : publicArtifacts )
{
if ( logger.isDebugEnabled() )
{
logger.debug( " Included: " + publicArtifact.getId() );
}
try
{
projectRealm.addURL( publicArtifact.getFile().toURI().toURL() );
}
catch ( MalformedURLException e )
{
// can't happen
}
}
projectRealm = classRealmManager.createProjectRealm( model, publicArtifacts );
Set<String> exclusions = new LinkedHashSet<String>();