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.building.ModelProblem;
46 import org.apache.maven.model.building.Result;
47 import org.apache.maven.plugin.LegacySupport;
48 import org.apache.maven.project.MavenProject;
49 import org.apache.maven.project.ProjectBuilder;
50 import org.apache.maven.repository.LocalRepositoryNotAccessibleException;
51 import org.apache.maven.session.scope.internal.SessionScope;
52 import org.codehaus.plexus.PlexusContainer;
53 import org.codehaus.plexus.component.annotations.Component;
54 import org.codehaus.plexus.component.annotations.Requirement;
55 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
56 import org.codehaus.plexus.logging.Logger;
57 import org.eclipse.aether.DefaultRepositorySystemSession;
58 import org.eclipse.aether.RepositorySystemSession;
59 import org.eclipse.aether.repository.WorkspaceReader;
60 import org.eclipse.aether.util.repository.ChainedWorkspaceReader;
61
62 import com.google.common.collect.Iterables;
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 for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( Collections
207 .<MavenProject>emptyList() ) )
208 {
209 listener.afterSessionStart( session );
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,
224 Iterables.toArray( graphResult.getProblems(), ModelProblem.class )[0]
225 .getException() );
226 }
227
228 try
229 {
230 session.setProjectMap( getProjectMap( session.getProjects() ) );
231 }
232 catch ( DuplicateProjectException e )
233 {
234 return addExceptionToResult( result, e );
235 }
236
237 WorkspaceReader reactorWorkspace;
238 try
239 {
240 reactorWorkspace = container.lookup( WorkspaceReader.class, ReactorReader.HINT );
241 }
242 catch ( ComponentLookupException e )
243 {
244 return addExceptionToResult( result, e );
245 }
246
247
248
249
250
251
252
253
254 repoSession.setWorkspaceReader( ChainedWorkspaceReader.newInstance( reactorWorkspace,
255 repoSession.getWorkspaceReader() ) );
256
257 repoSession.setReadOnly();
258
259 ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
260 try
261 {
262 for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( session.getProjects() ) )
263 {
264 Thread.currentThread().setContextClassLoader( listener.getClass().getClassLoader() );
265
266 listener.afterProjectsRead( session );
267 }
268 }
269 catch ( MavenExecutionException e )
270 {
271 return addExceptionToResult( result, e );
272 }
273 finally
274 {
275 Thread.currentThread().setContextClassLoader( originalClassLoader );
276 }
277
278
279
280
281
282
283
284
285
286
287 graphResult = buildGraph( session, result );
288
289 if ( graphResult.hasErrors() )
290 {
291 return addExceptionToResult( result,
292 Iterables.toArray( graphResult.getProblems(), ModelProblem.class )[0]
293 .getException() );
294 }
295
296 try
297 {
298 if ( result.hasExceptions() )
299 {
300 return result;
301 }
302
303 result.setTopologicallySortedProjects( session.getProjects() );
304
305 result.setProject( session.getTopLevelProject() );
306
307 lifecycleStarter.execute( session );
308
309 validateActivatedProfiles( session.getProjects(), request.getActiveProfiles() );
310
311 if ( session.getResult().hasExceptions() )
312 {
313 return addExceptionToResult( result, session.getResult().getExceptions().get( 0 ) );
314 }
315 }
316 finally
317 {
318 try
319 {
320 afterSessionEnd( session.getProjects(), session );
321 }
322 catch ( MavenExecutionException e )
323 {
324 return addExceptionToResult( result, e );
325 }
326 }
327
328 return result;
329 }
330
331 private void afterSessionEnd( Collection<MavenProject> projects, MavenSession session )
332 throws MavenExecutionException
333 {
334 ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
335 try
336 {
337 for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( projects ) )
338 {
339 Thread.currentThread().setContextClassLoader( listener.getClass().getClassLoader() );
340
341 listener.afterSessionEnd( session );
342 }
343 }
344 finally
345 {
346 Thread.currentThread().setContextClassLoader( originalClassLoader );
347 }
348 }
349
350 public RepositorySystemSession newRepositorySession( MavenExecutionRequest request )
351 {
352 return repositorySessionFactory.newRepositorySession( request );
353 }
354
355 private void validateLocalRepository( MavenExecutionRequest request )
356 throws LocalRepositoryNotAccessibleException
357 {
358 File localRepoDir = request.getLocalRepositoryPath();
359
360 logger.debug( "Using local repository at " + localRepoDir );
361
362 localRepoDir.mkdirs();
363
364 if ( !localRepoDir.isDirectory() )
365 {
366 throw new LocalRepositoryNotAccessibleException( "Could not create local repository at " + localRepoDir );
367 }
368 }
369
370 private Collection<AbstractMavenLifecycleParticipant> getLifecycleParticipants( Collection<MavenProject> projects )
371 {
372 Collection<AbstractMavenLifecycleParticipant> lifecycleListeners =
373 new LinkedHashSet<AbstractMavenLifecycleParticipant>();
374
375 ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
376 try
377 {
378 try
379 {
380 lifecycleListeners.addAll( container.lookupList( AbstractMavenLifecycleParticipant.class ) );
381 }
382 catch ( ComponentLookupException e )
383 {
384
385 logger.warn( "Failed to lookup lifecycle participants: " + e.getMessage() );
386 }
387
388 Collection<ClassLoader> scannedRealms = new HashSet<ClassLoader>();
389
390 for ( MavenProject project : projects )
391 {
392 ClassLoader projectRealm = project.getClassRealm();
393
394 if ( projectRealm != null && scannedRealms.add( projectRealm ) )
395 {
396 Thread.currentThread().setContextClassLoader( projectRealm );
397
398 try
399 {
400 lifecycleListeners.addAll( container.lookupList( AbstractMavenLifecycleParticipant.class ) );
401 }
402 catch ( ComponentLookupException e )
403 {
404
405 logger.warn( "Failed to lookup lifecycle participants: " + e.getMessage() );
406 }
407 }
408 }
409 }
410 finally
411 {
412 Thread.currentThread().setContextClassLoader( originalClassLoader );
413 }
414
415 return lifecycleListeners;
416 }
417
418 private MavenExecutionResult addExceptionToResult( MavenExecutionResult result, Throwable e )
419 {
420 if ( !result.getExceptions().contains( e ) )
421 {
422 result.addException( e );
423 }
424
425 return result;
426 }
427
428 private void validateActivatedProfiles( List<MavenProject> projects, List<String> activeProfileIds )
429 {
430 Collection<String> notActivatedProfileIds = new LinkedHashSet<String>( activeProfileIds );
431
432 for ( MavenProject project : projects )
433 {
434 for ( List<String> profileIds : project.getInjectedProfileIds().values() )
435 {
436 notActivatedProfileIds.removeAll( profileIds );
437 }
438 }
439
440 for ( String notActivatedProfileId : notActivatedProfileIds )
441 {
442 logger.warn( "The requested profile \"" + notActivatedProfileId
443 + "\" could not be activated because it does not exist." );
444 }
445 }
446
447 private Map<String, MavenProject> getProjectMap( Collection<MavenProject> projects )
448 throws DuplicateProjectException
449 {
450 Map<String, MavenProject> index = new LinkedHashMap<String, MavenProject>();
451 Map<String, List<File>> collisions = new LinkedHashMap<String, List<File>>();
452
453 for ( MavenProject project : projects )
454 {
455 String projectId = ArtifactUtils.key( project.getGroupId(), project.getArtifactId(), project.getVersion() );
456
457 MavenProject collision = index.get( projectId );
458
459 if ( collision == null )
460 {
461 index.put( projectId, project );
462 }
463 else
464 {
465 List<File> pomFiles = collisions.get( projectId );
466
467 if ( pomFiles == null )
468 {
469 pomFiles = new ArrayList<File>( Arrays.asList( collision.getFile(), project.getFile() ) );
470 collisions.put( projectId, pomFiles );
471 }
472 else
473 {
474 pomFiles.add( project.getFile() );
475 }
476 }
477 }
478
479 if ( !collisions.isEmpty() )
480 {
481 throw new DuplicateProjectException( "Two or more projects in the reactor"
482 + " have the same identifier, please make sure that <groupId>:<artifactId>:<version>"
483 + " is unique for each project: " + collisions, collisions );
484 }
485
486 return index;
487 }
488
489 private Result<? extends ProjectDependencyGraph> buildGraph( MavenSession session, MavenExecutionResult result )
490 {
491 Result<? extends ProjectDependencyGraph> graphResult = graphBuilder.build( session );
492 for ( ModelProblem problem : graphResult.getProblems() )
493 {
494 if ( problem.getSeverity() == ModelProblem.Severity.WARNING )
495 {
496 logger.warn( problem.toString() );
497 }
498 else
499 {
500 logger.error( problem.toString() );
501 }
502 }
503
504 if ( !graphResult.hasErrors() )
505 {
506 ProjectDependencyGraph projectDependencyGraph = graphResult.get();
507 session.setProjects( projectDependencyGraph.getSortedProjects() );
508 session.setAllProjects( projectDependencyGraph.getSortedProjects() );
509 session.setProjectDependencyGraph( projectDependencyGraph );
510 }
511
512 return graphResult;
513 }
514
515 @Deprecated
516
517 protected Logger getLogger()
518 {
519 return logger;
520 }
521 }