1 package org.apache.maven.archetype.common;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.archetype.common.util.Format;
23 import org.apache.maven.archetype.exception.InvalidPackaging;
24 import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
25 import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
26 import org.apache.maven.model.Model;
27 import org.apache.maven.model.Parent;
28 import org.apache.maven.model.Dependency;
29 import org.apache.maven.model.Build;
30 import org.apache.maven.model.Profile;
31 import org.apache.maven.model.ModelBase;
32 import org.apache.maven.model.Reporting;
33 import org.apache.maven.model.ReportPlugin;
34 import org.apache.maven.model.BuildBase;
35 import org.apache.maven.model.Plugin;
36 import org.codehaus.plexus.component.annotations.Component;
37 import org.codehaus.plexus.logging.AbstractLogEnabled;
38 import org.codehaus.plexus.util.FileUtils;
39 import org.codehaus.plexus.util.ReaderFactory;
40 import org.codehaus.plexus.util.StringUtils;
41 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
42 import org.codehaus.plexus.util.xml.Xpp3DomUtils;
43 import org.codehaus.plexus.util.xml.Xpp3Dom;
44 import org.dom4j.Document;
45 import org.dom4j.DocumentException;
46 import org.dom4j.Element;
47 import org.dom4j.Node;
48 import org.dom4j.io.SAXReader;
49 import org.dom4j.io.XMLWriter;
50 import org.jdom.JDOMException;
51 import org.jdom.input.SAXBuilder;
52
53 import java.io.File;
54 import java.io.FileInputStream;
55 import java.io.FileNotFoundException;
56 import java.io.FileOutputStream;
57 import java.io.IOException;
58 import java.io.InputStream;
59 import java.io.OutputStreamWriter;
60 import java.io.Reader;
61 import java.io.StringWriter;
62 import java.io.Writer;
63 import java.util.ArrayList;
64 import java.util.HashMap;
65 import java.util.Iterator;
66 import java.util.List;
67 import java.util.Map;
68
69 @Component( role = PomManager.class )
70 public class DefaultPomManager
71 extends AbstractLogEnabled
72 implements PomManager
73 {
74 @Override
75 public void addModule( File pom, String artifactId )
76 throws IOException, XmlPullParserException, DocumentException, InvalidPackaging
77 {
78 boolean found = false;
79
80 StringWriter writer = new StringWriter();
81
82 try ( Reader fileReader = ReaderFactory.newXmlReader( pom ) )
83 {
84 SAXReader reader = new SAXReader();
85 Document document = reader.read( fileReader );
86 Element project = document.getRootElement();
87
88 String packaging = null;
89 Element packagingElement = project.element( "packaging" );
90 if ( packagingElement != null )
91 {
92 packaging = packagingElement.getStringValue();
93 }
94 if ( !"pom".equals( packaging ) )
95 {
96 throw new InvalidPackaging(
97 "Unable to add module to the current project as it is not of packaging type 'pom'"
98 );
99 }
100
101 Element modules = project.element( "modules" );
102 if ( modules == null )
103 {
104 modules = project.addText( " " ).addElement( "modules" );
105 modules.setText( "\n " );
106 project.addText( "\n" );
107 }
108
109 for ( @SuppressWarnings( "unchecked" )
110 Iterator<Element> i = modules.elementIterator( "module" ); i.hasNext() && !found; )
111 {
112 Element module = i.next();
113 if ( module.getText().equals( artifactId ) )
114 {
115 found = true;
116 }
117 }
118 if ( !found )
119 {
120 Node lastTextNode = null;
121 for ( @SuppressWarnings( "unchecked" )
122 Iterator<Node> i = modules.nodeIterator(); i.hasNext(); )
123 {
124 Node node = i.next();
125 if ( node.getNodeType() == Node.ELEMENT_NODE )
126 {
127 lastTextNode = null;
128 }
129 else if ( node.getNodeType() == Node.TEXT_NODE )
130 {
131 lastTextNode = node;
132 }
133 }
134
135 if ( lastTextNode != null )
136 {
137 modules.remove( lastTextNode );
138 }
139
140 modules.addText( "\n " );
141 modules.addElement( "module" ).setText( artifactId );
142 modules.addText( "\n " );
143
144 XMLWriter xmlWriter = new XMLWriter( writer );
145 xmlWriter.write( document );
146
147 FileUtils.fileWrite( pom.getAbsolutePath(), writer.toString() );
148 }
149 }
150 }
151
152 @Override
153 public void addParent( File pom, File parentPom )
154 throws IOException, XmlPullParserException
155 {
156 Model generatedModel = readPom( pom );
157 if ( null != generatedModel.getParent() )
158 {
159 getLogger().info( "Parent element not overwritten in " + pom );
160 return;
161 }
162
163 Model parentModel = readPom( parentPom );
164
165 Parent parent = new Parent();
166 parent.setGroupId( parentModel.getGroupId() );
167 if ( parent.getGroupId() == null )
168 {
169 parent.setGroupId( parentModel.getParent().getGroupId() );
170 }
171 parent.setArtifactId( parentModel.getArtifactId() );
172 parent.setVersion( parentModel.getVersion() );
173 if ( parent.getVersion() == null )
174 {
175 parent.setVersion( parentModel.getParent().getVersion() );
176 }
177 generatedModel.setParent( parent );
178
179 writePom( generatedModel, pom, pom );
180 }
181
182 @Override
183 public void mergePoms( File pom, File temporaryPom )
184 throws IOException, XmlPullParserException
185 {
186 Model model = readPom( pom );
187 Model generatedModel = readPom( temporaryPom );
188
189 model.getProperties().putAll( generatedModel.getProperties() );
190
191 mergeModelBase( model, generatedModel );
192 mergeModelBuild( model, generatedModel );
193 mergeProfiles( model, generatedModel );
194 mergeReportPlugins( model, generatedModel );
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257 writePom( model, pom, pom );
258 }
259
260 @Override
261 public Model readPom( final File pomFile )
262 throws IOException, XmlPullParserException
263 {
264 try ( Reader pomReader = ReaderFactory.newXmlReader( pomFile ) )
265 {
266 MavenXpp3Reader reader = new MavenXpp3Reader();
267
268 return reader.read( pomReader );
269 }
270 }
271
272
273 @Override
274 public Model readPom( InputStream pomStream )
275 throws IOException, XmlPullParserException
276 {
277 try ( Reader pomReader = ReaderFactory.newXmlReader( pomStream ) )
278 {
279 MavenXpp3Reader reader = new MavenXpp3Reader();
280
281 return reader.read( pomReader );
282 }
283 }
284
285 @Override
286 public void writePom( final Model model, final File pomFile, final File initialPomFile )
287 throws IOException
288 {
289 String fileEncoding =
290 StringUtils.isEmpty( model.getModelEncoding() ) ? "UTF-8" : model.getModelEncoding();
291
292 org.jdom.Document doc;
293 try ( InputStream inputStream = new FileInputStream( initialPomFile ) )
294 {
295 SAXBuilder builder = new SAXBuilder();
296 doc = builder.build( inputStream );
297 }
298 catch ( JDOMException exc )
299 {
300 IOException ioe = new IOException( "Cannot parse the POM by JDOM while reading " + initialPomFile + ": "
301 + exc.getMessage() );
302 ioe.initCause( exc );
303 throw ioe;
304 }
305
306 try ( Writer outputStreamWriter = new OutputStreamWriter( new FileOutputStream( pomFile ), fileEncoding ) )
307 {
308
309 MavenJDOMWriter writer = new MavenJDOMWriter();
310
311 final String ls = System.lineSeparator();
312 Format form = Format.getRawFormat().setEncoding( fileEncoding ).setLineSeparator( ls );
313 writer.write( model, doc, outputStreamWriter, form );
314 }
315 catch ( FileNotFoundException e )
316 {
317 getLogger().debug( "Creating pom file " + pomFile );
318
319 try ( Writer pomWriter = new OutputStreamWriter( new FileOutputStream( pomFile ), fileEncoding ) )
320 {
321 MavenXpp3Writer writer = new MavenXpp3Writer();
322 writer.write( pomWriter, model );
323 }
324 }
325 }
326
327 private Map<String, Dependency> createDependencyMap( List<Dependency> dependencies )
328 {
329 Map<String, Dependency> dependencyMap = new HashMap<>();
330 for ( Dependency dependency : dependencies )
331 {
332 dependencyMap.put( dependency.getManagementKey(), dependency );
333 }
334
335 return dependencyMap;
336 }
337
338 private void mergeModelBuild( Model model, Model generatedModel )
339 {
340 if ( generatedModel.getBuild() != null )
341 {
342 if ( model.getBuild() == null )
343 {
344 model.setBuild( new Build() );
345 }
346
347 mergeBuildPlugins( model.getBuild(), generatedModel.getBuild() );
348 }
349 }
350
351 private void mergeProfiles( Model model, Model generatedModel )
352 {
353 List<Profile> generatedProfiles = generatedModel.getProfiles();
354 if ( generatedProfiles != null && generatedProfiles.size() > 0 )
355 {
356 List<Profile> modelProfiles = model.getProfiles();
357 Map<String, Profile> modelProfileIdMap = new HashMap<>();
358 if ( modelProfiles == null )
359 {
360 modelProfiles = new ArrayList<>();
361 model.setProfiles( modelProfiles );
362 }
363 else if ( modelProfiles.size() > 0 )
364 {
365
366 for ( Profile modelProfile : modelProfiles )
367 {
368 modelProfileIdMap.put( modelProfile.getId(), modelProfile );
369 }
370 }
371
372 for ( Profile generatedProfile : generatedProfiles )
373 {
374 String generatedProfileId = generatedProfile.getId();
375 if ( !modelProfileIdMap.containsKey( generatedProfileId ) )
376 {
377 model.addProfile( generatedProfile );
378 }
379 else
380 {
381 getLogger().warn( "Try to merge profiles with id " + generatedProfileId );
382 mergeModelBase( modelProfileIdMap.get( generatedProfileId ), generatedProfile );
383 mergeProfileBuild( modelProfileIdMap.get( generatedProfileId ), generatedProfile );
384 }
385 }
386 }
387 }
388
389 private void mergeProfileBuild( Profile modelProfile, Profile generatedProfile )
390 {
391 if ( generatedProfile.getBuild() != null )
392 {
393 if ( modelProfile.getBuild() == null )
394 {
395 modelProfile.setBuild( new Build() );
396 }
397 mergeBuildPlugins( modelProfile.getBuild(), generatedProfile.getBuild() );
398
399 }
400 }
401
402 private void mergeModelBase( ModelBase model, ModelBase generatedModel )
403 {
404
405 Map<String, Dependency> dependenciesByIds = createDependencyMap( model.getDependencies() );
406
407 Map<String, Dependency> generatedDependenciesByIds = createDependencyMap( generatedModel.getDependencies() );
408
409 for ( String generatedDependencyId : generatedDependenciesByIds.keySet() )
410 {
411 if ( !dependenciesByIds.containsKey( generatedDependencyId ) )
412 {
413 model.addDependency( generatedDependenciesByIds.get( generatedDependencyId ) );
414 }
415 else
416 {
417 getLogger().warn( "Can not override property: " + generatedDependencyId );
418 }
419
420
421 model.getProperties().putAll( generatedModel.getProperties() );
422
423
424 }
425 }
426
427 private void mergeReportPlugins( Model model, Model generatedModel )
428 {
429 if ( generatedModel.getReporting() != null )
430 {
431 if ( model.getReporting() == null )
432 {
433 model.setReporting( new Reporting() );
434 }
435
436 Map<String, ReportPlugin> reportPluginsByIds = model.getReporting().getReportPluginsAsMap();
437
438 Map<String, ReportPlugin> generatedReportPluginsByIds =
439 generatedModel.getReporting().getReportPluginsAsMap();
440
441 for ( String generatedReportPluginsId : generatedReportPluginsByIds.keySet() )
442 {
443 if ( !reportPluginsByIds.containsKey( generatedReportPluginsId ) )
444 {
445 model.getReporting().addPlugin( generatedReportPluginsByIds.get( generatedReportPluginsId ) );
446 }
447 else
448 {
449 getLogger().warn( "Can not override report: " + generatedReportPluginsId );
450 }
451 }
452 }
453 }
454
455 private void mergeBuildPlugins( BuildBase modelBuild, BuildBase generatedModelBuild )
456 {
457 Map<String, Plugin> pluginsByIds = modelBuild.getPluginsAsMap();
458
459 List<Plugin> generatedPlugins = generatedModelBuild.getPlugins();
460
461 for ( Plugin generatedPlugin : generatedPlugins )
462 {
463 String generatedPluginsId = generatedPlugin.getKey();
464
465 if ( !pluginsByIds.containsKey( generatedPluginsId ) )
466 {
467 modelBuild.addPlugin( generatedPlugin );
468 }
469 else
470 {
471 getLogger().info( "Try to merge plugin configuration of plugins with id: " + generatedPluginsId );
472 Plugin modelPlugin = pluginsByIds.get( generatedPluginsId );
473
474 modelPlugin.setConfiguration( Xpp3DomUtils.mergeXpp3Dom( (Xpp3Dom) generatedPlugin.getConfiguration(),
475 (Xpp3Dom) modelPlugin.getConfiguration() ) );
476 }
477 }
478 }
479 }