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 Format form = Format.getRawFormat().setEncoding( fileEncoding );
321 writer.write( model, doc, outputStreamWriter, form );
322 }
323 catch ( JDOMException exc )
324 {
325 IOException ioe = new IOException( "Cannot parse the POM by JDOM while reading " + initialPomFile + ": "
326 + exc.getMessage() );
327 ioe.initCause( exc );
328 throw ioe;
329 }
330 catch ( FileNotFoundException e )
331 {
332 getLogger().debug( "Creating pom file " + pomFile );
333
334 Writer pomWriter = null;
335
336 try
337 {
338 pomWriter =
339 new OutputStreamWriter( new FileOutputStream( pomFile ), fileEncoding );
340
341 MavenXpp3Writer writer = new MavenXpp3Writer();
342 writer.write( pomWriter, model );
343 }
344 finally
345 {
346 IOUtil.close( pomWriter );
347 }
348 }
349 finally
350 {
351 IOUtil.close( inputStream );
352 IOUtil.close( outputStreamWriter );
353 }
354 }
355
356 private Map<String, Dependency> createDependencyMap( List<Dependency> dependencies )
357 {
358 Map<String, Dependency> dependencyMap = new HashMap<String, Dependency>();
359 for ( Dependency dependency : dependencies )
360 {
361 dependencyMap.put( dependency.getManagementKey(), dependency );
362 }
363
364 return dependencyMap;
365 }
366
367 private void mergeModelBuild( Model model, Model generatedModel )
368 {
369 if ( generatedModel.getBuild() != null )
370 {
371 if ( model.getBuild() == null )
372 {
373 model.setBuild( new Build() );
374 }
375
376 mergeBuildPlugins( model.getBuild(), generatedModel.getBuild() );
377 }
378 }
379
380 private void mergeProfiles( Model model, Model generatedModel )
381 {
382 @SuppressWarnings( "unchecked" )
383 List<Profile> generatedProfiles = generatedModel.getProfiles();
384 if ( generatedProfiles != null && generatedProfiles.size() > 0 )
385 {
386 @SuppressWarnings( "unchecked" )
387 List<Profile> modelProfiles = model.getProfiles();
388 Map<String, Profile> modelProfileIdMap = new HashMap<String, Profile>();
389 if ( modelProfiles == null )
390 {
391 modelProfiles = new ArrayList<Profile>();
392 model.setProfiles( modelProfiles );
393 }
394 else if ( modelProfiles.size() > 0 )
395 {
396
397 for ( Profile modelProfile : modelProfiles )
398 {
399 modelProfileIdMap.put( modelProfile.getId(), modelProfile );
400 }
401 }
402
403 for ( Profile generatedProfile : generatedProfiles )
404 {
405 String generatedProfileId = generatedProfile.getId();
406 if ( !modelProfileIdMap.containsKey( generatedProfileId ) )
407 {
408 model.addProfile( generatedProfile );
409 }
410 else
411 {
412 getLogger().warn( "Try to merge profiles with id " + generatedProfileId );
413 mergeModelBase( (Profile) modelProfileIdMap.get( generatedProfileId ), generatedProfile );
414 mergeProfileBuild( (Profile) modelProfileIdMap.get( generatedProfileId ), generatedProfile );
415 }
416 }
417 }
418 }
419
420 private void mergeProfileBuild( Profile modelProfile, Profile generatedProfile )
421 {
422 if ( generatedProfile.getBuild() != null )
423 {
424 if ( modelProfile.getBuild() == null )
425 {
426 modelProfile.setBuild( new Build() );
427 }
428 mergeBuildPlugins( modelProfile.getBuild(), generatedProfile.getBuild() );
429
430 }
431 }
432
433 private void mergeModelBase( ModelBase model, ModelBase generatedModel )
434 {
435
436
437 @SuppressWarnings( "unchecked" )
438 Map<String, Dependency> dependenciesByIds = createDependencyMap( model.getDependencies() );
439 @SuppressWarnings( "unchecked" )
440 Map<String, Dependency> generatedDependenciesByIds = createDependencyMap( generatedModel.getDependencies() );
441
442 for ( String generatedDependencyId : generatedDependenciesByIds.keySet() )
443 {
444 if ( !dependenciesByIds.containsKey( generatedDependencyId ) )
445 {
446 model.addDependency( (Dependency) generatedDependenciesByIds.get( generatedDependencyId ) );
447 }
448 else
449 {
450 getLogger().warn( "Can not override property: " + generatedDependencyId );
451 }
452
453
454 model.getProperties().putAll( generatedModel.getProperties() );
455
456
457 }
458 }
459
460 private void mergeReportPlugins( Model model, Model generatedModel )
461 {
462 if ( generatedModel.getReporting() != null )
463 {
464 if ( model.getReporting() == null )
465 {
466 model.setReporting( new Reporting() );
467 }
468
469 @SuppressWarnings( "unchecked" )
470 Map<String, ReportPlugin> reportPluginsByIds = model.getReporting().getReportPluginsAsMap();
471 @SuppressWarnings( "unchecked" )
472 Map<String, ReportPlugin> generatedReportPluginsByIds =
473 generatedModel.getReporting().getReportPluginsAsMap();
474
475 for ( String generatedReportPluginsId : generatedReportPluginsByIds.keySet() )
476 {
477 if ( !reportPluginsByIds.containsKey( generatedReportPluginsId ) )
478 {
479 model.getReporting().addPlugin( generatedReportPluginsByIds.get( generatedReportPluginsId ) );
480 }
481 else
482 {
483 getLogger().warn( "Can not override report: " + generatedReportPluginsId );
484 }
485 }
486 }
487 }
488
489 private void mergeBuildPlugins( BuildBase modelBuild, BuildBase generatedModelBuild )
490 {
491 @SuppressWarnings( "unchecked" )
492 Map<String, Plugin> pluginsByIds = modelBuild.getPluginsAsMap();
493 @SuppressWarnings( "unchecked" )
494 List<Plugin> generatedPlugins = generatedModelBuild.getPlugins();
495
496 for ( Plugin generatedPlugin : generatedPlugins )
497 {
498 String generatedPluginsId = generatedPlugin.getKey();
499
500 if ( !pluginsByIds.containsKey( generatedPluginsId ) )
501 {
502 modelBuild.addPlugin( generatedPlugin );
503 }
504 else
505 {
506 getLogger().info( "Try to merge plugin configuration of plugins with id: " + generatedPluginsId );
507 Plugin modelPlugin = (Plugin) pluginsByIds.get( generatedPluginsId );
508
509 modelPlugin.setConfiguration( Xpp3DomUtils.mergeXpp3Dom( (Xpp3Dom) generatedPlugin.getConfiguration(),
510 (Xpp3Dom) modelPlugin.getConfiguration() ) );
511 }
512 }
513 }
514 }