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  /**
46   * MavenExecutionPlan
47   */
48  public class MavenExecutionPlan
49      implements Iterable<ExecutionPlanItem>
50  {
51  
52      /*
53         At the moment, this class is totally immutable, and this is in line with thoughts about the
54         pre-calculated execution plan that stays the same during the execution.
55  
56         If deciding to add mutable state to this class, it should be at least considered to
57         separate this into a separate mutable structure.
58  
59       */
60  
61      private final List<ExecutionPlanItem> planItem;
62  
63      private final Map<String, ExecutionPlanItem> lastMojoExecutionForAllPhases;
64  
65      final List<String> phasesInExecutionPlan;
66  
67      public MavenExecutionPlan( List<ExecutionPlanItem> planItem, DefaultLifecycles defaultLifecycles )
68      {
69          this.planItem = planItem;
70  
71          lastMojoExecutionForAllPhases = new LinkedHashMap<>();
72  
73          LinkedHashSet<String> totalPhaseSet = new LinkedHashSet<>();
74          if ( defaultLifecycles != null )
75          {
76              for ( String phase : getDistinctPhasesInOrderOfExecutionPlanAppearance( planItem ) )
77              {
78                  final Lifecycle lifecycle = defaultLifecycles.get( phase );
79                  if ( lifecycle != null )
80                  {
81                      totalPhaseSet.addAll( lifecycle.getPhases() );
82                  }
83              }
84          }
85          this.phasesInExecutionPlan = new ArrayList<>( totalPhaseSet );
86  
87          Map<String, ExecutionPlanItem> lastInExistingPhases = new HashMap<>();
88          for ( ExecutionPlanItem executionPlanItem : getExecutionPlanItems() )
89          {
90              lastInExistingPhases.put( executionPlanItem.getLifecyclePhase(), executionPlanItem );
91          }
92  
93          ExecutionPlanItem lastSeenExecutionPlanItem = null;
94  
95          for ( String phase : totalPhaseSet )
96          {
97              ExecutionPlanItem forThisPhase = lastInExistingPhases.get( phase );
98              if ( forThisPhase != null )
99              {
100                 lastSeenExecutionPlanItem = forThisPhase;
101             }
102 
103             lastMojoExecutionForAllPhases.put( phase, lastSeenExecutionPlanItem );
104         }
105     }
106 
107     public Iterator<ExecutionPlanItem> iterator()
108     {
109         return getExecutionPlanItems().iterator();
110     }
111 
112     /**
113      * Returns the last ExecutionPlanItem in the supplied phase. If no items are in the specified phase,
114      * the closest executionPlanItem from an earlier phase item will be returned.
115      *
116      * @param requestedPhase the requested phase
117      *                       The execution plan item
118      * @return The ExecutionPlanItem or null if none can be found
119      */
120     public ExecutionPlanItem findLastInPhase( String requestedPhase )
121     {
122         return lastMojoExecutionForAllPhases.get( requestedPhase );
123     }
124 
125     private List<ExecutionPlanItem> getExecutionPlanItems()
126     {
127         return planItem;
128     }
129 
130     private static Iterable<String> getDistinctPhasesInOrderOfExecutionPlanAppearance(
131         List<ExecutionPlanItem> planItems )
132     {
133         LinkedHashSet<String> result = new LinkedHashSet<>();
134         for ( ExecutionPlanItem executionPlanItem : planItems )
135         {
136             final String phase = executionPlanItem.getLifecyclePhase();
137             if ( !result.contains( phase ) )
138             {
139                 result.add( phase );
140             }
141         }
142         return result;
143     }
144 
145     public List<MojoExecution> getMojoExecutions()
146     {
147         List<MojoExecution> result = new ArrayList<>();
148         for ( ExecutionPlanItem executionPlanItem : planItem )
149         {
150             result.add( executionPlanItem.getMojoExecution() );
151         }
152         return result;
153     }
154 
155     /**
156      * Get set of plugins having a goal/mojo used but not marked @threadSafe
157      *
158      * @return the set of plugins (without info on which goal is concerned)
159      */
160     public Set<Plugin> getNonThreadSafePlugins()
161     {
162         Set<Plugin> plugins = new HashSet<>();
163         for ( ExecutionPlanItem executionPlanItem : planItem )
164         {
165             final MojoExecution mojoExecution = executionPlanItem.getMojoExecution();
166             if ( !mojoExecution.getMojoDescriptor().isThreadSafe() )
167             {
168                 plugins.add( mojoExecution.getPlugin() );
169             }
170         }
171         return plugins;
172     }
173 
174     /**
175      * Get set of mojos used but not marked @threadSafe
176      *
177      * @return the set of mojo descriptors
178      */
179     public Set<MojoDescriptor> getNonThreadSafeMojos()
180     {
181         Set<MojoDescriptor> mojos = new HashSet<>();
182         for ( ExecutionPlanItem executionPlanItem : planItem )
183         {
184             final MojoExecution mojoExecution = executionPlanItem.getMojoExecution();
185             if ( !mojoExecution.getMojoDescriptor().isThreadSafe() )
186             {
187                 mojos.add( mojoExecution.getMojoDescriptor() );
188             }
189         }
190         return mojos;
191     }
192 
193     // Used by m2e but will be removed, really.
194     @Deprecated
195     public List<MojoExecution> getExecutions()
196     {
197         return getMojoExecutions();
198     }
199 
200     public int size()
201     {
202         return planItem.size();
203     }
204 
205 }