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.model.plugin;
20  
21  import java.util.ArrayList;
22  import java.util.Collection;
23  import java.util.Collections;
24  import java.util.LinkedHashMap;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.stream.Collectors;
28  import javax.inject.Inject;
29  import javax.inject.Named;
30  import javax.inject.Singleton;
31  import org.apache.maven.api.model.Build;
32  import org.apache.maven.api.model.Model;
33  import org.apache.maven.api.model.Plugin;
34  import org.apache.maven.api.model.PluginContainer;
35  import org.apache.maven.api.model.PluginExecution;
36  import org.apache.maven.api.model.PluginManagement;
37  import org.apache.maven.lifecycle.LifeCyclePluginAnalyzer;
38  import org.apache.maven.model.building.ModelBuildingRequest;
39  import org.apache.maven.model.building.ModelProblem.Severity;
40  import org.apache.maven.model.building.ModelProblem.Version;
41  import org.apache.maven.model.building.ModelProblemCollector;
42  import org.apache.maven.model.building.ModelProblemCollectorRequest;
43  import org.apache.maven.model.merge.MavenModelMerger;
44  
45  /**
46   * Handles injection of plugin executions induced by the lifecycle bindings for a packaging.
47   *
48   * @author Benjamin Bentmann
49   */
50  @Named
51  @Singleton
52  public class DefaultLifecycleBindingsInjector implements LifecycleBindingsInjector {
53  
54      private final LifecycleBindingsMerger merger = new LifecycleBindingsMerger();
55  
56      private final LifeCyclePluginAnalyzer lifecycle;
57  
58      @Inject
59      public DefaultLifecycleBindingsInjector(LifeCyclePluginAnalyzer lifecycle) {
60          this.lifecycle = lifecycle;
61      }
62  
63      public void injectLifecycleBindings(
64              org.apache.maven.model.Model model, ModelBuildingRequest request, ModelProblemCollector problems) {
65          String packaging = model.getPackaging();
66  
67          Collection<org.apache.maven.model.Plugin> defaultPlugins =
68                  lifecycle.getPluginsBoundByDefaultToAllLifecycles(packaging);
69  
70          if (defaultPlugins == null) {
71              problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
72                      .setMessage("Unknown packaging: " + packaging)
73                      .setLocation(model.getLocation("packaging")));
74          } else if (!defaultPlugins.isEmpty()) {
75              List<Plugin> plugins = defaultPlugins.stream()
76                      .map(org.apache.maven.model.Plugin::getDelegate)
77                      .collect(Collectors.toList());
78              Model lifecycleModel = Model.newBuilder()
79                      .build(Build.newBuilder().plugins(plugins).build())
80                      .build();
81              model.update(merger.merge(model.getDelegate(), lifecycleModel));
82          }
83      }
84  
85      /**
86       *  The domain-specific model merger for lifecycle bindings
87       */
88      protected static class LifecycleBindingsMerger extends MavenModelMerger {
89  
90          private static final String PLUGIN_MANAGEMENT = "plugin-management";
91  
92          public Model merge(Model target, Model source) {
93              Build targetBuild = target.getBuild();
94              if (targetBuild == null) {
95                  targetBuild = Build.newInstance();
96              }
97  
98              Map<Object, Object> context = Collections.singletonMap(
99                      PLUGIN_MANAGEMENT, target.getBuild().getPluginManagement());
100 
101             Build.Builder builder = Build.newBuilder(target.getBuild());
102             mergePluginContainer_Plugins(builder, targetBuild, source.getBuild(), false, context);
103 
104             return target.withBuild(builder.build());
105         }
106 
107         @SuppressWarnings({"checkstyle:methodname"})
108         @Override
109         protected void mergePluginContainer_Plugins(
110                 PluginContainer.Builder builder,
111                 PluginContainer target,
112                 PluginContainer source,
113                 boolean sourceDominant,
114                 Map<Object, Object> context) {
115             List<Plugin> src = source.getPlugins();
116             if (!src.isEmpty()) {
117                 List<Plugin> tgt = target.getPlugins();
118 
119                 Map<Object, Plugin> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
120 
121                 for (Plugin element : tgt) {
122                     Object key = getPluginKey().apply(element);
123                     merged.put(key, element);
124                 }
125 
126                 Map<Object, Plugin> added = new LinkedHashMap<>();
127 
128                 for (Plugin element : src) {
129                     Object key = getPluginKey().apply(element);
130                     Plugin existing = merged.get(key);
131                     if (existing != null) {
132                         element = mergePlugin(existing, element, sourceDominant, context);
133                     } else {
134                         added.put(key, element);
135                     }
136                     merged.put(key, element);
137                 }
138 
139                 if (!added.isEmpty()) {
140                     PluginManagement pluginMgmt = (PluginManagement) context.get(PLUGIN_MANAGEMENT);
141                     if (pluginMgmt != null) {
142                         for (Plugin managedPlugin : pluginMgmt.getPlugins()) {
143                             Object key = getPluginKey().apply(managedPlugin);
144                             Plugin addedPlugin = added.get(key);
145                             if (addedPlugin != null) {
146                                 Plugin plugin =
147                                         mergePlugin(managedPlugin, addedPlugin, sourceDominant, Collections.emptyMap());
148                                 merged.put(key, plugin);
149                             }
150                         }
151                     }
152                 }
153 
154                 List<Plugin> result = new ArrayList<>(merged.values());
155 
156                 builder.plugins(result);
157             }
158         }
159 
160         @Override
161         protected void mergePluginExecution_Priority(
162                 PluginExecution.Builder builder,
163                 PluginExecution target,
164                 PluginExecution source,
165                 boolean sourceDominant,
166                 Map<Object, Object> context) {
167             if (target.getPriority() > source.getPriority()) {
168                 builder.priority(source.getPriority());
169                 builder.location("priority", source.getLocation("priority"));
170             }
171         }
172         // mergePluginExecution_Priority( builder, target, source, sourceDominant, context );
173 
174     }
175 }