001package 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 022import java.util.ArrayList; 023import java.util.HashMap; 024import java.util.HashSet; 025import java.util.Iterator; 026import java.util.LinkedHashMap; 027import java.util.LinkedHashSet; 028import java.util.List; 029import java.util.Map; 030import java.util.Set; 031 032import org.apache.maven.lifecycle.internal.ExecutionPlanItem; 033import org.apache.maven.model.Plugin; 034import org.apache.maven.plugin.MojoExecution; 035import 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 045public 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}