MavenSession.java
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.execution;
import java.io.File;
import java.nio.file.Path;
import java.time.Instant;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;
import org.apache.maven.api.Session;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.RepositoryCache;
import org.apache.maven.impl.SettingsUtilsV4;
import org.apache.maven.model.Profile;
import org.apache.maven.monitor.event.EventDispatcher;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuildingRequest;
import org.apache.maven.settings.Mirror;
import org.apache.maven.settings.Proxy;
import org.apache.maven.settings.Server;
import org.apache.maven.settings.Settings;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.eclipse.aether.RepositorySystemSession;
import static java.util.Objects.requireNonNull;
/**
* A Maven execution session.
*
*/
public class MavenSession implements Cloneable {
private final MavenExecutionRequest request;
private final MavenExecutionResult result;
private final RepositorySystemSession repositorySystemSession;
private final Properties executionProperties;
private ThreadLocal<MavenProject> currentProject = new ThreadLocal<>();
/**
* These projects have already been topologically sorted in the {@link org.apache.maven.Maven} component before
* being passed into the session. This is also the potentially constrained set of projects by using --projects
* on the command line.
*/
private List<MavenProject> projects;
/**
* The full set of projects before any potential constraining by --projects. Useful in the case where you want to
* build a smaller set of projects but perform other operations in the context of your reactor.
*/
private List<MavenProject> allProjects;
private MavenProject topLevelProject;
private ProjectDependencyGraph projectDependencyGraph;
private boolean parallel;
/**
* Plugin context keyed by project ({@link MavenProject#getId()}) and by plugin lookup key
* ({@link PluginDescriptor#getPluginLookupKey()}). Plugin contexts itself are mappings of {@link String} keys to
* {@link Object} values.
*/
private final ConcurrentMap<String, ConcurrentMap<String, ConcurrentMap<String, Object>>>
pluginContextsByProjectAndPluginKey = new ConcurrentHashMap<>();
public void setProjects(List<MavenProject> projects) {
if (!projects.isEmpty()) {
MavenProject first = projects.get(0);
this.currentProject = ThreadLocal.withInitial(() -> first);
this.topLevelProject = projects.stream()
.filter(project -> project.isExecutionRoot())
.findFirst()
.orElse(first);
} else {
this.currentProject = new ThreadLocal<>();
this.topLevelProject = null;
}
this.projects = projects;
}
public ArtifactRepository getLocalRepository() {
return request.getLocalRepository();
}
public List<String> getGoals() {
return request.getGoals();
}
/**
* Gets the user properties to use for interpolation and profile activation. The user properties have been
* configured directly by the user on his discretion, e.g. via the {@code -Dkey=value} parameter on the command
* line.
*
* @return The user properties, never {@code null}.
*/
public Properties getUserProperties() {
return request.getUserProperties();
}
/**
* Gets the system properties to use for interpolation and profile activation. The system properties are collected
* from the runtime environment like {@link System#getProperties()} and environment variables.
*
* @return The system properties, never {@code null}.
*/
public Properties getSystemProperties() {
return request.getSystemProperties();
}
public Settings getSettings() {
return settings;
}
public List<MavenProject> getProjects() {
return projects;
}
/**
* @deprecated use {@link #getTopDirectory()} ()}
*/
@Deprecated
public String getExecutionRootDirectory() {
return request.getBaseDirectory();
}
/**
* @see MavenExecutionRequest#getTopDirectory()
* @since 4.0.0
*/
public Path getTopDirectory() {
return request.getTopDirectory();
}
/**
* @see MavenExecutionRequest#getRootDirectory()
* @since 4.0.0
*/
public Path getRootDirectory() {
return request.getRootDirectory();
}
public MavenExecutionRequest getRequest() {
return request;
}
public void setCurrentProject(MavenProject currentProject) {
this.currentProject.set(currentProject);
}
public MavenProject getCurrentProject() {
return currentProject.get();
}
public ProjectBuildingRequest getProjectBuildingRequest() {
return request.getProjectBuildingRequest().setRepositorySession(getRepositorySession());
}
public List<String> getPluginGroups() {
return request.getPluginGroups();
}
public boolean isOffline() {
return request.isOffline();
}
public MavenProject getTopLevelProject() {
return topLevelProject;
}
public MavenExecutionResult getResult() {
return result;
}
// Backward compat
/**
* Returns the plugin context for given key ({@link PluginDescriptor#getPluginLookupKey()} and
* {@link MavenProject}, never returns {@code null} as if context not present, creates it.
*
* <strong>Implementation note:</strong> while this method return type is {@link Map}, the returned map instance
* implements {@link ConcurrentMap} as well.
*
*/
public Map<String, Object> getPluginContext(PluginDescriptor plugin, MavenProject project) {
String projectKey = project.getId();
ConcurrentMap<String, ConcurrentMap<String, Object>> pluginContextsByKey =
pluginContextsByProjectAndPluginKey.computeIfAbsent(projectKey, k -> new ConcurrentHashMap<>());
String pluginKey = plugin.getPluginLookupKey();
return pluginContextsByKey.computeIfAbsent(pluginKey, k -> new ConcurrentHashMap<>());
}
public ProjectDependencyGraph getProjectDependencyGraph() {
return projectDependencyGraph;
}
public void setProjectDependencyGraph(ProjectDependencyGraph projectDependencyGraph) {
this.projectDependencyGraph = projectDependencyGraph;
}
public String getReactorFailureBehavior() {
return request.getReactorFailureBehavior();
}
@Override
public MavenSession clone() {
try {
MavenSession clone = (MavenSession) super.clone();
// the default must become the current project of the thread that clones this
MavenProject current = getCurrentProject();
// we replace the thread local of the clone to prevent write through and enforce the new default value
clone.currentProject = ThreadLocal.withInitial(() -> current);
return clone;
} catch (CloneNotSupportedException e) {
throw new RuntimeException("Bug", e);
}
}
@Deprecated
public Date getStartTime() {
return request.getStartTime();
}
public Instant getStartInstant() {
return request.getStartInstant();
}
public boolean isParallel() {
return parallel;
}
public void setParallel(boolean parallel) {
this.parallel = parallel;
}
public RepositorySystemSession getRepositorySession() {
return repositorySystemSession;
}
private Map<String, MavenProject> projectMap;
public void setProjectMap(Map<String, MavenProject> projectMap) {
this.projectMap = projectMap;
}
/** This is a provisional method and may be removed */
public List<MavenProject> getAllProjects() {
return allProjects;
}
/** This is a provisional method and may be removed */
public void setAllProjects(List<MavenProject> allProjects) {
this.allProjects = allProjects;
}
/*if_not[MAVEN4]*/
//
// Deprecated
//
private final PlexusContainer container;
private final Settings settings;
private Session session;
@Deprecated
/** @deprecated This appears not to be used anywhere within Maven itself. */
public Map<String, MavenProject> getProjectMap() {
return projectMap;
}
public MavenSession(
RepositorySystemSession repositorySystemSession,
MavenExecutionRequest request,
MavenExecutionResult result) {
this.container = null;
this.request = requireNonNull(request);
this.result = requireNonNull(result);
this.settings = adaptSettings(request);
this.repositorySystemSession = requireNonNull(repositorySystemSession);
Properties executionProperties = new Properties();
executionProperties.putAll(request.getSystemProperties());
executionProperties.putAll(request.getUserProperties());
this.executionProperties = executionProperties;
}
@Deprecated
public MavenSession(
PlexusContainer container,
RepositorySystemSession repositorySession,
MavenExecutionRequest request,
MavenExecutionResult result) {
this.container = container;
this.request = request;
this.result = result;
this.settings = adaptSettings(request);
this.repositorySystemSession = repositorySession;
Properties executionProperties = new Properties();
executionProperties.putAll(request.getSystemProperties());
executionProperties.putAll(request.getUserProperties());
this.executionProperties = executionProperties;
}
@Deprecated
public MavenSession(
PlexusContainer container,
MavenExecutionRequest request,
MavenExecutionResult result,
MavenProject project) {
this(container, request, result, Arrays.asList(new MavenProject[] {project}));
}
@Deprecated
@SuppressWarnings("checkstyle:parameternumber")
public MavenSession(
PlexusContainer container,
Settings settings,
ArtifactRepository localRepository,
EventDispatcher eventDispatcher,
ReactorManager unused,
List<String> goals,
String executionRootDir,
Properties executionProperties,
Date startTime) {
this(
container,
settings,
localRepository,
eventDispatcher,
unused,
goals,
executionRootDir,
executionProperties,
null,
startTime);
}
@Deprecated
@SuppressWarnings("checkstyle:parameternumber")
public MavenSession(
PlexusContainer container,
Settings settings,
ArtifactRepository localRepository,
EventDispatcher eventDispatcher,
ReactorManager unused,
List<String> goals,
String executionRootDir,
Properties executionProperties,
Properties userProperties,
Date startTime) {
this.container = container;
this.settings = settings;
this.executionProperties = executionProperties;
this.request = new DefaultMavenExecutionRequest();
this.request.setUserProperties(userProperties);
this.request.setLocalRepository(localRepository);
this.request.setGoals(goals);
this.request.setBaseDirectory((executionRootDir != null) ? new File(executionRootDir) : null);
this.request.setStartTime(startTime);
this.result = null;
this.repositorySystemSession = null;
}
@Deprecated
public MavenSession(
PlexusContainer container,
MavenExecutionRequest request,
MavenExecutionResult result,
List<MavenProject> projects) {
this.container = container;
this.request = request;
this.result = result;
this.settings = adaptSettings(request);
Properties executionProperties = new Properties();
executionProperties.putAll(request.getSystemProperties());
executionProperties.putAll(request.getUserProperties());
this.executionProperties = executionProperties;
setProjects(projects);
this.repositorySystemSession = null;
}
/**
* Adapt a {@link MavenExecutionRequest} to a {@link Settings} object for use in the Maven core.
* We want to make sure that what is ask for in the execution request overrides what is in the settings.
* The CLI feeds into an execution request so if a particular value is present in the execution request
* then we will take that over the value coming from the user settings.
*/
private static Settings adaptSettings(MavenExecutionRequest request) {
File localRepo = request.getLocalRepositoryPath();
return new Settings(org.apache.maven.api.settings.Settings.newBuilder()
.localRepository(localRepo != null ? localRepo.getAbsolutePath() : null)
.interactiveMode(request.isInteractiveMode())
.offline(request.isOffline())
.proxies(request.getProxies().stream().map(Proxy::getDelegate).collect(Collectors.toList()))
.servers(request.getServers().stream().map(Server::getDelegate).collect(Collectors.toList()))
.mirrors(request.getMirrors().stream().map(Mirror::getDelegate).collect(Collectors.toList()))
.profiles(request.getProfiles().stream()
.map(Profile::getDelegate)
.map(SettingsUtilsV4::convertToSettingsProfile)
.collect(Collectors.toList()))
.activeProfiles(request.getActiveProfiles())
.pluginGroups(request.getPluginGroups())
.build());
}
@Deprecated
public List<MavenProject> getSortedProjects() {
return getProjects();
}
@Deprecated
//
// Used by Tycho and will break users and force them to upgrade to Maven 3.1 so we should really leave
// this here, possibly indefinitely.
//
public RepositoryCache getRepositoryCache() {
return null;
}
@Deprecated
public EventDispatcher getEventDispatcher() {
return null;
}
@Deprecated
public boolean isUsingPOMsFromFilesystem() {
return request.isProjectPresent();
}
/**
* @deprecated Use either {@link #getUserProperties()} or {@link #getSystemProperties()}.
*/
@Deprecated
public Properties getExecutionProperties() {
return executionProperties;
}
@Deprecated
public PlexusContainer getContainer() {
return container;
}
@Deprecated
public Object lookup(String role) throws ComponentLookupException {
return container.lookup(role);
}
@Deprecated
public Object lookup(String role, String roleHint) throws ComponentLookupException {
return container.lookup(role, roleHint);
}
@Deprecated
public List<Object> lookupList(String role) throws ComponentLookupException {
return container.lookupList(role);
}
@Deprecated
public Map<String, Object> lookupMap(String role) throws ComponentLookupException {
return container.lookupMap(role);
}
public Session getSession() {
return session;
}
public void setSession(Session session) {
this.session = session;
}
/*end[MAVEN4]*/
}