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.project;
20  
21  import java.util.ArrayList;
22  import java.util.Iterator;
23  import java.util.LinkedHashMap;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.TreeMap;
27  
28  import org.apache.maven.model.Dependency;
29  import org.apache.maven.model.Plugin;
30  import org.apache.maven.model.PluginContainer;
31  import org.apache.maven.model.PluginExecution;
32  import org.apache.maven.model.Repository;
33  import org.codehaus.plexus.util.xml.Xpp3Dom;
34  
35  /** @deprecated */
36  @Deprecated
37  public final class ModelUtils {
38  
39      /**
40       * This should be the resulting ordering of plugins after merging:
41       * <p>
42       * Given:
43       * <pre>
44       * parent: X -&gt; A -&gt; B -&gt; D -&gt; E
45       * child: Y -&gt; A -&gt; C -&gt; D -&gt; F
46       * </pre>
47       * Result:
48       * <pre>
49       * X -&gt; Y -&gt; A -&gt; B -&gt; C -&gt; D -&gt; E -&gt; F
50       * </pre>
51       */
52      public static void mergePluginLists(
53              PluginContainer childContainer, PluginContainer parentContainer, boolean handleAsInheritance) {
54          if ((childContainer == null) || (parentContainer == null)) {
55              // nothing to do.
56              return;
57          }
58  
59          List<Plugin> parentPlugins = parentContainer.getPlugins();
60  
61          if ((parentPlugins != null) && !parentPlugins.isEmpty()) {
62              parentPlugins = new ArrayList<>(parentPlugins);
63  
64              // If we're processing this merge as an inheritance, we have to build up a list of
65              // plugins that were considered for inheritance.
66              if (handleAsInheritance) {
67                  for (Iterator<Plugin> it = parentPlugins.iterator(); it.hasNext(); ) {
68                      Plugin plugin = it.next();
69  
70                      String inherited = plugin.getInherited();
71  
72                      if ((inherited != null) && !Boolean.parseBoolean(inherited)) {
73                          it.remove();
74                      }
75                  }
76              }
77  
78              List<Plugin> assembledPlugins = new ArrayList<>();
79  
80              Map<String, Plugin> childPlugins = childContainer.getPluginsAsMap();
81  
82              for (Plugin parentPlugin : parentPlugins) {
83                  String parentInherited = parentPlugin.getInherited();
84  
85                  // only merge plugin definition from the parent if at least one
86                  // of these is true:
87                  // 1. we're not processing the plugins in an inheritance-based merge
88                  // 2. the parent's <inherited/> flag is not set
89                  // 3. the parent's <inherited/> flag is set to true
90                  if (!handleAsInheritance || (parentInherited == null) || Boolean.parseBoolean(parentInherited)) {
91                      Plugin childPlugin = childPlugins.get(parentPlugin.getKey());
92  
93                      if ((childPlugin != null) && !assembledPlugins.contains(childPlugin)) {
94                          Plugin assembledPlugin = childPlugin;
95  
96                          mergePluginDefinitions(childPlugin, parentPlugin, handleAsInheritance);
97  
98                          // fix for MNG-2221 (assembly cache was not being populated for later reference):
99                          assembledPlugins.add(assembledPlugin);
100                     }
101 
102                     // if we're processing this as an inheritance-based merge, and
103                     // the parent's <inherited/> flag is not set, then we need to
104                     // clear the inherited flag in the merge result.
105                     if (handleAsInheritance && (parentInherited == null)) {
106                         parentPlugin.unsetInheritanceApplied();
107                     }
108                 }
109 
110                 // very important to use the parentPlugins List, rather than parentContainer.getPlugins()
111                 // since this list is a local one, and may have been modified during processing.
112                 List<Plugin> results =
113                         ModelUtils.orderAfterMerge(assembledPlugins, parentPlugins, childContainer.getPlugins());
114 
115                 childContainer.setPlugins(results);
116 
117                 childContainer.flushPluginMap();
118             }
119         }
120     }
121 
122     public static List<Plugin> orderAfterMerge(
123             List<Plugin> merged, List<Plugin> highPrioritySource, List<Plugin> lowPrioritySource) {
124         List<Plugin> results = new ArrayList<>();
125 
126         if (!merged.isEmpty()) {
127             results.addAll(merged);
128         }
129 
130         List<Plugin> missingFromResults = new ArrayList<>();
131 
132         List<List<Plugin>> sources = new ArrayList<>();
133 
134         sources.add(highPrioritySource);
135         sources.add(lowPrioritySource);
136 
137         for (List<Plugin> source : sources) {
138             for (Plugin item : source) {
139                 if (results.contains(item)) {
140                     if (!missingFromResults.isEmpty()) {
141                         int idx = results.indexOf(item);
142 
143                         if (idx < 0) {
144                             idx = 0;
145                         }
146 
147                         results.addAll(idx, missingFromResults);
148 
149                         missingFromResults.clear();
150                     }
151                 } else {
152                     missingFromResults.add(item);
153                 }
154             }
155 
156             if (!missingFromResults.isEmpty()) {
157                 results.addAll(missingFromResults);
158 
159                 missingFromResults.clear();
160             }
161         }
162 
163         return results;
164     }
165 
166     public static void mergePluginDefinitions(Plugin child, Plugin parent, boolean handleAsInheritance) {
167         if ((child == null) || (parent == null)) {
168             // nothing to do.
169             return;
170         }
171 
172         if (parent.isExtensions()) {
173             child.setExtensions(true);
174         }
175 
176         if ((child.getVersion() == null) && (parent.getVersion() != null)) {
177             child.setVersion(parent.getVersion());
178         }
179 
180         Xpp3Dom childConfiguration = (Xpp3Dom) child.getConfiguration();
181         Xpp3Dom parentConfiguration = (Xpp3Dom) parent.getConfiguration();
182 
183         childConfiguration = Xpp3Dom.mergeXpp3Dom(childConfiguration, parentConfiguration);
184 
185         child.setConfiguration(childConfiguration);
186 
187         child.setDependencies(mergeDependencyList(child.getDependencies(), parent.getDependencies()));
188 
189         // from here to the end of the method is dealing with merging of the <executions/> section.
190         String parentInherited = parent.getInherited();
191 
192         boolean parentIsInherited = (parentInherited == null) || Boolean.parseBoolean(parentInherited);
193 
194         List<PluginExecution> parentExecutions = parent.getExecutions();
195 
196         if ((parentExecutions != null) && !parentExecutions.isEmpty()) {
197             List<PluginExecution> mergedExecutions = new ArrayList<>();
198 
199             Map<String, PluginExecution> assembledExecutions = new TreeMap<>();
200 
201             Map<String, PluginExecution> childExecutions = child.getExecutionsAsMap();
202 
203             for (PluginExecution parentExecution : parentExecutions) {
204                 String inherited = parentExecution.getInherited();
205 
206                 boolean parentExecInherited =
207                         parentIsInherited && ((inherited == null) || Boolean.parseBoolean(inherited));
208 
209                 if (!handleAsInheritance || parentExecInherited) {
210                     PluginExecution assembled = parentExecution;
211 
212                     PluginExecution childExecution = childExecutions.get(parentExecution.getId());
213 
214                     if (childExecution != null) {
215                         mergePluginExecutionDefinitions(childExecution, parentExecution);
216 
217                         assembled = childExecution;
218                     } else if (handleAsInheritance && (parentInherited == null)) {
219                         parentExecution.unsetInheritanceApplied();
220                     }
221 
222                     assembledExecutions.put(assembled.getId(), assembled);
223                     mergedExecutions.add(assembled);
224                 }
225             }
226 
227             for (PluginExecution childExecution : child.getExecutions()) {
228                 if (!assembledExecutions.containsKey(childExecution.getId())) {
229                     mergedExecutions.add(childExecution);
230                 }
231             }
232 
233             child.setExecutions(mergedExecutions);
234 
235             child.flushExecutionMap();
236         }
237     }
238 
239     private static void mergePluginExecutionDefinitions(PluginExecution child, PluginExecution parent) {
240         if (child.getPhase() == null) {
241             child.setPhase(parent.getPhase());
242         }
243 
244         List<String> parentGoals = parent.getGoals();
245         List<String> childGoals = child.getGoals();
246 
247         List<String> goals = new ArrayList<>();
248 
249         if ((childGoals != null) && !childGoals.isEmpty()) {
250             goals.addAll(childGoals);
251         }
252 
253         if (parentGoals != null) {
254             for (String goal : parentGoals) {
255                 if (!goals.contains(goal)) {
256                     goals.add(goal);
257                 }
258             }
259         }
260 
261         child.setGoals(goals);
262 
263         Xpp3Dom childConfiguration = (Xpp3Dom) child.getConfiguration();
264         Xpp3Dom parentConfiguration = (Xpp3Dom) parent.getConfiguration();
265 
266         childConfiguration = Xpp3Dom.mergeXpp3Dom(childConfiguration, parentConfiguration);
267 
268         child.setConfiguration(childConfiguration);
269     }
270 
271     public static List<Repository> mergeRepositoryLists(List<Repository> dominant, List<Repository> recessive) {
272 
273         List<Repository> repositories = new ArrayList<>(dominant);
274 
275         for (Repository repository : recessive) {
276             if (!repositories.contains(repository)) {
277                 repositories.add(repository);
278             }
279         }
280 
281         return repositories;
282     }
283 
284     public static void mergeFilterLists(List<String> childFilters, List<String> parentFilters) {
285         for (String f : parentFilters) {
286             if (!childFilters.contains(f)) {
287                 childFilters.add(f);
288             }
289         }
290     }
291 
292     private static List<Dependency> mergeDependencyList(List<Dependency> child, List<Dependency> parent) {
293         Map<String, Dependency> depsMap = new LinkedHashMap<>();
294 
295         if (parent != null) {
296             for (Dependency dependency : parent) {
297                 depsMap.put(dependency.getManagementKey(), dependency);
298             }
299         }
300 
301         if (child != null) {
302             for (Dependency dependency : child) {
303                 depsMap.put(dependency.getManagementKey(), dependency);
304             }
305         }
306 
307         return new ArrayList<>(depsMap.values());
308     }
309 }