mirror of https://github.com/apache/maven.git
[MNG-4381] Allow extension plugins to contribute non-core components to be reused by other plugins
git-svn-id: https://svn.apache.org/repos/asf/maven/maven-3/trunk@819540 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
51b6120810
commit
5950571180
|
@ -43,6 +43,14 @@ public interface ClassRealmManager
|
|||
*/
|
||||
ClassRealm createProjectRealm( Model model );
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
* @return The new extension realm, never {@code null}.
|
||||
*/
|
||||
ClassRealm createExtensionRealm( Plugin extension );
|
||||
|
||||
/**
|
||||
* Creates a new class realm for the specified plugin.
|
||||
*
|
||||
|
|
|
@ -197,6 +197,16 @@ public class DefaultClassRealmManager
|
|||
return "project>" + model.getGroupId() + ":" + model.getArtifactId() + ":" + model.getVersion();
|
||||
}
|
||||
|
||||
public ClassRealm createExtensionRealm( Plugin plugin )
|
||||
{
|
||||
if ( plugin == null )
|
||||
{
|
||||
throw new IllegalArgumentException( "extension plugin missing" );
|
||||
}
|
||||
|
||||
return createRealm( getKey( plugin, true ), null, null );
|
||||
}
|
||||
|
||||
public ClassRealm createPluginRealm( Plugin plugin, ClassLoader parent, List<String> imports )
|
||||
{
|
||||
if ( plugin == null )
|
||||
|
@ -204,13 +214,14 @@ public class DefaultClassRealmManager
|
|||
throw new IllegalArgumentException( "plugin missing" );
|
||||
}
|
||||
|
||||
return createRealm( getKey( plugin ), parent, imports );
|
||||
return createRealm( getKey( plugin, false ), parent, imports );
|
||||
}
|
||||
|
||||
private String getKey( Plugin plugin )
|
||||
private String getKey( Plugin plugin, boolean extension )
|
||||
{
|
||||
String version = ArtifactUtils.toSnapshotVersion( plugin.getVersion() );
|
||||
return "plugin>" + plugin.getGroupId() + ":" + plugin.getArtifactId() + ":" + version;
|
||||
return ( extension ? "extension>" : "plugin>" ) + plugin.getGroupId() + ":" + plugin.getArtifactId() + ":"
|
||||
+ version;
|
||||
}
|
||||
|
||||
private List<ClassRealmManagerDelegate> getDelegates()
|
||||
|
|
|
@ -0,0 +1,231 @@
|
|||
package org.apache.maven.plugin;
|
||||
|
||||
/*
|
||||
* 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.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
import org.apache.maven.artifact.repository.ArtifactRepository;
|
||||
import org.apache.maven.artifact.repository.RepositoryRequest;
|
||||
import org.apache.maven.model.Dependency;
|
||||
import org.apache.maven.model.Exclusion;
|
||||
import org.apache.maven.model.Plugin;
|
||||
import org.apache.maven.project.ExtensionDescriptor;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.codehaus.plexus.classworlds.realm.ClassRealm;
|
||||
import org.codehaus.plexus.component.annotations.Component;
|
||||
|
||||
/**
|
||||
* Default extension realm cache implementation. Assumes cached data does not change.
|
||||
*/
|
||||
@Component( role = ExtensionRealmCache.class )
|
||||
public class DefaultExtensionRealmCache
|
||||
implements ExtensionRealmCache
|
||||
{
|
||||
|
||||
private static class CacheKey
|
||||
{
|
||||
|
||||
private final Plugin extension;
|
||||
|
||||
private final List<ArtifactRepository> repositories = new ArrayList<ArtifactRepository>();
|
||||
|
||||
private final int hashCode;
|
||||
|
||||
public CacheKey( Plugin extension, RepositoryRequest repositoryRequest )
|
||||
{
|
||||
this.extension = extension.clone();
|
||||
this.repositories.add( repositoryRequest.getLocalRepository() );
|
||||
this.repositories.addAll( repositoryRequest.getRemoteRepositories() );
|
||||
|
||||
int hash = 17;
|
||||
hash = hash * 31 + extensionHashCode( extension );
|
||||
hash = hash * 31 + repositories.hashCode();
|
||||
this.hashCode = hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals( Object o )
|
||||
{
|
||||
if ( o == this )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( !( o instanceof CacheKey ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CacheKey other = (CacheKey) o;
|
||||
|
||||
return extensionEquals( extension, other.extension ) && eq( repositories, other.repositories );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final Map<CacheKey, CacheRecord> cache = new HashMap<CacheKey, CacheRecord>();
|
||||
|
||||
public CacheRecord get( Plugin extension, RepositoryRequest repositoryRequest )
|
||||
{
|
||||
return cache.get( new CacheKey( extension, repositoryRequest ) );
|
||||
}
|
||||
|
||||
public void put( Plugin extension, RepositoryRequest repositoryRequest, ClassRealm extensionRealm,
|
||||
List<Artifact> extensionArtifacts, ExtensionDescriptor extensionDescriptor )
|
||||
{
|
||||
if ( extensionRealm == null || extensionArtifacts == null )
|
||||
{
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
CacheKey key = new CacheKey( extension, repositoryRequest );
|
||||
|
||||
if ( cache.containsKey( key ) )
|
||||
{
|
||||
throw new IllegalStateException( "Duplicate extension realm for extension " + extension.getId() );
|
||||
}
|
||||
|
||||
CacheRecord record = new CacheRecord( extensionRealm, extensionArtifacts, extensionDescriptor );
|
||||
cache.put( key, record );
|
||||
}
|
||||
|
||||
public void flush()
|
||||
{
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
protected static int extensionHashCode( Plugin extension )
|
||||
{
|
||||
int hash = 17;
|
||||
|
||||
hash = hash * 31 + extension.getGroupId().hashCode();
|
||||
hash = hash * 31 + extension.getArtifactId().hashCode();
|
||||
hash = hash * 31 + extension.getVersion().hashCode();
|
||||
|
||||
for ( Dependency dependency : extension.getDependencies() )
|
||||
{
|
||||
hash = hash * 31 + dependency.getGroupId().hashCode();
|
||||
hash = hash * 31 + dependency.getArtifactId().hashCode();
|
||||
hash = hash * 31 + dependency.getVersion().hashCode();
|
||||
hash = hash * 31 + dependency.getType().hashCode();
|
||||
hash = hash * 31 + ( dependency.getClassifier() != null ? dependency.getClassifier().hashCode() : 0 );
|
||||
hash = hash * 31 + ( dependency.getScope() != null ? dependency.getScope().hashCode() : 0 );
|
||||
|
||||
for ( Exclusion exclusion : dependency.getExclusions() )
|
||||
{
|
||||
hash = hash * 31 + exclusion.getGroupId().hashCode();
|
||||
hash = hash * 31 + exclusion.getArtifactId().hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
private static boolean extensionEquals( Plugin a, Plugin b )
|
||||
{
|
||||
return eq( a.getGroupId(), b.getGroupId() ) //
|
||||
&& eq( a.getArtifactId(), b.getArtifactId() ) //
|
||||
&& eq( a.getVersion(), b.getVersion() ) //
|
||||
&& a.isExtensions() == b.isExtensions() //
|
||||
&& dependenciesEquals( a.getDependencies(), b.getDependencies() );
|
||||
}
|
||||
|
||||
private static boolean dependenciesEquals( List<Dependency> a, List<Dependency> b )
|
||||
{
|
||||
if ( a.size() != b.size() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Iterator<Dependency> aI = a.iterator();
|
||||
Iterator<Dependency> bI = b.iterator();
|
||||
|
||||
while ( aI.hasNext() )
|
||||
{
|
||||
Dependency aD = aI.next();
|
||||
Dependency bD = bI.next();
|
||||
|
||||
boolean r = eq( aD.getGroupId(), bD.getGroupId() ) //
|
||||
&& eq( aD.getArtifactId(), bD.getArtifactId() ) //
|
||||
&& eq( aD.getVersion(), bD.getVersion() ) //
|
||||
&& eq( aD.getType(), bD.getType() ) //
|
||||
&& eq( aD.getClassifier(), bD.getClassifier() ) //
|
||||
&& eq( aD.getScope(), bD.getScope() );
|
||||
|
||||
r &= exclusionsEquals( aD.getExclusions(), bD.getExclusions() );
|
||||
|
||||
if ( !r )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean exclusionsEquals( List<Exclusion> a, List<Exclusion> b )
|
||||
{
|
||||
if ( a.size() != b.size() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Iterator<Exclusion> aI = a.iterator();
|
||||
Iterator<Exclusion> bI = b.iterator();
|
||||
|
||||
while ( aI.hasNext() )
|
||||
{
|
||||
Exclusion aD = aI.next();
|
||||
Exclusion bD = bI.next();
|
||||
|
||||
boolean r = eq( aD.getGroupId(), bD.getGroupId() ) //
|
||||
&& eq( aD.getArtifactId(), bD.getArtifactId() );
|
||||
|
||||
if ( !r )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static <T> boolean eq( T s1, T s2 )
|
||||
{
|
||||
return s1 != null ? s1.equals( s2 ) : s2 == null;
|
||||
}
|
||||
|
||||
public void register( MavenProject project, ClassRealm extensionRealm )
|
||||
{
|
||||
// default cache does not track extension usage
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package org.apache.maven.plugin;
|
||||
|
||||
/*
|
||||
* 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.Artifact;
|
||||
import org.apache.maven.artifact.repository.RepositoryRequest;
|
||||
import org.apache.maven.model.Plugin;
|
||||
import org.apache.maven.project.ExtensionDescriptor;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.codehaus.plexus.classworlds.realm.ClassRealm;
|
||||
|
||||
/**
|
||||
* Caches extension class realms. <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 Igor Fedorenko
|
||||
* @author Benjamin Bentmann
|
||||
*/
|
||||
public interface ExtensionRealmCache
|
||||
{
|
||||
|
||||
public static class CacheRecord
|
||||
{
|
||||
|
||||
public final ClassRealm realm;
|
||||
|
||||
public final List<Artifact> artifacts;
|
||||
|
||||
public final ExtensionDescriptor desciptor;
|
||||
|
||||
public CacheRecord( ClassRealm realm, List<Artifact> artifacts, ExtensionDescriptor descriptor )
|
||||
{
|
||||
this.realm = realm;
|
||||
this.artifacts = artifacts;
|
||||
this.desciptor = descriptor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CacheRecord get( Plugin extension, RepositoryRequest repositoryRequest );
|
||||
|
||||
void put( Plugin extension, RepositoryRequest repositoryRequest, ClassRealm extensionRealm,
|
||||
List<Artifact> extensionArtifacts, ExtensionDescriptor extensionDescriptor );
|
||||
|
||||
void flush();
|
||||
|
||||
/**
|
||||
* Registers the specified extension realm for usage with the given project. Integrators can use the information
|
||||
* collected from this method in combination with a custom cache implementation to dispose unused extension realms
|
||||
* from the cache.
|
||||
*
|
||||
* @param project The project that employs the extension realm, must not be {@code null}.
|
||||
* @param extensionRealm The extension realm being used for the project, must not be {@code null}.
|
||||
*/
|
||||
void register( MavenProject project, ClassRealm extensionRealm );
|
||||
|
||||
}
|
|
@ -27,6 +27,7 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -42,6 +43,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.artifact.resolver.filter.AndArtifactFilter;
|
||||
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
|
||||
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
|
||||
import org.apache.maven.classrealm.ClassRealmManager;
|
||||
|
@ -339,13 +341,16 @@ public class DefaultMavenPluginManager
|
|||
throw new IllegalArgumentException( "incomplete plugin descriptor, plugin artifact missing" );
|
||||
}
|
||||
|
||||
MavenProject project = session.getCurrentProject();
|
||||
|
||||
RepositoryRequest request = new DefaultRepositoryRequest();
|
||||
request.setLocalRepository( session.getLocalRepository() );
|
||||
request.setRemoteRepositories( session.getCurrentProject().getPluginArtifactRepositories() );
|
||||
request.setRemoteRepositories( project.getPluginArtifactRepositories() );
|
||||
request.setCache( session.getRepositoryCache() );
|
||||
request.setOffline( session.isOffline() );
|
||||
|
||||
List<Artifact> pluginArtifacts = resolvePluginArtifacts( plugin, pluginArtifact, request );
|
||||
List<Artifact> pluginArtifacts =
|
||||
resolvePluginArtifacts( plugin, pluginArtifact, request, project.getExtensionArtifactFilter() );
|
||||
|
||||
ClassRealm pluginRealm = classRealmManager.createPluginRealm( plugin, parent, imports );
|
||||
|
||||
|
@ -417,7 +422,8 @@ public class DefaultMavenPluginManager
|
|||
*/
|
||||
// FIXME: only exposed to allow workaround for MNG-4194
|
||||
protected List<Artifact> resolvePluginArtifacts( Plugin plugin, Artifact pluginArtifact,
|
||||
RepositoryRequest repositoryRequest )
|
||||
RepositoryRequest repositoryRequest,
|
||||
ArtifactFilter extensionArtifactFilter )
|
||||
throws PluginResolutionException
|
||||
{
|
||||
Set<Artifact> overrideArtifacts = new LinkedHashSet<Artifact>();
|
||||
|
@ -430,6 +436,11 @@ public class DefaultMavenPluginManager
|
|||
|
||||
ArtifactFilter resolutionFilter = artifactFilterManager.getCoreArtifactFilter();
|
||||
|
||||
if ( extensionArtifactFilter != null )
|
||||
{
|
||||
resolutionFilter = new AndArtifactFilter( Arrays.asList( resolutionFilter, extensionArtifactFilter ) );
|
||||
}
|
||||
|
||||
ArtifactResolutionRequest request = new ArtifactResolutionRequest( repositoryRequest );
|
||||
request.setArtifact( pluginArtifact );
|
||||
request.setArtifactDependencies( overrideArtifacts );
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.apache.maven.artifact.repository.ArtifactRepository;
|
|||
import org.apache.maven.artifact.repository.DefaultRepositoryRequest;
|
||||
import org.apache.maven.artifact.repository.RepositoryRequest;
|
||||
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
|
||||
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
|
||||
import org.apache.maven.model.Model;
|
||||
import org.apache.maven.model.building.AbstractModelBuildingListener;
|
||||
import org.apache.maven.model.building.ModelBuildingEvent;
|
||||
|
@ -46,6 +47,8 @@ class DefaultModelBuildingListener
|
|||
|
||||
private ClassRealm projectRealm;
|
||||
|
||||
private ArtifactFilter extensionArtifactFilter;
|
||||
|
||||
private List<ArtifactRepository> remoteRepositories;
|
||||
|
||||
private List<ArtifactRepository> pluginRepositories;
|
||||
|
@ -78,6 +81,16 @@ class DefaultModelBuildingListener
|
|||
return projectRealm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the artifact filter to exclude extension artifacts from plugin realms.
|
||||
*
|
||||
* @return The extension artifact filter or {@code null} if none.
|
||||
*/
|
||||
public ArtifactFilter getExtentionArtifactFilter()
|
||||
{
|
||||
return extensionArtifactFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the effective remote artifact repositories for the project. The repository list is created from the
|
||||
* repositories given by {@link ProjectBuildingRequest#getRemoteRepositories()} and the repositories given in the
|
||||
|
@ -111,17 +124,6 @@ class DefaultModelBuildingListener
|
|||
{
|
||||
Model model = event.getModel();
|
||||
|
||||
try
|
||||
{
|
||||
remoteRepositories =
|
||||
projectBuildingHelper.createArtifactRepositories( model.getRepositories(), remoteRepositories,
|
||||
projectBuildingRequest );
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
event.getProblems().addError( "Invalid artifact repository: " + e.getMessage(), e );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
pluginRepositories =
|
||||
|
@ -143,7 +145,11 @@ class DefaultModelBuildingListener
|
|||
repositoryRequest.setRemoteRepositories( pluginRepositories );
|
||||
repositoryRequest.setOffline( projectBuildingRequest.isOffline() );
|
||||
|
||||
projectRealm = projectBuildingHelper.createProjectRealm( model, repositoryRequest );
|
||||
ProjectRealmCache.CacheRecord record =
|
||||
projectBuildingHelper.createProjectRealm( model, repositoryRequest );
|
||||
|
||||
projectRealm = record.realm;
|
||||
extensionArtifactFilter = record.extensionArtifactFilter;
|
||||
}
|
||||
catch ( ArtifactResolutionException e )
|
||||
{
|
||||
|
@ -164,6 +170,18 @@ class DefaultModelBuildingListener
|
|||
Thread.currentThread().setContextClassLoader( projectRealm );
|
||||
}
|
||||
}
|
||||
|
||||
// build the regular repos after extensions are loaded to allow for custom layouts
|
||||
try
|
||||
{
|
||||
remoteRepositories =
|
||||
projectBuildingHelper.createArtifactRepositories( model.getRepositories(), remoteRepositories,
|
||||
projectBuildingRequest );
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
event.getProblems().addError( "Invalid artifact repository: " + e.getMessage(), e );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -486,6 +486,7 @@ public class DefaultProjectBuilder
|
|||
project.setPluginArtifactRepositories( listener.getPluginRepositories() );
|
||||
|
||||
project.setClassRealm( listener.getProjectRealm() );
|
||||
project.setExtensionArtifactFilter( listener.getExtentionArtifactFilter() );
|
||||
|
||||
Build build = project.getBuild();
|
||||
project.addScriptSourceRoot( build.getScriptSourceDirectory() );
|
||||
|
|
|
@ -19,10 +19,14 @@ package org.apache.maven.project;
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.maven.ArtifactFilterManager;
|
||||
|
@ -35,6 +39,8 @@ 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.artifact.resolver.filter.ArtifactFilter;
|
||||
import org.apache.maven.artifact.resolver.filter.ExclusionSetFilter;
|
||||
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
|
||||
import org.apache.maven.classrealm.ClassRealmManager;
|
||||
import org.apache.maven.model.Build;
|
||||
import org.apache.maven.model.Dependency;
|
||||
|
@ -42,6 +48,7 @@ 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.plugin.ExtensionRealmCache;
|
||||
import org.apache.maven.plugin.version.DefaultPluginVersionRequest;
|
||||
import org.apache.maven.plugin.version.PluginVersionRequest;
|
||||
import org.apache.maven.plugin.version.PluginVersionResolutionException;
|
||||
|
@ -74,6 +81,12 @@ public class DefaultProjectBuildingHelper
|
|||
@Requirement
|
||||
private ClassRealmManager classRealmManager;
|
||||
|
||||
@Requirement
|
||||
private ExtensionRealmCache extensionRealmCache;
|
||||
|
||||
@Requirement
|
||||
private ProjectRealmCache projectRealmCache;
|
||||
|
||||
@Requirement
|
||||
private RepositorySystem repositorySystem;
|
||||
|
||||
|
@ -86,6 +99,8 @@ public class DefaultProjectBuildingHelper
|
|||
@Requirement
|
||||
private PluginVersionResolver pluginVersionResolver;
|
||||
|
||||
private ExtensionDescriptorBuilder extensionDescriptorBuilder = new ExtensionDescriptorBuilder();
|
||||
|
||||
public List<ArtifactRepository> createArtifactRepositories( List<Repository> pomRepositories,
|
||||
List<ArtifactRepository> externalRepositories,
|
||||
ProjectBuildingRequest request )
|
||||
|
@ -114,52 +129,49 @@ public class DefaultProjectBuildingHelper
|
|||
return artifactRepositories;
|
||||
}
|
||||
|
||||
public ClassRealm createProjectRealm( Model model, RepositoryRequest repositoryRequest )
|
||||
public synchronized ProjectRealmCache.CacheRecord createProjectRealm( Model model,
|
||||
RepositoryRequest repositoryRequest )
|
||||
throws ArtifactResolutionException, PluginVersionResolutionException
|
||||
{
|
||||
ClassRealm projectRealm = null;
|
||||
|
||||
Build build = model.getBuild();
|
||||
|
||||
if ( build == null )
|
||||
{
|
||||
return projectRealm;
|
||||
}
|
||||
|
||||
List<Plugin> extensionPlugins = new ArrayList<Plugin>();
|
||||
|
||||
for ( Plugin plugin : build.getPlugins() )
|
||||
Build build = model.getBuild();
|
||||
|
||||
if ( build != null )
|
||||
{
|
||||
if ( plugin.isExtensions() )
|
||||
for ( Extension extension : build.getExtensions() )
|
||||
{
|
||||
Plugin plugin = new Plugin();
|
||||
plugin.setGroupId( extension.getGroupId() );
|
||||
plugin.setArtifactId( extension.getArtifactId() );
|
||||
plugin.setVersion( extension.getVersion() );
|
||||
extensionPlugins.add( plugin );
|
||||
}
|
||||
}
|
||||
|
||||
if ( build.getExtensions().isEmpty() && extensionPlugins.isEmpty() )
|
||||
{
|
||||
return projectRealm;
|
||||
}
|
||||
|
||||
projectRealm = classRealmManager.createProjectRealm( model );
|
||||
|
||||
for ( Extension extension : build.getExtensions() )
|
||||
{
|
||||
if ( extension.getVersion() == null )
|
||||
for ( Plugin plugin : build.getPlugins() )
|
||||
{
|
||||
PluginVersionRequest versionRequest = new DefaultPluginVersionRequest( repositoryRequest );
|
||||
versionRequest.setGroupId( extension.getGroupId() );
|
||||
versionRequest.setArtifactId( extension.getArtifactId() );
|
||||
extension.setVersion( pluginVersionResolver.resolve( versionRequest ).getVersion() );
|
||||
if ( plugin.isExtensions() )
|
||||
{
|
||||
extensionPlugins.add( plugin );
|
||||
}
|
||||
}
|
||||
|
||||
Artifact artifact =
|
||||
repositorySystem.createArtifact( extension.getGroupId(), extension.getArtifactId(),
|
||||
extension.getVersion(), "jar" );
|
||||
|
||||
populateRealm( projectRealm, artifact, null, repositoryRequest );
|
||||
}
|
||||
|
||||
if ( extensionPlugins.isEmpty() )
|
||||
{
|
||||
return new ProjectRealmCache.CacheRecord( null, null );
|
||||
}
|
||||
|
||||
List<ClassRealm> extensionRealms = new ArrayList<ClassRealm>();
|
||||
|
||||
Map<ClassRealm, List<String>> exportedPackages = new HashMap<ClassRealm, List<String>>();
|
||||
|
||||
Map<ClassRealm, List<String>> exportedArtifacts = new HashMap<ClassRealm, List<String>>();
|
||||
|
||||
List<Artifact> publicArtifacts = new ArrayList<Artifact>();
|
||||
|
||||
for ( Plugin plugin : extensionPlugins )
|
||||
{
|
||||
if ( plugin.getVersion() == null )
|
||||
|
@ -168,73 +180,206 @@ public class DefaultProjectBuildingHelper
|
|||
plugin.setVersion( pluginVersionResolver.resolve( versionRequest ).getVersion() );
|
||||
}
|
||||
|
||||
Artifact artifact = repositorySystem.createPluginArtifact( plugin );
|
||||
ClassRealm extensionRealm;
|
||||
List<Artifact> artifacts;
|
||||
ExtensionDescriptor extensionDescriptor = null;
|
||||
|
||||
Set<Artifact> dependencies = new LinkedHashSet<Artifact>();
|
||||
for ( Dependency dependency : plugin.getDependencies() )
|
||||
ExtensionRealmCache.CacheRecord record = extensionRealmCache.get( plugin, repositoryRequest );
|
||||
|
||||
if ( record != null )
|
||||
{
|
||||
dependencies.add( repositorySystem.createDependencyArtifact( dependency ) );
|
||||
extensionRealm = record.realm;
|
||||
artifacts = record.artifacts;
|
||||
extensionDescriptor = record.desciptor;
|
||||
}
|
||||
else
|
||||
{
|
||||
artifacts = resolveExtensionArtifacts( plugin, repositoryRequest );
|
||||
|
||||
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() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
container.discoverComponents( extensionRealm );
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
throw new IllegalStateException( "Failed to discover components in extension realm "
|
||||
+ extensionRealm.getId(), e );
|
||||
}
|
||||
|
||||
Artifact extensionArtifact = artifacts.get( 0 );
|
||||
try
|
||||
{
|
||||
extensionDescriptor = extensionDescriptorBuilder.build( extensionArtifact.getFile() );
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
String message = "Invalid extension descriptor for " + plugin.getId() + ": " + e.getMessage();
|
||||
if ( logger.isDebugEnabled() )
|
||||
{
|
||||
logger.error( message, e );
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.error( message );
|
||||
}
|
||||
}
|
||||
|
||||
extensionRealmCache.put( plugin, repositoryRequest, extensionRealm, artifacts, extensionDescriptor );
|
||||
}
|
||||
|
||||
populateRealm( projectRealm, artifact, dependencies, repositoryRequest );
|
||||
extensionRealms.add( extensionRealm );
|
||||
if ( extensionDescriptor != null )
|
||||
{
|
||||
exportedPackages.put( extensionRealm, extensionDescriptor.getExportedPackages() );
|
||||
exportedArtifacts.put( extensionRealm, extensionDescriptor.getExportedArtifacts() );
|
||||
}
|
||||
|
||||
if ( !plugin.isExtensions() && artifacts.size() == 1 && artifacts.get( 0 ).getFile() != null )
|
||||
{
|
||||
/*
|
||||
* This is purely for backward-compat with 2.x where <extensions> consisting of a single artifact where
|
||||
* loaded into the core and hence available to plugins, in contrast to bigger extensions that were
|
||||
* loaded into a dedicated realm which is invisible to plugins.
|
||||
*/
|
||||
publicArtifacts.addAll( artifacts );
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
ProjectRealmCache.CacheRecord record = projectRealmCache.get( extensionRealms );
|
||||
|
||||
if ( record == null )
|
||||
{
|
||||
container.discoverComponents( projectRealm );
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
throw new IllegalStateException( "Failed to discover components in project realm " + projectRealm.getId(),
|
||||
e );
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> exclusions = new LinkedHashSet<String>();
|
||||
|
||||
for ( ClassRealm extensionRealm : extensionRealms )
|
||||
{
|
||||
List<String> excludes = exportedArtifacts.get( extensionRealm );
|
||||
|
||||
if ( excludes != null )
|
||||
{
|
||||
exclusions.addAll( excludes );
|
||||
}
|
||||
|
||||
List<String> exports = exportedPackages.get( extensionRealm );
|
||||
|
||||
if ( exports == null || exports.isEmpty() )
|
||||
{
|
||||
/*
|
||||
* Most existing extensions don't define exported packages, i.e. no classes are to be exposed to
|
||||
* plugins, yet the components provided by the extension (e.g. artifact handlers) must be
|
||||
* accessible, i.e. we still must import the extension realm into the project realm.
|
||||
*/
|
||||
exports = Arrays.asList( extensionRealm.getId() );
|
||||
}
|
||||
|
||||
for ( String export : exports )
|
||||
{
|
||||
projectRealm.importFrom( extensionRealm, export );
|
||||
}
|
||||
}
|
||||
|
||||
ArtifactFilter extensionArtifactFilter = null;
|
||||
if ( !exclusions.isEmpty() )
|
||||
{
|
||||
extensionArtifactFilter = new ExclusionSetFilter( exclusions );
|
||||
}
|
||||
|
||||
projectRealmCache.put( extensionRealms, projectRealm, extensionArtifactFilter );
|
||||
|
||||
record = new ProjectRealmCache.CacheRecord( projectRealm, extensionArtifactFilter );
|
||||
}
|
||||
|
||||
return projectRealm;
|
||||
return record;
|
||||
}
|
||||
|
||||
private void populateRealm( ClassRealm realm, Artifact artifact, Set<Artifact> dependencies,
|
||||
RepositoryRequest repositoryRequest )
|
||||
private List<Artifact> resolveExtensionArtifacts( Plugin extensionPlugin, RepositoryRequest repositoryRequest )
|
||||
throws ArtifactResolutionException
|
||||
{
|
||||
Artifact extensionArtifact = repositorySystem.createPluginArtifact( extensionPlugin );
|
||||
|
||||
Set<Artifact> overrideArtifacts = new LinkedHashSet<Artifact>();
|
||||
for ( Dependency dependency : extensionPlugin.getDependencies() )
|
||||
{
|
||||
overrideArtifacts.add( repositorySystem.createDependencyArtifact( dependency ) );
|
||||
}
|
||||
|
||||
ArtifactFilter collectionFilter = new ScopeArtifactFilter( Artifact.SCOPE_RUNTIME_PLUS_SYSTEM );
|
||||
|
||||
ArtifactFilter resolutionFilter = artifactFilterManager.getCoreArtifactFilter();
|
||||
|
||||
ArtifactResolutionRequest request = new ArtifactResolutionRequest( repositoryRequest );
|
||||
request.setArtifact( artifact );
|
||||
request.setArtifactDependencies( dependencies );
|
||||
request.setArtifact( extensionArtifact );
|
||||
request.setArtifactDependencies( overrideArtifacts );
|
||||
request.setCollectionFilter( collectionFilter );
|
||||
request.setResolutionFilter( resolutionFilter );
|
||||
request.setResolveRoot( true );
|
||||
request.setResolveTransitively( true );
|
||||
// FIXME setTransferListener
|
||||
|
||||
ArtifactResolutionResult result = repositorySystem.resolve( request );
|
||||
|
||||
resolutionErrorHandler.throwErrors( request, result );
|
||||
|
||||
ArtifactFilter filter = artifactFilterManager.getCoreArtifactFilter();
|
||||
List<Artifact> extensionArtifacts = new ArrayList<Artifact>( result.getArtifacts() );
|
||||
|
||||
for ( Artifact resultArtifact : result.getArtifacts() )
|
||||
{
|
||||
if ( filter.include( resultArtifact ) )
|
||||
{
|
||||
if ( logger.isDebugEnabled() )
|
||||
{
|
||||
logger.debug( " Included: " + resultArtifact.getId() );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
realm.addURL( resultArtifact.getFile().toURI().toURL() );
|
||||
}
|
||||
catch ( MalformedURLException e )
|
||||
{
|
||||
throw new IllegalStateException( "Failed to populate project realm " + realm.getId() + " with "
|
||||
+ artifact.getFile(), e );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( logger.isDebugEnabled() )
|
||||
{
|
||||
logger.debug( " Excluded: " + resultArtifact.getId() );
|
||||
}
|
||||
}
|
||||
}
|
||||
return extensionArtifacts;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
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.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
|
||||
import org.codehaus.plexus.classworlds.realm.ClassRealm;
|
||||
import org.codehaus.plexus.component.annotations.Component;
|
||||
|
||||
/**
|
||||
* Default project realm cache implementation. Assumes cached data does not change.
|
||||
*/
|
||||
@Component( role = ProjectRealmCache.class )
|
||||
public class DefaultProjectRealmCache
|
||||
implements ProjectRealmCache
|
||||
{
|
||||
|
||||
private static class CacheKey
|
||||
{
|
||||
|
||||
private final List<? extends ClassRealm> extensionRealms;
|
||||
|
||||
private final int hashCode;
|
||||
|
||||
public CacheKey( List<? extends ClassRealm> extensionRealms )
|
||||
{
|
||||
this.extensionRealms = ( extensionRealms != null ) ? extensionRealms : Collections.<ClassRealm> emptyList();
|
||||
|
||||
this.hashCode = this.extensionRealms.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals( Object o )
|
||||
{
|
||||
if ( o == this )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( !( o instanceof CacheKey ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CacheKey other = (CacheKey) o;
|
||||
|
||||
return extensionRealms.equals( other.extensionRealms );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final Map<CacheKey, CacheRecord> cache = new HashMap<CacheKey, CacheRecord>();
|
||||
|
||||
public CacheRecord get( List<? extends ClassRealm> extensionRealms )
|
||||
{
|
||||
return cache.get( new CacheKey( extensionRealms ) );
|
||||
}
|
||||
|
||||
public void put( List<? extends ClassRealm> extensionRealms, ClassRealm projectRealm,
|
||||
ArtifactFilter extensionArtifactFilter )
|
||||
{
|
||||
if ( projectRealm == null )
|
||||
{
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
CacheKey key = new CacheKey( extensionRealms );
|
||||
|
||||
if ( cache.containsKey( key ) )
|
||||
{
|
||||
throw new IllegalStateException( "Duplicate project realm for extensions " + extensionRealms );
|
||||
}
|
||||
|
||||
CacheRecord record = new CacheRecord( projectRealm, extensionArtifactFilter );
|
||||
cache.put( key, record );
|
||||
}
|
||||
|
||||
public void flush()
|
||||
{
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
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;
|
||||
|
||||
/**
|
||||
* Provides metadata about a build extension. <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 class can be changed or deleted
|
||||
* without prior notice.
|
||||
*
|
||||
* @author Benjamin Bentmann
|
||||
*/
|
||||
public class ExtensionDescriptor
|
||||
{
|
||||
|
||||
private List<String> exportedPackages;
|
||||
|
||||
private List<String> exportedArtifacts;
|
||||
|
||||
ExtensionDescriptor()
|
||||
{
|
||||
// hide constructor
|
||||
}
|
||||
|
||||
public List<String> getExportedPackages()
|
||||
{
|
||||
if ( exportedPackages == null )
|
||||
{
|
||||
exportedPackages = new ArrayList<String>();
|
||||
}
|
||||
|
||||
return exportedPackages;
|
||||
}
|
||||
|
||||
public void setExportedPackages( List<String> exportedPackages )
|
||||
{
|
||||
if ( exportedPackages == null )
|
||||
{
|
||||
this.exportedPackages = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.exportedPackages = new ArrayList<String>( exportedPackages );
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getExportedArtifacts()
|
||||
{
|
||||
if ( exportedArtifacts == null )
|
||||
{
|
||||
exportedArtifacts = new ArrayList<String>();
|
||||
}
|
||||
|
||||
return exportedArtifacts;
|
||||
}
|
||||
|
||||
public void setExportedArtifacts( List<String> exportedArtifacts )
|
||||
{
|
||||
if ( exportedArtifacts == null )
|
||||
{
|
||||
this.exportedArtifacts = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.exportedArtifacts = new ArrayList<String>( exportedArtifacts );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
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.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
import org.codehaus.plexus.util.IOUtil;
|
||||
import org.codehaus.plexus.util.ReaderFactory;
|
||||
import org.codehaus.plexus.util.xml.Xpp3Dom;
|
||||
import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
|
||||
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
|
||||
|
||||
/**
|
||||
* Creates an extension descriptor from some XML stream.
|
||||
*
|
||||
* @author Benjamin Bentmann
|
||||
*/
|
||||
class ExtensionDescriptorBuilder
|
||||
{
|
||||
|
||||
private String getExtensionDescriptorLocation()
|
||||
{
|
||||
return "META-INF/maven/extension.xml";
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the extension descriptor (if any) from the specified JAR file.
|
||||
*
|
||||
* @param extensionJar The JAR file or directory to extract the descriptor from, must not be {@code null}.
|
||||
* @return The extracted descriptor or {@code null} if no descriptor was found.
|
||||
* @throws IOException If the descriptor is present but could not be parsed.
|
||||
*/
|
||||
public ExtensionDescriptor build( File extensionJar )
|
||||
throws IOException
|
||||
{
|
||||
ExtensionDescriptor extensionDescriptor = null;
|
||||
|
||||
if ( extensionJar.isFile() )
|
||||
{
|
||||
JarFile pluginJar = new JarFile( extensionJar, false );
|
||||
try
|
||||
{
|
||||
ZipEntry pluginDescriptorEntry = pluginJar.getEntry( getExtensionDescriptorLocation() );
|
||||
|
||||
if ( pluginDescriptorEntry != null )
|
||||
{
|
||||
InputStream is = pluginJar.getInputStream( pluginDescriptorEntry );
|
||||
|
||||
extensionDescriptor = build( is );
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
pluginJar.close();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
File pluginXml = new File( extensionJar, getExtensionDescriptorLocation() );
|
||||
|
||||
if ( pluginXml.canRead() )
|
||||
{
|
||||
InputStream is = new BufferedInputStream( new FileInputStream( pluginXml ) );
|
||||
try
|
||||
{
|
||||
extensionDescriptor = build( is );
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtil.close( is );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return extensionDescriptor;
|
||||
}
|
||||
|
||||
ExtensionDescriptor build( InputStream is )
|
||||
throws IOException
|
||||
{
|
||||
ExtensionDescriptor extensionDescriptor = new ExtensionDescriptor();
|
||||
|
||||
Xpp3Dom dom;
|
||||
try
|
||||
{
|
||||
dom = Xpp3DomBuilder.build( ReaderFactory.newXmlReader( is ) );
|
||||
}
|
||||
catch ( XmlPullParserException e )
|
||||
{
|
||||
throw (IOException) new IOException( e.getMessage() ).initCause( e );
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtil.close( is );
|
||||
}
|
||||
|
||||
if ( !"extension".equals( dom.getName() ) )
|
||||
{
|
||||
throw new IOException( "Unexpected root element \"" + dom.getName() + "\", expected \"extension\"" );
|
||||
}
|
||||
|
||||
extensionDescriptor.setExportedPackages( parseStrings( dom.getChild( "exportedPackages" ) ) );
|
||||
|
||||
extensionDescriptor.setExportedArtifacts( parseStrings( dom.getChild( "exportedArtifacts" ) ) );
|
||||
|
||||
return extensionDescriptor;
|
||||
}
|
||||
|
||||
private List<String> parseStrings( Xpp3Dom dom )
|
||||
{
|
||||
List<String> strings = null;
|
||||
|
||||
if ( dom != null )
|
||||
{
|
||||
strings = new ArrayList<String>();
|
||||
|
||||
for ( Xpp3Dom child : dom.getChildren() )
|
||||
{
|
||||
String string = child.getValue();
|
||||
if ( string != null )
|
||||
{
|
||||
string = string.trim();
|
||||
if ( string.length() > 0 )
|
||||
{
|
||||
strings.add( string );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return strings;
|
||||
}
|
||||
|
||||
}
|
|
@ -167,6 +167,8 @@ public class MavenProject
|
|||
|
||||
private ClassRealm classRealm;
|
||||
|
||||
private ArtifactFilter extensionArtifactFilter;
|
||||
|
||||
//
|
||||
|
||||
public MavenProject()
|
||||
|
@ -1948,7 +1950,9 @@ public class MavenProject
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the project's class realm.
|
||||
* Sets the project's class realm. <strong>Warning:</strong> This is an internal utility method that is only public
|
||||
* for technical reasons, it is not part of the public API. In particular, this method can be changed or deleted
|
||||
* without prior notice and must not be used by plugins.
|
||||
*
|
||||
* @param classRealm The class realm hosting the build extensions of this project, may be {@code null}.
|
||||
*/
|
||||
|
@ -1959,6 +1963,9 @@ public class MavenProject
|
|||
|
||||
/**
|
||||
* Gets the project's class realm. This class realm hosts the build extensions of the project.
|
||||
* <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
|
||||
* part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
|
||||
* used by plugins.
|
||||
*
|
||||
* @return The project's class realm or {@code null}.
|
||||
*/
|
||||
|
@ -1967,4 +1974,28 @@ public class MavenProject
|
|||
return classRealm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the artifact filter used to exclude shared extension artifacts from plugin realms. <strong>Warning:</strong>
|
||||
* This is an internal utility method that is only public for technical reasons, it is not part of the public API.
|
||||
* In particular, this method can be changed or deleted without prior notice and must not be used by plugins.
|
||||
*
|
||||
* @param extensionArtifactFilter The artifact filter to apply to plugins, may be {@code null}.
|
||||
*/
|
||||
public void setExtensionArtifactFilter( ArtifactFilter extensionArtifactFilter )
|
||||
{
|
||||
this.extensionArtifactFilter = extensionArtifactFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the artifact filter used to exclude shared extension artifacts from plugin realms. <strong>Warning:</strong>
|
||||
* This is an internal utility method that is only public for technical reasons, it is not part of the public API.
|
||||
* In particular, this method can be changed or deleted without prior notice and must not be used by plugins.
|
||||
*
|
||||
* @return The artifact filter or {@code null}.
|
||||
*/
|
||||
public ArtifactFilter getExtensionArtifactFilter()
|
||||
{
|
||||
return extensionArtifactFilter;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ import org.apache.maven.artifact.resolver.ArtifactResolutionException;
|
|||
import org.apache.maven.model.Model;
|
||||
import org.apache.maven.model.Repository;
|
||||
import org.apache.maven.plugin.version.PluginVersionResolutionException;
|
||||
import org.codehaus.plexus.classworlds.realm.ClassRealm;
|
||||
|
||||
/**
|
||||
* Assists the project builder. <strong>Warning:</strong> This is an internal utility interface that is only public for
|
||||
|
@ -61,10 +60,10 @@ public interface ProjectBuildingHelper
|
|||
*
|
||||
* @param model The model to create the project realm for, must not be {@code null}
|
||||
* @param repositoryRequest The repository request to use for artifact resolution, must not be {@code null}.
|
||||
* @return The project realm or {@code null} if the project uses no extensions.
|
||||
* @return The record with the project realm and extension artifact filter, never {@code null}.
|
||||
* @throws ArtifactResolutionException If any build extension could not be resolved.
|
||||
*/
|
||||
ClassRealm createProjectRealm( Model model, RepositoryRequest repositoryRequest )
|
||||
ProjectRealmCache.CacheRecord createProjectRealm( Model model, RepositoryRequest repositoryRequest )
|
||||
throws ArtifactResolutionException, PluginVersionResolutionException;
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
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.resolver.filter.ArtifactFilter;
|
||||
import org.codehaus.plexus.classworlds.realm.ClassRealm;
|
||||
|
||||
/**
|
||||
* Caches project class realms. <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 Igor Fedorenko
|
||||
* @author Benjamin Bentmann
|
||||
*/
|
||||
public interface ProjectRealmCache
|
||||
{
|
||||
|
||||
public static class CacheRecord
|
||||
{
|
||||
|
||||
public final ClassRealm realm;
|
||||
|
||||
public final ArtifactFilter extensionArtifactFilter;
|
||||
|
||||
public CacheRecord( ClassRealm realm, ArtifactFilter extensionArtifactFilter )
|
||||
{
|
||||
this.realm = realm;
|
||||
this.extensionArtifactFilter = extensionArtifactFilter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CacheRecord get( List<? extends ClassRealm> extensionRealms );
|
||||
|
||||
void put( List<? extends ClassRealm> extensionRealms, ClassRealm projectRealm,
|
||||
ArtifactFilter extensionArtifactFilter );
|
||||
|
||||
void flush();
|
||||
|
||||
}
|
|
@ -28,7 +28,6 @@ import org.apache.maven.artifact.repository.RepositoryRequest;
|
|||
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;
|
||||
|
||||
/**
|
||||
|
@ -56,10 +55,10 @@ public class EmptyProjectBuildingHelper
|
|||
}
|
||||
}
|
||||
|
||||
public ClassRealm createProjectRealm( Model model, RepositoryRequest repositoryRequest )
|
||||
public ProjectRealmCache.CacheRecord createProjectRealm( Model model, RepositoryRequest repositoryRequest )
|
||||
throws ArtifactResolutionException
|
||||
{
|
||||
return null;
|
||||
return new ProjectRealmCache.CacheRecord( null, null );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
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.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Tests {@link ExtensionDescriptorBuilder}.
|
||||
*
|
||||
* @author Benjamin Bentmann
|
||||
*/
|
||||
public class ExtensionDescriptorBuilderTest
|
||||
extends TestCase
|
||||
{
|
||||
|
||||
private ExtensionDescriptorBuilder builder;
|
||||
|
||||
@Override
|
||||
protected void setUp()
|
||||
throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
builder = new ExtensionDescriptorBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown()
|
||||
throws Exception
|
||||
{
|
||||
builder = null;
|
||||
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
private InputStream toStream( String xml )
|
||||
{
|
||||
try
|
||||
{
|
||||
return new ByteArrayInputStream( xml.getBytes( "UTF-8" ) );
|
||||
}
|
||||
catch ( UnsupportedEncodingException e )
|
||||
{
|
||||
throw new IllegalStateException( e );
|
||||
}
|
||||
}
|
||||
|
||||
public void testEmptyDescriptor()
|
||||
throws Exception
|
||||
{
|
||||
String xml = "<extension></extension>";
|
||||
|
||||
ExtensionDescriptor ed = builder.build( toStream( xml ) );
|
||||
|
||||
assertNotNull( ed );
|
||||
assertNotNull( ed.getExportedPackages() );
|
||||
assertTrue( ed.getExportedPackages().isEmpty() );
|
||||
assertNotNull( ed.getExportedArtifacts() );
|
||||
assertTrue( ed.getExportedArtifacts().isEmpty() );
|
||||
}
|
||||
|
||||
public void testCompleteDescriptor()
|
||||
throws Exception
|
||||
{
|
||||
String xml =
|
||||
"<?xml version='1.0' encoding='UTF-8'?>" + "<extension>" + "<exportedPackages>"
|
||||
+ "<exportedPackage>a</exportedPackage>" + "<exportedPackage>b</exportedPackage>"
|
||||
+ "<exportedPackage>c</exportedPackage>" + "</exportedPackages>" + "<exportedArtifacts>"
|
||||
+ "<exportedArtifact>x</exportedArtifact>" + "<exportedArtifact>y</exportedArtifact>"
|
||||
+ "<exportedArtifact> z </exportedArtifact>" + "</exportedArtifacts>" + "</extension>";
|
||||
|
||||
ExtensionDescriptor ed = builder.build( toStream( xml ) );
|
||||
|
||||
assertNotNull( ed );
|
||||
assertEquals( Arrays.asList( "a", "b", "c" ), ed.getExportedPackages() );
|
||||
assertEquals( Arrays.asList( "x", "y", "z" ), ed.getExportedArtifacts() );
|
||||
}
|
||||
|
||||
}
|
12
pom.xml
12
pom.xml
|
@ -38,11 +38,11 @@
|
|||
<inceptionYear>2001</inceptionYear>
|
||||
|
||||
<properties>
|
||||
<classWorldsVersion>2.1.0</classWorldsVersion>
|
||||
<classWorldsVersion>2.2.0-SNAPSHOT</classWorldsVersion>
|
||||
<commonsCliVersion>1.2</commonsCliVersion>
|
||||
<easyMockVersion>1.2_Java1.3</easyMockVersion>
|
||||
<junitVersion>3.8.2</junitVersion>
|
||||
<plexusVersion>1.2.1</plexusVersion>
|
||||
<plexusVersion>1.3.0-SNAPSHOT</plexusVersion>
|
||||
<plexusInterpolationVersion>1.11</plexusInterpolationVersion>
|
||||
<plexusPluginManagerVersion>1.0-alpha-1</plexusPluginManagerVersion>
|
||||
<plexusUtilsVersion>2.0.0</plexusUtilsVersion>
|
||||
|
@ -158,6 +158,14 @@
|
|||
</site>
|
||||
</distributionManagement>
|
||||
|
||||
<!-- FIXME: Remove once snapshots have been released -->
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>sonatype.public</id>
|
||||
<url>http://repository.sonatype.org/content/groups/public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<!--bootstrap-start-comment-->
|
||||
<dependencyManagement>
|
||||
<!--bootstrap-end-comment-->
|
||||
|
|
Loading…
Reference in New Issue