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