001 /*
002 * SonarQube, open source software quality management tool.
003 * Copyright (C) 2008-2014 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * SonarQube is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * SonarQube is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public License
017 * along with this program; if not, write to the Free Software Foundation,
018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
019 */
020 package org.sonar.api.batch.maven;
021
022 import org.apache.commons.lang.StringUtils;
023 import org.apache.commons.lang.builder.ToStringBuilder;
024 import org.apache.maven.model.Plugin;
025 import org.apache.maven.model.ReportPlugin;
026 import org.apache.maven.project.MavenProject;
027 import org.codehaus.plexus.util.xml.Xpp3Dom;
028
029 import java.util.Collection;
030 import java.util.Iterator;
031 import java.util.List;
032
033 /**
034 * A class to handle maven plugins
035 *
036 * @since 1.10
037 */
038 public class MavenPlugin {
039
040 private static final String CONFIGURATION_ELEMENT = "configuration";
041 private Plugin plugin;
042 private Xpp3Dom configuration;
043
044 /**
045 * Creates a MavenPlugin based on a Plugin
046 *
047 * @param plugin the plugin
048 */
049 public MavenPlugin(Plugin plugin) {
050 this.plugin = plugin;
051 this.configuration = (Xpp3Dom) plugin.getConfiguration();
052 if (this.configuration == null) {
053 configuration = new Xpp3Dom(CONFIGURATION_ELEMENT);
054 plugin.setConfiguration(this.configuration);
055 }
056 }
057
058 /**
059 * Creates a Maven plugin based on artifact + group + version
060 *
061 * @param groupId the group id
062 * @param artifactId the artifact id
063 * @param version the version
064 */
065 public MavenPlugin(String groupId, String artifactId, String version) {
066 this.plugin = new Plugin();
067 plugin.setGroupId(groupId);
068 plugin.setArtifactId(artifactId);
069 plugin.setVersion(version);
070 configuration = new Xpp3Dom(CONFIGURATION_ELEMENT);
071 plugin.setConfiguration(this.configuration);
072 }
073
074 /**
075 * @since 3.5 - see SONAR-4070
076 * @return the XML node <configuration> of pom
077 */
078 public Xpp3Dom getConfigurationXmlNode() {
079 return configuration;
080 }
081
082 /**
083 * Sets the maven plugin version
084 *
085 * @param version the version
086 * @return this
087 */
088 public MavenPlugin setVersion(String version) {
089 this.plugin.setVersion(version);
090 return this;
091 }
092
093 /**
094 * @return the underlying plugin
095 */
096 public Plugin getPlugin() {
097 return plugin;
098 }
099
100 /**
101 * Gets a parameter of the plugin based on its key
102 *
103 * @param key the param key
104 * @return the parameter if exist, null otherwise
105 */
106 public String getParameter(String key) {
107 Xpp3Dom node = findNodeWith(key);
108 return node == null ? null : node.getValue();
109 }
110
111 /**
112 * Gets a list of parameters of the plugin from a param key
113 *
114 * @param key param key with option-index snippet: e.g. item[0], item[1]. If no index snippet is passed, then
115 * 0 is default (index <=> index[0])
116 * @return an array of parameters if any, an empty array otherwise
117 */
118 public String[] getParameters(String key) {
119 String[] keyParts = StringUtils.split(key, "/");
120 Xpp3Dom node = configuration;
121 for (int i = 0; i < keyParts.length - 1; i++) {
122 node = getOrCreateChild(node, keyParts[i]);
123 }
124 Xpp3Dom[] children = node.getChildren(keyParts[keyParts.length - 1]);
125 String[] result = new String[children.length];
126 for (int i = 0; i < children.length; i++) {
127 result[i] = children[i].getValue();
128 }
129 return result;
130 }
131
132 /**
133 * Sets a parameter for the maven plugin. This will overrides an existing parameter.
134 *
135 * @param key the param key
136 * @param value the param value
137 * @return this
138 */
139 public MavenPlugin setParameter(String key, String value) {
140 checkKeyArgument(key);
141 String[] keyParts = StringUtils.split(key, "/");
142 Xpp3Dom node = configuration;
143 for (String keyPart : keyParts) {
144 node = getOrCreateChild(node, keyPart);
145 }
146 node.setValue(value);
147 return this;
148 }
149
150 /**
151 * Sets a parameter to the maven plugin. Overrides existing parameter only id specified.
152 *
153 * @param key the param key
154 * @param value the param value
155 * @param override whether to override existing parameter
156 */
157 public void setParameter(String key, String value, boolean override) {
158 if (getParameter(key) == null || override) {
159 setParameter(key, value);
160 }
161 }
162
163 /**
164 * Removes all parameters from the maven plugin
165 */
166 public void removeParameters() {
167 configuration = new Xpp3Dom(CONFIGURATION_ELEMENT);
168 plugin.setConfiguration(this.configuration);
169 }
170
171 /**
172 * Adds a parameter to the maven plugin
173 *
174 * @param key the param key with option-index snippet: e.g. item[0], item[1]. If no index snippet is passed, then
175 * 0 is default (index <=> index[0])
176 * @param value the param value
177 * @return this
178 */
179 public MavenPlugin addParameter(String key, String value) {
180 String[] keyParts = StringUtils.split(key, "/");
181 Xpp3Dom node = configuration;
182 for (int i = 0; i < keyParts.length - 1; i++) {
183 node = getOrCreateChild(node, keyParts[i]);
184 }
185 Xpp3Dom leaf = new Xpp3Dom(keyParts[keyParts.length - 1]);
186 leaf.setValue(value);
187 node.addChild(leaf);
188 return this;
189 }
190
191 private static Xpp3Dom getOrCreateChild(Xpp3Dom node, String key) {
192 int childIndex = getIndex(key);
193
194 if (node.getChildren(removeIndexSnippet(key)).length <= childIndex) {
195 Xpp3Dom child = new Xpp3Dom(removeIndexSnippet(key));
196 node.addChild(child);
197 return child;
198 }
199 return node.getChildren(removeIndexSnippet(key))[childIndex];
200
201 }
202
203 private static int getIndex(String key) {
204 // parsing index-syntax (e.g. item[1])
205 if (key.matches(".*?\\[\\d+\\]")) {
206 return Integer.parseInt(StringUtils.substringBetween(key, "[", "]"));
207 }
208 // for down-compatibility of api we fallback to default 0
209 return 0;
210 }
211
212 private static String removeIndexSnippet(String key) {
213 return StringUtils.substringBefore(key, "[");
214 }
215
216 /**
217 * Remove a parameter from the maven plugin based on its key
218 *
219 * @param key param key with option-index snippet: e.g. item[0], item[1]. If no index snippet is passed, then
220 * 0 is default (index <=> index[0])
221 */
222 public void removeParameter(String key) {
223 Xpp3Dom node = findNodeWith(key);
224 if (node != null) {
225 remove(node);
226 }
227 }
228
229 private Xpp3Dom findNodeWith(String key) {
230 checkKeyArgument(key);
231 String[] keyParts = key.split("/");
232 Xpp3Dom node = configuration;
233 for (String keyPart : keyParts) {
234
235 if (node.getChildren(removeIndexSnippet(keyPart)).length <= getIndex(keyPart)) {
236 return null;
237 }
238
239 node = node.getChildren(removeIndexSnippet(keyPart))[getIndex(keyPart)];
240 if (node == null) {
241 return null;
242 }
243 }
244 return node;
245 }
246
247 private static void remove(Xpp3Dom node) {
248 Xpp3Dom parent = node.getParent();
249 for (int i = 0; i < parent.getChildCount(); i++) {
250 Xpp3Dom child = parent.getChild(i);
251 if (child.equals(node)) {
252 parent.removeChild(i);
253 break;
254 }
255 }
256 }
257
258 /**
259 * @return whether the maven plugin has got configuration
260 */
261 public boolean hasConfiguration() {
262 return configuration.getChildCount() > 0;
263 }
264
265 private static void checkKeyArgument(String key) {
266 if (key == null) {
267 throw new IllegalArgumentException("Parameter 'key' should not be null.");
268 }
269 }
270
271 /**
272 * Registers a plugin in a project pom
273 * <p/>
274 * <p>Adds the plugin if it does not exist or amend its version if it does exist and specified</p>
275 *
276 * @param pom the project pom
277 * @param groupId the plugin group id
278 * @param artifactId the plugin artifact id
279 * @param version the plugin version
280 * @param overrideVersion whether to override the version if the plugin is already registered
281 * @return the registered plugin
282 */
283 public static MavenPlugin registerPlugin(MavenProject pom, String groupId, String artifactId, String version, boolean overrideVersion) {
284 MavenPlugin plugin = getPlugin(pom, groupId, artifactId);
285 if (plugin == null) {
286 plugin = new MavenPlugin(groupId, artifactId, version);
287
288 } else if (overrideVersion) {
289 plugin.setVersion(version);
290 }
291
292 // remove from pom
293 unregisterPlugin(pom, groupId, artifactId);
294
295 // register
296 pom.getBuild().addPlugin(plugin.getPlugin());
297
298 return plugin;
299 }
300
301 /**
302 * Returns a plugin from a pom based on its group id and artifact id
303 * <p/>
304 * <p>It searches in the build section, then the reporting section and finally the pluginManagement section</p>
305 *
306 * @param pom the project pom
307 * @param groupId the plugin group id
308 * @param artifactId the plugin artifact id
309 * @return the plugin if it exists, null otherwise
310 */
311 public static MavenPlugin getPlugin(MavenProject pom, String groupId, String artifactId) {
312 if (pom == null) {
313 return null;
314 }
315 // look for plugin in <build> section
316 Plugin plugin = null;
317 if (pom.getBuildPlugins() != null) {
318 plugin = getPlugin(pom.getBuildPlugins(), groupId, artifactId);
319 }
320
321 // look for plugin in <report> section
322 if (plugin == null && pom.getReportPlugins() != null) {
323 plugin = getReportPlugin(pom.getReportPlugins(), groupId, artifactId);
324 }
325
326 // look for plugin in <pluginManagement> section
327 if (pom.getPluginManagement() != null) {
328 Plugin pluginManagement = getPlugin(pom.getPluginManagement().getPlugins(), groupId, artifactId);
329 if (plugin == null) {
330 plugin = pluginManagement;
331
332 } else if (pluginManagement != null) {
333 if (pluginManagement.getConfiguration() != null) {
334 if (plugin.getConfiguration() == null) {
335 plugin.setConfiguration(pluginManagement.getConfiguration());
336 } else {
337 Xpp3Dom.mergeXpp3Dom((Xpp3Dom) plugin.getConfiguration(), (Xpp3Dom) pluginManagement.getConfiguration());
338 }
339 }
340 if (plugin.getDependencies() == null && pluginManagement.getDependencies() != null) {
341 plugin.setDependencies(pluginManagement.getDependencies());
342 }
343 if (plugin.getVersion() == null) {
344 plugin.setVersion(pluginManagement.getVersion());
345 }
346 }
347 }
348
349 if (plugin != null) {
350 return new MavenPlugin(plugin);
351 }
352 return null;
353 }
354
355 private static Plugin getPlugin(Collection<Plugin> plugins, String groupId, String artifactId) {
356 if (plugins == null) {
357 return null;
358 }
359
360 for (Plugin plugin : plugins) {
361 if (MavenUtils.equals(plugin, groupId, artifactId)) {
362 return plugin;
363 }
364 }
365 return null;
366 }
367
368 private static Plugin getReportPlugin(Collection<ReportPlugin> plugins, String groupId, String artifactId) {
369 if (plugins == null) {
370 return null;
371 }
372
373 for (ReportPlugin plugin : plugins) {
374 if (MavenUtils.equals(plugin, groupId, artifactId)) {
375 return cloneReportPluginToPlugin(plugin);
376 }
377 }
378 return null;
379 }
380
381 private static Plugin cloneReportPluginToPlugin(ReportPlugin reportPlugin) {
382 Plugin plugin = new Plugin();
383 plugin.setGroupId(reportPlugin.getGroupId());
384 plugin.setArtifactId(reportPlugin.getArtifactId());
385 plugin.setVersion(reportPlugin.getVersion());
386 plugin.setConfiguration(reportPlugin.getConfiguration());
387 return plugin;
388 }
389
390 private static void unregisterPlugin(MavenProject pom, String groupId, String artifactId) {
391 if (pom.getPluginManagement() != null && pom.getPluginManagement().getPlugins() != null) {
392 unregisterPlugin(pom.getPluginManagement().getPlugins(), groupId, artifactId);
393 }
394 if (pom.getBuildPlugins() != null && pom.getBuildPlugins() != null) {
395 unregisterPlugin(pom.getBuildPlugins(), groupId, artifactId);
396 }
397 if (pom.getReportPlugins() != null) {
398 unregisterReportPlugin(pom.getReportPlugins(), groupId, artifactId);
399 }
400 }
401
402 private static void unregisterPlugin(List<Plugin> plugins, String groupId, String artifactId) {
403 for (Iterator<Plugin> iterator = plugins.iterator(); iterator.hasNext();) {
404 Plugin p = iterator.next();
405 if (MavenUtils.equals(p, groupId, artifactId)) {
406 iterator.remove();
407 }
408 }
409 }
410
411 private static void unregisterReportPlugin(List<ReportPlugin> plugins, String groupId, String artifactId) {
412 for (Iterator<ReportPlugin> iterator = plugins.iterator(); iterator.hasNext();) {
413 ReportPlugin p = iterator.next();
414 if (MavenUtils.equals(p, groupId, artifactId)) {
415 iterator.remove();
416 }
417 }
418 }
419
420 @Override
421 public String toString() {
422 return new ToStringBuilder(this)
423 .append("groupId", plugin.getGroupId())
424 .append("artifactId", plugin.getArtifactId())
425 .append("version", plugin.getVersion())
426 .toString();
427 }
428 }