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