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<>(); 069 070 LinkedHashSet<String> totalPhaseSet = new LinkedHashSet<>(); 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<>( totalPhaseSet ); 083 084 Map<String, ExecutionPlanItem> lastInExistingPhases = new HashMap<>(); 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<>(); 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<>(); 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<>(); 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<>(); 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}