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