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