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 lifecycleStarter.execute( session );
295
296 validateActivatedProfiles( session.getProjects(), request.getActiveProfiles() );
297
298 if ( session.getResult().hasExceptions() )
299 {
300 return addExceptionToResult( result, session.getResult().getExceptions().get( 0 ) );
301 }
302 }
303 finally
304 {
305 try
306 {
307 afterSessionEnd( session.getProjects(), session );
308 }
309 catch ( MavenExecutionException e )
310 {
311 return addExceptionToResult( result, e );
312 }
313 }
314
315 return result;
316 }
317
318 private void setupWorkspaceReader( MavenSession session, DefaultRepositorySystemSession repoSession )
319 throws ComponentLookupException
320 {
321
322 List<WorkspaceReader> workspaceReaders = new ArrayList<WorkspaceReader>();
323
324 workspaceReaders.add( container.lookup( WorkspaceReader.class, ReactorReader.HINT ) );
325
326 WorkspaceReader repoWorkspaceReader = repoSession.getWorkspaceReader();
327 if ( repoWorkspaceReader != null )
328 {
329 workspaceReaders.add( repoWorkspaceReader );
330 }
331
332 for ( WorkspaceReader workspaceReader : getProjectScopedExtensionComponents( session.getProjects(),
333 WorkspaceReader.class ) )
334 {
335 if ( workspaceReaders.contains( workspaceReader ) )
336 {
337 continue;
338 }
339 workspaceReaders.add( workspaceReader );
340 }
341 repoSession.setWorkspaceReader( MavenChainedWorkspaceReader.of( workspaceReaders ) );
342 }
343
344 private void afterSessionEnd( Collection<MavenProject> projects, MavenSession session )
345 throws MavenExecutionException
346 {
347 ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
348 try
349 {
350 for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( projects ) )
351 {
352 Thread.currentThread().setContextClassLoader( listener.getClass().getClassLoader() );
353
354 listener.afterSessionEnd( session );
355 }
356 }
357 finally
358 {
359 Thread.currentThread().setContextClassLoader( originalClassLoader );
360 }
361 }
362
363 public RepositorySystemSession newRepositorySession( MavenExecutionRequest request )
364 {
365 return repositorySessionFactory.newRepositorySession( request );
366 }
367
368 private void validateLocalRepository( MavenExecutionRequest request )
369 throws LocalRepositoryNotAccessibleException
370 {
371 File localRepoDir = request.getLocalRepositoryPath();
372
373 logger.debug( "Using local repository at " + localRepoDir );
374
375 localRepoDir.mkdirs();
376
377 if ( !localRepoDir.isDirectory() )
378 {
379 throw new LocalRepositoryNotAccessibleException( "Could not create local repository at " + localRepoDir );
380 }
381 }
382
383 private Collection<AbstractMavenLifecycleParticipant> getLifecycleParticipants( Collection<MavenProject> projects )
384 {
385 Collection<AbstractMavenLifecycleParticipant> lifecycleListeners = new LinkedHashSet<>();
386
387 try
388 {
389 lifecycleListeners.addAll( container.lookupList( AbstractMavenLifecycleParticipant.class ) );
390 }
391 catch ( ComponentLookupException e )
392 {
393
394 logger.warn( "Failed to lookup lifecycle participants: " + e.getMessage() );
395 }
396
397 lifecycleListeners.addAll( getProjectScopedExtensionComponents( projects,
398 AbstractMavenLifecycleParticipant.class ) );
399
400 return lifecycleListeners;
401 }
402
403 protected <T> Collection<T> getProjectScopedExtensionComponents( Collection<MavenProject> projects, Class<T> role )
404 {
405
406 Collection<T> foundComponents = new LinkedHashSet<>();
407 Collection<ClassLoader> scannedRealms = new HashSet<>();
408
409 Thread currentThread = Thread.currentThread();
410 ClassLoader originalContextClassLoader = currentThread.getContextClassLoader();
411 try
412 {
413 for ( MavenProject project : projects )
414 {
415 ClassLoader projectRealm = project.getClassRealm();
416
417 if ( projectRealm != null && scannedRealms.add( projectRealm ) )
418 {
419 currentThread.setContextClassLoader( projectRealm );
420
421 try
422 {
423 foundComponents.addAll( container.lookupList( role ) );
424 }
425 catch ( ComponentLookupException e )
426 {
427
428 logger.warn( "Failed to lookup " + role + ": " + e.getMessage() );
429 }
430 }
431 }
432 return foundComponents;
433 }
434 finally
435 {
436 currentThread.setContextClassLoader( originalContextClassLoader );
437 }
438 }
439
440 private MavenExecutionResult addExceptionToResult( MavenExecutionResult result, Throwable e )
441 {
442 if ( !result.getExceptions().contains( e ) )
443 {
444 result.addException( e );
445 }
446
447 return result;
448 }
449
450 private void validatePrerequisitesForNonMavenPluginProjects( List<MavenProject> projects )
451 {
452 for ( MavenProject mavenProject : projects )
453 {
454 if ( !"maven-plugin".equals( mavenProject.getPackaging() ) )
455 {
456 Prerequisites prerequisites = mavenProject.getPrerequisites();
457 if ( prerequisites != null && prerequisites.getMaven() != null )
458 {
459 logger.warn( "The project " + mavenProject.getId() + " uses prerequisites"
460 + " which is only intended for maven-plugin projects "
461 + "but not for non maven-plugin projects. "
462 + "For such purposes you should use the maven-enforcer-plugin. "
463 + "See https://maven.apache.org/enforcer/enforcer-rules/requireMavenVersion.html" );
464 }
465 }
466 }
467 }
468
469 private void validateActivatedProfiles( List<MavenProject> projects, List<String> activeProfileIds )
470 {
471 Collection<String> notActivatedProfileIds = new LinkedHashSet<>( activeProfileIds );
472
473 for ( MavenProject project : projects )
474 {
475 for ( List<String> profileIds : project.getInjectedProfileIds().values() )
476 {
477 notActivatedProfileIds.removeAll( profileIds );
478 }
479 }
480
481 for ( String notActivatedProfileId : notActivatedProfileIds )
482 {
483 logger.warn( "The requested profile \"" + notActivatedProfileId
484 + "\" could not be activated because it does not exist." );
485 }
486 }
487
488 private Map<String, MavenProject> getProjectMap( Collection<MavenProject> projects )
489 throws DuplicateProjectException
490 {
491 Map<String, MavenProject> index = new LinkedHashMap<>();
492 Map<String, List<File>> collisions = new LinkedHashMap<>();
493
494 for ( MavenProject project : projects )
495 {
496 String projectId = ArtifactUtils.key( project.getGroupId(), project.getArtifactId(), project.getVersion() );
497
498 MavenProject collision = index.get( projectId );
499
500 if ( collision == null )
501 {
502 index.put( projectId, project );
503 }
504 else
505 {
506 List<File> pomFiles = collisions.get( projectId );
507
508 if ( pomFiles == null )
509 {
510 pomFiles = new ArrayList<>( Arrays.asList( collision.getFile(), project.getFile() ) );
511 collisions.put( projectId, pomFiles );
512 }
513 else
514 {
515 pomFiles.add( project.getFile() );
516 }
517 }
518 }
519
520 if ( !collisions.isEmpty() )
521 {
522 throw new DuplicateProjectException( "Two or more projects in the reactor"
523 + " have the same identifier, please make sure that <groupId>:<artifactId>:<version>"
524 + " is unique for each project: " + collisions, collisions );
525 }
526
527 return index;
528 }
529
530 private Result<? extends ProjectDependencyGraph> buildGraph( MavenSession session, MavenExecutionResult result )
531 {
532 Result<? extends ProjectDependencyGraph> graphResult = graphBuilder.build( session );
533 for ( ModelProblem problem : graphResult.getProblems() )
534 {
535 if ( problem.getSeverity() == ModelProblem.Severity.WARNING )
536 {
537 logger.warn( problem.toString() );
538 }
539 else
540 {
541 logger.error( problem.toString() );
542 }
543 }
544
545 if ( !graphResult.hasErrors() )
546 {
547 ProjectDependencyGraph projectDependencyGraph = graphResult.get();
548 session.setProjects( projectDependencyGraph.getSortedProjects() );
549 session.setAllProjects( projectDependencyGraph.getAllProjects() );
550 session.setProjectDependencyGraph( projectDependencyGraph );
551 }
552
553 return graphResult;
554 }
555
556 @Deprecated
557
558 protected Logger getLogger()
559 {
560 return logger;
561 }
562 }