1 package org.apache.maven.plugins.enforcer;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.ArrayList;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Map.Entry;
27
28 import org.apache.commons.lang3.SystemUtils;
29 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
30 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
31 import org.apache.maven.execution.MavenSession;
32 import org.apache.maven.model.Dependency;
33 import org.apache.maven.plugin.logging.Log;
34 import org.apache.maven.project.MavenProject;
35 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
36 import org.codehaus.plexus.util.StringUtils;
37
38
39
40
41
42
43
44 public class ReactorModuleConvergence
45 extends AbstractNonCacheableEnforcerRule
46 {
47 private boolean ignoreModuleDependencies = false;
48
49 private Log logger;
50
51 @Override
52 public void execute( EnforcerRuleHelper helper )
53 throws EnforcerRuleException
54 {
55 logger = helper.getLog();
56
57 MavenSession session;
58 try
59 {
60 session = (MavenSession) helper.evaluate( "${session}" );
61 }
62 catch ( ExpressionEvaluationException eee )
63 {
64 throw new EnforcerRuleException( "Unable to retrieve the MavenSession: ", eee );
65 }
66
67 List<MavenProject> sortedProjects = session.getProjectDependencyGraph().getSortedProjects();
68 if ( sortedProjects != null && !sortedProjects.isEmpty() )
69 {
70 checkReactor( sortedProjects );
71 checkParentsInReactor( sortedProjects );
72 checkMissingParentsInReactor( sortedProjects );
73 checkParentsPartOfTheReactor( sortedProjects );
74 if ( !isIgnoreModuleDependencies() )
75 {
76 checkDependenciesWithinReactor( sortedProjects );
77 }
78 }
79
80 }
81
82 private void checkParentsPartOfTheReactor( List<MavenProject> sortedProjects )
83 throws EnforcerRuleException
84 {
85 List<MavenProject> parentsWhichAreNotPartOfTheReactor =
86 existParentsWhichAreNotPartOfTheReactor( sortedProjects );
87 if ( !parentsWhichAreNotPartOfTheReactor.isEmpty() )
88 {
89 StringBuilder sb = new StringBuilder().append( SystemUtils.LINE_SEPARATOR );
90 addMessageIfExist( sb );
91 for ( MavenProject mavenProject : parentsWhichAreNotPartOfTheReactor )
92 {
93 sb.append( " module: " );
94 sb.append( mavenProject.getId() );
95 sb.append( SystemUtils.LINE_SEPARATOR );
96 }
97 throw new EnforcerRuleException( "Module parents have been found which could not be found in the reactor."
98 + sb.toString() );
99 }
100 }
101
102
103
104
105
106
107
108 private void checkMissingParentsInReactor( List<MavenProject> sortedProjects )
109 throws EnforcerRuleException
110 {
111 List<MavenProject> modulesWithoutParentsInReactor = existModulesWithoutParentsInReactor( sortedProjects );
112 if ( !modulesWithoutParentsInReactor.isEmpty() )
113 {
114 StringBuilder sb = new StringBuilder().append( SystemUtils.LINE_SEPARATOR );
115 addMessageIfExist( sb );
116 for ( MavenProject mavenProject : modulesWithoutParentsInReactor )
117 {
118 sb.append( " module: " );
119 sb.append( mavenProject.getId() );
120 sb.append( SystemUtils.LINE_SEPARATOR );
121 }
122 throw new EnforcerRuleException( "Reactor contains modules without parents." + sb.toString() );
123 }
124 }
125
126 private void checkDependenciesWithinReactor( List<MavenProject> sortedProjects )
127 throws EnforcerRuleException
128 {
129
130 String reactorVersion = sortedProjects.get( 0 ).getVersion();
131
132 Map<MavenProject, List<Dependency>> areThereDependenciesWhichAreNotPartOfTheReactor =
133 areThereDependenciesWhichAreNotPartOfTheReactor( reactorVersion, sortedProjects );
134 if ( !areThereDependenciesWhichAreNotPartOfTheReactor.isEmpty() )
135 {
136 StringBuilder sb = new StringBuilder().append( SystemUtils.LINE_SEPARATOR );
137 addMessageIfExist( sb );
138
139 for ( Entry<MavenProject, List<Dependency>> item : areThereDependenciesWhichAreNotPartOfTheReactor.entrySet() )
140 {
141 sb.append( " module: " );
142 sb.append( item.getKey().getId() );
143 sb.append( SystemUtils.LINE_SEPARATOR );
144 for ( Dependency dependency : item.getValue() )
145 {
146 String id =
147 dependency.getGroupId() + ":" + dependency.getArtifactId() + ":" + dependency.getVersion();
148 sb.append( " dependency: " );
149 sb.append( id );
150 sb.append( SystemUtils.LINE_SEPARATOR );
151 }
152 }
153 throw new EnforcerRuleException(
154 "Reactor modules contains dependencies which do not reference the reactor."
155 + sb.toString() );
156
157 }
158 }
159
160
161
162
163
164
165
166 private void checkParentsInReactor( List<MavenProject> sortedProjects )
167 throws EnforcerRuleException
168 {
169
170 String reactorVersion = sortedProjects.get( 0 ).getVersion();
171
172 List<MavenProject> areParentsFromTheReactor = areParentsFromTheReactor( reactorVersion, sortedProjects );
173 if ( !areParentsFromTheReactor.isEmpty() )
174 {
175 StringBuilder sb = new StringBuilder().append( SystemUtils.LINE_SEPARATOR );
176 addMessageIfExist( sb );
177 for ( MavenProject mavenProject : areParentsFromTheReactor )
178 {
179 sb.append( " --> " );
180 sb.append( mavenProject.getId() );
181 sb.append( " parent:" );
182 sb.append( mavenProject.getParent().getId() );
183 sb.append( SystemUtils.LINE_SEPARATOR );
184 }
185 throw new EnforcerRuleException( "Reactor modules have parents which contain a wrong version."
186 + sb.toString() );
187 }
188 }
189
190
191
192
193
194
195
196 private void checkReactor( List<MavenProject> sortedProjects )
197 throws EnforcerRuleException
198 {
199 List<MavenProject> consistenceCheckResult = isReactorVersionConsistent( sortedProjects );
200 if ( !consistenceCheckResult.isEmpty() )
201 {
202 StringBuilder sb = new StringBuilder().append( SystemUtils.LINE_SEPARATOR );
203 addMessageIfExist( sb );
204 for ( MavenProject mavenProject : consistenceCheckResult )
205 {
206 sb.append( " --> " );
207 sb.append( mavenProject.getId() );
208 sb.append( SystemUtils.LINE_SEPARATOR );
209 }
210 throw new EnforcerRuleException( "The reactor contains different versions." + sb.toString() );
211 }
212 }
213
214 private List<MavenProject> areParentsFromTheReactor( String reactorVersion, List<MavenProject> sortedProjects )
215 {
216 List<MavenProject> result = new ArrayList<MavenProject>();
217
218 for ( MavenProject mavenProject : sortedProjects )
219 {
220 logger.debug( "Project: " + mavenProject.getId() );
221 if ( hasParent( mavenProject ) )
222 {
223 if ( !mavenProject.isExecutionRoot() )
224 {
225 MavenProject parent = mavenProject.getParent();
226 if ( !reactorVersion.equals( parent.getVersion() ) )
227 {
228 logger.debug( "The project: " + mavenProject.getId()
229 + " has a parent which version does not match the other elements in reactor" );
230 result.add( mavenProject );
231 }
232 }
233 }
234 else
235 {
236
237 }
238 }
239
240 return result;
241 }
242
243 private List<MavenProject> existParentsWhichAreNotPartOfTheReactor( List<MavenProject> sortedProjects )
244 {
245 List<MavenProject> result = new ArrayList<MavenProject>();
246
247 for ( MavenProject mavenProject : sortedProjects )
248 {
249 logger.debug( "Project: " + mavenProject.getId() );
250 if ( hasParent( mavenProject ) )
251 {
252 if ( !mavenProject.isExecutionRoot() )
253 {
254 MavenProject parent = mavenProject.getParent();
255 if ( !isProjectPartOfTheReactor( parent, sortedProjects ) )
256 {
257 result.add( mavenProject );
258 }
259 }
260 }
261 }
262
263 return result;
264 }
265
266
267
268
269
270
271
272
273
274 private boolean isProjectPartOfTheReactor( MavenProject project, List<MavenProject> sortedProjects )
275 {
276 return isGAPartOfTheReactor( project.getGroupId(), project.getArtifactId(), sortedProjects );
277 }
278
279 private boolean isDependencyPartOfTheReactor( Dependency dependency, List<MavenProject> sortedProjects )
280 {
281 return isGAPartOfTheReactor( dependency.getGroupId(), dependency.getArtifactId(), sortedProjects );
282 }
283
284
285
286
287
288
289
290
291
292 private boolean isGAPartOfTheReactor( String groupId, String artifactId, List<MavenProject> sortedProjects )
293 {
294 boolean result = false;
295 for ( MavenProject mavenProject : sortedProjects )
296 {
297 String parentId = groupId + ":" + artifactId;
298 String projectId = mavenProject.getGroupId() + ":" + mavenProject.getArtifactId();
299 if ( parentId.equals( projectId ) )
300 {
301 result = true;
302 }
303 }
304 return result;
305 }
306
307
308
309
310
311
312
313
314
315 private List<MavenProject> existModulesWithoutParentsInReactor( List<MavenProject> sortedProjects )
316 {
317 List<MavenProject> result = new ArrayList<MavenProject>();
318
319 for ( MavenProject mavenProject : sortedProjects )
320 {
321 logger.debug( "Project: " + mavenProject.getId() );
322 if ( !hasParent( mavenProject ) )
323 {
324
325 if ( mavenProject.isExecutionRoot() )
326 {
327 logger.debug( "The root does not need having a parent." );
328 }
329 else
330 {
331 logger.debug( "The module: " + mavenProject.getId() + " has no parent." );
332 result.add( mavenProject );
333 }
334 }
335 }
336
337 return result;
338 }
339
340
341
342
343
344
345
346
347 private void addDep( Map<MavenProject, List<Dependency>> result, MavenProject project, Dependency dependency )
348 {
349 if ( result.containsKey( project ) )
350 {
351 List<Dependency> list = result.get( project );
352 if ( list == null )
353 {
354 list = new ArrayList<Dependency>();
355 }
356 list.add( dependency );
357 result.put( project, list );
358 }
359 else
360 {
361 List<Dependency> list = new ArrayList<Dependency>();
362 list.add( dependency );
363 result.put( project, list );
364 }
365 }
366
367
368
369
370
371
372
373
374
375
376
377 private Map<MavenProject, List<Dependency>> areThereDependenciesWhichAreNotPartOfTheReactor( String reactorVersion,
378 List<MavenProject> sortedProjects )
379
380 {
381 Map<MavenProject, List<Dependency>> result = new HashMap<MavenProject, List<Dependency>>();
382 for ( MavenProject mavenProject : sortedProjects )
383 {
384 logger.debug( "Project: " + mavenProject.getId() );
385
386 List<Dependency> dependencies = mavenProject.getDependencies();
387 if ( hasDependencies( dependencies ) )
388 {
389 for ( Dependency dependency : dependencies )
390 {
391 logger.debug( " -> Dep:" + dependency.getGroupId() + ":" + dependency.getArtifactId() + ":"
392 + dependency.getVersion() );
393 if ( isDependencyPartOfTheReactor( dependency, sortedProjects ) )
394 {
395 if ( !dependency.getVersion().equals( reactorVersion ) )
396 {
397 addDep( result, mavenProject, dependency );
398 }
399 }
400 }
401 }
402 }
403
404 return result;
405 }
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424 private List<MavenProject> isReactorVersionConsistent( List<MavenProject> projectList )
425 {
426 List<MavenProject> result = new ArrayList<MavenProject>();
427
428 if ( projectList != null && !projectList.isEmpty() )
429 {
430 String version = projectList.get( 0 ).getVersion();
431 logger.debug( "First version:" + version );
432 for ( MavenProject mavenProject : projectList )
433 {
434 logger.debug( " -> checking " + mavenProject.getId() );
435 if ( !version.equals( mavenProject.getVersion() ) )
436 {
437 result.add( mavenProject );
438 }
439 }
440 }
441 return result;
442 }
443
444 private boolean hasDependencies( List<Dependency> dependencies )
445 {
446 return dependencies != null && !dependencies.isEmpty();
447 }
448
449 private boolean hasParent( MavenProject mavenProject )
450 {
451 return mavenProject.getParent() != null;
452 }
453
454 public boolean isIgnoreModuleDependencies()
455 {
456 return ignoreModuleDependencies;
457 }
458
459 public void setIgnoreModuleDependencies( boolean ignoreModuleDependencies )
460 {
461 this.ignoreModuleDependencies = ignoreModuleDependencies;
462 }
463
464
465
466
467
468
469 private void addMessageIfExist( StringBuilder sb )
470 {
471 if ( !StringUtils.isEmpty( getMessage() ) )
472 {
473 sb.append( getMessage() );
474 sb.append( SystemUtils.LINE_SEPARATOR );
475 }
476 }
477
478 }