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