View Javadoc
1   package org.apache.maven.cli.internal;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
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.Set;
27  
28  import javax.inject.Inject;
29  import javax.inject.Named;
30  
31  import org.apache.maven.RepositoryUtils;
32  import org.apache.maven.cli.internal.extension.model.CoreExtension;
33  import org.apache.maven.execution.MavenExecutionRequest;
34  import org.apache.maven.extension.internal.CoreExtensionEntry;
35  import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory;
36  import org.apache.maven.model.Plugin;
37  import org.apache.maven.plugin.PluginResolutionException;
38  import org.apache.maven.plugin.internal.DefaultPluginDependenciesResolver;
39  import org.codehaus.plexus.DefaultPlexusContainer;
40  import org.codehaus.plexus.PlexusContainer;
41  import org.codehaus.plexus.classworlds.ClassWorld;
42  import org.codehaus.plexus.classworlds.realm.ClassRealm;
43  import org.codehaus.plexus.interpolation.InterpolationException;
44  import org.codehaus.plexus.interpolation.Interpolator;
45  import org.codehaus.plexus.interpolation.MapBasedValueSource;
46  import org.codehaus.plexus.interpolation.StringSearchInterpolator;
47  import org.codehaus.plexus.logging.Logger;
48  import org.eclipse.aether.RepositorySystemSession;
49  import org.eclipse.aether.artifact.Artifact;
50  import org.eclipse.aether.graph.DependencyFilter;
51  import org.eclipse.aether.graph.DependencyNode;
52  import org.eclipse.aether.repository.RemoteRepository;
53  import org.eclipse.aether.util.filter.ExclusionsDependencyFilter;
54  import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator;
55  
56  /**
57   * BootstrapCoreExtensionManager
58   */
59  @Named
60  public class BootstrapCoreExtensionManager
61  {
62      private final Logger log;
63  
64      private final DefaultPluginDependenciesResolver pluginDependenciesResolver;
65  
66      private final DefaultRepositorySystemSessionFactory repositorySystemSessionFactory;
67  
68      private final ClassWorld classWorld;
69  
70      private final ClassRealm parentRealm;
71  
72      @Inject
73      public BootstrapCoreExtensionManager( Logger log, DefaultPluginDependenciesResolver pluginDependenciesResolver,
74                                            DefaultRepositorySystemSessionFactory repositorySystemSessionFactory,
75                                            PlexusContainer container )
76      {
77          this.log = log;
78          this.pluginDependenciesResolver = pluginDependenciesResolver;
79          this.repositorySystemSessionFactory = repositorySystemSessionFactory;
80          this.classWorld = ( (DefaultPlexusContainer) container ).getClassWorld();
81          this.parentRealm = container.getContainerRealm();
82      }
83  
84      public List<CoreExtensionEntry> loadCoreExtensions( MavenExecutionRequest request, Set<String> providedArtifacts,
85                                                          List<CoreExtension> extensions )
86          throws Exception
87      {
88          RepositorySystemSession repoSession = repositorySystemSessionFactory.newRepositorySession( request );
89          List<RemoteRepository> repositories = RepositoryUtils.toRepos( request.getPluginArtifactRepositories() );
90          Interpolator interpolator = createInterpolator( request );
91  
92          return resolveCoreExtensions( repoSession, repositories, providedArtifacts, extensions, interpolator );
93      }
94  
95      private List<CoreExtensionEntry> resolveCoreExtensions( RepositorySystemSession repoSession,
96                                                              List<RemoteRepository> repositories,
97                                                              Set<String> providedArtifacts,
98                                                              List<CoreExtension> configuration,
99                                                              Interpolator interpolator )
100         throws Exception
101     {
102         List<CoreExtensionEntry> extensions = new ArrayList<>();
103 
104         DependencyFilter dependencyFilter = new ExclusionsDependencyFilter( providedArtifacts );
105 
106         for ( CoreExtension extension : configuration )
107         {
108             List<Artifact> artifacts = resolveExtension( extension, repoSession, repositories,
109                                                          dependencyFilter, interpolator );
110             if ( !artifacts.isEmpty() )
111             {
112                 extensions.add( createExtension( extension, artifacts ) );
113             }
114         }
115 
116         return Collections.unmodifiableList( extensions );
117     }
118 
119     private CoreExtensionEntry createExtension( CoreExtension extension, List<Artifact> artifacts )
120         throws Exception
121     {
122         String realmId =
123             "coreExtension>" + extension.getGroupId() + ":" + extension.getArtifactId() + ":" + extension.getVersion();
124         ClassRealm realm = classWorld.newRealm( realmId, null );
125         log.debug( "Populating class realm " + realm.getId() );
126         realm.setParentRealm( parentRealm );
127         for ( Artifact artifact : artifacts )
128         {
129             File file = artifact.getFile();
130             log.debug( "  Included " + file );
131             realm.addURL( file.toURI().toURL() );
132         }
133         return CoreExtensionEntry.discoverFrom( realm, Collections.singleton( artifacts.get( 0 ).getFile() ) );
134     }
135 
136     private List<Artifact> resolveExtension( CoreExtension extension, RepositorySystemSession repoSession,
137                                              List<RemoteRepository> repositories, DependencyFilter dependencyFilter,
138                                              Interpolator interpolator )
139         throws ExtensionResolutionException
140     {
141         try
142         {
143             /* TODO: Enhance the PluginDependenciesResolver to provide a
144              * resolveCoreExtension method which uses a CoreExtension
145              * object instead of a Plugin as this makes no sense.
146              */
147             Plugin plugin = new Plugin();
148             plugin.setGroupId( interpolator.interpolate( extension.getGroupId() ) );
149             plugin.setArtifactId( interpolator.interpolate( extension.getArtifactId() ) );
150             plugin.setVersion( interpolator.interpolate( extension.getVersion() ) );
151 
152             DependencyNode root = pluginDependenciesResolver
153                     .resolveCoreExtension( plugin, dependencyFilter, repositories, repoSession );
154             PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
155             root.accept( nlg );
156             List<Artifact> artifacts = nlg.getArtifacts( false );
157 
158             return artifacts;
159         }
160         catch ( PluginResolutionException e )
161         {
162             throw new ExtensionResolutionException( extension, e.getCause() );
163         }
164         catch ( InterpolationException e )
165         {
166             throw new ExtensionResolutionException( extension, e );
167         }
168     }
169 
170     private static Interpolator createInterpolator( MavenExecutionRequest request )
171     {
172         StringSearchInterpolator interpolator = new StringSearchInterpolator();
173         interpolator.addValueSource( new MapBasedValueSource( request.getUserProperties() ) );
174         interpolator.addValueSource( new MapBasedValueSource( request.getSystemProperties() ) );
175         return interpolator;
176     }
177 
178 }