1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven;
20
21 import java.io.File;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.Date;
27 import java.util.HashSet;
28 import java.util.LinkedHashMap;
29 import java.util.LinkedHashSet;
30 import java.util.List;
31 import java.util.Map;
32
33 import org.apache.maven.artifact.ArtifactUtils;
34 import org.apache.maven.execution.DefaultMavenExecutionResult;
35 import org.apache.maven.execution.ExecutionEvent;
36 import org.apache.maven.execution.MavenExecutionRequest;
37 import org.apache.maven.execution.MavenExecutionResult;
38 import org.apache.maven.execution.MavenSession;
39 import org.apache.maven.execution.ProjectDependencyGraph;
40 import org.apache.maven.graph.GraphBuilder;
41 import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory;
42 import org.apache.maven.internal.aether.MavenChainedWorkspaceReader;
43 import org.apache.maven.lifecycle.internal.ExecutionEventCatapult;
44 import org.apache.maven.lifecycle.internal.LifecycleStarter;
45 import org.apache.maven.model.Prerequisites;
46 import org.apache.maven.model.building.ModelProblem;
47 import org.apache.maven.model.building.Result;
48 import org.apache.maven.plugin.LegacySupport;
49 import org.apache.maven.project.MavenProject;
50 import org.apache.maven.project.ProjectBuilder;
51 import org.apache.maven.repository.LocalRepositoryNotAccessibleException;
52 import org.apache.maven.session.scope.internal.SessionScope;
53 import org.codehaus.plexus.PlexusContainer;
54 import org.codehaus.plexus.component.annotations.Component;
55 import org.codehaus.plexus.component.annotations.Requirement;
56 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
57 import org.codehaus.plexus.logging.Logger;
58 import org.eclipse.aether.DefaultRepositorySystemSession;
59 import org.eclipse.aether.RepositorySystemSession;
60 import org.eclipse.aether.repository.WorkspaceReader;
61
62
63
64
65 @Component(role = Maven.class)
66 public class DefaultMaven implements Maven {
67
68 @Requirement
69 private Logger logger;
70
71 @Requirement
72 protected ProjectBuilder projectBuilder;
73
74 @Requirement
75 private LifecycleStarter lifecycleStarter;
76
77 @Requirement
78 protected PlexusContainer container;
79
80 @Requirement
81 private ExecutionEventCatapult eventCatapult;
82
83 @Requirement
84 private LegacySupport legacySupport;
85
86 @Requirement
87 private SessionScope sessionScope;
88
89 @Requirement
90 private DefaultRepositorySystemSessionFactory repositorySessionFactory;
91
92 @Requirement(hint = GraphBuilder.HINT)
93 private GraphBuilder graphBuilder;
94
95 @Override
96 public MavenExecutionResult execute(MavenExecutionRequest request) {
97 MavenExecutionResult result;
98
99 try {
100 result = doExecute(request);
101 } catch (OutOfMemoryError e) {
102 result = addExceptionToResult(new DefaultMavenExecutionResult(), e);
103 } catch (RuntimeException e) {
104
105 if (e.getCause() instanceof ProjectCycleException) {
106 result = addExceptionToResult(new DefaultMavenExecutionResult(), e.getCause());
107 } else {
108 result = addExceptionToResult(
109 new DefaultMavenExecutionResult(), new InternalErrorException("Internal error: " + e, e));
110 }
111 } finally {
112 legacySupport.setSession(null);
113 }
114
115 return result;
116 }
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146 @SuppressWarnings("checkstyle:methodlength")
147 private MavenExecutionResult doExecute(MavenExecutionRequest request) {
148 request.setStartTime(new Date());
149
150 MavenExecutionResult result = new DefaultMavenExecutionResult();
151
152 try {
153 validateLocalRepository(request);
154 } catch (LocalRepositoryNotAccessibleException e) {
155 return addExceptionToResult(result, e);
156 }
157
158
159
160
161
162
163 sessionScope.enter();
164 try {
165 DefaultRepositorySystemSession repoSession = (DefaultRepositorySystemSession) newRepositorySession(request);
166 MavenSession session = new MavenSession(container, repoSession, request, result);
167
168 sessionScope.seed(MavenSession.class, session);
169
170 legacySupport.setSession(session);
171
172 return doExecute(request, session, result, repoSession);
173 } finally {
174 sessionScope.exit();
175 }
176 }
177
178 private MavenExecutionResult doExecute(
179 MavenExecutionRequest request,
180 MavenSession session,
181 MavenExecutionResult result,
182 DefaultRepositorySystemSession repoSession) {
183 try {
184
185 for (AbstractMavenLifecycleParticipant listener :
186 getLifecycleParticipants(Collections.<MavenProject>emptyList())) {
187 listener.afterSessionStart(session);
188 }
189
190 } catch (MavenExecutionException e) {
191 return addExceptionToResult(result, e);
192 }
193
194 eventCatapult.fire(ExecutionEvent.Type.ProjectDiscoveryStarted, session, null);
195
196 Result<? extends ProjectDependencyGraph> graphResult = buildGraph(session, result);
197
198 if (graphResult.hasErrors()) {
199 return addExceptionToResult(
200 result, graphResult.getProblems().iterator().next().getException());
201 }
202
203 try {
204 session.setProjectMap(getProjectMap(session.getProjects()));
205 } catch (DuplicateProjectException e) {
206 return addExceptionToResult(result, e);
207 }
208
209 try {
210 setupWorkspaceReader(session, repoSession);
211 } catch (ComponentLookupException e) {
212 return addExceptionToResult(result, e);
213 }
214
215 repoSession.setReadOnly();
216
217 ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
218 try {
219 for (AbstractMavenLifecycleParticipant listener : getLifecycleParticipants(session.getProjects())) {
220 Thread.currentThread().setContextClassLoader(listener.getClass().getClassLoader());
221
222 listener.afterProjectsRead(session);
223 }
224 } catch (MavenExecutionException e) {
225 return addExceptionToResult(result, e);
226 } finally {
227 Thread.currentThread().setContextClassLoader(originalClassLoader);
228 }
229
230
231
232
233
234
235
236
237
238
239 graphResult = buildGraph(session, result);
240
241 if (graphResult.hasErrors()) {
242 return addExceptionToResult(
243 result, graphResult.getProblems().iterator().next().getException());
244 }
245
246 try {
247 if (result.hasExceptions()) {
248 return result;
249 }
250
251 result.setTopologicallySortedProjects(session.getProjects());
252
253 result.setProject(session.getTopLevelProject());
254
255 validatePrerequisitesForNonMavenPluginProjects(session.getProjects());
256
257 validateActivatedProfiles(
258 session.getProjects(), request.getActiveProfiles(), request.getInactiveProfiles());
259
260 lifecycleStarter.execute(session);
261
262 validateActivatedProfiles(
263 session.getProjects(), request.getActiveProfiles(), request.getInactiveProfiles());
264
265 if (session.getResult().hasExceptions()) {
266 return addExceptionToResult(
267 result, session.getResult().getExceptions().get(0));
268 }
269 } finally {
270 try {
271 afterSessionEnd(session.getProjects(), session);
272 } catch (MavenExecutionException e) {
273 return addExceptionToResult(result, e);
274 }
275 }
276
277 return result;
278 }
279
280 private void setupWorkspaceReader(MavenSession session, DefaultRepositorySystemSession repoSession)
281 throws ComponentLookupException {
282
283 List<WorkspaceReader> workspaceReaders = new ArrayList<WorkspaceReader>();
284
285 workspaceReaders.add(container.lookup(WorkspaceReader.class, ReactorReader.HINT));
286
287 WorkspaceReader repoWorkspaceReader = repoSession.getWorkspaceReader();
288 if (repoWorkspaceReader != null) {
289 workspaceReaders.add(repoWorkspaceReader);
290 }
291
292 for (WorkspaceReader workspaceReader :
293 getProjectScopedExtensionComponents(session.getProjects(), WorkspaceReader.class)) {
294 if (workspaceReaders.contains(workspaceReader)) {
295 continue;
296 }
297 workspaceReaders.add(workspaceReader);
298 }
299 repoSession.setWorkspaceReader(MavenChainedWorkspaceReader.of(workspaceReaders));
300 }
301
302 private void afterSessionEnd(Collection<MavenProject> projects, MavenSession session)
303 throws MavenExecutionException {
304 ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
305 try {
306 for (AbstractMavenLifecycleParticipant listener : getLifecycleParticipants(projects)) {
307 Thread.currentThread().setContextClassLoader(listener.getClass().getClassLoader());
308
309 listener.afterSessionEnd(session);
310 }
311 } finally {
312 Thread.currentThread().setContextClassLoader(originalClassLoader);
313 }
314 }
315
316 public RepositorySystemSession newRepositorySession(MavenExecutionRequest request) {
317 return repositorySessionFactory.newRepositorySession(request);
318 }
319
320 private void validateLocalRepository(MavenExecutionRequest request) throws LocalRepositoryNotAccessibleException {
321 File localRepoDir = request.getLocalRepositoryPath();
322
323 logger.debug("Using local repository at " + localRepoDir);
324
325 localRepoDir.mkdirs();
326
327 if (!localRepoDir.isDirectory()) {
328 throw new LocalRepositoryNotAccessibleException("Could not create local repository at " + localRepoDir);
329 }
330 }
331
332 private Collection<AbstractMavenLifecycleParticipant> getLifecycleParticipants(Collection<MavenProject> projects) {
333 Collection<AbstractMavenLifecycleParticipant> lifecycleListeners = new LinkedHashSet<>();
334
335 try {
336 lifecycleListeners.addAll(container.lookupList(AbstractMavenLifecycleParticipant.class));
337 } catch (ComponentLookupException e) {
338
339 logger.warn("Failed to lookup lifecycle participants: " + e.getMessage());
340 }
341
342 lifecycleListeners.addAll(
343 getProjectScopedExtensionComponents(projects, AbstractMavenLifecycleParticipant.class));
344
345 return lifecycleListeners;
346 }
347
348 protected <T> Collection<T> getProjectScopedExtensionComponents(Collection<MavenProject> projects, Class<T> role) {
349
350 Collection<T> foundComponents = new LinkedHashSet<>();
351 Collection<ClassLoader> scannedRealms = new HashSet<>();
352
353 Thread currentThread = Thread.currentThread();
354 ClassLoader originalContextClassLoader = currentThread.getContextClassLoader();
355 try {
356 for (MavenProject project : projects) {
357 ClassLoader projectRealm = project.getClassRealm();
358
359 if (projectRealm != null && scannedRealms.add(projectRealm)) {
360 currentThread.setContextClassLoader(projectRealm);
361
362 try {
363 foundComponents.addAll(container.lookupList(role));
364 } catch (ComponentLookupException e) {
365
366 logger.warn("Failed to lookup " + role + ": " + e.getMessage());
367 }
368 }
369 }
370 return foundComponents;
371 } finally {
372 currentThread.setContextClassLoader(originalContextClassLoader);
373 }
374 }
375
376 private MavenExecutionResult addExceptionToResult(MavenExecutionResult result, Throwable e) {
377 if (!result.getExceptions().contains(e)) {
378 result.addException(e);
379 }
380
381 return result;
382 }
383
384 private void validatePrerequisitesForNonMavenPluginProjects(List<MavenProject> projects) {
385 for (MavenProject mavenProject : projects) {
386 if (!"maven-plugin".equals(mavenProject.getPackaging())) {
387 Prerequisites prerequisites = mavenProject.getPrerequisites();
388 if (prerequisites != null && prerequisites.getMaven() != null) {
389 logger.warn("The project " + mavenProject.getId() + " uses prerequisites"
390 + " which is only intended for maven-plugin projects "
391 + "but not for non maven-plugin projects. "
392 + "For such purposes you should use the maven-enforcer-plugin. "
393 + "See https://maven.apache.org/enforcer/enforcer-rules/requireMavenVersion.html");
394 }
395 }
396 }
397 }
398
399 private void validateActivatedProfiles(
400 List<MavenProject> projects, List<String> activeProfileIds, List<String> inactiveProfileIds) {
401 Collection<String> notActivatedProfileIds = new LinkedHashSet<>(activeProfileIds);
402
403 for (MavenProject project : projects) {
404 for (List<String> profileIds : project.getInjectedProfileIds().values()) {
405 notActivatedProfileIds.removeAll(profileIds);
406 }
407 }
408
409 notActivatedProfileIds.removeAll(inactiveProfileIds);
410
411 for (String notActivatedProfileId : notActivatedProfileIds) {
412 logger.warn("The requested profile \"" + notActivatedProfileId
413 + "\" could not be activated because it does not exist.");
414 }
415 }
416
417 private Map<String, MavenProject> getProjectMap(Collection<MavenProject> projects)
418 throws DuplicateProjectException {
419 Map<String, MavenProject> index = new LinkedHashMap<>();
420 Map<String, List<File>> collisions = new LinkedHashMap<>();
421
422 for (MavenProject project : projects) {
423 String projectId = ArtifactUtils.key(project.getGroupId(), project.getArtifactId(), project.getVersion());
424
425 MavenProject collision = index.get(projectId);
426
427 if (collision == null) {
428 index.put(projectId, project);
429 } else {
430 List<File> pomFiles = collisions.get(projectId);
431
432 if (pomFiles == null) {
433 pomFiles = new ArrayList<>(Arrays.asList(collision.getFile(), project.getFile()));
434 collisions.put(projectId, pomFiles);
435 } else {
436 pomFiles.add(project.getFile());
437 }
438 }
439 }
440
441 if (!collisions.isEmpty()) {
442 throw new DuplicateProjectException(
443 "Two or more projects in the reactor"
444 + " have the same identifier, please make sure that <groupId>:<artifactId>:<version>"
445 + " is unique for each project: " + collisions,
446 collisions);
447 }
448
449 return index;
450 }
451
452 private Result<? extends ProjectDependencyGraph> buildGraph(MavenSession session, MavenExecutionResult result) {
453 Result<? extends ProjectDependencyGraph> graphResult = graphBuilder.build(session);
454 for (ModelProblem problem : graphResult.getProblems()) {
455 if (problem.getSeverity() == ModelProblem.Severity.WARNING) {
456 logger.warn(problem.toString());
457 } else {
458 logger.error(problem.toString());
459 }
460 }
461
462 if (!graphResult.hasErrors()) {
463 ProjectDependencyGraph projectDependencyGraph = graphResult.get();
464 session.setProjects(projectDependencyGraph.getSortedProjects());
465 session.setAllProjects(projectDependencyGraph.getAllProjects());
466 session.setProjectDependencyGraph(projectDependencyGraph);
467 }
468
469 return graphResult;
470 }
471
472 @Deprecated
473
474 protected Logger getLogger() {
475 return logger;
476 }
477 }