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.ArrayList;
24  import java.util.Arrays;
25  import java.util.Collections;
26  import java.util.Date;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Objects;
30  import java.util.Optional;
31  import java.util.Properties;
32  import java.util.concurrent.ConcurrentHashMap;
33  
34  import org.apache.maven.artifact.repository.ArtifactRepository;
35  import org.apache.maven.artifact.repository.RepositoryCache;
36  import org.apache.maven.model.building.ModelProblem;
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.Settings;
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      /**
61       * The current project set on a thread, {@link Optional#empty()} if it was set to {@code null}. Threads without a
62       * value use {@link #defaultProject}, so that reading the current project never stores a project in the thread.
63       */
64      private ThreadLocal<Optional<MavenProject>> currentProject = new ThreadLocal<>();
65  
66      private MavenProject defaultProject;
67  
68      /**
69       * These projects have already been topologically sorted in the {@link org.apache.maven.Maven} component before
70       * being passed into the session. This is also the potentially constrained set of projects by using --projects
71       * on the command line.
72       */
73      private List<MavenProject> projects;
74  
75      /**
76       * The full set of projects before any potential constraining by --projects. Useful in the case where you want to
77       * build a smaller set of projects but perform other operations in the context of your reactor.
78       */
79      private List<MavenProject> allProjects;
80  
81      private MavenProject topLevelProject;
82  
83      private ProjectDependencyGraph projectDependencyGraph;
84  
85      private boolean parallel;
86  
87      private List<ModelProblem> modelProblems = Collections.emptyList();
88  
89      private final Map<String, Map<String, Map<String, Object>>> pluginContextsByProjectAndPluginKey =
90              new ConcurrentHashMap<>();
91  
92      public void setProjects(List<MavenProject> projects) {
93          if (!projects.isEmpty()) {
94              MavenProject first = projects.get(0);
95              this.currentProject = new ThreadLocal<>();
96              this.defaultProject = 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.defaultProject = null;
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     public String getExecutionRootDirectory() {
147         return request.getBaseDirectory();
148     }
149 
150     public MavenExecutionRequest getRequest() {
151         return request;
152     }
153 
154     public void setCurrentProject(MavenProject currentProject) {
155         this.currentProject.set(Optional.ofNullable(currentProject));
156     }
157 
158     public MavenProject getCurrentProject() {
159         Optional<MavenProject> project = currentProject.get();
160         return project != null ? project.orElse(null) : defaultProject;
161     }
162 
163     public ProjectBuildingRequest getProjectBuildingRequest() {
164         return request.getProjectBuildingRequest().setRepositorySession(getRepositorySession());
165     }
166 
167     public List<String> getPluginGroups() {
168         return request.getPluginGroups();
169     }
170 
171     public boolean isOffline() {
172         return request.isOffline();
173     }
174 
175     public MavenProject getTopLevelProject() {
176         return topLevelProject;
177     }
178 
179     public MavenExecutionResult getResult() {
180         return result;
181     }
182 
183     /**
184      * Returns top directory if discovered or {@code null}.
185      * Top directory is directory where top level POM resides with respect of any reactor limiting or shaping like use
186      * of {@code -f} or alike CLI options.
187      *
188      * @since 3.10.0
189      */
190     public Path getTopDirectory() {
191         return request.getTopDirectory();
192     }
193 
194     /**
195      * Returns root directory if discovered or throws {@link IllegalStateException} if it could not be found.
196      * Root directory is detected, usually by the presence of {@code .mvn} directory, and is used to discover
197      * extensions and other configuration files. It usually represents the "project root" or "checkout root".
198      * Root directory may be equal to top directory or some parent of it (first directory where {@code .mvn} is found).
199      *
200      *  @throws IllegalStateException if the root directory could not be found
201      *
202      * @since 3.10.0
203      */
204     public Path getRootDirectory() {
205         return request.getRootDirectory();
206     }
207 
208     // Backward compat
209 
210     public Map<String, Object> getPluginContext(PluginDescriptor plugin, MavenProject project) {
211         String projectKey = project.getId();
212 
213         Map<String, Map<String, Object>> pluginContextsByKey = pluginContextsByProjectAndPluginKey.get(projectKey);
214 
215         if (pluginContextsByKey == null) {
216             pluginContextsByKey = new ConcurrentHashMap<>();
217 
218             pluginContextsByProjectAndPluginKey.put(projectKey, pluginContextsByKey);
219         }
220 
221         String pluginKey = plugin.getPluginLookupKey();
222 
223         Map<String, Object> pluginContext = pluginContextsByKey.get(pluginKey);
224 
225         if (pluginContext == null) {
226             pluginContext = new ConcurrentHashMap<>();
227 
228             pluginContextsByKey.put(pluginKey, pluginContext);
229         }
230 
231         return pluginContext;
232     }
233 
234     public ProjectDependencyGraph getProjectDependencyGraph() {
235         return projectDependencyGraph;
236     }
237 
238     public void setProjectDependencyGraph(ProjectDependencyGraph projectDependencyGraph) {
239         this.projectDependencyGraph = projectDependencyGraph;
240     }
241 
242     public String getReactorFailureBehavior() {
243         return request.getReactorFailureBehavior();
244     }
245 
246     @Override
247     public MavenSession clone() {
248         try {
249             MavenSession clone = (MavenSession) super.clone();
250             // the default must become the current project of the thread that clones this
251             clone.defaultProject = getCurrentProject();
252             // we replace the thread local of the clone to prevent write through
253             clone.currentProject = new ThreadLocal<>();
254             return clone;
255         } catch (CloneNotSupportedException e) {
256             throw new RuntimeException("Bug", e);
257         }
258     }
259 
260     public Date getStartTime() {
261         return request.getStartTime();
262     }
263 
264     public boolean isParallel() {
265         return parallel;
266     }
267 
268     public void setParallel(boolean parallel) {
269         this.parallel = parallel;
270     }
271 
272     /**
273      * Returns the problems detected while building the Maven models.
274      *
275      * @return the model problems, never {@code null}
276      * @since 3.10.0
277      */
278     public List<ModelProblem> getModelProblems() {
279         return modelProblems;
280     }
281 
282     /**
283      * Records the problems detected while building the Maven models.
284      *
285      * @param modelProblems the model problems, must not be {@code null}
286      * @since 3.10.0
287      */
288     public void setModelProblems(List<ModelProblem> modelProblems) {
289         this.modelProblems = Collections.unmodifiableList(new ArrayList<>(Objects.requireNonNull(modelProblems)));
290     }
291 
292     public RepositorySystemSession getRepositorySession() {
293         return repositorySession;
294     }
295 
296     private Map<String, MavenProject> projectMap;
297 
298     public void setProjectMap(Map<String, MavenProject> projectMap) {
299         this.projectMap = projectMap;
300     }
301 
302     /** This is a provisional method and may be removed */
303     public List<MavenProject> getAllProjects() {
304         return allProjects;
305     }
306 
307     /** This is a provisional method and may be removed */
308     public void setAllProjects(List<MavenProject> allProjects) {
309         this.allProjects = allProjects;
310     }
311 
312     /*if_not[MAVEN4]*/
313 
314     //
315     // Deprecated
316     //
317 
318     private PlexusContainer container;
319 
320     private final Settings settings;
321 
322     @Deprecated
323     /** @deprecated This appears to only be used in the ReactorReader and we can do any processing required there */
324     public Map<String, MavenProject> getProjectMap() {
325         return projectMap;
326     }
327 
328     @Deprecated
329     public MavenSession(
330             PlexusContainer container,
331             RepositorySystemSession repositorySession,
332             MavenExecutionRequest request,
333             MavenExecutionResult result) {
334         this.container = container;
335         this.request = request;
336         this.result = result;
337         this.settings = new SettingsAdapter(request);
338         this.repositorySession = repositorySession;
339     }
340 
341     @Deprecated
342     public MavenSession(
343             PlexusContainer container,
344             MavenExecutionRequest request,
345             MavenExecutionResult result,
346             MavenProject project) {
347         this(container, request, result, Arrays.asList(new MavenProject[] {project}));
348     }
349 
350     @Deprecated
351     @SuppressWarnings("checkstyle:parameternumber")
352     public MavenSession(
353             PlexusContainer container,
354             Settings settings,
355             ArtifactRepository localRepository,
356             EventDispatcher eventDispatcher,
357             ReactorManager unused,
358             List<String> goals,
359             String executionRootDir,
360             Properties executionProperties,
361             Date startTime) {
362         this(
363                 container,
364                 settings,
365                 localRepository,
366                 eventDispatcher,
367                 unused,
368                 goals,
369                 executionRootDir,
370                 executionProperties,
371                 null,
372                 startTime);
373     }
374 
375     @Deprecated
376     @SuppressWarnings("checkstyle:parameternumber")
377     public MavenSession(
378             PlexusContainer container,
379             Settings settings,
380             ArtifactRepository localRepository,
381             EventDispatcher eventDispatcher,
382             ReactorManager unused,
383             List<String> goals,
384             String executionRootDir,
385             Properties executionProperties,
386             Properties userProperties,
387             Date startTime) {
388         this.container = container;
389         this.settings = settings;
390         this.executionProperties = executionProperties;
391         this.request = new DefaultMavenExecutionRequest();
392         this.request.setUserProperties(userProperties);
393         this.request.setLocalRepository(localRepository);
394         this.request.setGoals(goals);
395         this.request.setBaseDirectory((executionRootDir != null) ? new File(executionRootDir) : null);
396         this.request.setStartTime(startTime);
397     }
398 
399     @Deprecated
400     public MavenSession(
401             PlexusContainer container,
402             MavenExecutionRequest request,
403             MavenExecutionResult result,
404             List<MavenProject> projects) {
405         this.container = container;
406         this.request = request;
407         this.result = result;
408         this.settings = new SettingsAdapter(request);
409         setProjects(projects);
410     }
411 
412     @Deprecated
413     public List<MavenProject> getSortedProjects() {
414         return getProjects();
415     }
416 
417     @Deprecated
418     //
419     // Used by Tycho and will break users and force them to upgrade to Maven 3.1 so we should really leave
420     // this here, possibly indefinitely.
421     //
422     public RepositoryCache getRepositoryCache() {
423         return null;
424     }
425 
426     @Deprecated
427     public EventDispatcher getEventDispatcher() {
428         return null;
429     }
430 
431     @Deprecated
432     public boolean isUsingPOMsFromFilesystem() {
433         return request.isProjectPresent();
434     }
435 
436     /**
437      * @deprecated Use either {@link #getUserProperties()} or {@link #getSystemProperties()}.
438      */
439     @Deprecated
440     public Properties getExecutionProperties() {
441         if (executionProperties == null) {
442             executionProperties = new Properties();
443             executionProperties.putAll(request.getSystemProperties());
444             executionProperties.putAll(request.getUserProperties());
445         }
446 
447         return executionProperties;
448     }
449 
450     @Deprecated
451     public PlexusContainer getContainer() {
452         return container;
453     }
454 
455     @Deprecated
456     public Object lookup(String role) throws ComponentLookupException {
457         return container.lookup(role);
458     }
459 
460     @Deprecated
461     public Object lookup(String role, String roleHint) throws ComponentLookupException {
462         return container.lookup(role, roleHint);
463     }
464 
465     @Deprecated
466     public List<Object> lookupList(String role) throws ComponentLookupException {
467         return container.lookupList(role);
468     }
469 
470     @Deprecated
471     public Map<String, Object> lookupMap(String role) throws ComponentLookupException {
472         return container.lookupMap(role);
473     }
474 
475     /*end[MAVEN4]*/
476 }