View Javadoc
1   package org.apache.maven.execution;
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.Arrays;
24  import java.util.Date;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Properties;
28  import java.util.concurrent.ConcurrentHashMap;
29  import java.util.concurrent.ConcurrentMap;
30  import java.util.stream.Collectors;
31  
32  import org.apache.maven.api.Session;
33  import org.apache.maven.artifact.repository.ArtifactRepository;
34  import org.apache.maven.artifact.repository.RepositoryCache;
35  import org.apache.maven.monitor.event.EventDispatcher;
36  import org.apache.maven.plugin.descriptor.PluginDescriptor;
37  import org.apache.maven.project.MavenProject;
38  import org.apache.maven.project.ProjectBuildingRequest;
39  import org.apache.maven.settings.Mirror;
40  import org.apache.maven.settings.Proxy;
41  import org.apache.maven.settings.Server;
42  import org.apache.maven.settings.Settings;
43  import org.apache.maven.settings.SettingsUtils;
44  import org.codehaus.plexus.PlexusContainer;
45  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
46  import org.eclipse.aether.RepositorySystemSession;
47  
48  /**
49   * A Maven execution session.
50   *
51   * @author Jason van Zyl
52   */
53  public class MavenSession
54      implements Cloneable
55  {
56      private MavenExecutionRequest request;
57  
58      private MavenExecutionResult result;
59  
60      private RepositorySystemSession repositorySession;
61  
62      private Properties executionProperties;
63  
64      private ThreadLocal<MavenProject> currentProject = new ThreadLocal<>();
65  
66      /**
67       * These projects have already been topologically sorted in the {@link org.apache.maven.Maven} component before
68       * being passed into the session. This is also the potentially constrained set of projects by using --projects
69       * on the command line.
70       */
71      private List<MavenProject> projects;
72  
73      /**
74       * The full set of projects before any potential constraining by --projects. Useful in the case where you want to
75       * build a smaller set of projects but perform other operations in the context of your reactor.
76       */
77      private List<MavenProject> allProjects;
78  
79      private MavenProject topLevelProject;
80  
81      private ProjectDependencyGraph projectDependencyGraph;
82  
83      private boolean parallel;
84  
85      /**
86       * Plugin context keyed by project ({@link MavenProject#getId()}) and by plugin lookup key
87       * ({@link PluginDescriptor#getPluginLookupKey()}). Plugin contexts itself are mappings of {@link String} keys to
88       * {@link Object} values.
89       */
90      @SuppressWarnings( "checkstyle:linelength" )
91      private final ConcurrentMap<String, ConcurrentMap<String, ConcurrentMap<String, Object>>> pluginContextsByProjectAndPluginKey =
92          new ConcurrentHashMap<>();
93  
94  
95      public void setProjects( List<MavenProject> projects )
96      {
97          if ( !projects.isEmpty() )
98          {
99              MavenProject first = projects.get( 0 );
100             this.currentProject = ThreadLocal.withInitial( () -> first );
101             this.topLevelProject =
102                     projects.stream().filter( project -> project.isExecutionRoot() ).findFirst()
103                             .orElse( first );
104         }
105         else
106         {
107             this.currentProject = new ThreadLocal<>();
108             this.topLevelProject = null;
109         }
110         this.projects = projects;
111     }
112 
113     public ArtifactRepository getLocalRepository()
114     {
115         return request.getLocalRepository();
116     }
117 
118     public List<String> getGoals()
119     {
120         return request.getGoals();
121     }
122 
123     /**
124      * Gets the user properties to use for interpolation and profile activation. The user properties have been
125      * configured directly by the user on his discretion, e.g. via the {@code -Dkey=value} parameter on the command
126      * line.
127      *
128      * @return The user properties, never {@code null}.
129      */
130     public Properties getUserProperties()
131     {
132         return request.getUserProperties();
133     }
134 
135     /**
136      * Gets the system properties to use for interpolation and profile activation. The system properties are collected
137      * from the runtime environment like {@link System#getProperties()} and environment variables.
138      *
139      * @return The system properties, never {@code null}.
140      */
141     public Properties getSystemProperties()
142     {
143         return request.getSystemProperties();
144     }
145 
146     public Settings getSettings()
147     {
148         return settings;
149     }
150 
151     public List<MavenProject> getProjects()
152     {
153         return projects;
154     }
155 
156     public String getExecutionRootDirectory()
157     {
158         return request.getBaseDirectory();
159     }
160 
161     public MavenExecutionRequest getRequest()
162     {
163         return request;
164     }
165 
166     public void setCurrentProject( MavenProject currentProject )
167     {
168         this.currentProject.set( currentProject );
169     }
170 
171     public MavenProject getCurrentProject()
172     {
173         return currentProject.get();
174     }
175 
176     public ProjectBuildingRequest getProjectBuildingRequest()
177     {
178         return request.getProjectBuildingRequest().setRepositorySession( getRepositorySession() );
179     }
180 
181     public List<String> getPluginGroups()
182     {
183         return request.getPluginGroups();
184     }
185 
186     public boolean isOffline()
187     {
188         return request.isOffline();
189     }
190 
191     public MavenProject getTopLevelProject()
192     {
193         return topLevelProject;
194     }
195 
196     public MavenExecutionResult getResult()
197     {
198         return result;
199     }
200 
201     // Backward compat
202 
203 
204     /**
205      * Returns the plugin context for given key ({@link PluginDescriptor#getPluginLookupKey()} and
206      * {@link MavenProject}, never returns {@code null} as if context not present, creates it.
207      *
208      * <strong>Implementation note:</strong> while this method return type is {@link Map}, the returned map instance
209      * implements {@link ConcurrentMap} as well.
210      *
211      */
212     public Map<String, Object> getPluginContext( PluginDescriptor plugin, MavenProject project )
213     {
214         String projectKey = project.getId();
215 
216         ConcurrentMap<String, ConcurrentMap<String, Object>> pluginContextsByKey = pluginContextsByProjectAndPluginKey
217                 .computeIfAbsent( projectKey, k -> new ConcurrentHashMap<>() );
218 
219         String pluginKey = plugin.getPluginLookupKey();
220 
221         return pluginContextsByKey.computeIfAbsent( pluginKey, k -> new ConcurrentHashMap<>() );
222     }
223 
224     public ProjectDependencyGraph getProjectDependencyGraph()
225     {
226         return projectDependencyGraph;
227     }
228 
229     public void setProjectDependencyGraph( ProjectDependencyGraph projectDependencyGraph )
230     {
231         this.projectDependencyGraph = projectDependencyGraph;
232     }
233 
234     public String getReactorFailureBehavior()
235     {
236         return request.getReactorFailureBehavior();
237     }
238 
239     @Override
240     public MavenSession clone()
241     {
242         try
243         {
244             MavenSession clone = (MavenSession) super.clone();
245             // the default must become the current project of the thread that clones this
246             MavenProject current = getCurrentProject();
247             // we replace the thread local of the clone to prevent write through and enforce the new default value
248             clone.currentProject = ThreadLocal.withInitial( () -> current );
249             return clone;
250         }
251         catch ( CloneNotSupportedException e )
252         {
253             throw new RuntimeException( "Bug", e );
254         }
255     }
256 
257     public Date getStartTime()
258     {
259         return request.getStartTime();
260     }
261 
262     public boolean isParallel()
263     {
264         return parallel;
265     }
266 
267     public void setParallel( boolean parallel )
268     {
269         this.parallel = parallel;
270     }
271 
272     public RepositorySystemSession getRepositorySession()
273     {
274         return repositorySession;
275     }
276 
277     private Map<String, MavenProject> projectMap;
278 
279     public void setProjectMap( Map<String, MavenProject> projectMap )
280     {
281         this.projectMap = projectMap;
282     }
283 
284     /** This is a provisional method and may be removed */
285     public List<MavenProject> getAllProjects()
286     {
287         return allProjects;
288     }
289 
290     /** This is a provisional method and may be removed */
291     public void setAllProjects( List<MavenProject> allProjects )
292     {
293         this.allProjects = allProjects;
294     }
295 
296     /*if_not[MAVEN4]*/
297 
298     //
299     // Deprecated
300     //
301 
302     private PlexusContainer container;
303 
304     private final Settings settings;
305 
306     private Session session;
307 
308     @Deprecated
309     /** @deprecated This appears not to be used anywhere within Maven itself. */
310     public Map<String, MavenProject> getProjectMap()
311     {
312         return projectMap;
313     }
314 
315     @Deprecated
316     public MavenSession( PlexusContainer container, RepositorySystemSession repositorySession,
317                          MavenExecutionRequest request, MavenExecutionResult result )
318     {
319         this.container = container;
320         this.request = request;
321         this.result = result;
322         this.settings = adaptSettings( request );
323         this.repositorySession = repositorySession;
324     }
325 
326     @Deprecated
327     public MavenSession( PlexusContainer container, MavenExecutionRequest request, MavenExecutionResult result,
328                          MavenProject project )
329     {
330         this( container, request, result, Arrays.asList( new MavenProject[]{project} ) );
331     }
332 
333     @Deprecated
334     @SuppressWarnings( "checkstyle:parameternumber" )
335     public MavenSession( PlexusContainer container, Settings settings, ArtifactRepository localRepository,
336                          EventDispatcher eventDispatcher, ReactorManager unused, List<String> goals,
337                          String executionRootDir, Properties executionProperties, Date startTime )
338     {
339         this( container, settings, localRepository, eventDispatcher, unused, goals, executionRootDir,
340               executionProperties, null, startTime );
341     }
342 
343     @Deprecated
344     @SuppressWarnings( "checkstyle:parameternumber" )
345     public MavenSession( PlexusContainer container, Settings settings, ArtifactRepository localRepository,
346                          EventDispatcher eventDispatcher, ReactorManager unused, List<String> goals,
347                          String executionRootDir, Properties executionProperties, Properties userProperties,
348                          Date startTime )
349     {
350         this.container = container;
351         this.settings = settings;
352         this.executionProperties = executionProperties;
353         this.request = new DefaultMavenExecutionRequest();
354         this.request.setUserProperties( userProperties );
355         this.request.setLocalRepository( localRepository );
356         this.request.setGoals( goals );
357         this.request.setBaseDirectory( ( executionRootDir != null ) ? new File( executionRootDir ) : null );
358         this.request.setStartTime( startTime );
359     }
360 
361     @Deprecated
362     public MavenSession( PlexusContainer container, MavenExecutionRequest request, MavenExecutionResult result,
363                          List<MavenProject> projects )
364     {
365         this.container = container;
366         this.request = request;
367         this.result = result;
368         this.settings = adaptSettings( request );
369         setProjects( projects );
370     }
371 
372     /**
373      * Adapt a {@link MavenExecutionRequest} to a {@link Settings} object for use in the Maven core.
374      * We want to make sure that what is ask for in the execution request overrides what is in the settings.
375      * The CLI feeds into an execution request so if a particular value is present in the execution request
376      * then we will take that over the value coming from the user settings.
377      */
378     private static Settings adaptSettings( MavenExecutionRequest request )
379     {
380         File localRepo = request.getLocalRepositoryPath();
381         return new Settings( org.apache.maven.api.settings.Settings.newBuilder()
382                 .localRepository( localRepo != null ? localRepo.getAbsolutePath() : null )
383                 .interactiveMode( request.isInteractiveMode() )
384                 .offline( request.isOffline() )
385                 .proxies( request.getProxies().stream().map( Proxy::getDelegate ).collect( Collectors.toList() ) )
386                 .servers( request.getServers().stream().map( Server::getDelegate ).collect( Collectors.toList() ) )
387                 .mirrors( request.getMirrors().stream().map( Mirror::getDelegate ).collect( Collectors.toList() ) )
388                 .profiles( request.getProfiles().stream()
389                         .map( SettingsUtils::convertToSettingsProfile ).collect( Collectors.toList() ) )
390                 .activeProfiles( request.getActiveProfiles() )
391                 .pluginGroups( request.getPluginGroups() )
392                 .build() );
393     }
394 
395     @Deprecated
396     public List<MavenProject> getSortedProjects()
397     {
398         return getProjects();
399     }
400 
401     @Deprecated
402     //
403     // Used by Tycho and will break users and force them to upgrade to Maven 3.1 so we should really leave
404     // this here, possibly indefinitely.
405     //
406     public RepositoryCache getRepositoryCache()
407     {
408         return null;
409     }
410 
411     @Deprecated
412     public EventDispatcher getEventDispatcher()
413     {
414         return null;
415     }
416 
417     @Deprecated
418     public boolean isUsingPOMsFromFilesystem()
419     {
420         return request.isProjectPresent();
421     }
422 
423     /**
424      * @deprecated Use either {@link #getUserProperties()} or {@link #getSystemProperties()}.
425      */
426     @Deprecated
427     public Properties getExecutionProperties()
428     {
429         if ( executionProperties == null )
430         {
431             executionProperties = new Properties();
432             executionProperties.putAll( request.getSystemProperties() );
433             executionProperties.putAll( request.getUserProperties() );
434         }
435 
436         return executionProperties;
437     }
438 
439     @Deprecated
440     public PlexusContainer getContainer()
441     {
442         return container;
443     }
444 
445     @Deprecated
446     public Object lookup( String role )
447         throws ComponentLookupException
448     {
449         return container.lookup( role );
450     }
451 
452     @Deprecated
453     public Object lookup( String role, String roleHint )
454         throws ComponentLookupException
455     {
456         return container.lookup( role, roleHint );
457     }
458 
459     @Deprecated
460     public List<Object> lookupList( String role )
461         throws ComponentLookupException
462     {
463         return container.lookupList( role );
464     }
465 
466     @Deprecated
467     public Map<String, Object> lookupMap( String role )
468         throws ComponentLookupException
469     {
470         return container.lookupMap( role );
471     }
472 
473     public Session getSession()
474     {
475         return session;
476     }
477 
478     public void setSession( Session session )
479     {
480         this.session = session;
481     }
482     /*end[MAVEN4]*/
483 }