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