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  import org.apache.maven.lifecycle.internal.ExecutionPlanItem;
31  import org.apache.maven.model.Plugin;
32  import org.apache.maven.plugin.MojoExecution;
33  import org.apache.maven.plugin.descriptor.MojoDescriptor;
34  
35  // TODO lifecycles being executed
36  // TODO what runs in each phase
37  // TODO plugins that need downloading
38  // TODO project dependencies that need downloading
39  // TODO unfortunately the plugins need to be downloaded in order to get the plugin.xml file. need to externalize this
40  //      from the plugin archive.
41  // TODO this will be the class that people get in IDEs to modify
42  
43  /**
44   * MavenExecutionPlan
45   */
46  public class MavenExecutionPlan implements Iterable<ExecutionPlanItem> {
47  
48      /*
49        At the moment, this class is totally immutable, and this is in line with thoughts about the
50        pre-calculated execution plan that stays the same during the execution.
51  
52        If deciding to add mutable state to this class, it should be at least considered to
53        separate this into a separate mutable structure.
54  
55      */
56  
57      private final List<ExecutionPlanItem> planItem;
58  
59      private final Map<String, ExecutionPlanItem> lastMojoExecutionForAllPhases;
60  
61      final List<String> phasesInExecutionPlan;
62  
63      public MavenExecutionPlan(List<ExecutionPlanItem> planItem, DefaultLifecycles defaultLifecycles) {
64          this.planItem = planItem;
65  
66          lastMojoExecutionForAllPhases = new LinkedHashMap<>();
67  
68          LinkedHashSet<String> totalPhaseSet = new LinkedHashSet<>();
69          if (defaultLifecycles != null) {
70              for (String phase : getDistinctPhasesInOrderOfExecutionPlanAppearance(planItem)) {
71                  final Lifecycle lifecycle = defaultLifecycles.get(phase);
72                  if (lifecycle != null) {
73                      totalPhaseSet.addAll(lifecycle.getPhases());
74                  }
75              }
76          }
77          this.phasesInExecutionPlan = new ArrayList<>(totalPhaseSet);
78  
79          Map<String, ExecutionPlanItem> lastInExistingPhases = new HashMap<>();
80          for (ExecutionPlanItem executionPlanItem : getExecutionPlanItems()) {
81              lastInExistingPhases.put(executionPlanItem.getLifecyclePhase(), executionPlanItem);
82          }
83  
84          ExecutionPlanItem lastSeenExecutionPlanItem = null;
85  
86          for (String phase : totalPhaseSet) {
87              ExecutionPlanItem forThisPhase = lastInExistingPhases.get(phase);
88              if (forThisPhase != null) {
89                  lastSeenExecutionPlanItem = forThisPhase;
90              }
91  
92              lastMojoExecutionForAllPhases.put(phase, lastSeenExecutionPlanItem);
93          }
94      }
95  
96      public Iterator<ExecutionPlanItem> iterator() {
97          return getExecutionPlanItems().iterator();
98      }
99  
100     /**
101      * Returns the last ExecutionPlanItem in the supplied phase. If no items are in the specified phase,
102      * the closest executionPlanItem from an earlier phase item will be returned.
103      *
104      * @param requestedPhase the requested phase
105      *                       The execution plan item
106      * @return The ExecutionPlanItem or null if none can be found
107      */
108     public ExecutionPlanItem findLastInPhase(String requestedPhase) {
109         return lastMojoExecutionForAllPhases.get(requestedPhase);
110     }
111 
112     private List<ExecutionPlanItem> getExecutionPlanItems() {
113         return planItem;
114     }
115 
116     private static Iterable<String> getDistinctPhasesInOrderOfExecutionPlanAppearance(
117             List<ExecutionPlanItem> planItems) {
118         LinkedHashSet<String> result = new LinkedHashSet<>();
119         for (ExecutionPlanItem executionPlanItem : planItems) {
120             final String phase = executionPlanItem.getLifecyclePhase();
121             if (!result.contains(phase)) {
122                 result.add(phase);
123             }
124         }
125         return result;
126     }
127 
128     public List<MojoExecution> getMojoExecutions() {
129         List<MojoExecution> result = new ArrayList<>();
130         for (ExecutionPlanItem executionPlanItem : planItem) {
131             result.add(executionPlanItem.getMojoExecution());
132         }
133         return result;
134     }
135 
136     /**
137      * Get set of plugins having a goal/mojo used but not marked @threadSafe
138      *
139      * @return the set of plugins (without info on which goal is concerned)
140      */
141     public Set<Plugin> getNonThreadSafePlugins() {
142         Set<Plugin> plugins = new HashSet<>();
143         for (ExecutionPlanItem executionPlanItem : planItem) {
144             final MojoExecution mojoExecution = executionPlanItem.getMojoExecution();
145             if (!mojoExecution.getMojoDescriptor().isThreadSafe()) {
146                 plugins.add(mojoExecution.getPlugin());
147             }
148         }
149         return plugins;
150     }
151 
152     /**
153      * Get set of mojos used but not marked @threadSafe
154      *
155      * @return the set of mojo descriptors
156      */
157     public Set<MojoDescriptor> getNonThreadSafeMojos() {
158         Set<MojoDescriptor> mojos = new HashSet<>();
159         for (ExecutionPlanItem executionPlanItem : planItem) {
160             final MojoExecution mojoExecution = executionPlanItem.getMojoExecution();
161             if (!mojoExecution.getMojoDescriptor().isThreadSafe()) {
162                 mojos.add(mojoExecution.getMojoDescriptor());
163             }
164         }
165         return mojos;
166     }
167 
168     // Used by m2e but will be removed, really.
169     @Deprecated
170     public List<MojoExecution> getExecutions() {
171         return getMojoExecutions();
172     }
173 
174     public int size() {
175         return planItem.size();
176     }
177 }