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