1 package org.apache.maven.cli.internal;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.List;
26 import java.util.Map.Entry;
27 import java.util.Set;
28
29 import javax.inject.Inject;
30 import javax.inject.Named;
31
32 import org.apache.maven.RepositoryUtils;
33 import org.apache.maven.cli.internal.extension.model.CoreExtension;
34 import org.apache.maven.execution.MavenExecutionRequest;
35 import org.apache.maven.extension.internal.CoreExports;
36 import org.apache.maven.extension.internal.CoreExtensionEntry;
37 import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory;
38 import org.apache.maven.model.Plugin;
39 import org.apache.maven.plugin.PluginResolutionException;
40 import org.apache.maven.plugin.internal.DefaultPluginDependenciesResolver;
41 import org.codehaus.plexus.DefaultPlexusContainer;
42 import org.codehaus.plexus.PlexusContainer;
43 import org.codehaus.plexus.classworlds.ClassWorld;
44 import org.codehaus.plexus.classworlds.realm.ClassRealm;
45 import org.codehaus.plexus.interpolation.InterpolationException;
46 import org.codehaus.plexus.interpolation.Interpolator;
47 import org.codehaus.plexus.interpolation.MapBasedValueSource;
48 import org.codehaus.plexus.interpolation.StringSearchInterpolator;
49 import org.codehaus.plexus.logging.Logger;
50 import org.eclipse.aether.RepositorySystemSession;
51 import org.eclipse.aether.artifact.Artifact;
52 import org.eclipse.aether.graph.DependencyFilter;
53 import org.eclipse.aether.graph.DependencyNode;
54 import org.eclipse.aether.repository.RemoteRepository;
55 import org.eclipse.aether.util.filter.ExclusionsDependencyFilter;
56 import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator;
57
58
59
60
61 @Named
62 public class BootstrapCoreExtensionManager
63 {
64 public static final String STRATEGY_PARENT_FIRST = "parent-first";
65 public static final String STRATEGY_PLUGIN = "plugin";
66 public static final String STRATEGY_SELF_FIRST = "self-first";
67
68 private final Logger log;
69
70 private final DefaultPluginDependenciesResolver pluginDependenciesResolver;
71
72 private final DefaultRepositorySystemSessionFactory repositorySystemSessionFactory;
73
74 private final CoreExports coreExports;
75
76 private final ClassWorld classWorld;
77
78 private final ClassRealm parentRealm;
79
80 @Inject
81 public BootstrapCoreExtensionManager( Logger log, DefaultPluginDependenciesResolver pluginDependenciesResolver,
82 DefaultRepositorySystemSessionFactory repositorySystemSessionFactory,
83 CoreExports coreExports,
84 PlexusContainer container )
85 {
86 this.log = log;
87 this.pluginDependenciesResolver = pluginDependenciesResolver;
88 this.repositorySystemSessionFactory = repositorySystemSessionFactory;
89 this.coreExports = coreExports;
90 this.classWorld = ( (DefaultPlexusContainer) container ).getClassWorld();
91 this.parentRealm = container.getContainerRealm();
92 }
93
94 public List<CoreExtensionEntry> loadCoreExtensions( MavenExecutionRequest request, Set<String> providedArtifacts,
95 List<CoreExtension> extensions )
96 throws Exception
97 {
98 RepositorySystemSession repoSession = repositorySystemSessionFactory.newRepositorySession( request );
99 List<RemoteRepository> repositories = RepositoryUtils.toRepos( request.getPluginArtifactRepositories() );
100 Interpolator interpolator = createInterpolator( request );
101
102 return resolveCoreExtensions( repoSession, repositories, providedArtifacts, extensions, interpolator );
103 }
104
105 private List<CoreExtensionEntry> resolveCoreExtensions( RepositorySystemSession repoSession,
106 List<RemoteRepository> repositories,
107 Set<String> providedArtifacts,
108 List<CoreExtension> configuration,
109 Interpolator interpolator )
110 throws Exception
111 {
112 List<CoreExtensionEntry> extensions = new ArrayList<>();
113
114 DependencyFilter dependencyFilter = new ExclusionsDependencyFilter( providedArtifacts );
115
116 for ( CoreExtension extension : configuration )
117 {
118 List<Artifact> artifacts = resolveExtension( extension, repoSession, repositories,
119 dependencyFilter, interpolator );
120 if ( !artifacts.isEmpty() )
121 {
122 extensions.add( createExtension( extension, artifacts ) );
123 }
124 }
125
126 return Collections.unmodifiableList( extensions );
127 }
128
129 private CoreExtensionEntry createExtension( CoreExtension extension, List<Artifact> artifacts )
130 throws Exception
131 {
132 String realmId =
133 "coreExtension>" + extension.getGroupId() + ":" + extension.getArtifactId() + ":" + extension.getVersion();
134 final ClassRealm realm = classWorld.newRealm( realmId, null );
135 Set<String> providedArtifacts = Collections.emptySet();
136 String classLoadingStrategy = extension.getClassLoadingStrategy();
137 if ( STRATEGY_PARENT_FIRST.equals( classLoadingStrategy ) )
138 {
139 realm.importFrom( parentRealm, "" );
140 }
141 else if ( STRATEGY_PLUGIN.equals( classLoadingStrategy ) )
142 {
143 for ( Entry<String, ClassLoader> entry : coreExports.getExportedPackages().entrySet() )
144 {
145 realm.importFrom( entry.getValue(), entry.getKey() );
146 }
147 providedArtifacts = coreExports.getExportedArtifacts();
148 }
149 else if ( STRATEGY_SELF_FIRST.equals( classLoadingStrategy ) )
150 {
151 realm.setParentRealm( parentRealm );
152 }
153 else
154 {
155 throw new IllegalArgumentException( "Unsupported class-loading strategy '"
156 + classLoadingStrategy + "'. Supported values are: " + STRATEGY_PARENT_FIRST
157 + ", " + STRATEGY_PLUGIN + " and " + STRATEGY_SELF_FIRST );
158 }
159 log.debug( "Populating class realm " + realm.getId() );
160 for ( Artifact artifact : artifacts )
161 {
162 String id = artifact.getGroupId() + ":" + artifact.getArtifactId();
163 if ( providedArtifacts.contains( id ) )
164 {
165 log.debug( " Excluded " + id );
166 }
167 else
168 {
169 File file = artifact.getFile();
170 log.debug( " Included " + id + " located at " + file );
171 realm.addURL( file.toURI().toURL() );
172 }
173 }
174 return CoreExtensionEntry.discoverFrom( realm, Collections.singleton( artifacts.get( 0 ).getFile() ) );
175 }
176
177 private List<Artifact> resolveExtension( CoreExtension extension, RepositorySystemSession repoSession,
178 List<RemoteRepository> repositories, DependencyFilter dependencyFilter,
179 Interpolator interpolator )
180 throws ExtensionResolutionException
181 {
182 try
183 {
184
185
186
187
188 Plugin plugin = new Plugin();
189 plugin.setGroupId( interpolator.interpolate( extension.getGroupId() ) );
190 plugin.setArtifactId( interpolator.interpolate( extension.getArtifactId() ) );
191 plugin.setVersion( interpolator.interpolate( extension.getVersion() ) );
192
193 DependencyNode root = pluginDependenciesResolver
194 .resolveCoreExtension( plugin, dependencyFilter, repositories, repoSession );
195 PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
196 root.accept( nlg );
197 List<Artifact> artifacts = nlg.getArtifacts( false );
198
199 return artifacts;
200 }
201 catch ( PluginResolutionException e )
202 {
203 throw new ExtensionResolutionException( extension, e.getCause() );
204 }
205 catch ( InterpolationException e )
206 {
207 throw new ExtensionResolutionException( extension, e );
208 }
209 }
210
211 private static Interpolator createInterpolator( MavenExecutionRequest request )
212 {
213 StringSearchInterpolator interpolator = new StringSearchInterpolator();
214 interpolator.addValueSource( new MapBasedValueSource( request.getUserProperties() ) );
215 interpolator.addValueSource( new MapBasedValueSource( request.getSystemProperties() ) );
216 return interpolator;
217 }
218
219 }