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