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