1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.internal.impl.model;
20
21 import java.nio.file.Files;
22 import java.nio.file.Path;
23 import java.util.ArrayList;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.concurrent.ConcurrentHashMap;
29
30 import org.apache.maven.api.model.Model;
31 import org.apache.maven.api.services.ModelBuilderException;
32 import org.apache.maven.api.services.ModelBuilderRequest;
33 import org.apache.maven.api.services.ModelProblem;
34 import org.apache.maven.api.services.ModelProblemCollector;
35 import org.apache.maven.api.services.ModelSource;
36 import org.apache.maven.api.services.ModelTransformerContext;
37 import org.apache.maven.api.services.ModelTransformerContextBuilder;
38 import org.apache.maven.internal.impl.model.DefaultModelTransformerContext.GAKey;
39 import org.apache.maven.internal.impl.model.DefaultModelTransformerContext.Holder;
40
41
42
43
44
45
46
47
48 class DefaultModelTransformerContextBuilder implements ModelTransformerContextBuilder {
49 private final Graph dag = new Graph();
50 private final DefaultModelBuilder defaultModelBuilder;
51 private final DefaultModelTransformerContext context;
52
53 private final Map<String, Set<ModelSource>> mappedSources = new ConcurrentHashMap<>(64);
54
55 private volatile boolean fullReactorLoaded;
56
57 DefaultModelTransformerContextBuilder(DefaultModelBuilder defaultModelBuilder) {
58 this.defaultModelBuilder = defaultModelBuilder;
59 this.context = new DefaultModelTransformerContext(defaultModelBuilder.getModelProcessor());
60 }
61
62
63
64
65 @Override
66 public ModelTransformerContext initialize(ModelBuilderRequest request, ModelProblemCollector collector) {
67
68 DefaultModelProblemCollector problems = (DefaultModelProblemCollector) collector;
69 return new ModelTransformerContext() {
70
71 @Override
72 public Path locate(Path path) {
73 return context.locate(path);
74 }
75
76 @Override
77 public String getUserProperty(String key) {
78 return context.userProperties.computeIfAbsent(
79 key, k -> request.getUserProperties().get(key));
80 }
81
82 @Override
83 public Model getRawModel(Path from, String gId, String aId) {
84 Model model = findRawModel(from, gId, aId);
85 if (model != null) {
86 context.modelByGA.put(new GAKey(gId, aId), new Holder(model));
87 context.modelByPath.put(model.getPomFile(), new Holder(model));
88 }
89 return model;
90 }
91
92 @Override
93 public Model getRawModel(Path from, Path path) {
94 Model model = findRawModel(from, path);
95 if (model != null) {
96 String groupId = DefaultModelBuilder.getGroupId(model);
97 context.modelByGA.put(
98 new DefaultModelTransformerContext.GAKey(groupId, model.getArtifactId()),
99 new Holder(model));
100 context.modelByPath.put(path, new Holder(model));
101 }
102 return model;
103 }
104
105 private Model findRawModel(Path from, String groupId, String artifactId) {
106 ModelSource source = getSource(groupId, artifactId);
107 if (source == null) {
108
109 loadFullReactor();
110 source = getSource(groupId, artifactId);
111 }
112 if (source != null) {
113 if (!addEdge(from, source.getPath(), problems)) {
114 return null;
115 }
116 try {
117 ModelBuilderRequest gaBuildingRequest = ModelBuilderRequest.build(request, source);
118 return defaultModelBuilder.readRawModel(gaBuildingRequest, problems);
119 } catch (ModelBuilderException e) {
120
121 }
122 }
123 return null;
124 }
125
126 private void loadFullReactor() {
127 if (!fullReactorLoaded) {
128 synchronized (DefaultModelTransformerContextBuilder.this) {
129 if (!fullReactorLoaded) {
130 doLoadFullReactor();
131 fullReactorLoaded = true;
132 }
133 }
134 }
135 }
136
137 private void doLoadFullReactor() {
138 Path rootDirectory;
139 try {
140 rootDirectory = request.getSession().getRootDirectory();
141 } catch (IllegalStateException e) {
142
143 return;
144 }
145 List<Path> toLoad = new ArrayList<>();
146 Path root = defaultModelBuilder.getModelProcessor().locateExistingPom(rootDirectory);
147 toLoad.add(root);
148 while (!toLoad.isEmpty()) {
149 Path pom = toLoad.remove(0);
150 try {
151 ModelBuilderRequest gaBuildingRequest =
152 ModelBuilderRequest.build(request, ModelSource.fromPath(pom));
153 Model rawModel = defaultModelBuilder.readFileModel(gaBuildingRequest, problems);
154 for (String module : rawModel.getModules()) {
155 Path moduleFile = defaultModelBuilder
156 .getModelProcessor()
157 .locateExistingPom(pom.getParent().resolve(module));
158 if (moduleFile != null) {
159 toLoad.add(moduleFile);
160 }
161 }
162 } catch (ModelBuilderException e) {
163
164 }
165 }
166 }
167
168 private Model findRawModel(Path from, Path p) {
169 if (!Files.isRegularFile(p)) {
170 throw new IllegalArgumentException("Not a regular file: " + p);
171 }
172
173 if (!addEdge(from, p, problems)) {
174 return null;
175 }
176
177 ModelBuilderRequest req = ModelBuilderRequest.build(request, ModelSource.fromPath(p));
178
179 try {
180 return defaultModelBuilder.readRawModel(req, problems);
181 } catch (ModelBuilderException e) {
182
183 }
184 return null;
185 }
186 };
187 }
188
189 private boolean addEdge(Path from, Path p, DefaultModelProblemCollector problems) {
190 try {
191 dag.addEdge(from.toString(), p.toString());
192 return true;
193 } catch (Graph.CycleDetectedException e) {
194 problems.add(new DefaultModelProblem(
195 "Cycle detected between models at " + from + " and " + p,
196 ModelProblem.Severity.FATAL,
197 null,
198 null,
199 0,
200 0,
201 null,
202 e));
203 return false;
204 }
205 }
206
207 @Override
208 public ModelTransformerContext build() {
209 return context;
210 }
211
212 public ModelSource getSource(String groupId, String artifactId) {
213 Set<ModelSource> sources = mappedSources.get(groupId + ":" + artifactId);
214 if (sources == null) {
215 return null;
216 }
217 return sources.stream()
218 .reduce((a, b) -> {
219 throw new IllegalStateException(String.format(
220 "No unique Source for %s:%s: %s and %s",
221 groupId, artifactId, a.getLocation(), b.getLocation()));
222 })
223 .orElse(null);
224 }
225
226 public void putSource(String groupId, String artifactId, ModelSource source) {
227 mappedSources
228 .computeIfAbsent(groupId + ":" + artifactId, k -> new HashSet<>())
229 .add(source);
230 }
231 }