1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  package org.apache.maven.model.inheritance;
20  
21  import javax.inject.Named;
22  import javax.inject.Singleton;
23  
24  import java.util.ArrayList;
25  import java.util.HashMap;
26  import java.util.LinkedHashMap;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Properties;
30  
31  import org.apache.maven.model.InputLocation;
32  import org.apache.maven.model.Model;
33  import org.apache.maven.model.ModelBase;
34  import org.apache.maven.model.Plugin;
35  import org.apache.maven.model.PluginContainer;
36  import org.apache.maven.model.ReportPlugin;
37  import org.apache.maven.model.Reporting;
38  import org.apache.maven.model.building.ModelBuildingRequest;
39  import org.apache.maven.model.building.ModelProblemCollector;
40  import org.apache.maven.model.merge.MavenModelMerger;
41  import org.codehaus.plexus.util.StringUtils;
42  
43  
44  
45  
46  
47  
48  @SuppressWarnings({"checkstyle:methodname"})
49  @Named
50  @Singleton
51  @Deprecated(since = "4.0.0")
52  public class DefaultInheritanceAssembler implements InheritanceAssembler {
53  
54      private InheritanceModelMerger merger = new InheritanceModelMerger();
55  
56      private static final String CHILD_DIRECTORY = "child-directory";
57  
58      private static final String CHILD_DIRECTORY_PROPERTY = "project.directory";
59  
60      @Override
61      public void assembleModelInheritance(
62              Model child, Model parent, ModelBuildingRequest request, ModelProblemCollector problems) {
63          Map<Object, Object> hints = new HashMap<>();
64          String childPath = child.getProperties().getProperty(CHILD_DIRECTORY_PROPERTY, child.getArtifactId());
65          hints.put(CHILD_DIRECTORY, childPath);
66          hints.put(MavenModelMerger.CHILD_PATH_ADJUSTMENT, getChildPathAdjustment(child, parent, childPath));
67          merger.merge(child, parent, false, hints);
68      }
69  
70      
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89      private String getChildPathAdjustment(Model child, Model parent, String childDirectory) {
90          String adjustment = "";
91  
92          if (parent != null) {
93              String childName = child.getArtifactId();
94  
95              
96  
97  
98  
99  
100 
101 
102             if (child.getProjectDirectory() != null) {
103                 childName = child.getProjectDirectory().getName();
104             }
105 
106             for (String module : parent.getModules()) {
107                 module = module.replace('\\', '/');
108 
109                 if (module.regionMatches(true, module.length() - 4, ".xml", 0, 4)) {
110                     module = module.substring(0, module.lastIndexOf('/') + 1);
111                 }
112 
113                 String moduleName = module;
114                 if (moduleName.endsWith("/")) {
115                     moduleName = moduleName.substring(0, moduleName.length() - 1);
116                 }
117 
118                 int lastSlash = moduleName.lastIndexOf('/');
119 
120                 moduleName = moduleName.substring(lastSlash + 1);
121 
122                 if ((moduleName.equals(childName) || (moduleName.equals(childDirectory))) && lastSlash >= 0) {
123                     adjustment = module.substring(0, lastSlash);
124                     break;
125                 }
126             }
127         }
128 
129         return adjustment;
130     }
131 
132     
133 
134 
135     protected static class InheritanceModelMerger extends MavenModelMerger {
136 
137         @Override
138         protected String extrapolateChildUrl(String parentUrl, boolean appendPath, Map<Object, Object> context) {
139             Object childDirectory = context.get(CHILD_DIRECTORY);
140             Object childPathAdjustment = context.get(CHILD_PATH_ADJUSTMENT);
141 
142             if (StringUtils.isBlank(parentUrl)
143                     || childDirectory == null
144                     || childPathAdjustment == null
145                     || !appendPath) {
146                 return parentUrl;
147             }
148 
149             
150             return appendPath(parentUrl, childDirectory.toString(), childPathAdjustment.toString());
151         }
152 
153         private String appendPath(String parentUrl, String childPath, String pathAdjustment) {
154             StringBuilder url = new StringBuilder(parentUrl.length()
155                     + pathAdjustment.length()
156                     + childPath.length()
157                     + ((pathAdjustment.length() == 0) ? 1 : 2));
158 
159             url.append(parentUrl);
160             concatPath(url, pathAdjustment);
161             concatPath(url, childPath);
162 
163             return url.toString();
164         }
165 
166         private void concatPath(StringBuilder url, String path) {
167             if (path.length() > 0) {
168                 boolean initialUrlEndsWithSlash = url.charAt(url.length() - 1) == '/';
169                 boolean pathStartsWithSlash = path.charAt(0) == '/';
170 
171                 if (pathStartsWithSlash) {
172                     if (initialUrlEndsWithSlash) {
173                         
174                         url.setLength(url.length() - 1);
175                     }
176                 } else if (!initialUrlEndsWithSlash) {
177                     
178                     url.append('/');
179                 }
180 
181                 url.append(path);
182 
183                 
184                 if (initialUrlEndsWithSlash && !path.endsWith("/")) {
185                     url.append('/');
186                 }
187             }
188         }
189 
190         @Override
191         protected void mergeModelBase_Properties(
192                 ModelBase target, ModelBase source, boolean sourceDominant, Map<Object, Object> context) {
193             Properties merged = new Properties();
194             if (sourceDominant) {
195                 merged.putAll(target.getProperties());
196                 putAll(merged, source.getProperties(), CHILD_DIRECTORY_PROPERTY);
197             } else {
198                 putAll(merged, source.getProperties(), CHILD_DIRECTORY_PROPERTY);
199                 merged.putAll(target.getProperties());
200             }
201             target.setProperties(merged);
202             target.setLocation(
203                     "properties",
204                     InputLocation.merge(
205                             target.getLocation("properties"), source.getLocation("properties"), sourceDominant));
206         }
207 
208         private void putAll(Map<Object, Object> s, Map<Object, Object> t, Object excludeKey) {
209             for (Map.Entry<Object, Object> e : t.entrySet()) {
210                 if (!e.getKey().equals(excludeKey)) {
211                     s.put(e.getKey(), e.getValue());
212                 }
213             }
214         }
215 
216         @Override
217         protected void mergePluginContainer_Plugins(
218                 PluginContainer target, PluginContainer source, boolean sourceDominant, Map<Object, Object> context) {
219             List<Plugin> src = source.getPlugins();
220             if (!src.isEmpty()) {
221                 List<Plugin> tgt = target.getPlugins();
222                 Map<Object, Plugin> master = new LinkedHashMap<>(src.size() * 2);
223 
224                 for (Plugin element : src) {
225                     if (element.isInherited() || !element.getExecutions().isEmpty()) {
226                         
227                         Plugin plugin = new Plugin();
228                         plugin.setLocation("", element.getLocation(""));
229                         plugin.setGroupId(null);
230                         mergePlugin(plugin, element, sourceDominant, context);
231 
232                         Object key = getPluginKey(element);
233 
234                         master.put(key, plugin);
235                     }
236                 }
237 
238                 Map<Object, List<Plugin>> predecessors = new LinkedHashMap<>();
239                 List<Plugin> pending = new ArrayList<>();
240                 for (Plugin element : tgt) {
241                     Object key = getPluginKey(element);
242                     Plugin existing = master.get(key);
243                     if (existing != null) {
244                         mergePlugin(element, existing, sourceDominant, context);
245 
246                         master.put(key, element);
247 
248                         if (!pending.isEmpty()) {
249                             predecessors.put(key, pending);
250                             pending = new ArrayList<>();
251                         }
252                     } else {
253                         pending.add(element);
254                     }
255                 }
256 
257                 List<Plugin> result = new ArrayList<>(src.size() + tgt.size());
258                 for (Map.Entry<Object, Plugin> entry : master.entrySet()) {
259                     List<Plugin> pre = predecessors.get(entry.getKey());
260                     if (pre != null) {
261                         result.addAll(pre);
262                     }
263                     result.add(entry.getValue());
264                 }
265                 result.addAll(pending);
266 
267                 target.setPlugins(result);
268             }
269         }
270 
271         @Override
272         protected void mergePlugin(Plugin target, Plugin source, boolean sourceDominant, Map<Object, Object> context) {
273             if (source.isInherited()) {
274                 mergeConfigurationContainer(target, source, sourceDominant, context);
275             }
276             mergePlugin_GroupId(target, source, sourceDominant, context);
277             mergePlugin_ArtifactId(target, source, sourceDominant, context);
278             mergePlugin_Version(target, source, sourceDominant, context);
279             mergePlugin_Extensions(target, source, sourceDominant, context);
280             mergePlugin_Dependencies(target, source, sourceDominant, context);
281             mergePlugin_Executions(target, source, sourceDominant, context);
282         }
283 
284         @Override
285         protected void mergeReporting_Plugins(
286                 Reporting target, Reporting source, boolean sourceDominant, Map<Object, Object> context) {
287             List<ReportPlugin> src = source.getPlugins();
288             if (!src.isEmpty()) {
289                 List<ReportPlugin> tgt = target.getPlugins();
290                 Map<Object, ReportPlugin> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
291 
292                 for (ReportPlugin element : src) {
293                     Object key = getReportPluginKey(element);
294                     if (element.isInherited()) {
295                         
296                         ReportPlugin plugin = new ReportPlugin();
297                         plugin.setLocation("", element.getLocation(""));
298                         plugin.setGroupId(null);
299                         mergeReportPlugin(plugin, element, sourceDominant, context);
300 
301                         merged.put(key, plugin);
302                     }
303                 }
304 
305                 for (ReportPlugin element : tgt) {
306                     Object key = getReportPluginKey(element);
307                     ReportPlugin existing = merged.get(key);
308                     if (existing != null) {
309                         mergeReportPlugin(element, existing, sourceDominant, context);
310                     }
311                     merged.put(key, element);
312                 }
313 
314                 target.setPlugins(new ArrayList<>(merged.values()));
315             }
316         }
317     }
318 }