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