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      @Override
98      public Iterator<ExecutionPlanItem> iterator() {
99          return getExecutionPlanItems().iterator();
100     }
101 
102     /**
103      * Returns the last ExecutionPlanItem in the supplied phase. If no items are in the specified phase,
104      * the closest executionPlanItem from an earlier phase item will be returned.
105      *
106      * @param requestedPhase the requested phase
107      *                       The execution plan item
108      * @return The ExecutionPlanItem or null if none can be found
109      */
110     public ExecutionPlanItem findLastInPhase(String requestedPhase) {
111         return lastMojoExecutionForAllPhases.get(requestedPhase);
112     }
113 
114     private List<ExecutionPlanItem> getExecutionPlanItems() {
115         return planItem;
116     }
117 
118     private static Iterable<String> getDistinctPhasesInOrderOfExecutionPlanAppearance(
119             List<ExecutionPlanItem> planItems) {
120         LinkedHashSet<String> result = new LinkedHashSet<>();
121         for (ExecutionPlanItem executionPlanItem : planItems) {
122             result.add(executionPlanItem.getLifecyclePhase());
123         }
124         return result;
125     }
126 
127     public List<MojoExecution> getMojoExecutions() {
128         List<MojoExecution> result = new ArrayList<>();
129         for (ExecutionPlanItem executionPlanItem : planItem) {
130             result.add(executionPlanItem.getMojoExecution());
131         }
132         return result;
133     }
134 
135     /**
136      * Get set of plugins having a goal/mojo used but not marked @threadSafe
137      *
138      * @return the set of plugins (without info on which goal is concerned)
139      */
140     public Set<Plugin> getNonThreadSafePlugins() {
141         Set<Plugin> plugins = new HashSet<>();
142         for (ExecutionPlanItem executionPlanItem : planItem) {
143             final MojoExecution mojoExecution = executionPlanItem.getMojoExecution();
144             if (!mojoExecution.getMojoDescriptor().isThreadSafe()) {
145                 plugins.add(mojoExecution.getPlugin());
146             }
147         }
148         return plugins;
149     }
150 
151     /**
152      * Get set of mojos used but not marked @threadSafe
153      *
154      * @return the set of mojo descriptors
155      */
156     public Set<MojoDescriptor> getNonThreadSafeMojos() {
157         Set<MojoDescriptor> mojos = new HashSet<>();
158         for (ExecutionPlanItem executionPlanItem : planItem) {
159             final MojoExecution mojoExecution = executionPlanItem.getMojoExecution();
160             if (!mojoExecution.getMojoDescriptor().isThreadSafe()) {
161                 mojos.add(mojoExecution.getMojoDescriptor());
162             }
163         }
164         return mojos;
165     }
166 
167     // Used by m2e but will be removed, really.
168     @Deprecated
169     public List<MojoExecution> getExecutions() {
170         return getMojoExecutions();
171     }
172 
173     public int size() {
174         return planItem.size();
175     }
176 }