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