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.io.IOException;
24  import java.io.InputStream;
25  import java.util.ArrayList;
26  import java.util.Arrays;
27  import java.util.Collection;
28  import java.util.Collections;
29  import java.util.Date;
30  import java.util.HashMap;
31  import java.util.HashSet;
32  import java.util.LinkedHashMap;
33  import java.util.LinkedHashSet;
34  import java.util.List;
35  import java.util.Map;
36  import java.util.Properties;
37  
38  import org.apache.maven.artifact.ArtifactUtils;
39  import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
40  import org.apache.maven.eventspy.internal.EventSpyDispatcher;
41  import org.apache.maven.execution.DefaultMavenExecutionResult;
42  import org.apache.maven.execution.ExecutionEvent;
43  import org.apache.maven.execution.MavenExecutionRequest;
44  import org.apache.maven.execution.MavenExecutionRequestPopulationException;
45  import org.apache.maven.execution.MavenExecutionRequestPopulator;
46  import org.apache.maven.execution.MavenExecutionResult;
47  import org.apache.maven.execution.MavenSession;
48  import org.apache.maven.execution.ProjectDependencyGraph;
49  import org.apache.maven.lifecycle.internal.ExecutionEventCatapult;
50  import org.apache.maven.lifecycle.internal.LifecycleStarter;
51  import org.apache.maven.model.Plugin;
52  import org.apache.maven.model.building.ModelProblem;
53  import org.apache.maven.model.building.ModelProblemUtils;
54  import org.apache.maven.model.building.ModelSource;
55  import org.apache.maven.model.building.UrlModelSource;
56  import org.apache.maven.plugin.LegacySupport;
57  import org.apache.maven.project.MavenProject;
58  import org.apache.maven.project.ProjectBuilder;
59  import org.apache.maven.project.ProjectBuildingException;
60  import org.apache.maven.project.ProjectBuildingRequest;
61  import org.apache.maven.project.ProjectBuildingResult;
62  import org.apache.maven.repository.LocalRepositoryNotAccessibleException;
63  import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
64  import org.apache.maven.settings.Mirror;
65  import org.apache.maven.settings.Proxy;
66  import org.apache.maven.settings.Server;
67  import org.apache.maven.settings.building.SettingsProblem;
68  import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest;
69  import org.apache.maven.settings.crypto.SettingsDecrypter;
70  import org.apache.maven.settings.crypto.SettingsDecryptionResult;
71  import org.codehaus.plexus.PlexusContainer;
72  import org.codehaus.plexus.component.annotations.Component;
73  import org.codehaus.plexus.component.annotations.Requirement;
74  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
75  import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
76  import org.codehaus.plexus.logging.Logger;
77  import org.codehaus.plexus.util.IOUtil;
78  import org.codehaus.plexus.util.StringUtils;
79  import org.codehaus.plexus.util.dag.CycleDetectedException;
80  import org.codehaus.plexus.util.xml.Xpp3Dom;
81  import org.eclipse.aether.ConfigurationProperties;
82  import org.eclipse.aether.DefaultRepositorySystemSession;
83  import org.eclipse.aether.RepositorySystem;
84  import org.eclipse.aether.RepositorySystemSession;
85  import org.eclipse.aether.repository.LocalRepository;
86  import org.eclipse.aether.repository.NoLocalRepositoryManagerException;
87  import org.eclipse.aether.repository.RepositoryPolicy;
88  import org.eclipse.aether.repository.WorkspaceReader;
89  import org.eclipse.aether.resolution.ResolutionErrorPolicy;
90  import org.eclipse.aether.spi.localrepo.LocalRepositoryManagerFactory;
91  import org.eclipse.aether.util.repository.AuthenticationBuilder;
92  import org.eclipse.aether.util.repository.ChainedWorkspaceReader;
93  import org.eclipse.aether.util.repository.DefaultAuthenticationSelector;
94  import org.eclipse.aether.util.repository.DefaultMirrorSelector;
95  import org.eclipse.aether.util.repository.DefaultProxySelector;
96  import org.eclipse.aether.util.repository.SimpleResolutionErrorPolicy;
97  
98  
99  
100 
101 @Component( role = Maven.class )
102 public class DefaultMaven
103     implements Maven
104 {
105 
106     @Requirement
107     private Logger logger;
108 
109     @Requirement
110     protected ProjectBuilder projectBuilder;
111 
112     @Requirement
113     private LifecycleStarter lifecycleStarter;
114 
115     @Requirement
116     protected PlexusContainer container;
117 
118     @Requirement
119     MavenExecutionRequestPopulator populator;
120 
121     @Requirement
122     private ExecutionEventCatapult eventCatapult;
123 
124     @Requirement
125     private ArtifactHandlerManager artifactHandlerManager;
126 
127     @Requirement( optional = true, hint = "ide" )
128     private WorkspaceReader workspaceRepository;
129 
130     @Requirement
131     private RepositorySystem repoSystem;
132 
133     @Requirement( optional = true, hint = "simple" )
134     private LocalRepositoryManagerFactory simpleLocalRepositoryManagerFactory;
135 
136     @Requirement
137     private SettingsDecrypter settingsDecrypter;
138 
139     @Requirement
140     private LegacySupport legacySupport;
141 
142     @Requirement
143     private EventSpyDispatcher eventSpyDispatcher;
144 
145     @Requirement
146     private SessionScope sessionScope;
147         
148     public MavenExecutionResult execute( MavenExecutionRequest request )
149     {
150         MavenExecutionResult result;
151 
152         try
153         {
154             result = doExecute( populator.populateDefaults( request ) );
155         }
156         catch ( OutOfMemoryError e )
157         {
158             result = addExceptionToResult( new DefaultMavenExecutionResult(), e );
159         }
160         catch ( MavenExecutionRequestPopulationException e )
161         {
162             result = addExceptionToResult( new DefaultMavenExecutionResult(), e );
163         }
164         catch ( RuntimeException e )
165         {
166             result =
167                 addExceptionToResult( new DefaultMavenExecutionResult(), new InternalErrorException( "Internal error: "
168                     + e, e ) );
169         }
170         finally
171         {
172             legacySupport.setSession( null );
173         }
174 
175         return result;
176     }
177 
178     
179     
180     
181     
182     
183     
184     
185     
186     
187     
188     
189     
190     
191     
192     
193     
194     
195     
196     
197     
198     
199     
200     
201     
202     
203     
204     
205     
206     private MavenExecutionResult doExecute( MavenExecutionRequest request )
207     {
208         request.setStartTime( new Date() );
209         
210         MavenExecutionResult result = new DefaultMavenExecutionResult();
211 
212         try
213         {
214             validateLocalRepository( request );
215         }
216         catch ( LocalRepositoryNotAccessibleException e )
217         {
218             return addExceptionToResult( result, e );
219         }
220 
221         DefaultRepositorySystemSession repoSession = (DefaultRepositorySystemSession) newRepositorySession( request );
222 
223         MavenSession session = new MavenSession( container, repoSession, request, result );
224         legacySupport.setSession( session );
225 
226         try
227         {
228             for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( Collections.<MavenProject> emptyList() ) )
229             {
230                 listener.afterSessionStart( session );
231             }
232         }
233         catch ( MavenExecutionException e )
234         {
235             return addExceptionToResult( result, e );
236         }
237 
238         eventCatapult.fire( ExecutionEvent.Type.ProjectDiscoveryStarted, session, null );
239 
240         List<MavenProject> projects;
241         try
242         {
243             projects = getProjectsForMavenReactor( session );
244             
245             
246             
247             session.setAllProjects( projects );
248         }
249         catch ( ProjectBuildingException e )
250         {
251             return addExceptionToResult( result, e );
252         }
253 
254         validateProjects( projects );
255 
256         
257         
258         
259         
260         
261         ProjectDependencyGraph projectDependencyGraph = createProjectDependencyGraph( projects, request, result, true );
262 
263         if ( result.hasExceptions() )
264         {
265             return result;
266         }
267 
268         session.setProjects( projectDependencyGraph.getSortedProjects() );
269 
270         try
271         {
272             session.setProjectMap( getProjectMap( session.getProjects() ) );
273         }
274         catch ( DuplicateProjectException e )
275         {
276             return addExceptionToResult( result, e );
277         }
278         
279         WorkspaceReader reactorWorkspace;
280         sessionScope.enter();
281         sessionScope.seed( MavenSession.class, session );
282         try
283         {
284             reactorWorkspace = container.lookup( WorkspaceReader.class, ReactorReader.HINT );
285         }
286         catch ( ComponentLookupException e )
287         {
288             return addExceptionToResult( result, e );
289         }
290         
291         
292         
293         
294         
295         
296         
297         
298         repoSession.setWorkspaceReader( ChainedWorkspaceReader.newInstance( reactorWorkspace,
299                                                                             repoSession.getWorkspaceReader() ) );
300 
301         repoSession.setReadOnly();
302 
303         ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
304         try
305         {
306             for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( projects ) )
307             {
308                 Thread.currentThread().setContextClassLoader( listener.getClass().getClassLoader() );
309 
310                 listener.afterProjectsRead( session );
311             }
312         }
313         catch ( MavenExecutionException e )
314         {
315             return addExceptionToResult( result, e );
316         }
317         finally
318         {
319             Thread.currentThread().setContextClassLoader( originalClassLoader );
320         }
321 
322         
323         
324         
325         
326         
327         
328         
329         
330         projectDependencyGraph = createProjectDependencyGraph( session.getProjects(), request, result, false );
331 
332         try
333         {
334             if ( result.hasExceptions() )
335             {
336                 return result;
337             }
338 
339             session.setProjects( projectDependencyGraph.getSortedProjects() );
340 
341             session.setProjectDependencyGraph( projectDependencyGraph );
342 
343             result.setTopologicallySortedProjects( session.getProjects() );
344 
345             result.setProject( session.getTopLevelProject() );
346 
347             lifecycleStarter.execute( session );
348 
349             validateActivatedProfiles( session.getProjects(), request.getActiveProfiles() );
350 
351             if ( session.getResult().hasExceptions() )
352             {
353                 return addExceptionToResult( result, session.getResult().getExceptions().get( 0 ) );
354             }
355         }
356         finally
357         {
358             try
359             {
360                 afterSessionEnd( projects, session );
361             }
362             catch ( MavenExecutionException e )
363             {
364                 return addExceptionToResult( result, e );
365             }
366             finally
367             {
368                 sessionScope.exit();
369             }
370         }
371 
372         return result;
373     }
374 
375     private void afterSessionEnd( Collection<MavenProject> projects, MavenSession session ) 
376         throws MavenExecutionException
377     {
378         ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
379         try
380         {
381             for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( projects ) )
382             {
383                 Thread.currentThread().setContextClassLoader( listener.getClass().getClassLoader() );
384 
385                 listener.afterSessionEnd( session );
386             }
387         }
388         finally
389         {
390             Thread.currentThread().setContextClassLoader( originalClassLoader );
391         }
392     }
393 
394     public RepositorySystemSession newRepositorySession( MavenExecutionRequest request )
395     {
396         DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
397 
398         session.setCache( request.getRepositoryCache() );
399 
400         Map<Object, Object> configProps = new LinkedHashMap<Object, Object>();
401         configProps.put( ConfigurationProperties.USER_AGENT, getUserAgent() );
402         configProps.put( ConfigurationProperties.INTERACTIVE, request.isInteractiveMode() );
403         configProps.putAll( request.getSystemProperties() );
404         configProps.putAll( request.getUserProperties() );
405 
406         session.setOffline( request.isOffline() );
407         session.setChecksumPolicy( request.getGlobalChecksumPolicy() );
408         if ( request.isNoSnapshotUpdates() )
409         {
410             session.setUpdatePolicy( RepositoryPolicy.UPDATE_POLICY_NEVER );
411         }
412         else if ( request.isUpdateSnapshots() )
413         {
414             session.setUpdatePolicy( RepositoryPolicy.UPDATE_POLICY_ALWAYS );
415         }
416         else
417         {
418             session.setUpdatePolicy( null );
419         }
420 
421         int errorPolicy = 0;
422         errorPolicy |= request.isCacheNotFound() ? ResolutionErrorPolicy.CACHE_NOT_FOUND : 0;
423         errorPolicy |= request.isCacheTransferError() ? ResolutionErrorPolicy.CACHE_TRANSFER_ERROR : 0;
424         session.setResolutionErrorPolicy( new SimpleResolutionErrorPolicy( errorPolicy, errorPolicy
425             | ResolutionErrorPolicy.CACHE_NOT_FOUND ) );
426 
427         session.setArtifactTypeRegistry( RepositoryUtils.newArtifactTypeRegistry( artifactHandlerManager ) );
428 
429         LocalRepository localRepo = new LocalRepository( request.getLocalRepository().getBasedir() );
430 
431         if ( request.isUseLegacyLocalRepository() )
432         {
433             logger.warn( "Disabling enhanced local repository: using legacy is strongly discouraged to ensure build reproducibility." );
434             try
435             {
436                 session.setLocalRepositoryManager( simpleLocalRepositoryManagerFactory.newInstance( session, localRepo ) );
437             }
438             catch ( NoLocalRepositoryManagerException e )
439             {
440 
441                 logger.warn( "Failed to configure legacy local repository: back to default" );
442                 session.setLocalRepositoryManager( repoSystem.newLocalRepositoryManager( session, localRepo ) );
443             }
444         }
445         else
446         {
447             session.setLocalRepositoryManager( repoSystem.newLocalRepositoryManager( session, localRepo ) );
448         }
449 
450         if ( request.getWorkspaceReader() != null )
451         {
452             session.setWorkspaceReader( request.getWorkspaceReader() );
453         }
454         else
455         {
456             session.setWorkspaceReader( workspaceRepository );
457         }
458 
459         DefaultSettingsDecryptionRequest decrypt = new DefaultSettingsDecryptionRequest();
460         decrypt.setProxies( request.getProxies() );
461         decrypt.setServers( request.getServers() );
462         SettingsDecryptionResult decrypted = settingsDecrypter.decrypt( decrypt );
463 
464         if ( logger.isDebugEnabled() )
465         {
466             for ( SettingsProblem problem : decrypted.getProblems() )
467             {
468                 logger.debug( problem.getMessage(), problem.getException() );
469             }
470         }
471 
472         DefaultMirrorSelector mirrorSelector = new DefaultMirrorSelector();
473         for ( Mirror mirror : request.getMirrors() )
474         {
475             mirrorSelector.add( mirror.getId(), mirror.getUrl(), mirror.getLayout(), false, mirror.getMirrorOf(),
476                                 mirror.getMirrorOfLayouts() );
477         }
478         session.setMirrorSelector( mirrorSelector );
479 
480         DefaultProxySelector proxySelector = new DefaultProxySelector();
481         for ( Proxy proxy : decrypted.getProxies() )
482         {
483             AuthenticationBuilder authBuilder = new AuthenticationBuilder();
484             authBuilder.addUsername( proxy.getUsername() ).addPassword( proxy.getPassword() );
485             proxySelector.add( new org.eclipse.aether.repository.Proxy( proxy.getProtocol(), proxy.getHost(),
486                                                                         proxy.getPort(), authBuilder.build() ),
487                                proxy.getNonProxyHosts() );
488         }
489         session.setProxySelector( proxySelector );
490 
491         DefaultAuthenticationSelector authSelector = new DefaultAuthenticationSelector();
492         for ( Server server : decrypted.getServers() )
493         {
494             AuthenticationBuilder authBuilder = new AuthenticationBuilder();
495             authBuilder.addUsername( server.getUsername() ).addPassword( server.getPassword() );
496             authBuilder.addPrivateKey( server.getPrivateKey(), server.getPassphrase() );
497             authSelector.add( server.getId(), authBuilder.build() );
498 
499             if ( server.getConfiguration() != null )
500             {
501                 Xpp3Dom dom = (Xpp3Dom) server.getConfiguration();
502                 for ( int i = dom.getChildCount() - 1; i >= 0; i-- )
503                 {
504                     Xpp3Dom child = dom.getChild( i );
505                     if ( "wagonProvider".equals( child.getName() ) )
506                     {
507                         dom.removeChild( i );
508                     }
509                 }
510 
511                 XmlPlexusConfiguration config = new XmlPlexusConfiguration( dom );
512                 configProps.put( "aether.connector.wagon.config." + server.getId(), config );
513             }
514 
515             configProps.put( "aether.connector.perms.fileMode." + server.getId(), server.getFilePermissions() );
516             configProps.put( "aether.connector.perms.dirMode." + server.getId(), server.getDirectoryPermissions() );
517         }
518         session.setAuthenticationSelector( authSelector );
519 
520         session.setTransferListener( request.getTransferListener() );
521 
522         session.setRepositoryListener( eventSpyDispatcher.chainListener( new LoggingRepositoryListener( logger ) ) );
523 
524         session.setUserProperties( request.getUserProperties() );
525         session.setSystemProperties( request.getSystemProperties() );
526         session.setConfigProperties( configProps );
527 
528         return session;
529     }
530 
531     private String getUserAgent()
532     {
533         return "Apache-Maven/" + getMavenVersion() + " (Java " + System.getProperty( "java.version" ) + "; "
534             + System.getProperty( "os.name" ) + " " + System.getProperty( "os.version" ) + ")";
535     }
536 
537     private String getMavenVersion()
538     {
539         Properties props = new Properties();
540 
541         InputStream is = getClass().getResourceAsStream( "/META-INF/maven/org.apache.maven/maven-core/pom.properties" );
542         if ( is != null )
543         {
544             try
545             {
546                 props.load( is );
547             }
548             catch ( IOException e )
549             {
550                 logger.debug( "Failed to read Maven version", e );
551             }
552             IOUtil.close( is );
553         }
554 
555         return props.getProperty( "version", "unknown-version" );
556     }
557 
558     private void validateLocalRepository( MavenExecutionRequest request )
559         throws LocalRepositoryNotAccessibleException
560     {
561         File localRepoDir = request.getLocalRepositoryPath();
562 
563         logger.debug( "Using local repository at " + localRepoDir );
564 
565         localRepoDir.mkdirs();
566 
567         if ( !localRepoDir.isDirectory() )
568         {
569             throw new LocalRepositoryNotAccessibleException( "Could not create local repository at " + localRepoDir );
570         }
571     }
572 
573     private Collection<AbstractMavenLifecycleParticipant> getLifecycleParticipants( Collection<MavenProject> projects )
574     {
575         Collection<AbstractMavenLifecycleParticipant> lifecycleListeners =
576             new LinkedHashSet<AbstractMavenLifecycleParticipant>();
577 
578         ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
579         try
580         {
581             try
582             {
583                 lifecycleListeners.addAll( container.lookupList( AbstractMavenLifecycleParticipant.class ) );
584             }
585             catch ( ComponentLookupException e )
586             {
587                 
588                 logger.warn( "Failed to lookup lifecycle participants: " + e.getMessage() );
589             }
590 
591             Collection<ClassLoader> scannedRealms = new HashSet<ClassLoader>();
592 
593             for ( MavenProject project : projects )
594             {
595                 ClassLoader projectRealm = project.getClassRealm();
596 
597                 if ( projectRealm != null && scannedRealms.add( projectRealm ) )
598                 {
599                     Thread.currentThread().setContextClassLoader( projectRealm );
600 
601                     try
602                     {
603                         lifecycleListeners.addAll( container.lookupList( AbstractMavenLifecycleParticipant.class ) );
604                     }
605                     catch ( ComponentLookupException e )
606                     {
607                         
608                         logger.warn( "Failed to lookup lifecycle participants: " + e.getMessage() );
609                     }
610                 }
611             }
612         }
613         finally
614         {
615             Thread.currentThread().setContextClassLoader( originalClassLoader );
616         }
617 
618         return lifecycleListeners;
619     }
620 
621     private MavenExecutionResult addExceptionToResult( MavenExecutionResult result, Throwable e )
622     {
623         if ( !result.getExceptions().contains( e ) )
624         {
625             result.addException( e );
626         }
627 
628         return result;
629     }
630 
631     private List<MavenProject> getProjectsForMavenReactor( MavenSession session )
632         throws ProjectBuildingException
633     {
634         MavenExecutionRequest request = session.getRequest();
635         
636         request.getProjectBuildingRequest().setRepositorySession( session.getRepositorySession() );
637 
638         List<MavenProject> projects = new ArrayList<MavenProject>();
639 
640         
641         
642         if ( request.getPom() == null )
643         {
644             ModelSource modelSource = new UrlModelSource( DefaultMaven.class.getResource( "project/standalone.xml" ) );
645             MavenProject project =
646                 projectBuilder.build( modelSource, request.getProjectBuildingRequest() ).getProject();
647             project.setExecutionRoot( true );
648             projects.add( project );
649             request.setProjectPresent( false );
650             return projects;
651         }
652 
653         List<File> files = Arrays.asList( request.getPom().getAbsoluteFile() );
654         collectProjects( projects, files, request );
655         return projects;
656     }
657 
658     private void collectProjects( List<MavenProject> projects, List<File> files, MavenExecutionRequest request )
659         throws ProjectBuildingException
660     {
661         ProjectBuildingRequest projectBuildingRequest = request.getProjectBuildingRequest();
662 
663         List<ProjectBuildingResult> results =
664             projectBuilder.build( files, request.isRecursive(), projectBuildingRequest );
665 
666         boolean problems = false;
667 
668         for ( ProjectBuildingResult result : results )
669         {
670             projects.add( result.getProject() );
671 
672             if ( !result.getProblems().isEmpty() && logger.isWarnEnabled() )
673             {
674                 logger.warn( "" );
675                 logger.warn( "Some problems were encountered while building the effective model for "
676                     + result.getProject().getId() );
677 
678                 for ( ModelProblem problem : result.getProblems() )
679                 {
680                     String location = ModelProblemUtils.formatLocation( problem, result.getProjectId() );
681                     logger.warn( problem.getMessage() + ( StringUtils.isNotEmpty( location ) ? " @ " + location : "" ) );
682                 }
683 
684                 problems = true;
685             }
686         }
687 
688         if ( problems )
689         {
690             logger.warn( "" );
691             logger.warn( "It is highly recommended to fix these problems"
692                 + " because they threaten the stability of your build." );
693             logger.warn( "" );
694             logger.warn( "For this reason, future Maven versions might no"
695                 + " longer support building such malformed projects." );
696             logger.warn( "" );
697         }
698     }
699 
700     private Map<String, MavenProject> getProjectMap( Collection<MavenProject> projects )
701         throws DuplicateProjectException
702     {
703         Map<String, MavenProject> index = new LinkedHashMap<String, MavenProject>();
704         Map<String, List<File>> collisions = new LinkedHashMap<String, List<File>>();
705 
706         for ( MavenProject project : projects )
707         {
708             String projectId = ArtifactUtils.key( project.getGroupId(), project.getArtifactId(), project.getVersion() );
709 
710             MavenProject collision = index.get( projectId );
711 
712             if ( collision == null )
713             {
714                 index.put( projectId, project );
715             }
716             else
717             {
718                 List<File> pomFiles = collisions.get( projectId );
719 
720                 if ( pomFiles == null )
721                 {
722                     pomFiles = new ArrayList<File>( Arrays.asList( collision.getFile(), project.getFile() ) );
723                     collisions.put( projectId, pomFiles );
724                 }
725                 else
726                 {
727                     pomFiles.add( project.getFile() );
728                 }
729             }
730         }
731 
732         if ( !collisions.isEmpty() )
733         {
734             throw new DuplicateProjectException( "Two or more projects in the reactor"
735                 + " have the same identifier, please make sure that <groupId>:<artifactId>:<version>"
736                 + " is unique for each project: " + collisions, collisions );
737         }
738 
739         return index;
740     }
741 
742     private void validateProjects( List<MavenProject> projects )
743     {
744         Map<String, MavenProject> projectsMap = new HashMap<String, MavenProject>();
745 
746         for ( MavenProject project : projects )
747         {
748             String projectKey = ArtifactUtils.key( project.getGroupId(), project.getArtifactId(), project.getVersion() );
749 
750             projectsMap.put( projectKey, project );
751         }
752 
753         for ( MavenProject project : projects )
754         {
755             
756             for ( Plugin plugin : project.getBuildPlugins() )
757             {
758                 if ( plugin.isExtensions() )
759                 {
760                     String pluginKey =
761                         ArtifactUtils.key( plugin.getGroupId(), plugin.getArtifactId(), plugin.getVersion() );
762 
763                     if ( projectsMap.containsKey( pluginKey ) )
764                     {
765                         logger.warn( project.getName() + " uses " + plugin.getKey()
766                             + " as extensions, which is not possible within the same reactor build. This plugin was pulled from the local repository!" );
767                     }
768                 }
769             }
770         }
771     }
772 
773     private void validateActivatedProfiles( List<MavenProject> projects, List<String> activeProfileIds )
774     {
775         Collection<String> notActivatedProfileIds = new LinkedHashSet<String>( activeProfileIds );
776 
777         for ( MavenProject project : projects )
778         {
779             for ( List<String> profileIds : project.getInjectedProfileIds().values() )
780             {
781                 notActivatedProfileIds.removeAll( profileIds );
782             }
783         }
784 
785         for ( String notActivatedProfileId : notActivatedProfileIds )
786         {
787             logger.warn( "The requested profile \"" + notActivatedProfileId
788                 + "\" could not be activated because it does not exist." );
789         }
790     }
791 
792     @Deprecated 
793     protected Logger getLogger()
794     {
795         return logger;
796     }
797 
798     private ProjectDependencyGraph createProjectDependencyGraph( Collection<MavenProject> projects, MavenExecutionRequest request,
799                                                                  MavenExecutionResult result, boolean trimming )
800     {
801         ProjectDependencyGraph projectDependencyGraph = null;
802 
803         try
804         {
805             projectDependencyGraph = new DefaultProjectDependencyGraph( projects );
806 
807             if ( trimming )
808             {
809                 List<MavenProject> activeProjects = projectDependencyGraph.getSortedProjects();
810 
811                 activeProjects = trimSelectedProjects( activeProjects, projectDependencyGraph, request );
812                 activeProjects = trimExcludedProjects( activeProjects,  request );
813                 activeProjects = trimResumedProjects( activeProjects, request );
814 
815                 if ( activeProjects.size() != projectDependencyGraph.getSortedProjects().size() )
816                 {
817                     projectDependencyGraph =
818                         new FilteredProjectDependencyGraph( projectDependencyGraph, activeProjects );
819                 }
820             }
821         }
822         catch ( CycleDetectedException e )
823         {
824             String message = "The projects in the reactor contain a cyclic reference: " + e.getMessage();
825 
826             ProjectCycleException error = new ProjectCycleException( message, e );
827 
828             addExceptionToResult( result, error );
829         }
830         catch ( org.apache.maven.project.DuplicateProjectException e )
831         {
832             addExceptionToResult( result, e );
833         }
834         catch ( MavenExecutionException e )
835         {
836             addExceptionToResult( result, e );
837         }
838 
839         return projectDependencyGraph;
840     }
841 
842     private List<MavenProject> trimSelectedProjects( List<MavenProject> projects, ProjectDependencyGraph graph,
843                                                      MavenExecutionRequest request )
844         throws MavenExecutionException
845     {
846         List<MavenProject> result = projects;
847 
848         if ( !request.getSelectedProjects().isEmpty() )
849         {
850             File reactorDirectory = null;
851             if ( request.getBaseDirectory() != null )
852             {
853                 reactorDirectory = new File( request.getBaseDirectory() );
854             }
855 
856             Collection<MavenProject> selectedProjects = new LinkedHashSet<MavenProject>( projects.size() );
857 
858             for ( String selector : request.getSelectedProjects() )
859             {
860                 MavenProject selectedProject = null;
861 
862                 for ( MavenProject project : projects )
863                 {
864                     if ( isMatchingProject( project, selector, reactorDirectory ) )
865                     {
866                         selectedProject = project;
867                         break;
868                     }
869                 }
870 
871                 if ( selectedProject != null )
872                 {
873                     selectedProjects.add( selectedProject );
874                 }
875                 else
876                 {
877                     throw new MavenExecutionException( "Could not find the selected project in the reactor: "
878                         + selector, request.getPom() );
879                 }
880             }
881 
882             boolean makeUpstream = false;
883             boolean makeDownstream = false;
884 
885             if ( MavenExecutionRequest.REACTOR_MAKE_UPSTREAM.equals( request.getMakeBehavior() ) )
886             {
887                 makeUpstream = true;
888             }
889             else if ( MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM.equals( request.getMakeBehavior() ) )
890             {
891                 makeDownstream = true;
892             }
893             else if ( MavenExecutionRequest.REACTOR_MAKE_BOTH.equals( request.getMakeBehavior() ) )
894             {
895                 makeUpstream = true;
896                 makeDownstream = true;
897             }
898             else if ( StringUtils.isNotEmpty( request.getMakeBehavior() ) )
899             {
900                 throw new MavenExecutionException( "Invalid reactor make behavior: " + request.getMakeBehavior(),
901                                                    request.getPom() );
902             }
903 
904             if ( makeUpstream || makeDownstream )
905             {
906                 for ( MavenProject selectedProject : new ArrayList<MavenProject>( selectedProjects ) )
907                 {
908                     if ( makeUpstream )
909                     {
910                         selectedProjects.addAll( graph.getUpstreamProjects( selectedProject, true ) );
911                     }
912                     if ( makeDownstream )
913                     {
914                         selectedProjects.addAll( graph.getDownstreamProjects( selectedProject, true ) );
915                     }
916                 }
917             }
918 
919             result = new ArrayList<MavenProject>( selectedProjects.size() );
920 
921             for ( MavenProject project : projects )
922             {
923                 if ( selectedProjects.contains( project ) )
924                 {
925                     result.add( project );
926                 }
927             }
928         }
929 
930         return result;
931     }
932     
933     private List<MavenProject> trimExcludedProjects( List<MavenProject> projects, MavenExecutionRequest request )
934         throws MavenExecutionException
935     {
936         List<MavenProject> result = projects;
937 
938         if ( !request.getExcludedProjects().isEmpty() )
939         {
940             File reactorDirectory = null;
941 
942             if ( request.getBaseDirectory() != null )
943             {
944                 reactorDirectory = new File( request.getBaseDirectory() );
945             }
946 
947             Collection<MavenProject> excludedProjects = new LinkedHashSet<MavenProject>( projects.size() );
948 
949             for ( String selector : request.getExcludedProjects() )
950             {
951                 MavenProject excludedProject = null;
952 
953                 for ( MavenProject project : projects )
954                 {
955                     if ( isMatchingProject( project, selector, reactorDirectory ) )
956                     {
957                         excludedProject = project;
958                         break;
959                     }
960                 }
961 
962                 if ( excludedProject != null )
963                 {
964                     excludedProjects.add( excludedProject );
965                 }
966                 else
967                 {
968                     throw new MavenExecutionException( "Could not find the selected project in the reactor: "
969                         + selector, request.getPom() );
970                 }
971             }
972 
973             result = new ArrayList<MavenProject>( projects.size() );
974             for ( MavenProject project : projects )
975             {
976                 if ( !excludedProjects.contains( project ) )
977                 {
978                     result.add( project );
979                 }
980             }
981         }
982 
983         return result;
984     }
985 
986     private List<MavenProject> trimResumedProjects( List<MavenProject> projects, MavenExecutionRequest request )
987         throws MavenExecutionException
988     {
989         List<MavenProject> result = projects;
990 
991         if ( StringUtils.isNotEmpty( request.getResumeFrom() ) )
992         {
993             File reactorDirectory = null;
994             if ( request.getBaseDirectory() != null )
995             {
996                 reactorDirectory = new File( request.getBaseDirectory() );
997             }
998 
999             String selector = request.getResumeFrom();
1000 
1001             result = new ArrayList<MavenProject>( projects.size() );
1002 
1003             boolean resumed = false;
1004 
1005             for ( MavenProject project : projects )
1006             {
1007                 if ( !resumed && isMatchingProject( project, selector, reactorDirectory ) )
1008                 {
1009                     resumed = true;
1010                 }
1011 
1012                 if ( resumed )
1013                 {
1014                     result.add( project );
1015                 }
1016             }
1017 
1018             if ( !resumed )
1019             {
1020                 throw new MavenExecutionException( "Could not find project to resume reactor build from: " + selector
1021                     + " vs " + projects, request.getPom() );
1022             }
1023         }
1024 
1025         return result;
1026     }
1027 
1028     private boolean isMatchingProject( MavenProject project, String selector, File reactorDirectory )
1029     {
1030         
1031         if ( selector.indexOf( ':' ) >= 0 )
1032         {
1033             String id = ':' + project.getArtifactId();
1034 
1035             if ( id.equals( selector ) )
1036             {
1037                 return true;
1038             }
1039 
1040             id = project.getGroupId() + id;
1041 
1042             if ( id.equals( selector ) )
1043             {
1044                 return true;
1045             }
1046         }
1047 
1048         
1049         else if ( reactorDirectory != null )
1050         {
1051             File selectedProject = new File( new File( reactorDirectory, selector ).toURI().normalize() );
1052 
1053             if ( selectedProject.isFile() )
1054             {
1055                 return selectedProject.equals( project.getFile() );
1056             }
1057             else if ( selectedProject.isDirectory() )
1058             {
1059                 return selectedProject.equals( project.getBasedir() );
1060             }
1061         }
1062 
1063         return false;
1064     }
1065 
1066 }