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   * @author Jason van Zyl
53   */
54  public class MavenSession implements Cloneable {
55      private MavenExecutionRequest request;
56  
57      private MavenExecutionResult result;
58  
59      private RepositorySystemSession repositorySession;
60  
61      private Properties executionProperties;
62  
63      private ThreadLocal<MavenProject> currentProject = new ThreadLocal<>();
64  
65      /**
66       * These projects have already been topologically sorted in the {@link org.apache.maven.Maven} component before
67       * being passed into the session. This is also the potentially constrained set of projects by using --projects
68       * on the command line.
69       */
70      private List<MavenProject> projects;
71  
72      /**
73       * The full set of projects before any potential constraining by --projects. Useful in the case where you want to
74       * build a smaller set of projects but perform other operations in the context of your reactor.
75       */
76      private List<MavenProject> allProjects;
77  
78      private MavenProject topLevelProject;
79  
80      private ProjectDependencyGraph projectDependencyGraph;
81  
82      private boolean parallel;
83  
84      /**
85       * Plugin context keyed by project ({@link MavenProject#getId()}) and by plugin lookup key
86       * ({@link PluginDescriptor#getPluginLookupKey()}). Plugin contexts itself are mappings of {@link String} keys to
87       * {@link Object} values.
88       */
89      @SuppressWarnings("checkstyle:linelength")
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 repositorySession;
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 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     @Deprecated
299     public MavenSession(
300             PlexusContainer container,
301             RepositorySystemSession repositorySession,
302             MavenExecutionRequest request,
303             MavenExecutionResult result) {
304         this.container = container;
305         this.request = request;
306         this.result = result;
307         this.settings = adaptSettings(request);
308         this.repositorySession = repositorySession;
309     }
310 
311     @Deprecated
312     public MavenSession(
313             PlexusContainer container,
314             MavenExecutionRequest request,
315             MavenExecutionResult result,
316             MavenProject project) {
317         this(container, request, result, Arrays.asList(new MavenProject[] {project}));
318     }
319 
320     @Deprecated
321     @SuppressWarnings("checkstyle:parameternumber")
322     public MavenSession(
323             PlexusContainer container,
324             Settings settings,
325             ArtifactRepository localRepository,
326             EventDispatcher eventDispatcher,
327             ReactorManager unused,
328             List<String> goals,
329             String executionRootDir,
330             Properties executionProperties,
331             Date startTime) {
332         this(
333                 container,
334                 settings,
335                 localRepository,
336                 eventDispatcher,
337                 unused,
338                 goals,
339                 executionRootDir,
340                 executionProperties,
341                 null,
342                 startTime);
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             Properties userProperties,
357             Date startTime) {
358         this.container = container;
359         this.settings = settings;
360         this.executionProperties = executionProperties;
361         this.request = new DefaultMavenExecutionRequest();
362         this.request.setUserProperties(userProperties);
363         this.request.setLocalRepository(localRepository);
364         this.request.setGoals(goals);
365         this.request.setBaseDirectory((executionRootDir != null) ? new File(executionRootDir) : null);
366         this.request.setStartTime(startTime);
367     }
368 
369     @Deprecated
370     public MavenSession(
371             PlexusContainer container,
372             MavenExecutionRequest request,
373             MavenExecutionResult result,
374             List<MavenProject> projects) {
375         this.container = container;
376         this.request = request;
377         this.result = result;
378         this.settings = adaptSettings(request);
379         setProjects(projects);
380     }
381 
382     /**
383      * Adapt a {@link MavenExecutionRequest} to a {@link Settings} object for use in the Maven core.
384      * We want to make sure that what is ask for in the execution request overrides what is in the settings.
385      * The CLI feeds into an execution request so if a particular value is present in the execution request
386      * then we will take that over the value coming from the user settings.
387      */
388     private static Settings adaptSettings(MavenExecutionRequest request) {
389         File localRepo = request.getLocalRepositoryPath();
390         return new Settings(org.apache.maven.api.settings.Settings.newBuilder()
391                 .localRepository(localRepo != null ? localRepo.getAbsolutePath() : null)
392                 .interactiveMode(request.isInteractiveMode())
393                 .offline(request.isOffline())
394                 .proxies(request.getProxies().stream().map(Proxy::getDelegate).collect(Collectors.toList()))
395                 .servers(request.getServers().stream().map(Server::getDelegate).collect(Collectors.toList()))
396                 .mirrors(request.getMirrors().stream().map(Mirror::getDelegate).collect(Collectors.toList()))
397                 .profiles(request.getProfiles().stream()
398                         .map(Profile::getDelegate)
399                         .map(SettingsUtilsV4::convertToSettingsProfile)
400                         .collect(Collectors.toList()))
401                 .activeProfiles(request.getActiveProfiles())
402                 .pluginGroups(request.getPluginGroups())
403                 .build());
404     }
405 
406     @Deprecated
407     public List<MavenProject> getSortedProjects() {
408         return getProjects();
409     }
410 
411     @Deprecated
412     //
413     // Used by Tycho and will break users and force them to upgrade to Maven 3.1 so we should really leave
414     // this here, possibly indefinitely.
415     //
416     public RepositoryCache getRepositoryCache() {
417         return null;
418     }
419 
420     @Deprecated
421     public EventDispatcher getEventDispatcher() {
422         return null;
423     }
424 
425     @Deprecated
426     public boolean isUsingPOMsFromFilesystem() {
427         return request.isProjectPresent();
428     }
429 
430     /**
431      * @deprecated Use either {@link #getUserProperties()} or {@link #getSystemProperties()}.
432      */
433     @Deprecated
434     public Properties getExecutionProperties() {
435         if (executionProperties == null) {
436             executionProperties = new Properties();
437             executionProperties.putAll(request.getSystemProperties());
438             executionProperties.putAll(request.getUserProperties());
439         }
440 
441         return executionProperties;
442     }
443 
444     @Deprecated
445     public PlexusContainer getContainer() {
446         return container;
447     }
448 
449     @Deprecated
450     public Object lookup(String role) throws ComponentLookupException {
451         return container.lookup(role);
452     }
453 
454     @Deprecated
455     public Object lookup(String role, String roleHint) throws ComponentLookupException {
456         return container.lookup(role, roleHint);
457     }
458 
459     @Deprecated
460     public List<Object> lookupList(String role) throws ComponentLookupException {
461         return container.lookupList(role);
462     }
463 
464     @Deprecated
465     public Map<String, Object> lookupMap(String role) throws ComponentLookupException {
466         return container.lookupMap(role);
467     }
468 
469     public Session getSession() {
470         return session;
471     }
472 
473     public void setSession(Session session) {
474         this.session = session;
475     }
476     /*end[MAVEN4]*/
477 }