001 package org.apache.maven.lifecycle;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import java.util.ArrayList;
023 import java.util.HashMap;
024 import java.util.HashSet;
025 import java.util.Iterator;
026 import java.util.LinkedHashMap;
027 import java.util.LinkedHashSet;
028 import java.util.List;
029 import java.util.Map;
030 import java.util.Set;
031
032 import org.apache.maven.lifecycle.internal.ExecutionPlanItem;
033 import org.apache.maven.model.Plugin;
034 import org.apache.maven.plugin.MojoExecution;
035 import org.apache.maven.plugin.descriptor.MojoDescriptor;
036
037 //TODO: lifecycles being executed
038 //TODO: what runs in each phase
039 //TODO: plugins that need downloading
040 //TODO: project dependencies that need downloading
041 //TODO: unfortunately the plugins need to be downloaded in order to get the plugin.xml file. need to externalize this
042 // from the plugin archive.
043 //TODO: this will be the class that people get in IDEs to modify
044
045 public class MavenExecutionPlan
046 implements Iterable<ExecutionPlanItem>
047 {
048
049 /*
050 At the moment, this class is totally immutable, and this is in line with thoughts about the
051 pre-calculated execution plan that stays the same during the execution.
052
053 If deciding to add mutable state to this class, it should be at least considered to
054 separate this into a separate mutable structure.
055
056 */
057
058 private final List<ExecutionPlanItem> planItem;
059
060 private final Map<String, ExecutionPlanItem> lastMojoExecutionForAllPhases;
061
062 final List<String> phasesInExecutionPlan;
063
064 public MavenExecutionPlan( List<ExecutionPlanItem> planItem, DefaultLifecycles defaultLifecycles )
065 {
066 this.planItem = planItem;
067
068 lastMojoExecutionForAllPhases = new LinkedHashMap<String, ExecutionPlanItem>();
069
070 LinkedHashSet<String> totalPhaseSet = new LinkedHashSet<String>();
071 if ( defaultLifecycles != null )
072 {
073 for ( String phase : getDistinctPhasesInOrderOfExecutionPlanAppearance( planItem ) )
074 {
075 final Lifecycle lifecycle = defaultLifecycles.get( phase );
076 if ( lifecycle != null )
077 {
078 totalPhaseSet.addAll( lifecycle.getPhases() );
079 }
080 }
081 }
082 this.phasesInExecutionPlan = new ArrayList<String>( totalPhaseSet );
083
084 Map<String, ExecutionPlanItem> lastInExistingPhases = new HashMap<String, ExecutionPlanItem>();
085 for ( ExecutionPlanItem executionPlanItem : getExecutionPlanItems() )
086 {
087 lastInExistingPhases.put( executionPlanItem.getLifecyclePhase(), executionPlanItem );
088 }
089
090 ExecutionPlanItem lastSeenExecutionPlanItem = null;
091
092 for ( String phase : totalPhaseSet )
093 {
094 ExecutionPlanItem forThisPhase = lastInExistingPhases.get( phase );
095 if ( forThisPhase != null )
096 {
097 lastSeenExecutionPlanItem = forThisPhase;
098 }
099
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 void forceAllComplete()
143 {
144 for ( ExecutionPlanItem executionPlanItem : getExecutionPlanItems() )
145 {
146 executionPlanItem.forceComplete();
147 }
148 }
149
150 public void waitUntilAllDone()
151 throws InterruptedException
152 {
153 for ( ExecutionPlanItem executionPlanItem : getExecutionPlanItems() )
154 {
155 executionPlanItem.waitUntilDone();
156 }
157 }
158
159 public boolean containsPhase( String phase )
160 {
161 return phasesInExecutionPlan.contains( phase );
162 }
163
164 public List<MojoExecution> getMojoExecutions()
165 {
166 List<MojoExecution> result = new ArrayList<MojoExecution>();
167 for ( ExecutionPlanItem executionPlanItem : planItem )
168 {
169 result.add( executionPlanItem.getMojoExecution() );
170 }
171 return result;
172 }
173
174 /**
175 * Get set of plugins having a goal/mojo used but not marked @threadSafe
176 *
177 * @return the set of plugins (without info on which goal is concerned)
178 */
179 public Set<Plugin> getNonThreadSafePlugins()
180 {
181 Set<Plugin> plugins = new HashSet<Plugin>();
182 for ( ExecutionPlanItem executionPlanItem : planItem )
183 {
184 final MojoExecution mojoExecution = executionPlanItem.getMojoExecution();
185 if ( !mojoExecution.getMojoDescriptor().isThreadSafe() )
186 {
187 plugins.add( mojoExecution.getPlugin() );
188 }
189 }
190 return plugins;
191 }
192
193 /**
194 * Get set of mojos used but not marked @threadSafe
195 *
196 * @return the set of mojo descriptors
197 */
198 public Set<MojoDescriptor> getNonThreadSafeMojos()
199 {
200 Set<MojoDescriptor> mojos = new HashSet<MojoDescriptor>();
201 for ( ExecutionPlanItem executionPlanItem : planItem )
202 {
203 final MojoExecution mojoExecution = executionPlanItem.getMojoExecution();
204 if ( !mojoExecution.getMojoDescriptor().isThreadSafe() )
205 {
206 mojos.add( mojoExecution.getMojoDescriptor() );
207 }
208 }
209 return mojos;
210 }
211
212 // Used by m2e but will be removed, really.
213 @Deprecated
214 public List<MojoExecution> getExecutions()
215 {
216 return getMojoExecutions();
217 }
218
219 public int size()
220 {
221 return planItem.size();
222 }
223
224 }