1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.internal.aether;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.LinkedHashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.stream.Collectors;
32
33 import org.apache.maven.RepositoryUtils;
34 import org.apache.maven.api.xml.XmlNode;
35 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
36 import org.apache.maven.bridge.MavenRepositorySystem;
37 import org.apache.maven.eventspy.internal.EventSpyDispatcher;
38 import org.apache.maven.execution.MavenExecutionRequest;
39 import org.apache.maven.internal.xml.XmlNodeImpl;
40 import org.apache.maven.internal.xml.XmlPlexusConfiguration;
41 import org.apache.maven.model.ModelBase;
42 import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
43 import org.apache.maven.rtinfo.RuntimeInformation;
44 import org.apache.maven.settings.Mirror;
45 import org.apache.maven.settings.Proxy;
46 import org.apache.maven.settings.Server;
47 import org.apache.maven.settings.building.SettingsProblem;
48 import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest;
49 import org.apache.maven.settings.crypto.SettingsDecrypter;
50 import org.apache.maven.settings.crypto.SettingsDecryptionResult;
51 import org.codehaus.plexus.configuration.PlexusConfiguration;
52 import org.eclipse.aether.ConfigurationProperties;
53 import org.eclipse.aether.DefaultRepositorySystemSession;
54 import org.eclipse.aether.RepositorySystem;
55 import org.eclipse.aether.repository.LocalRepository;
56 import org.eclipse.aether.repository.LocalRepositoryManager;
57 import org.eclipse.aether.repository.RepositoryPolicy;
58 import org.eclipse.aether.repository.WorkspaceReader;
59 import org.eclipse.aether.resolution.ResolutionErrorPolicy;
60 import org.eclipse.aether.util.ConfigUtils;
61 import org.eclipse.aether.util.listener.ChainedRepositoryListener;
62 import org.eclipse.aether.util.repository.AuthenticationBuilder;
63 import org.eclipse.aether.util.repository.ChainedLocalRepositoryManager;
64 import org.eclipse.aether.util.repository.DefaultAuthenticationSelector;
65 import org.eclipse.aether.util.repository.DefaultMirrorSelector;
66 import org.eclipse.aether.util.repository.DefaultProxySelector;
67 import org.eclipse.aether.util.repository.SimpleResolutionErrorPolicy;
68 import org.eclipse.sisu.Nullable;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
71
72 import static java.util.stream.Collectors.toList;
73
74
75
76
77 @Named
78 public class DefaultRepositorySystemSessionFactory {
79
80
81
82
83
84
85
86 private static final String MAVEN_REPO_LOCAL_TAIL = "maven.repo.local.tail";
87
88
89
90
91
92
93
94 private static final String MAVEN_REPO_LOCAL_TAIL_IGNORE_AVAILABILITY = "maven.repo.local.tail.ignoreAvailability";
95
96
97
98
99
100
101
102
103
104 private static final String MAVEN_REPO_LOCAL_RECORD_REVERSE_TREE = "maven.repo.local.recordReverseTree";
105
106 private static final String MAVEN_RESOLVER_TRANSPORT_KEY = "maven.resolver.transport";
107
108 private static final String MAVEN_RESOLVER_TRANSPORT_DEFAULT = "default";
109
110 private static final String MAVEN_RESOLVER_TRANSPORT_WAGON = "wagon";
111
112 private static final String MAVEN_RESOLVER_TRANSPORT_NATIVE = "native";
113
114 private static final String MAVEN_RESOLVER_TRANSPORT_AUTO = "auto";
115
116 private static final String WAGON_TRANSPORTER_PRIORITY_KEY = "aether.priority.WagonTransporterFactory";
117
118 private static final String NATIVE_HTTP_TRANSPORTER_PRIORITY_KEY = "aether.priority.HttpTransporterFactory";
119
120 private static final String NATIVE_FILE_TRANSPORTER_PRIORITY_KEY = "aether.priority.FileTransporterFactory";
121
122 private static final String RESOLVER_MAX_PRIORITY = String.valueOf(Float.MAX_VALUE);
123
124 private final Logger logger = LoggerFactory.getLogger(getClass());
125
126 private final ArtifactHandlerManager artifactHandlerManager;
127
128 private final RepositorySystem repoSystem;
129
130 private final WorkspaceReader workspaceRepository;
131
132 private final SettingsDecrypter settingsDecrypter;
133
134 private final EventSpyDispatcher eventSpyDispatcher;
135
136 private final MavenRepositorySystem mavenRepositorySystem;
137
138 private final RuntimeInformation runtimeInformation;
139
140 @SuppressWarnings("checkstyle:ParameterNumber")
141 @Inject
142 public DefaultRepositorySystemSessionFactory(
143 ArtifactHandlerManager artifactHandlerManager,
144 RepositorySystem repoSystem,
145 @Nullable @Named("ide") WorkspaceReader workspaceRepository,
146 SettingsDecrypter settingsDecrypter,
147 EventSpyDispatcher eventSpyDispatcher,
148 MavenRepositorySystem mavenRepositorySystem,
149 RuntimeInformation runtimeInformation) {
150 this.artifactHandlerManager = artifactHandlerManager;
151 this.repoSystem = repoSystem;
152 this.workspaceRepository = workspaceRepository;
153 this.settingsDecrypter = settingsDecrypter;
154 this.eventSpyDispatcher = eventSpyDispatcher;
155 this.mavenRepositorySystem = mavenRepositorySystem;
156 this.runtimeInformation = runtimeInformation;
157 }
158
159 @SuppressWarnings("checkstyle:methodLength")
160 public DefaultRepositorySystemSession newRepositorySession(MavenExecutionRequest request) {
161 DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
162 session.setCache(request.getRepositoryCache());
163
164 Map<Object, Object> configProps = new LinkedHashMap<>();
165 configProps.put(ConfigurationProperties.USER_AGENT, getUserAgent());
166 configProps.put(ConfigurationProperties.INTERACTIVE, request.isInteractiveMode());
167 configProps.put("maven.startTime", request.getStartTime());
168
169 configProps.putAll(getPropertiesFromRequestedProfiles(request));
170
171 configProps.putAll(request.getSystemProperties());
172 configProps.putAll(request.getUserProperties());
173
174 session.setOffline(request.isOffline());
175 session.setChecksumPolicy(request.getGlobalChecksumPolicy());
176 session.setUpdatePolicy(
177 request.isNoSnapshotUpdates()
178 ? RepositoryPolicy.UPDATE_POLICY_NEVER
179 : request.isUpdateSnapshots() ? RepositoryPolicy.UPDATE_POLICY_ALWAYS : null);
180
181 int errorPolicy = 0;
182 errorPolicy |= request.isCacheNotFound()
183 ? ResolutionErrorPolicy.CACHE_NOT_FOUND
184 : ResolutionErrorPolicy.CACHE_DISABLED;
185 errorPolicy |= request.isCacheTransferError()
186 ? ResolutionErrorPolicy.CACHE_TRANSFER_ERROR
187 : ResolutionErrorPolicy.CACHE_DISABLED;
188 session.setResolutionErrorPolicy(
189 new SimpleResolutionErrorPolicy(errorPolicy, errorPolicy | ResolutionErrorPolicy.CACHE_NOT_FOUND));
190
191 session.setArtifactTypeRegistry(RepositoryUtils.newArtifactTypeRegistry(artifactHandlerManager));
192
193 session.setWorkspaceReader(
194 request.getWorkspaceReader() != null ? request.getWorkspaceReader() : workspaceRepository);
195
196 DefaultSettingsDecryptionRequest decrypt = new DefaultSettingsDecryptionRequest();
197 decrypt.setProxies(request.getProxies());
198 decrypt.setServers(request.getServers());
199 SettingsDecryptionResult decrypted = settingsDecrypter.decrypt(decrypt);
200
201 if (logger.isDebugEnabled()) {
202 for (SettingsProblem problem : decrypted.getProblems()) {
203 logger.debug(problem.getMessage(), problem.getException());
204 }
205 }
206
207 DefaultMirrorSelector mirrorSelector = new DefaultMirrorSelector();
208 for (Mirror mirror : request.getMirrors()) {
209 mirrorSelector.add(
210 mirror.getId(),
211 mirror.getUrl(),
212 mirror.getLayout(),
213 false,
214 mirror.isBlocked(),
215 mirror.getMirrorOf(),
216 mirror.getMirrorOfLayouts());
217 }
218 session.setMirrorSelector(mirrorSelector);
219
220 DefaultProxySelector proxySelector = new DefaultProxySelector();
221 for (Proxy proxy : decrypted.getProxies()) {
222 AuthenticationBuilder authBuilder = new AuthenticationBuilder();
223 authBuilder.addUsername(proxy.getUsername()).addPassword(proxy.getPassword());
224 proxySelector.add(
225 new org.eclipse.aether.repository.Proxy(
226 proxy.getProtocol(), proxy.getHost(), proxy.getPort(), authBuilder.build()),
227 proxy.getNonProxyHosts());
228 }
229 session.setProxySelector(proxySelector);
230
231 DefaultAuthenticationSelector authSelector = new DefaultAuthenticationSelector();
232 for (Server server : decrypted.getServers()) {
233 AuthenticationBuilder authBuilder = new AuthenticationBuilder();
234 authBuilder.addUsername(server.getUsername()).addPassword(server.getPassword());
235 authBuilder.addPrivateKey(server.getPrivateKey(), server.getPassphrase());
236 authSelector.add(server.getId(), authBuilder.build());
237
238 if (server.getConfiguration() != null) {
239 XmlNode dom = ((org.codehaus.plexus.util.xml.Xpp3Dom) server.getConfiguration()).getDom();
240 List<XmlNode> children = dom.getChildren().stream()
241 .filter(c -> !"wagonProvider".equals(c.getName()))
242 .collect(Collectors.toList());
243 dom = new XmlNodeImpl(dom.getName(), null, null, children, null);
244 PlexusConfiguration config = XmlPlexusConfiguration.toPlexusConfiguration(dom);
245 configProps.put("aether.connector.wagon.config." + server.getId(), config);
246
247
248
249
250 Map<String, String> headers = null;
251 Integer connectTimeout = null;
252 Integer requestTimeout = null;
253
254 PlexusConfiguration httpHeaders = config.getChild("httpHeaders", false);
255 if (httpHeaders != null) {
256 PlexusConfiguration[] properties = httpHeaders.getChildren("property");
257 if (properties != null && properties.length > 0) {
258 headers = new HashMap<>();
259 for (PlexusConfiguration property : properties) {
260 headers.put(
261 property.getChild("name").getValue(),
262 property.getChild("value").getValue());
263 }
264 }
265 }
266
267 PlexusConfiguration connectTimeoutXml = config.getChild("connectTimeout", false);
268 if (connectTimeoutXml != null) {
269 connectTimeout = Integer.parseInt(connectTimeoutXml.getValue());
270 } else {
271
272 PlexusConfiguration httpConfiguration = config.getChild("httpConfiguration", false);
273 if (httpConfiguration != null) {
274 PlexusConfiguration httpConfigurationAll = httpConfiguration.getChild("all", false);
275 if (httpConfigurationAll != null) {
276 connectTimeoutXml = httpConfigurationAll.getChild("connectionTimeout", false);
277 if (connectTimeoutXml != null) {
278 connectTimeout = Integer.parseInt(connectTimeoutXml.getValue());
279 logger.warn("Settings for server {} uses legacy format", server.getId());
280 }
281 }
282 }
283 }
284
285 PlexusConfiguration requestTimeoutXml = config.getChild("requestTimeout", false);
286 if (requestTimeoutXml != null) {
287 requestTimeout = Integer.parseInt(requestTimeoutXml.getValue());
288 } else {
289
290 PlexusConfiguration httpConfiguration = config.getChild("httpConfiguration", false);
291 if (httpConfiguration != null) {
292 PlexusConfiguration httpConfigurationAll = httpConfiguration.getChild("all", false);
293 if (httpConfigurationAll != null) {
294 requestTimeoutXml = httpConfigurationAll.getChild("readTimeout", false);
295 if (requestTimeoutXml != null) {
296 requestTimeout = Integer.parseInt(requestTimeoutXml.getValue());
297 logger.warn("Settings for server {} uses legacy format", server.getId());
298 }
299 }
300 }
301 }
302
303
304 if (headers != null) {
305 configProps.put(ConfigurationProperties.HTTP_HEADERS + "." + server.getId(), headers);
306 }
307
308 if (connectTimeout != null) {
309 configProps.put(ConfigurationProperties.CONNECT_TIMEOUT + "." + server.getId(), connectTimeout);
310 }
311
312 if (requestTimeout != null) {
313 configProps.put(ConfigurationProperties.REQUEST_TIMEOUT + "." + server.getId(), requestTimeout);
314 }
315 }
316
317 configProps.put("aether.connector.perms.fileMode." + server.getId(), server.getFilePermissions());
318 configProps.put("aether.connector.perms.dirMode." + server.getId(), server.getDirectoryPermissions());
319 }
320 session.setAuthenticationSelector(authSelector);
321
322 Object transport = configProps.getOrDefault(MAVEN_RESOLVER_TRANSPORT_KEY, MAVEN_RESOLVER_TRANSPORT_DEFAULT);
323 if (MAVEN_RESOLVER_TRANSPORT_DEFAULT.equals(transport)) {
324
325 } else if (MAVEN_RESOLVER_TRANSPORT_NATIVE.equals(transport)) {
326
327 configProps.put(NATIVE_FILE_TRANSPORTER_PRIORITY_KEY, RESOLVER_MAX_PRIORITY);
328 configProps.put(NATIVE_HTTP_TRANSPORTER_PRIORITY_KEY, RESOLVER_MAX_PRIORITY);
329 } else if (MAVEN_RESOLVER_TRANSPORT_WAGON.equals(transport)) {
330
331 configProps.put(WAGON_TRANSPORTER_PRIORITY_KEY, RESOLVER_MAX_PRIORITY);
332 } else if (!MAVEN_RESOLVER_TRANSPORT_AUTO.equals(transport)) {
333 throw new IllegalArgumentException("Unknown resolver transport '" + transport
334 + "'. Supported transports are: " + MAVEN_RESOLVER_TRANSPORT_WAGON + ", "
335 + MAVEN_RESOLVER_TRANSPORT_NATIVE + ", " + MAVEN_RESOLVER_TRANSPORT_AUTO);
336 }
337
338 session.setUserProperties(request.getUserProperties());
339 session.setSystemProperties(request.getSystemProperties());
340 session.setConfigProperties(configProps);
341
342 session.setTransferListener(request.getTransferListener());
343
344 session.setRepositoryListener(eventSpyDispatcher.chainListener(new LoggingRepositoryListener(logger)));
345
346 boolean recordReverseTree = ConfigUtils.getBoolean(session, false, MAVEN_REPO_LOCAL_RECORD_REVERSE_TREE);
347 if (recordReverseTree) {
348 session.setRepositoryListener(new ChainedRepositoryListener(
349 session.getRepositoryListener(), new ReverseTreeRepositoryListener()));
350 }
351
352 mavenRepositorySystem.injectMirror(request.getRemoteRepositories(), request.getMirrors());
353 mavenRepositorySystem.injectProxy(session, request.getRemoteRepositories());
354 mavenRepositorySystem.injectAuthentication(session, request.getRemoteRepositories());
355
356 mavenRepositorySystem.injectMirror(request.getPluginArtifactRepositories(), request.getMirrors());
357 mavenRepositorySystem.injectProxy(session, request.getPluginArtifactRepositories());
358 mavenRepositorySystem.injectAuthentication(session, request.getPluginArtifactRepositories());
359
360 setUpLocalRepositoryManager(request, session);
361
362 return session;
363 }
364
365 private void setUpLocalRepositoryManager(MavenExecutionRequest request, DefaultRepositorySystemSession session) {
366 LocalRepository localRepo =
367 new LocalRepository(request.getLocalRepository().getBasedir());
368
369 LocalRepositoryManager lrm = repoSystem.newLocalRepositoryManager(session, localRepo);
370
371 String localRepoTail = ConfigUtils.getString(session, null, MAVEN_REPO_LOCAL_TAIL);
372 if (localRepoTail != null) {
373 boolean ignoreTailAvailability =
374 ConfigUtils.getBoolean(session, true, MAVEN_REPO_LOCAL_TAIL_IGNORE_AVAILABILITY);
375 List<LocalRepositoryManager> tail = new ArrayList<>();
376 List<String> paths = Arrays.stream(localRepoTail.split(","))
377 .filter(p -> p != null && !p.trim().isEmpty())
378 .collect(toList());
379 for (String path : paths) {
380 tail.add(repoSystem.newLocalRepositoryManager(session, new LocalRepository(path)));
381 }
382 session.setLocalRepositoryManager(new ChainedLocalRepositoryManager(lrm, tail, ignoreTailAvailability));
383 } else {
384 session.setLocalRepositoryManager(lrm);
385 }
386 }
387
388 private Map<?, ?> getPropertiesFromRequestedProfiles(MavenExecutionRequest request) {
389
390 HashSet<String> activeProfileId =
391 new HashSet<>(request.getProfileActivation().getRequiredActiveProfileIds());
392 activeProfileId.addAll(request.getProfileActivation().getOptionalActiveProfileIds());
393
394 return request.getProfiles().stream()
395 .filter(profile -> activeProfileId.contains(profile.getId()))
396 .map(ModelBase::getProperties)
397 .flatMap(properties -> properties.entrySet().stream())
398 .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (k1, k2) -> k2));
399 }
400
401 private String getUserAgent() {
402 String version = runtimeInformation.getMavenVersion();
403 version = version.isEmpty() ? version : "/" + version;
404 return "Apache-Maven" + version + " (Java " + System.getProperty("java.version") + "; "
405 + System.getProperty("os.name") + " " + System.getProperty("os.version") + ")";
406 }
407 }