1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.impl;
20
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Objects;
25 import java.util.Optional;
26 import java.util.concurrent.ConcurrentHashMap;
27 import java.util.stream.Stream;
28
29 import org.apache.maven.api.Project;
30 import org.apache.maven.api.Session;
31 import org.apache.maven.api.SessionData;
32 import org.apache.maven.api.Toolchain;
33 import org.apache.maven.api.annotations.Nonnull;
34 import org.apache.maven.api.annotations.Nullable;
35 import org.apache.maven.api.di.Inject;
36 import org.apache.maven.api.di.Named;
37 import org.apache.maven.api.di.Singleton;
38 import org.apache.maven.api.services.Lookup;
39 import org.apache.maven.api.services.ToolchainFactory;
40 import org.apache.maven.api.services.ToolchainFactoryException;
41 import org.apache.maven.api.services.ToolchainManager;
42 import org.apache.maven.api.services.ToolchainManagerException;
43 import org.apache.maven.api.toolchain.ToolchainModel;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 @Named
48 @Singleton
49 public class DefaultToolchainManager implements ToolchainManager {
50 private final Map<String, ToolchainFactory> factories;
51 private final Logger logger;
52
53 @Inject
54 public DefaultToolchainManager(Map<String, ToolchainFactory> factories) {
55 this(factories, null);
56 }
57
58
59
60
61 protected DefaultToolchainManager(Map<String, ToolchainFactory> factories, Logger logger) {
62 this.factories = factories;
63 this.logger = logger != null ? logger : LoggerFactory.getLogger(DefaultToolchainManager.class);
64 }
65
66 @Nonnull
67 @Override
68 public List<Toolchain> getToolchains(
69 @Nonnull Session session, @Nonnull String type, @Nullable Map<String, String> requirements)
70 throws ToolchainManagerException {
71 ToolchainFactory factory = factories.get(Objects.requireNonNull(type, "type"));
72 if (factory == null) {
73 logger.error("Missing toolchain factory for type: " + type + ". Possibly caused by misconfigured project.");
74 return List.of();
75 }
76 return Stream.concat(
77 session.getToolchains().stream()
78 .filter(model -> Objects.equals(type, model.getType()))
79 .map(this::createToolchain)
80 .flatMap(Optional::stream),
81 factory.createDefaultToolchain().stream())
82 .filter(toolchain -> requirements == null || toolchain.matchesRequirements(requirements))
83 .toList();
84 }
85
86 @Nonnull
87 @Override
88 public Optional<Toolchain> getToolchainFromBuildContext(@Nonnull Session session, @Nonnull String type)
89 throws ToolchainManagerException {
90 Map<String, Object> context = retrieveContext(session);
91 ToolchainModel model = (ToolchainModel) context.get("toolchain-" + type);
92 return Optional.ofNullable(model).flatMap(this::createToolchain);
93 }
94
95 @Override
96 public void storeToolchainToBuildContext(@Nonnull Session session, @Nonnull Toolchain toolchain) {
97 Map<String, Object> context = retrieveContext(session);
98 context.put("toolchain-" + toolchain.getType(), toolchain.getModel());
99 }
100
101 private Optional<Toolchain> createToolchain(ToolchainModel model) {
102 String type = Objects.requireNonNull(model.getType(), "model.getType()");
103 ToolchainFactory factory = factories.get(type);
104 if (factory != null) {
105 try {
106 return Optional.of(factory.createToolchain(model));
107 } catch (ToolchainFactoryException e) {
108 throw new ToolchainManagerException("Error creating toolchain of type " + type, e);
109 }
110 } else {
111 logger.error("Missing toolchain factory for type: " + type + ". Possibly caused by misconfigured project.");
112 }
113 return Optional.empty();
114 }
115
116 private static final SessionData.Key<ConcurrentHashMap<Project, ConcurrentHashMap<String, Object>>>
117 TOOLCHAIN_CONTEXT_KEY = (SessionData.Key) SessionData.key(ConcurrentHashMap.class, "toolchain-context");
118
119 protected Map<String, Object> retrieveContext(Session session) {
120 Optional<Project> current = session.getService(Lookup.class).lookupOptional(Project.class);
121 if (current.isPresent()) {
122 var map = session.getData().computeIfAbsent(TOOLCHAIN_CONTEXT_KEY, ConcurrentHashMap::new);
123 return map.computeIfAbsent(current.get(), p -> new ConcurrentHashMap<>());
124 }
125 return new HashMap<>();
126 }
127 }