View Javadoc
1   package org.apache.maven.lifecycle;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.HashMap;
24  import java.util.HashSet;
25  import java.util.Iterator;
26  import java.util.LinkedHashMap;
27  import java.util.LinkedHashSet;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.Set;
31  
32  import org.apache.maven.lifecycle.internal.ExecutionPlanItem;
33  import org.apache.maven.model.Plugin;
34  import org.apache.maven.plugin.MojoExecution;
35  import org.apache.maven.plugin.descriptor.MojoDescriptor;
36  
37  //TODO: lifecycles being executed
38  //TODO: what runs in each phase
39  //TODO: plugins that need downloading
40  //TODO: project dependencies that need downloading
41  //TODO: unfortunately the plugins need to be downloaded in order to get the plugin.xml file. need to externalize this
42  //      from the plugin archive.
43  //TODO: this will be the class that people get in IDEs to modify
44  
45  public class MavenExecutionPlan
46      implements Iterable<ExecutionPlanItem>
47  {
48  
49      /*
50         At the moment, this class is totally immutable, and this is in line with thoughts about the
51         pre-calculated execution plan that stays the same during the execution.
52  
53         If deciding to add mutable state to this class, it should be at least considered to
54         separate this into a separate mutable structure.
55  
56       */
57  
58      private final List<ExecutionPlanItem> planItem;
59  
60      private final Map<String, ExecutionPlanItem> lastMojoExecutionForAllPhases;
61  
62      final List<String> phasesInExecutionPlan;
63  
64      public MavenExecutionPlan( List<ExecutionPlanItem> planItem, DefaultLifecycles defaultLifecycles )
65      {
66          this.planItem = planItem;
67  
68          lastMojoExecutionForAllPhases = new LinkedHashMap<String, ExecutionPlanItem>();
69  
70          LinkedHashSet<String> totalPhaseSet = new LinkedHashSet<String>();
71          if ( defaultLifecycles != null )
72          {
73              for ( String phase : getDistinctPhasesInOrderOfExecutionPlanAppearance( planItem ) )
74              {
75                  final Lifecycle lifecycle = defaultLifecycles.get( phase );
76                  if ( lifecycle != null )
77                  {
78                      totalPhaseSet.addAll( lifecycle.getPhases() );
79                  }
80              }
81          }
82          this.phasesInExecutionPlan = new ArrayList<String>( totalPhaseSet );
83  
84          Map<String, ExecutionPlanItem> lastInExistingPhases = new HashMap<String, ExecutionPlanItem>();
85          for ( ExecutionPlanItem executionPlanItem : getExecutionPlanItems() )
86          {
87              lastInExistingPhases.put( executionPlanItem.getLifecyclePhase(), executionPlanItem );
88          }
89  
90          ExecutionPlanItem lastSeenExecutionPlanItem = null;
91  
92          for ( String phase : totalPhaseSet )
93          {
94              ExecutionPlanItem forThisPhase = lastInExistingPhases.get( phase );
95              if ( forThisPhase != null )
96              {
97                  lastSeenExecutionPlanItem = forThisPhase;
98              }
99  
100             lastMojoExecutionForAllPhases.put( phase, lastSeenExecutionPlanItem );
101         }
102     }
103 
104     public Iterator<ExecutionPlanItem> iterator()
105     {
106         return getExecutionPlanItems().iterator();
107     }
108 
109     /**
110      * Returns the last ExecutionPlanItem in the supplied phase. If no items are in the specified phase,
111      * the closest executionPlanItem from an earlier phase item will be returned.
112      *
113      * @param requestedPhase the requested phase
114      *                       The execution plan item
115      * @return The ExecutionPlanItem or null if none can be found
116      */
117     public ExecutionPlanItem findLastInPhase( String requestedPhase )
118     {
119         return lastMojoExecutionForAllPhases.get( requestedPhase );
120     }
121 
122     private List<ExecutionPlanItem> getExecutionPlanItems()
123     {
124         return planItem;
125     }
126 
127     private static Iterable<String> getDistinctPhasesInOrderOfExecutionPlanAppearance(
128         List<ExecutionPlanItem> planItems )
129     {
130         LinkedHashSet<String> result = new LinkedHashSet<String>();
131         for ( ExecutionPlanItem executionPlanItem : planItems )
132         {
133             final String phase = executionPlanItem.getLifecyclePhase();
134             if ( !result.contains( phase ) )
135             {
136                 result.add( phase );
137             }
138         }
139         return result;
140     }
141 
142     public List<MojoExecution> getMojoExecutions()
143     {
144         List<MojoExecution> result = new ArrayList<MojoExecution>();
145         for ( ExecutionPlanItem executionPlanItem : planItem )
146         {
147             result.add( executionPlanItem.getMojoExecution() );
148         }
149         return result;
150     }
151 
152     /**
153      * Get set of plugins having a goal/mojo used but not marked @threadSafe
154      *
155      * @return the set of plugins (without info on which goal is concerned)
156      */
157     public Set<Plugin> getNonThreadSafePlugins()
158     {
159         Set<Plugin> plugins = new HashSet<Plugin>();
160         for ( ExecutionPlanItem executionPlanItem : planItem )
161         {
162             final MojoExecution mojoExecution = executionPlanItem.getMojoExecution();
163             if ( !mojoExecution.getMojoDescriptor().isThreadSafe() )
164             {
165                 plugins.add( mojoExecution.getPlugin() );
166             }
167         }
168         return plugins;
169     }
170 
171     /**
172      * Get set of mojos used but not marked @threadSafe
173      *
174      * @return the set of mojo descriptors
175      */
176     public Set<MojoDescriptor> getNonThreadSafeMojos()
177     {
178         Set<MojoDescriptor> mojos = new HashSet<MojoDescriptor>();
179         for ( ExecutionPlanItem executionPlanItem : planItem )
180         {
181             final MojoExecution mojoExecution = executionPlanItem.getMojoExecution();
182             if ( !mojoExecution.getMojoDescriptor().isThreadSafe() )
183             {
184                 mojos.add( mojoExecution.getMojoDescriptor() );
185             }
186         }
187         return mojos;
188     }
189 
190     // Used by m2e but will be removed, really.
191     @Deprecated
192     public List<MojoExecution> getExecutions()
193     {
194         return getMojoExecutions();
195     }
196 
197     public int size()
198     {
199         return planItem.size();
200     }
201 
202 }