1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.archetype.common;
20
21 import javax.inject.Named;
22 import javax.inject.Singleton;
23 import javax.xml.parsers.ParserConfigurationException;
24 import javax.xml.transform.TransformerException;
25
26 import java.io.File;
27 import java.io.FileNotFoundException;
28 import java.io.FileOutputStream;
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.io.OutputStreamWriter;
32 import java.io.Reader;
33 import java.io.StringWriter;
34 import java.io.Writer;
35 import java.nio.file.Files;
36 import java.util.ArrayList;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Map;
40
41 import org.apache.maven.archetype.common.util.Format;
42 import org.apache.maven.archetype.common.util.PomUtils;
43 import org.apache.maven.archetype.exception.InvalidPackaging;
44 import org.apache.maven.archetype.old.ArchetypeTemplateProcessingException;
45 import org.apache.maven.model.Build;
46 import org.apache.maven.model.BuildBase;
47 import org.apache.maven.model.Dependency;
48 import org.apache.maven.model.Model;
49 import org.apache.maven.model.ModelBase;
50 import org.apache.maven.model.Parent;
51 import org.apache.maven.model.Plugin;
52 import org.apache.maven.model.Profile;
53 import org.apache.maven.model.ReportPlugin;
54 import org.apache.maven.model.Reporting;
55 import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
56 import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
57 import org.codehaus.plexus.util.FileUtils;
58 import org.codehaus.plexus.util.StringUtils;
59 import org.codehaus.plexus.util.xml.XmlStreamReader;
60 import org.codehaus.plexus.util.xml.Xpp3Dom;
61 import org.codehaus.plexus.util.xml.Xpp3DomUtils;
62 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
63 import org.jdom2.JDOMException;
64 import org.jdom2.input.SAXBuilder;
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
67 import org.xml.sax.SAXException;
68
69 @Named
70 @Singleton
71 public class DefaultPomManager implements PomManager {
72 private static final Logger LOGGER = LoggerFactory.getLogger(DefaultPomManager.class);
73
74 @Override
75 public void addModule(File pom, String artifactId)
76 throws IOException, ParserConfigurationException, TransformerException, SAXException, InvalidPackaging,
77 ArchetypeTemplateProcessingException {
78 StringWriter out = new StringWriter();
79 boolean found = PomUtils.addNewModule(artifactId, new XmlStreamReader(pom), out);
80 if (found) {
81 FileUtils.fileWrite(pom.getAbsolutePath(), out.toString());
82 }
83 }
84
85 @Override
86 public void addParent(File pom, File parentPom) throws IOException, XmlPullParserException {
87 Model generatedModel = readPom(pom);
88 if (null != generatedModel.getParent()) {
89 LOGGER.info("Parent element not overwritten in " + pom);
90 return;
91 }
92
93 Model parentModel = readPom(parentPom);
94
95 Parent parent = new Parent();
96 parent.setGroupId(parentModel.getGroupId());
97 if (parent.getGroupId() == null) {
98 parent.setGroupId(parentModel.getParent().getGroupId());
99 }
100 parent.setArtifactId(parentModel.getArtifactId());
101 parent.setVersion(parentModel.getVersion());
102 if (parent.getVersion() == null) {
103 parent.setVersion(parentModel.getParent().getVersion());
104 }
105 generatedModel.setParent(parent);
106
107 writePom(generatedModel, pom, pom);
108 }
109
110 @Override
111 public void mergePoms(File pom, File temporaryPom) throws IOException, XmlPullParserException {
112 Model model = readPom(pom);
113 Model generatedModel = readPom(temporaryPom);
114
115 model.getProperties().putAll(generatedModel.getProperties());
116
117 mergeModelBase(model, generatedModel);
118 mergeModelBuild(model, generatedModel);
119 mergeProfiles(model, generatedModel);
120 mergeReportPlugins(model, generatedModel);
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183 writePom(model, pom, pom);
184 }
185
186 @Override
187 public Model readPom(final File pomFile) throws IOException, XmlPullParserException {
188 try (Reader pomReader = new XmlStreamReader(pomFile)) {
189 MavenXpp3Reader reader = new MavenXpp3Reader();
190
191 return reader.read(pomReader);
192 }
193 }
194
195 @Override
196 public Model readPom(InputStream pomStream) throws IOException, XmlPullParserException {
197 try (Reader pomReader = new XmlStreamReader(pomStream)) {
198 MavenXpp3Reader reader = new MavenXpp3Reader();
199
200 return reader.read(pomReader);
201 }
202 }
203
204 @Override
205 public void writePom(final Model model, final File pomFile, final File initialPomFile) throws IOException {
206 String fileEncoding = StringUtils.isEmpty(model.getModelEncoding()) ? "UTF-8" : model.getModelEncoding();
207
208 org.jdom2.Document doc;
209 try (InputStream inputStream = Files.newInputStream(initialPomFile.toPath())) {
210 SAXBuilder builder = new SAXBuilder();
211 doc = builder.build(inputStream);
212 } catch (JDOMException exc) {
213 throw new IOException(
214 "Cannot parse the POM by JDOM while reading " + initialPomFile + ": " + exc.getMessage(), exc);
215 }
216
217 if (!pomFile.exists() && !pomFile.createNewFile()) {
218 LOGGER.warn("Could not create new file \"" + pomFile.getPath() + "\" or the file already exists.");
219 }
220
221 try (Writer outputStreamWriter = new OutputStreamWriter(new FileOutputStream(pomFile), fileEncoding)) {
222
223 MavenJDOMWriter writer = new MavenJDOMWriter();
224
225 final String ls = System.lineSeparator();
226 Format form = Format.getRawFormat().setEncoding(fileEncoding).setLineSeparator(ls);
227 writer.write(model, doc, outputStreamWriter, form);
228 } catch (FileNotFoundException e) {
229 LOGGER.debug("Creating pom file " + pomFile);
230
231 try (Writer pomWriter = new OutputStreamWriter(Files.newOutputStream(pomFile.toPath()), fileEncoding)) {
232 MavenXpp3Writer writer = new MavenXpp3Writer();
233 writer.write(pomWriter, model);
234 }
235 }
236 }
237
238 private Map<String, Dependency> createDependencyMap(List<Dependency> dependencies) {
239 Map<String, Dependency> dependencyMap = new HashMap<>();
240 for (Dependency dependency : dependencies) {
241 dependencyMap.put(dependency.getManagementKey(), dependency);
242 }
243
244 return dependencyMap;
245 }
246
247 private void mergeModelBuild(Model model, Model generatedModel) {
248 if (generatedModel.getBuild() != null) {
249 if (model.getBuild() == null) {
250 model.setBuild(new Build());
251 }
252
253 mergeBuildPlugins(model.getBuild(), generatedModel.getBuild());
254 }
255 }
256
257 private void mergeProfiles(Model model, Model generatedModel) {
258 List<Profile> generatedProfiles = generatedModel.getProfiles();
259 if (generatedProfiles != null && !generatedProfiles.isEmpty()) {
260 List<Profile> modelProfiles = model.getProfiles();
261 Map<String, Profile> modelProfileIdMap = new HashMap<>();
262 if (modelProfiles == null) {
263 modelProfiles = new ArrayList<>();
264 model.setProfiles(modelProfiles);
265 } else if (!modelProfiles.isEmpty()) {
266
267 for (Profile modelProfile : modelProfiles) {
268 modelProfileIdMap.put(modelProfile.getId(), modelProfile);
269 }
270 }
271
272 for (Profile generatedProfile : generatedProfiles) {
273 String generatedProfileId = generatedProfile.getId();
274 if (!modelProfileIdMap.containsKey(generatedProfileId)) {
275 model.addProfile(generatedProfile);
276 } else {
277 LOGGER.warn("Try to merge profiles with id " + generatedProfileId);
278 mergeModelBase(modelProfileIdMap.get(generatedProfileId), generatedProfile);
279 mergeProfileBuild(modelProfileIdMap.get(generatedProfileId), generatedProfile);
280 }
281 }
282 }
283 }
284
285 private void mergeProfileBuild(Profile modelProfile, Profile generatedProfile) {
286 if (generatedProfile.getBuild() != null) {
287 if (modelProfile.getBuild() == null) {
288 modelProfile.setBuild(new Build());
289 }
290 mergeBuildPlugins(modelProfile.getBuild(), generatedProfile.getBuild());
291
292 }
293 }
294
295 private void mergeModelBase(ModelBase model, ModelBase generatedModel) {
296
297 Map<String, Dependency> dependenciesByIds = createDependencyMap(model.getDependencies());
298
299 Map<String, Dependency> generatedDependenciesByIds = createDependencyMap(generatedModel.getDependencies());
300
301 for (String generatedDependencyId : generatedDependenciesByIds.keySet()) {
302 if (!dependenciesByIds.containsKey(generatedDependencyId)) {
303 model.addDependency(generatedDependenciesByIds.get(generatedDependencyId));
304 } else {
305 LOGGER.warn("Can not override property: " + generatedDependencyId);
306 }
307
308
309 model.getProperties().putAll(generatedModel.getProperties());
310
311
312 }
313 }
314
315 private void mergeReportPlugins(Model model, Model generatedModel) {
316 if (generatedModel.getReporting() != null) {
317 if (model.getReporting() == null) {
318 model.setReporting(new Reporting());
319 }
320
321 Map<String, ReportPlugin> reportPluginsByIds = model.getReporting().getReportPluginsAsMap();
322
323 Map<String, ReportPlugin> generatedReportPluginsByIds =
324 generatedModel.getReporting().getReportPluginsAsMap();
325
326 for (String generatedReportPluginsId : generatedReportPluginsByIds.keySet()) {
327 if (!reportPluginsByIds.containsKey(generatedReportPluginsId)) {
328 model.getReporting().addPlugin(generatedReportPluginsByIds.get(generatedReportPluginsId));
329 } else {
330 LOGGER.warn("Can not override report: " + generatedReportPluginsId);
331 }
332 }
333 }
334 }
335
336 private void mergeBuildPlugins(BuildBase modelBuild, BuildBase generatedModelBuild) {
337 Map<String, Plugin> pluginsByIds = modelBuild.getPluginsAsMap();
338
339 List<Plugin> generatedPlugins = generatedModelBuild.getPlugins();
340
341 for (Plugin generatedPlugin : generatedPlugins) {
342 String generatedPluginsId = generatedPlugin.getKey();
343
344 if (!pluginsByIds.containsKey(generatedPluginsId)) {
345 modelBuild.addPlugin(generatedPlugin);
346 } else {
347 LOGGER.info("Try to merge plugin configuration of plugins with id: " + generatedPluginsId);
348 Plugin modelPlugin = pluginsByIds.get(generatedPluginsId);
349
350 modelPlugin.setConfiguration(Xpp3DomUtils.mergeXpp3Dom(
351 (Xpp3Dom) generatedPlugin.getConfiguration(), (Xpp3Dom) modelPlugin.getConfiguration()));
352 }
353 }
354 }
355 }