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