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