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