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