| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.maven.plugin.resources.remote; |
| |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.TreeMap; |
| |
| import org.apache.maven.model.Dependency; |
| import org.apache.maven.model.Plugin; |
| import org.apache.maven.model.PluginContainer; |
| import org.apache.maven.model.PluginExecution; |
| import org.apache.maven.model.Repository; |
| import org.codehaus.plexus.util.xml.Xpp3Dom; |
| |
| /** HELPER CLASS */ |
| public final class ModelUtils { |
| |
| /** |
| * This should be the resulting ordering of plugins after merging: |
| * <p> |
| * Given: |
| * <pre> |
| * parent: X -> A -> B -> D -> E |
| * child: Y -> A -> C -> D -> F |
| * </pre> |
| * Result: |
| * <pre> |
| * X -> Y -> A -> B -> C -> D -> E -> F |
| * </pre> |
| */ |
| public static void mergePluginLists( |
| PluginContainer childContainer, PluginContainer parentContainer, boolean handleAsInheritance) { |
| if ((childContainer == null) || (parentContainer == null)) { |
| // nothing to do. |
| return; |
| } |
| |
| List<Plugin> parentPlugins = parentContainer.getPlugins(); |
| |
| if ((parentPlugins != null) && !parentPlugins.isEmpty()) { |
| parentPlugins = new ArrayList<>(parentPlugins); |
| |
| // If we're processing this merge as an inheritance, we have to build up a list of |
| // plugins that were considered for inheritance. |
| if (handleAsInheritance) { |
| for (Iterator<Plugin> it = parentPlugins.iterator(); it.hasNext(); ) { |
| Plugin plugin = it.next(); |
| |
| String inherited = plugin.getInherited(); |
| |
| if ((inherited != null) && !Boolean.parseBoolean(inherited)) { |
| it.remove(); |
| } |
| } |
| } |
| |
| List<Plugin> assembledPlugins = new ArrayList<>(); |
| |
| Map<String, Plugin> childPlugins = childContainer.getPluginsAsMap(); |
| |
| for (Plugin parentPlugin : parentPlugins) { |
| String parentInherited = parentPlugin.getInherited(); |
| |
| // only merge plugin definition from the parent if at least one |
| // of these is true: |
| // 1. we're not processing the plugins in an inheritance-based merge |
| // 2. the parent's <inherited/> flag is not set |
| // 3. the parent's <inherited/> flag is set to true |
| if (!handleAsInheritance || (parentInherited == null) || Boolean.parseBoolean(parentInherited)) { |
| Plugin childPlugin = childPlugins.get(parentPlugin.getKey()); |
| |
| if ((childPlugin != null) && !assembledPlugins.contains(childPlugin)) { |
| Plugin assembledPlugin = childPlugin; |
| |
| mergePluginDefinitions(childPlugin, parentPlugin, handleAsInheritance); |
| |
| // fix for MNG-2221 (assembly cache was not being populated for later reference): |
| assembledPlugins.add(assembledPlugin); |
| } |
| |
| // if we're processing this as an inheritance-based merge, and |
| // the parent's <inherited/> flag is not set, then we need to |
| // clear the inherited flag in the merge result. |
| if (handleAsInheritance && (parentInherited == null)) { |
| parentPlugin.unsetInheritanceApplied(); |
| } |
| } |
| |
| // very important to use the parentPlugins List, rather than parentContainer.getPlugins() |
| // since this list is a local one, and may have been modified during processing. |
| List<Plugin> results = |
| ModelUtils.orderAfterMerge(assembledPlugins, parentPlugins, childContainer.getPlugins()); |
| |
| childContainer.setPlugins(results); |
| |
| childContainer.flushPluginMap(); |
| } |
| } |
| } |
| |
| public static List<Plugin> orderAfterMerge( |
| List<Plugin> merged, List<Plugin> highPrioritySource, List<Plugin> lowPrioritySource) { |
| List<Plugin> results = new ArrayList<>(); |
| |
| if (!merged.isEmpty()) { |
| results.addAll(merged); |
| } |
| |
| List<Plugin> missingFromResults = new ArrayList<>(); |
| |
| List<List<Plugin>> sources = new ArrayList<>(); |
| |
| sources.add(highPrioritySource); |
| sources.add(lowPrioritySource); |
| |
| for (List<Plugin> source : sources) { |
| for (Plugin item : source) { |
| if (results.contains(item)) { |
| if (!missingFromResults.isEmpty()) { |
| int idx = results.indexOf(item); |
| |
| if (idx < 0) { |
| idx = 0; |
| } |
| |
| results.addAll(idx, missingFromResults); |
| |
| missingFromResults.clear(); |
| } |
| } else { |
| missingFromResults.add(item); |
| } |
| } |
| |
| if (!missingFromResults.isEmpty()) { |
| results.addAll(missingFromResults); |
| |
| missingFromResults.clear(); |
| } |
| } |
| |
| return results; |
| } |
| |
| public static void mergePluginDefinitions(Plugin child, Plugin parent, boolean handleAsInheritance) { |
| if ((child == null) || (parent == null)) { |
| // nothing to do. |
| return; |
| } |
| |
| if (parent.isExtensions()) { |
| child.setExtensions(true); |
| } |
| |
| if ((child.getVersion() == null) && (parent.getVersion() != null)) { |
| child.setVersion(parent.getVersion()); |
| } |
| |
| Xpp3Dom childConfiguration = (Xpp3Dom) child.getConfiguration(); |
| Xpp3Dom parentConfiguration = (Xpp3Dom) parent.getConfiguration(); |
| |
| childConfiguration = Xpp3Dom.mergeXpp3Dom(childConfiguration, parentConfiguration); |
| |
| child.setConfiguration(childConfiguration); |
| |
| child.setDependencies(mergeDependencyList(child.getDependencies(), parent.getDependencies())); |
| |
| // from here to the end of the method is dealing with merging of the <executions/> section. |
| String parentInherited = parent.getInherited(); |
| |
| boolean parentIsInherited = (parentInherited == null) || Boolean.parseBoolean(parentInherited); |
| |
| List<PluginExecution> parentExecutions = parent.getExecutions(); |
| |
| if ((parentExecutions != null) && !parentExecutions.isEmpty()) { |
| List<PluginExecution> mergedExecutions = new ArrayList<>(); |
| |
| Map<String, PluginExecution> assembledExecutions = new TreeMap<>(); |
| |
| Map<String, PluginExecution> childExecutions = child.getExecutionsAsMap(); |
| |
| for (PluginExecution parentExecution : parentExecutions) { |
| String inherited = parentExecution.getInherited(); |
| |
| boolean parentExecInherited = |
| parentIsInherited && ((inherited == null) || Boolean.parseBoolean(inherited)); |
| |
| if (!handleAsInheritance || parentExecInherited) { |
| PluginExecution assembled = parentExecution; |
| |
| PluginExecution childExecution = childExecutions.get(parentExecution.getId()); |
| |
| if (childExecution != null) { |
| mergePluginExecutionDefinitions(childExecution, parentExecution); |
| |
| assembled = childExecution; |
| } else if (handleAsInheritance && (parentInherited == null)) { |
| parentExecution.unsetInheritanceApplied(); |
| } |
| |
| assembledExecutions.put(assembled.getId(), assembled); |
| mergedExecutions.add(assembled); |
| } |
| } |
| |
| for (PluginExecution childExecution : child.getExecutions()) { |
| if (!assembledExecutions.containsKey(childExecution.getId())) { |
| mergedExecutions.add(childExecution); |
| } |
| } |
| |
| child.setExecutions(mergedExecutions); |
| |
| child.flushExecutionMap(); |
| } |
| } |
| |
| private static void mergePluginExecutionDefinitions(PluginExecution child, PluginExecution parent) { |
| if (child.getPhase() == null) { |
| child.setPhase(parent.getPhase()); |
| } |
| |
| List<String> parentGoals = parent.getGoals(); |
| List<String> childGoals = child.getGoals(); |
| |
| List<String> goals = new ArrayList<>(); |
| |
| if ((childGoals != null) && !childGoals.isEmpty()) { |
| goals.addAll(childGoals); |
| } |
| |
| if (parentGoals != null) { |
| for (String goal : parentGoals) { |
| if (!goals.contains(goal)) { |
| goals.add(goal); |
| } |
| } |
| } |
| |
| child.setGoals(goals); |
| |
| Xpp3Dom childConfiguration = (Xpp3Dom) child.getConfiguration(); |
| Xpp3Dom parentConfiguration = (Xpp3Dom) parent.getConfiguration(); |
| |
| childConfiguration = Xpp3Dom.mergeXpp3Dom(childConfiguration, parentConfiguration); |
| |
| child.setConfiguration(childConfiguration); |
| } |
| |
| public static List<Repository> mergeRepositoryLists(List<Repository> dominant, List<Repository> recessive) { |
| |
| List<Repository> repositories = new ArrayList<>(dominant); |
| |
| for (Repository repository : recessive) { |
| if (!repositories.contains(repository)) { |
| repositories.add(repository); |
| } |
| } |
| |
| return repositories; |
| } |
| |
| public static void mergeFilterLists(List<String> childFilters, List<String> parentFilters) { |
| for (String f : parentFilters) { |
| if (!childFilters.contains(f)) { |
| childFilters.add(f); |
| } |
| } |
| } |
| |
| private static List<Dependency> mergeDependencyList(List<Dependency> child, List<Dependency> parent) { |
| Map<String, Dependency> depsMap = new LinkedHashMap<>(); |
| |
| if (parent != null) { |
| for (Dependency dependency : parent) { |
| depsMap.put(dependency.getManagementKey(), dependency); |
| } |
| } |
| |
| if (child != null) { |
| for (Dependency dependency : child) { |
| depsMap.put(dependency.getManagementKey(), dependency); |
| } |
| } |
| |
| return new ArrayList<>(depsMap.values()); |
| } |
| } |