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