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