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