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             final String phase = executionPlanItem.getLifecyclePhase();
122             if (!result.contains(phase)) {
123                 result.add(phase);
124             }
125         }
126         return result;
127     }
128 
129     public List<MojoExecution> getMojoExecutions() {
130         List<MojoExecution> result = new ArrayList<>();
131         for (ExecutionPlanItem executionPlanItem : planItem) {
132             result.add(executionPlanItem.getMojoExecution());
133         }
134         return result;
135     }
136 
137     /**
138      * Get set of plugins having a goal/mojo used but not marked @threadSafe
139      *
140      * @return the set of plugins (without info on which goal is concerned)
141      */
142     public Set<Plugin> getNonThreadSafePlugins() {
143         Set<Plugin> plugins = new HashSet<>();
144         for (ExecutionPlanItem executionPlanItem : planItem) {
145             final MojoExecution mojoExecution = executionPlanItem.getMojoExecution();
146             if (!mojoExecution.getMojoDescriptor().isThreadSafe()) {
147                 plugins.add(mojoExecution.getPlugin());
148             }
149         }
150         return plugins;
151     }
152 
153     /**
154      * Get set of mojos used but not marked @threadSafe
155      *
156      * @return the set of mojo descriptors
157      */
158     public Set<MojoDescriptor> getNonThreadSafeMojos() {
159         Set<MojoDescriptor> mojos = new HashSet<>();
160         for (ExecutionPlanItem executionPlanItem : planItem) {
161             final MojoExecution mojoExecution = executionPlanItem.getMojoExecution();
162             if (!mojoExecution.getMojoDescriptor().isThreadSafe()) {
163                 mojos.add(mojoExecution.getMojoDescriptor());
164             }
165         }
166         return mojos;
167     }
168 
169     // Used by m2e but will be removed, really.
170     @Deprecated
171     public List<MojoExecution> getExecutions() {
172         return getMojoExecutions();
173     }
174 
175     public int size() {
176         return planItem.size();
177     }
178 }