001 /* 002 * SonarQube, open source software quality management tool. 003 * Copyright (C) 2008-2013 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 }