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.time.Instant;
24  import java.util.Arrays;
25  import java.util.Date;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Properties;
29  import java.util.concurrent.ConcurrentHashMap;
30  import java.util.concurrent.ConcurrentMap;
31  import java.util.stream.Collectors;
32  
33  import org.apache.maven.api.Session;
34  import org.apache.maven.artifact.repository.ArtifactRepository;
35  import org.apache.maven.artifact.repository.RepositoryCache;
36  import org.apache.maven.internal.impl.SettingsUtilsV4;
37  import org.apache.maven.model.Profile;
38  import org.apache.maven.monitor.event.EventDispatcher;
39  import org.apache.maven.plugin.descriptor.PluginDescriptor;
40  import org.apache.maven.project.MavenProject;
41  import org.apache.maven.project.ProjectBuildingRequest;
42  import org.apache.maven.settings.Mirror;
43  import org.apache.maven.settings.Proxy;
44  import org.apache.maven.settings.Server;
45  import org.apache.maven.settings.Settings;
46  import org.codehaus.plexus.PlexusContainer;
47  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
48  import org.eclipse.aether.RepositorySystemSession;
49  
50  import static java.util.Objects.requireNonNull;
51  
52  /**
53   * A Maven execution session.
54   *
55   */
56  public class MavenSession implements Cloneable {
57      private final MavenExecutionRequest request;
58  
59      private final MavenExecutionResult result;
60  
61      private final RepositorySystemSession repositorySystemSession;
62  
63      private final Properties executionProperties;
64  
65      private ThreadLocal<MavenProject> currentProject = new ThreadLocal<>();
66  
67      /**
68       * These projects have already been topologically sorted in the {@link org.apache.maven.Maven} component before
69       * being passed into the session. This is also the potentially constrained set of projects by using --projects
70       * on the command line.
71       */
72      private List<MavenProject> projects;
73  
74      /**
75       * The full set of projects before any potential constraining by --projects. Useful in the case where you want to
76       * build a smaller set of projects but perform other operations in the context of your reactor.
77       */
78      private List<MavenProject> allProjects;
79  
80      private MavenProject topLevelProject;
81  
82      private ProjectDependencyGraph projectDependencyGraph;
83  
84      private boolean parallel;
85  
86      /**
87       * Plugin context keyed by project ({@link MavenProject#getId()}) and by plugin lookup key
88       * ({@link PluginDescriptor#getPluginLookupKey()}). Plugin contexts itself are mappings of {@link String} keys to
89       * {@link Object} values.
90       */
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     @Deprecated
250     public Date getStartTime() {
251         return request.getStartTime();
252     }
253 
254     public Instant getStartInstant() {
255         return request.getStartInstant();
256     }
257 
258     public boolean isParallel() {
259         return parallel;
260     }
261 
262     public void setParallel(boolean parallel) {
263         this.parallel = parallel;
264     }
265 
266     public RepositorySystemSession getRepositorySession() {
267         return repositorySystemSession;
268     }
269 
270     private Map<String, MavenProject> projectMap;
271 
272     public void setProjectMap(Map<String, MavenProject> projectMap) {
273         this.projectMap = projectMap;
274     }
275 
276     /** This is a provisional method and may be removed */
277     public List<MavenProject> getAllProjects() {
278         return allProjects;
279     }
280 
281     /** This is a provisional method and may be removed */
282     public void setAllProjects(List<MavenProject> allProjects) {
283         this.allProjects = allProjects;
284     }
285 
286     /*if_not[MAVEN4]*/
287 
288     //
289     // Deprecated
290     //
291 
292     private final PlexusContainer container;
293 
294     private final Settings settings;
295 
296     private Session session;
297 
298     @Deprecated
299     /** @deprecated This appears not to be used anywhere within Maven itself. */
300     public Map<String, MavenProject> getProjectMap() {
301         return projectMap;
302     }
303 
304     public MavenSession(
305             RepositorySystemSession repositorySystemSession,
306             MavenExecutionRequest request,
307             MavenExecutionResult result) {
308         this.container = null;
309         this.request = requireNonNull(request);
310         this.result = requireNonNull(result);
311         this.settings = adaptSettings(request);
312         this.repositorySystemSession = requireNonNull(repositorySystemSession);
313         Properties executionProperties = new Properties();
314         executionProperties.putAll(request.getSystemProperties());
315         executionProperties.putAll(request.getUserProperties());
316         this.executionProperties = executionProperties;
317     }
318 
319     @Deprecated
320     public MavenSession(
321             PlexusContainer container,
322             RepositorySystemSession repositorySession,
323             MavenExecutionRequest request,
324             MavenExecutionResult result) {
325         this.container = container;
326         this.request = request;
327         this.result = result;
328         this.settings = adaptSettings(request);
329         this.repositorySystemSession = repositorySession;
330         Properties executionProperties = new Properties();
331         executionProperties.putAll(request.getSystemProperties());
332         executionProperties.putAll(request.getUserProperties());
333         this.executionProperties = executionProperties;
334     }
335 
336     @Deprecated
337     public MavenSession(
338             PlexusContainer container,
339             MavenExecutionRequest request,
340             MavenExecutionResult result,
341             MavenProject project) {
342         this(container, request, result, Arrays.asList(new MavenProject[] {project}));
343     }
344 
345     @Deprecated
346     @SuppressWarnings("checkstyle:parameternumber")
347     public MavenSession(
348             PlexusContainer container,
349             Settings settings,
350             ArtifactRepository localRepository,
351             EventDispatcher eventDispatcher,
352             ReactorManager unused,
353             List<String> goals,
354             String executionRootDir,
355             Properties executionProperties,
356             Date startTime) {
357         this(
358                 container,
359                 settings,
360                 localRepository,
361                 eventDispatcher,
362                 unused,
363                 goals,
364                 executionRootDir,
365                 executionProperties,
366                 null,
367                 startTime);
368     }
369 
370     @Deprecated
371     @SuppressWarnings("checkstyle:parameternumber")
372     public MavenSession(
373             PlexusContainer container,
374             Settings settings,
375             ArtifactRepository localRepository,
376             EventDispatcher eventDispatcher,
377             ReactorManager unused,
378             List<String> goals,
379             String executionRootDir,
380             Properties executionProperties,
381             Properties userProperties,
382             Date startTime) {
383         this.container = container;
384         this.settings = settings;
385         this.executionProperties = executionProperties;
386         this.request = new DefaultMavenExecutionRequest();
387         this.request.setUserProperties(userProperties);
388         this.request.setLocalRepository(localRepository);
389         this.request.setGoals(goals);
390         this.request.setBaseDirectory((executionRootDir != null) ? new File(executionRootDir) : null);
391         this.request.setStartTime(startTime);
392         this.result = null;
393         this.repositorySystemSession = null;
394     }
395 
396     @Deprecated
397     public MavenSession(
398             PlexusContainer container,
399             MavenExecutionRequest request,
400             MavenExecutionResult result,
401             List<MavenProject> projects) {
402         this.container = container;
403         this.request = request;
404         this.result = result;
405         this.settings = adaptSettings(request);
406         Properties executionProperties = new Properties();
407         executionProperties.putAll(request.getSystemProperties());
408         executionProperties.putAll(request.getUserProperties());
409         this.executionProperties = executionProperties;
410         setProjects(projects);
411         this.repositorySystemSession = null;
412     }
413 
414     /**
415      * Adapt a {@link MavenExecutionRequest} to a {@link Settings} object for use in the Maven core.
416      * We want to make sure that what is ask for in the execution request overrides what is in the settings.
417      * The CLI feeds into an execution request so if a particular value is present in the execution request
418      * then we will take that over the value coming from the user settings.
419      */
420     private static Settings adaptSettings(MavenExecutionRequest request) {
421         File localRepo = request.getLocalRepositoryPath();
422         return new Settings(org.apache.maven.api.settings.Settings.newBuilder()
423                 .localRepository(localRepo != null ? localRepo.getAbsolutePath() : null)
424                 .interactiveMode(request.isInteractiveMode())
425                 .offline(request.isOffline())
426                 .proxies(request.getProxies().stream().map(Proxy::getDelegate).collect(Collectors.toList()))
427                 .servers(request.getServers().stream().map(Server::getDelegate).collect(Collectors.toList()))
428                 .mirrors(request.getMirrors().stream().map(Mirror::getDelegate).collect(Collectors.toList()))
429                 .profiles(request.getProfiles().stream()
430                         .map(Profile::getDelegate)
431                         .map(SettingsUtilsV4::convertToSettingsProfile)
432                         .collect(Collectors.toList()))
433                 .activeProfiles(request.getActiveProfiles())
434                 .pluginGroups(request.getPluginGroups())
435                 .build());
436     }
437 
438     @Deprecated
439     public List<MavenProject> getSortedProjects() {
440         return getProjects();
441     }
442 
443     @Deprecated
444     //
445     // Used by Tycho and will break users and force them to upgrade to Maven 3.1 so we should really leave
446     // this here, possibly indefinitely.
447     //
448     public RepositoryCache getRepositoryCache() {
449         return null;
450     }
451 
452     @Deprecated
453     public EventDispatcher getEventDispatcher() {
454         return null;
455     }
456 
457     @Deprecated
458     public boolean isUsingPOMsFromFilesystem() {
459         return request.isProjectPresent();
460     }
461 
462     /**
463      * @deprecated Use either {@link #getUserProperties()} or {@link #getSystemProperties()}.
464      */
465     @Deprecated
466     public Properties getExecutionProperties() {
467         return executionProperties;
468     }
469 
470     @Deprecated
471     public PlexusContainer getContainer() {
472         return container;
473     }
474 
475     @Deprecated
476     public Object lookup(String role) throws ComponentLookupException {
477         return container.lookup(role);
478     }
479 
480     @Deprecated
481     public Object lookup(String role, String roleHint) throws ComponentLookupException {
482         return container.lookup(role, roleHint);
483     }
484 
485     @Deprecated
486     public List<Object> lookupList(String role) throws ComponentLookupException {
487         return container.lookupList(role);
488     }
489 
490     @Deprecated
491     public Map<String, Object> lookupMap(String role) throws ComponentLookupException {
492         return container.lookupMap(role);
493     }
494 
495     public Session getSession() {
496         return session;
497     }
498 
499     public void setSession(Session session) {
500         this.session = session;
501     }
502     /*end[MAVEN4]*/
503 }