View Javadoc

1   package org.apache.maven;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
5    * agreements. See the NOTICE file distributed with this work for additional information regarding
6    * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance with the License. You may obtain a
8    * copy of the License at
9    * 
10   * http://www.apache.org/licenses/LICENSE-2.0
11   * 
12   * Unless required by applicable law or agreed to in writing, software distributed under the License
13   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14   * or implied. See the License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  
18  import java.io.File;
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.text.SimpleDateFormat;
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.Collection;
25  import java.util.Collections;
26  import java.util.Date;
27  import java.util.HashSet;
28  import java.util.LinkedHashMap;
29  import java.util.LinkedHashSet;
30  import java.util.List;
31  import java.util.Map;
32  import java.util.Properties;
33  
34  import org.apache.maven.artifact.ArtifactUtils;
35  import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
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.MavenExecutionRequestPopulationException;
40  import org.apache.maven.execution.MavenExecutionRequestPopulator;
41  import org.apache.maven.execution.MavenExecutionResult;
42  import org.apache.maven.execution.MavenSession;
43  import org.apache.maven.execution.ProjectDependencyGraph;
44  import org.apache.maven.lifecycle.internal.ExecutionEventCatapult;
45  import org.apache.maven.lifecycle.internal.LifecycleStarter;
46  import org.apache.maven.model.building.ModelProblem;
47  import org.apache.maven.model.building.ModelProblemUtils;
48  import org.apache.maven.model.building.ModelSource;
49  import org.apache.maven.model.building.UrlModelSource;
50  import org.apache.maven.plugin.LegacySupport;
51  import org.apache.maven.project.DuplicateProjectException;
52  import org.apache.maven.project.MavenProject;
53  import org.apache.maven.project.ProjectBuilder;
54  import org.apache.maven.project.ProjectBuildingException;
55  import org.apache.maven.project.ProjectBuildingRequest;
56  import org.apache.maven.project.ProjectBuildingResult;
57  import org.apache.maven.project.ProjectSorter;
58  import org.apache.maven.repository.DelegatingLocalArtifactRepository;
59  import org.apache.maven.repository.LocalRepositoryNotAccessibleException;
60  import org.apache.maven.settings.Mirror;
61  import org.apache.maven.settings.Proxy;
62  import org.apache.maven.settings.Server;
63  import org.apache.maven.settings.building.SettingsProblem;
64  import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest;
65  import org.apache.maven.settings.crypto.SettingsDecrypter;
66  import org.apache.maven.settings.crypto.SettingsDecryptionResult;
67  import org.codehaus.plexus.PlexusContainer;
68  import org.codehaus.plexus.component.annotations.Component;
69  import org.codehaus.plexus.component.annotations.Requirement;
70  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
71  import org.codehaus.plexus.logging.Logger;
72  import org.codehaus.plexus.util.IOUtil;
73  import org.codehaus.plexus.util.StringUtils;
74  import org.codehaus.plexus.util.dag.CycleDetectedException;
75  import org.sonatype.aether.ConfigurationProperties;
76  import org.sonatype.aether.RepositoryEvent;
77  import org.sonatype.aether.RepositorySystem;
78  import org.sonatype.aether.RepositorySystemSession;
79  import org.sonatype.aether.collection.DependencyGraphTransformer;
80  import org.sonatype.aether.collection.DependencyManager;
81  import org.sonatype.aether.collection.DependencySelector;
82  import org.sonatype.aether.collection.DependencyTraverser;
83  import org.sonatype.aether.repository.Authentication;
84  import org.sonatype.aether.repository.LocalRepository;
85  import org.sonatype.aether.repository.RepositoryPolicy;
86  import org.sonatype.aether.repository.WorkspaceReader;
87  import org.sonatype.aether.util.DefaultRepositorySystemSession;
88  import org.sonatype.aether.util.graph.manager.ClassicDependencyManager;
89  import org.sonatype.aether.util.graph.selector.AndDependencySelector;
90  import org.sonatype.aether.util.graph.selector.ExclusionDependencySelector;
91  import org.sonatype.aether.util.graph.selector.OptionalDependencySelector;
92  import org.sonatype.aether.util.graph.selector.ScopeDependencySelector;
93  import org.sonatype.aether.util.graph.transformer.ChainedDependencyGraphTransformer;
94  import org.sonatype.aether.util.graph.transformer.NearestVersionConflictResolver;
95  import org.sonatype.aether.util.graph.transformer.ConflictMarker;
96  import org.sonatype.aether.util.graph.transformer.JavaDependencyContextRefiner;
97  import org.sonatype.aether.util.graph.transformer.JavaEffectiveScopeCalculator;
98  import org.sonatype.aether.util.graph.traverser.FatArtifactTraverser;
99  import org.sonatype.aether.util.repository.ChainedWorkspaceReader;
100 import org.sonatype.aether.util.repository.DefaultAuthenticationSelector;
101 import org.sonatype.aether.util.repository.DefaultMirrorSelector;
102 import org.sonatype.aether.util.repository.DefaultProxySelector;
103 
104 /**
105  * @author Jason van Zyl
106  */
107 @Component(role = Maven.class)
108 public class DefaultMaven
109     implements Maven
110 {
111 
112     @Requirement
113     private Logger logger;
114 
115     @Requirement
116     protected ProjectBuilder projectBuilder;
117 
118     @Requirement
119     private LifecycleStarter lifecycleStarter;
120 
121     @Requirement
122     protected PlexusContainer container;
123 
124     @Requirement
125     MavenExecutionRequestPopulator populator;
126 
127     @Requirement
128     private ExecutionEventCatapult eventCatapult;
129 
130     @Requirement
131     private ArtifactHandlerManager artifactHandlerManager;
132 
133     @Requirement( optional = true, hint = "ide" )
134     private WorkspaceReader workspaceRepository;
135 
136     @Requirement
137     private RepositorySystem repoSystem;
138 
139     @Requirement
140     private SettingsDecrypter settingsDecrypter;
141 
142     @Requirement
143     private LegacySupport legacySupport;
144 
145     public MavenExecutionResult execute( MavenExecutionRequest request )
146     {
147         MavenExecutionResult result;
148 
149         try
150         {
151             result = doExecute( populator.populateDefaults( request ) );
152         }
153         catch ( OutOfMemoryError e )
154         {
155             result = processResult( new DefaultMavenExecutionResult(), e );
156         }
157         catch ( MavenExecutionRequestPopulationException e )
158         {
159             result = processResult( new DefaultMavenExecutionResult(), e );
160         }
161         catch ( RuntimeException e )
162         {
163             result =
164                 processResult( new DefaultMavenExecutionResult(),
165                                new InternalErrorException( "Internal error: " + e, e ) );
166         }
167         finally
168         {
169             legacySupport.setSession( null );
170         }
171 
172         return result;
173     }
174 
175     @SuppressWarnings({"ThrowableInstanceNeverThrown", "ThrowableResultOfMethodCallIgnored"})
176     private MavenExecutionResult doExecute( MavenExecutionRequest request )
177     {
178         //TODO: Need a general way to inject standard properties
179         if ( request.getStartTime() != null )
180         {
181             request.getSystemProperties().put( "${build.timestamp}", new SimpleDateFormat( "yyyyMMdd-hhmm" ).format( request.getStartTime() ) );
182         }        
183         
184         request.setStartTime( new Date() );
185         
186         MavenExecutionResult result = new DefaultMavenExecutionResult();
187 
188         try
189         {
190             validateLocalRepository( request );
191         }
192         catch ( LocalRepositoryNotAccessibleException e )
193         {
194             return processResult( result, e );
195         }
196 
197         DelegatingLocalArtifactRepository delegatingLocalArtifactRepository =
198             new DelegatingLocalArtifactRepository( request.getLocalRepository() );
199         
200         request.setLocalRepository( delegatingLocalArtifactRepository );        
201 
202         DefaultRepositorySystemSession repoSession = (DefaultRepositorySystemSession) newRepositorySession( request );
203 
204         MavenSession session = new MavenSession( container, repoSession, request, result );
205         legacySupport.setSession( session );
206 
207         try
208         {
209             for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( Collections.<MavenProject> emptyList() ) )
210             {
211                 listener.afterSessionStart( session );
212             }
213         }
214         catch ( MavenExecutionException e )
215         {
216             return processResult( result, e );
217         }
218 
219         eventCatapult.fire( ExecutionEvent.Type.ProjectDiscoveryStarted, session, null );
220 
221         request.getProjectBuildingRequest().setRepositorySession( session.getRepositorySession() );
222 
223         //TODO: optimize for the single project or no project
224         
225         List<MavenProject> projects;
226         try
227         {
228             projects = getProjectsForMavenReactor( request );                                                
229         }
230         catch ( ProjectBuildingException e )
231         {
232             return processResult( result, e );
233         }
234 
235         session.setProjects( projects );
236 
237         result.setTopologicallySortedProjects( session.getProjects() );
238         
239         result.setProject( session.getTopLevelProject() );
240 
241         try
242         {
243             Map<String, MavenProject> projectMap;
244             projectMap = getProjectMap( session.getProjects() );
245     
246             // Desired order of precedence for local artifact repositories
247             //
248             // Reactor
249             // Workspace
250             // User Local Repository
251             ReactorReader reactorRepository = new ReactorReader( projectMap );
252 
253             repoSession.setWorkspaceReader( ChainedWorkspaceReader.newInstance( reactorRepository,
254                                                                                 repoSession.getWorkspaceReader() ) );
255         }
256         catch ( org.apache.maven.DuplicateProjectException e )
257         {
258             return processResult( result, e );
259         }
260 
261         ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
262         try
263         {
264             for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( projects ) )
265             {
266                 Thread.currentThread().setContextClassLoader( listener.getClass().getClassLoader() );
267 
268                 listener.afterProjectsRead( session );
269             }
270         }
271         catch ( MavenExecutionException e )
272         {
273             return processResult( result, e );
274         }
275         finally
276         {
277             Thread.currentThread().setContextClassLoader( originalClassLoader );
278         }
279 
280         try
281         {
282             ProjectSorter projectSorter = new ProjectSorter( session.getProjects() );
283 
284             ProjectDependencyGraph projectDependencyGraph = createDependencyGraph( projectSorter, request );
285 
286             session.setProjects( projectDependencyGraph.getSortedProjects() );
287 
288             session.setProjectDependencyGraph( projectDependencyGraph );
289         }
290         catch ( CycleDetectedException e )
291         {            
292             String message = "The projects in the reactor contain a cyclic reference: " + e.getMessage();
293 
294             ProjectCycleException error = new ProjectCycleException( message, e );
295 
296             return processResult( result, error );
297         }
298         catch ( DuplicateProjectException e )
299         {
300             return processResult( result, e );
301         }
302         catch ( MavenExecutionException e )
303         {
304             return processResult( result, e );
305         }
306 
307         result.setTopologicallySortedProjects( session.getProjects() );
308 
309         if ( result.hasExceptions() )
310         {
311             return result;
312         }
313 
314         lifecycleStarter.execute( session );
315 
316         validateActivatedProfiles( session.getProjects(), request.getActiveProfiles() );
317 
318         if ( session.getResult().hasExceptions() )
319         {
320             return processResult( result, session.getResult().getExceptions().get( 0 ) );
321         }
322 
323         return result;
324     }
325 
326     public RepositorySystemSession newRepositorySession( MavenExecutionRequest request )
327     {
328         DefaultRepositorySystemSession session = new DefaultRepositorySystemSession();
329 
330         session.setCache( request.getRepositoryCache() );
331 
332         session.setIgnoreInvalidArtifactDescriptor( true ).setIgnoreMissingArtifactDescriptor( true );
333 
334         session.setUserProps( request.getUserProperties() );
335         session.setSystemProps( request.getSystemProperties() );
336         Map<Object, Object> configProps = new LinkedHashMap<Object, Object>();
337         configProps.put( ConfigurationProperties.USER_AGENT, getUserAgent() );
338         configProps.put( ConfigurationProperties.INTERACTIVE, Boolean.valueOf( request.isInteractiveMode() ) );
339         configProps.putAll( request.getSystemProperties() );
340         configProps.putAll( request.getUserProperties() );
341         session.setConfigProps( configProps );
342 
343         session.setOffline( request.isOffline() );
344         session.setChecksumPolicy( request.getGlobalChecksumPolicy() );
345         session.setUpdatePolicy( request.isUpdateSnapshots() ? RepositoryPolicy.UPDATE_POLICY_ALWAYS : null );
346 
347         session.setNotFoundCachingEnabled( request.isCacheNotFound() );
348         session.setTransferErrorCachingEnabled( request.isCacheTransferError() );
349 
350         session.setArtifactTypeRegistry( RepositoryUtils.newArtifactTypeRegistry( artifactHandlerManager ) );
351 
352         LocalRepository localRepo = new LocalRepository( request.getLocalRepository().getBasedir() );
353         session.setLocalRepositoryManager( repoSystem.newLocalRepositoryManager( localRepo ) );
354 
355         if ( request.getWorkspaceReader() != null )
356         {
357             session.setWorkspaceReader( request.getWorkspaceReader() );
358         }
359         else
360         {
361             session.setWorkspaceReader( workspaceRepository );
362         }
363 
364         DefaultSettingsDecryptionRequest decrypt = new DefaultSettingsDecryptionRequest();
365         decrypt.setProxies( request.getProxies() );
366         decrypt.setServers( request.getServers() );
367         SettingsDecryptionResult decrypted = settingsDecrypter.decrypt( decrypt );
368 
369         if ( logger.isDebugEnabled() )
370         {
371             for ( SettingsProblem problem : decrypted.getProblems() )
372             {
373                 logger.debug( problem.getMessage(), problem.getException() );
374             }
375         }
376 
377         DefaultMirrorSelector mirrorSelector = new DefaultMirrorSelector();
378         for ( Mirror mirror : request.getMirrors() )
379         {
380             mirrorSelector.add( mirror.getId(), mirror.getUrl(), mirror.getLayout(), false, mirror.getMirrorOf(),
381                                 mirror.getMirrorOfLayouts() );
382         }
383         session.setMirrorSelector( mirrorSelector );
384 
385         DefaultProxySelector proxySelector = new DefaultProxySelector();
386         for ( Proxy proxy : decrypted.getProxies() )
387         {
388             Authentication proxyAuth = new Authentication( proxy.getUsername(), proxy.getPassword() );
389             proxySelector.add( new org.sonatype.aether.repository.Proxy( proxy.getProtocol(), proxy.getHost(), proxy.getPort(),
390                                                                 proxyAuth ), proxy.getNonProxyHosts() );
391         }
392         session.setProxySelector( proxySelector );
393 
394         DefaultAuthenticationSelector authSelector = new DefaultAuthenticationSelector();
395         for ( Server server : decrypted.getServers() )
396         {
397             Authentication auth =
398                 new Authentication( server.getUsername(), server.getPassword(), server.getPrivateKey(),
399                                     server.getPassphrase() );
400             authSelector.add( server.getId(), auth );
401         }
402         session.setAuthenticationSelector( authSelector );
403 
404         DependencyTraverser depTraverser = new FatArtifactTraverser();
405         session.setDependencyTraverser( depTraverser );
406 
407         DependencyManager depManager = new ClassicDependencyManager();
408         session.setDependencyManager( depManager );
409 
410         DependencySelector depFilter =
411             new AndDependencySelector( new ScopeDependencySelector( "test", "provided" ), new OptionalDependencySelector(),
412                                      new ExclusionDependencySelector() );
413         session.setDependencySelector( depFilter );
414 
415         DependencyGraphTransformer transformer =
416             new ChainedDependencyGraphTransformer( new ConflictMarker(), new JavaEffectiveScopeCalculator(),
417                                                    new NearestVersionConflictResolver(),
418                                                    new JavaDependencyContextRefiner() );
419         session.setDependencyGraphTransformer( transformer );
420 
421         session.setTransferListener( request.getTransferListener() );
422 
423         session.setRepositoryListener( new LoggingRepositoryListener( logger ) );
424 
425         return session;
426     }
427 
428     private String getUserAgent()
429     {
430         StringBuilder buffer = new StringBuilder( 128 );
431 
432         buffer.append( "Apache-Maven/" ).append( getMavenVersion() );
433         buffer.append( " (" );
434         buffer.append( "Java " ).append( System.getProperty( "java.version" ) );
435         buffer.append( "; " );
436         buffer.append( System.getProperty( "os.name" ) ).append( " " ).append( System.getProperty( "os.version" ) );
437         buffer.append( ")" );
438 
439         return buffer.toString();
440     }
441 
442     private String getMavenVersion()
443     {
444         Properties props = new Properties();
445 
446         InputStream is = getClass().getResourceAsStream( "/META-INF/maven/org.apache.maven/maven-core/pom.properties" );
447         if ( is != null )
448         {
449             try
450             {
451                 props.load( is );
452             }
453             catch ( IOException e )
454             {
455                 logger.debug( "Failed to read Maven version", e );
456             }
457             IOUtil.close( is );
458         }
459 
460         return props.getProperty( "version", "unknown-version" );
461     }
462 
463     @SuppressWarnings({"ResultOfMethodCallIgnored"})
464     private void validateLocalRepository( MavenExecutionRequest request )
465         throws LocalRepositoryNotAccessibleException
466     {
467         File localRepoDir = request.getLocalRepositoryPath();
468 
469         logger.debug( "Using local repository at " + localRepoDir );
470 
471         localRepoDir.mkdirs();
472 
473         if ( !localRepoDir.isDirectory() )
474         {
475             throw new LocalRepositoryNotAccessibleException( "Could not create local repository at " + localRepoDir );
476         }
477     }
478 
479     private Collection<AbstractMavenLifecycleParticipant> getLifecycleParticipants( Collection<MavenProject> projects )
480     {
481         Collection<AbstractMavenLifecycleParticipant> lifecycleListeners =
482             new LinkedHashSet<AbstractMavenLifecycleParticipant>();
483 
484         ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
485         try
486         {
487             try
488             {
489                 lifecycleListeners.addAll( container.lookupList( AbstractMavenLifecycleParticipant.class ) );
490             }
491             catch ( ComponentLookupException e )
492             {
493                 // this is just silly, lookupList should return an empty list!
494                 logger.warn( "Failed to lookup lifecycle participants: " + e.getMessage() );
495             }
496 
497             Collection<ClassLoader> scannedRealms = new HashSet<ClassLoader>();
498 
499             for ( MavenProject project : projects )
500             {
501                 ClassLoader projectRealm = project.getClassRealm();
502 
503                 if ( projectRealm != null && scannedRealms.add( projectRealm ) )
504                 {
505                     Thread.currentThread().setContextClassLoader( projectRealm );
506 
507                     try
508                     {
509                         lifecycleListeners.addAll( container.lookupList( AbstractMavenLifecycleParticipant.class ) );
510                     }
511                     catch ( ComponentLookupException e )
512                     {
513                         // this is just silly, lookupList should return an empty list!
514                         logger.warn( "Failed to lookup lifecycle participants: " + e.getMessage() );
515                     }
516                 }
517             }
518         }
519         finally
520         {
521             Thread.currentThread().setContextClassLoader( originalClassLoader );
522         }
523 
524         return lifecycleListeners;
525     }
526 
527     private MavenExecutionResult processResult( MavenExecutionResult result, Throwable e )
528     {
529         if ( !result.getExceptions().contains( e ) )
530         {
531             result.addException( e );
532         }
533 
534         return result;
535     }
536     
537     private List<MavenProject> getProjectsForMavenReactor( MavenExecutionRequest request )
538         throws ProjectBuildingException
539     {
540         List<MavenProject> projects =  new ArrayList<MavenProject>();
541 
542         // We have no POM file.
543         //
544         if ( request.getPom() == null )
545         {
546             ModelSource modelSource = new UrlModelSource( getClass().getResource( "project/standalone.xml" ) );
547             MavenProject project =
548                 projectBuilder.build( modelSource, request.getProjectBuildingRequest() ).getProject();
549             project.setExecutionRoot( true );
550             projects.add( project );
551             request.setProjectPresent( false );
552             return projects;
553         }
554         
555         List<File> files = Arrays.asList( request.getPom().getAbsoluteFile() );        
556         collectProjects( projects, files, request );
557         return projects;
558     }
559 
560     private Map<String, MavenProject> getProjectMap( List<MavenProject> projects )
561         throws org.apache.maven.DuplicateProjectException
562     {
563         Map<String, MavenProject> index = new LinkedHashMap<String, MavenProject>();
564         Map<String, List<File>> collisions = new LinkedHashMap<String, List<File>>();
565 
566         for ( MavenProject project : projects )
567         {
568             String projectId = ArtifactUtils.key( project.getGroupId(), project.getArtifactId(), project.getVersion() );
569 
570             MavenProject collision = index.get( projectId );
571 
572             if ( collision == null )
573             {
574                 index.put( projectId, project );
575             }
576             else
577             {
578                 List<File> pomFiles = collisions.get( projectId );
579 
580                 if ( pomFiles == null )
581                 {
582                     pomFiles = new ArrayList<File>( Arrays.asList( collision.getFile(), project.getFile() ) );
583                     collisions.put( projectId, pomFiles );
584                 }
585                 else
586                 {
587                     pomFiles.add( project.getFile() );
588                 }
589             }
590         }
591 
592         if ( !collisions.isEmpty() )
593         {
594             throw new org.apache.maven.DuplicateProjectException( "Two or more projects in the reactor"
595                 + " have the same identifier, please make sure that <groupId>:<artifactId>:<version>"
596                 + " is unique for each project: " + collisions, collisions );
597         }
598 
599         return index;
600     }
601 
602     private void collectProjects( List<MavenProject> projects, List<File> files, MavenExecutionRequest request )
603         throws ProjectBuildingException
604     {
605         ProjectBuildingRequest projectBuildingRequest = request.getProjectBuildingRequest();
606 
607         List<ProjectBuildingResult> results = projectBuilder.build( files, request.isRecursive(), projectBuildingRequest );
608 
609         boolean problems = false;
610 
611         for ( ProjectBuildingResult result : results )
612         {
613             projects.add( result.getProject() );
614 
615             if ( !result.getProblems().isEmpty() && logger.isWarnEnabled() )
616             {
617                 logger.warn( "" );
618                 logger.warn( "Some problems were encountered while building the effective model for "
619                     + result.getProject().getId() );
620 
621                 for ( ModelProblem problem : result.getProblems() )
622                 {
623                     String location = ModelProblemUtils.formatLocation( problem, result.getProjectId() );
624                     logger.warn( problem.getMessage() + ( StringUtils.isNotEmpty( location ) ? " @ " + location : "" ) );
625                 }
626 
627                 problems = true;
628             }
629         }
630 
631         if ( problems )
632         {
633             logger.warn( "" );
634             logger.warn( "It is highly recommended to fix these problems"
635                 + " because they threaten the stability of your build." );
636             logger.warn( "" );
637             logger.warn( "For this reason, future Maven versions might no"
638                 + " longer support building such malformed projects." );
639             logger.warn( "" );
640         }
641     }
642 
643     private void validateActivatedProfiles( List<MavenProject> projects, List<String> activeProfileIds )
644     {
645         Collection<String> notActivatedProfileIds = new LinkedHashSet<String>( activeProfileIds );
646 
647         for ( MavenProject project : projects )
648         {
649             for ( List<String> profileIds : project.getInjectedProfileIds().values() )
650             {
651                 notActivatedProfileIds.removeAll( profileIds );
652             }
653         }
654 
655         for ( String notActivatedProfileId : notActivatedProfileIds )
656         {
657             logger.warn( "The requested profile \"" + notActivatedProfileId
658                 + "\" could not be activated because it does not exist." );
659         }
660     }
661 
662     protected Logger getLogger()
663     {
664         return logger;
665     }
666 
667     private ProjectDependencyGraph createDependencyGraph( ProjectSorter sorter, MavenExecutionRequest request )
668         throws MavenExecutionException
669     {
670         ProjectDependencyGraph graph = new DefaultProjectDependencyGraph( sorter );
671 
672         Collection<MavenProject> activeProjects = sorter.getSortedProjects();
673 
674         File reactorDirectory;
675         if ( request.getBaseDirectory() != null )
676         {
677             reactorDirectory = new File( request.getBaseDirectory() );
678         }
679         else
680         {
681             reactorDirectory = null;
682         }
683 
684         if ( !request.getSelectedProjects().isEmpty() )
685         {
686             List<MavenProject> selectedProjects = new ArrayList<MavenProject>( request.getSelectedProjects().size() );
687 
688             for ( String selectedProject : request.getSelectedProjects() )
689             {
690                 MavenProject project = null;
691 
692                 for ( MavenProject activeProject : activeProjects )
693                 {
694                     if ( isMatchingProject( activeProject, selectedProject, reactorDirectory ) )
695                     {
696                         project = activeProject;
697                         break;
698                     }
699                 }
700 
701                 if ( project != null )
702                 {
703                     selectedProjects.add( project );
704                 }
705                 else
706                 {
707                     throw new MavenExecutionException( "Could not find the selected project in the reactor: "
708                         + selectedProject, request.getPom() );
709                 }
710             }
711 
712             activeProjects = selectedProjects;
713 
714             boolean makeUpstream = false;
715             boolean makeDownstream = false;
716 
717             if ( MavenExecutionRequest.REACTOR_MAKE_UPSTREAM.equals( request.getMakeBehavior() ) )
718             {
719                 makeUpstream = true;
720             }
721             else if ( MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM.equals( request.getMakeBehavior() ) )
722             {
723                 makeDownstream = true;
724             }
725             else if ( MavenExecutionRequest.REACTOR_MAKE_BOTH.equals( request.getMakeBehavior() ) )
726             {
727                 makeUpstream = true;
728                 makeDownstream = true;
729             }
730             else if ( StringUtils.isNotEmpty( request.getMakeBehavior() ) )
731             {
732                 throw new MavenExecutionException( "Invalid reactor make behavior: " + request.getMakeBehavior(),
733                                                    request.getPom() );
734             }
735 
736             if ( makeUpstream || makeDownstream )
737             {
738                 activeProjects = new LinkedHashSet<MavenProject>( selectedProjects );
739 
740                 for ( MavenProject selectedProject : selectedProjects )
741                 {
742                     if ( makeUpstream )
743                     {
744                         activeProjects.addAll( graph.getUpstreamProjects( selectedProject, true ) );
745                     }
746                     if ( makeDownstream )
747                     {
748                         activeProjects.addAll( graph.getDownstreamProjects( selectedProject, true ) );
749                     }
750                 }
751             }
752         }
753 
754         if ( StringUtils.isNotEmpty( request.getResumeFrom() ) )
755         {
756             String selectedProject = request.getResumeFrom();
757 
758             List<MavenProject> projects = new ArrayList<MavenProject>( activeProjects.size() );
759 
760             boolean resumed = false;
761 
762             for ( MavenProject project : activeProjects )
763             {
764                 if ( !resumed && isMatchingProject( project, selectedProject, reactorDirectory ) )
765                 {
766                     resumed = true;
767                 }
768 
769                 if ( resumed )
770                 {
771                     projects.add( project );
772                 }
773             }
774 
775             if ( !resumed )
776             {
777                 throw new MavenExecutionException( "Could not find project to resume reactor build from: "
778                     + selectedProject + " vs " + activeProjects, request.getPom() );
779             }
780 
781             activeProjects = projects;
782         }
783 
784         if ( activeProjects.size() != sorter.getSortedProjects().size() )
785         {
786             graph = new FilteredProjectDependencyGraph( graph, activeProjects );
787         }
788 
789         return graph;
790     }
791 
792     private boolean isMatchingProject( MavenProject project, String selector, File reactorDirectory )
793     {
794         // [groupId]:artifactId
795         if ( selector.indexOf( ':' ) >= 0 )
796         {
797             String id = ':' + project.getArtifactId();
798 
799             if ( id.equals( selector ) )
800             {
801                 return true;
802             }
803 
804             id = project.getGroupId() + id;
805 
806             if ( id.equals( selector ) )
807             {
808                 return true;
809             }
810         }
811 
812         // relative path, e.g. "sub", "../sub" or "."
813         else if ( reactorDirectory != null )
814         {
815             File selectedProject = new File( new File( reactorDirectory, selector ).toURI().normalize() );
816 
817             if ( selectedProject.isFile() )
818             {
819                 return selectedProject.equals( project.getFile() );
820             }
821             else if ( selectedProject.isDirectory() )
822             {
823                 return selectedProject.equals( project.getBasedir() );
824             }
825         }
826 
827         return false;
828     }
829 
830 }