1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.buildcache;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Provider;
24
25 import java.io.File;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.HashSet;
29 import java.util.LinkedHashSet;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Optional;
33 import java.util.Properties;
34 import java.util.Set;
35 import java.util.TreeSet;
36 import java.util.function.Function;
37 import java.util.stream.Collectors;
38
39 import org.apache.maven.SessionScoped;
40 import org.apache.maven.buildcache.checksum.KeyUtils;
41 import org.apache.maven.buildcache.xml.CacheConfig;
42 import org.apache.maven.buildcache.xml.config.Discovery;
43 import org.apache.maven.buildcache.xml.config.MultiModule;
44 import org.apache.maven.execution.MavenSession;
45 import org.apache.maven.project.DefaultProjectBuildingRequest;
46 import org.apache.maven.project.MavenProject;
47 import org.apache.maven.project.ProjectBuilder;
48 import org.apache.maven.project.ProjectBuildingException;
49 import org.apache.maven.project.ProjectBuildingRequest;
50 import org.apache.maven.project.ProjectBuildingResult;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 @SessionScoped
55 @Named
56 public class DefaultMultiModuleSupport implements MultiModuleSupport {
57
58 private static final Logger LOGGER = LoggerFactory.getLogger(DefaultMultiModuleSupport.class);
59
60 private final ProjectBuilder projectBuilder;
61 private final CacheConfig cacheConfig;
62 private final Provider<MavenSession> providerSession;
63
64 private volatile boolean built;
65 private volatile Map<String, MavenProject> projectMap;
66 private volatile Map<String, MavenProject> sessionProjectMap;
67
68 @Inject
69 public DefaultMultiModuleSupport(
70 ProjectBuilder projectBuilder, CacheConfig cacheConfig, Provider<MavenSession> providerSession) {
71 this.projectBuilder = projectBuilder;
72 this.cacheConfig = cacheConfig;
73 this.providerSession = providerSession;
74 }
75
76 @Override
77 public boolean isPartOfSession(String groupId, String artifactId, String version) {
78 MavenSession session = providerSession.get();
79 return getProjectMap(session).containsKey(KeyUtils.getProjectKey(groupId, artifactId, version));
80 }
81
82 @Override
83 public Optional<MavenProject> tryToResolveProject(String groupId, String artifactId, String version) {
84 return Optional.ofNullable(
85 getMultiModuleProjectsMap().get(KeyUtils.getProjectKey(groupId, artifactId, version)));
86 }
87
88 @Override
89 public boolean isPartOfMultiModule(String groupId, String artifactId, String version) {
90 String projectKey = KeyUtils.getProjectKey(groupId, artifactId, version);
91 MavenSession session = providerSession.get();
92 return getProjectMap(session).containsKey(projectKey)
93 || getMultiModuleProjectsMap().containsKey(projectKey);
94 }
95
96 private Map<String, MavenProject> getProjectMap(MavenSession session) {
97 if (sessionProjectMap != null) {
98 return sessionProjectMap;
99 }
100 sessionProjectMap =
101 session.getProjects().stream().collect(Collectors.toMap(KeyUtils::getProjectKey, Function.identity()));
102 return sessionProjectMap;
103 }
104
105 private Map<String, MavenProject> getMultiModuleProjectsMap() {
106 if (projectMap != null) {
107 return projectMap;
108 }
109 MavenSession session = providerSession.get();
110 return getMultiModuleProjectsMapInner(session);
111 }
112
113 private synchronized Map<String, MavenProject> getMultiModuleProjectsMapInner(MavenSession session) {
114 if (projectMap != null) {
115 return projectMap;
116 }
117 buildModel(session);
118 return projectMap;
119 }
120
121 private synchronized void buildModel(MavenSession session) {
122 if (built) {
123 return;
124 }
125
126 Optional<Discovery> multiModuleDiscovery =
127 Optional.ofNullable(cacheConfig.getMultiModule()).map(MultiModule::getDiscovery);
128
129
130 if (!multiModuleDiscovery.isPresent()) {
131 projectMap = buildProjectMap(session.getProjects());
132 return;
133 }
134
135 Set<String> scanProfiles = new TreeSet<>(
136 multiModuleDiscovery.map(Discovery::getScanProfiles).orElse(Collections.emptyList()));
137 MavenProject currentProject = session.getCurrentProject();
138 File multiModulePomFile = getMultiModulePomFile(session);
139
140 ProjectBuildingRequest projectBuildingRequest = currentProject.getProjectBuildingRequest();
141 boolean profilesMatched = new HashSet<>(projectBuildingRequest.getActiveProfileIds()).containsAll(scanProfiles);
142
143
144 if (currentProject.getFile().getAbsolutePath().equals(multiModulePomFile.getAbsolutePath())
145 && profilesMatched) {
146 projectMap = buildProjectMap(session.getProjects());
147 return;
148 }
149
150 long t0 = System.currentTimeMillis();
151
152 ProjectBuildingRequest buildingRequest = new DefaultProjectBuildingRequest(projectBuildingRequest);
153
154
155
156
157
158
159 buildingRequest.setProfiles(buildingRequest.getProfiles().stream()
160 .peek(it -> it.setProperties(new Properties()))
161 .collect(Collectors.toList()));
162 if (!profilesMatched) {
163 Set<String> profiles = new LinkedHashSet<>(buildingRequest.getActiveProfileIds());
164
165 profiles.addAll(scanProfiles);
166 buildingRequest.setActiveProfileIds(new ArrayList<>(profiles));
167 }
168 try {
169 List<ProjectBuildingResult> buildingResults =
170 projectBuilder.build(Collections.singletonList(multiModulePomFile), true, buildingRequest);
171 LOGGER.info(
172 "Multi module project model calculated [activeProfiles={}, time={} ms ",
173 buildingRequest.getActiveProfileIds(),
174 System.currentTimeMillis() - t0);
175
176 List<MavenProject> projectList = buildingResults.stream()
177 .map(ProjectBuildingResult::getProject)
178 .collect(Collectors.toList());
179 projectMap = buildProjectMap(projectList);
180
181 } catch (ProjectBuildingException e) {
182 LOGGER.error("Unable to build model", e);
183 } finally {
184 built = true;
185 }
186 }
187
188 private Map<String, MavenProject> buildProjectMap(List<MavenProject> projectList) {
189 return projectList.stream().collect(Collectors.toMap(KeyUtils::getProjectKey, Function.identity()));
190 }
191
192 private static File getMultiModulePomFile(MavenSession session) {
193 return CacheUtils.getMultimoduleRoot(session).resolve("pom.xml").toFile();
194 }
195 }