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       * Gets a parameter of the plugin based on its key
094       *
095       * @param key the param key
096       * @return the parameter if exist, null otherwise
097       */
098      public String getParameter(String key) {
099        Xpp3Dom node = findNodeWith(key);
100        return node == null ? null : node.getValue();
101      }
102    
103      /**
104       * Gets a list of parameters of the plugin from a param key
105       *
106       * @param key the param key
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
166       * @param value the param value
167       * @return this
168       */
169      public MavenPlugin addParameter(String key, String value) {
170        String[] keyParts = StringUtils.split(key, "/");
171        Xpp3Dom node = configuration;
172        for (int i = 0; i < keyParts.length - 1; i++) {
173          node = getOrCreateChild(node, keyParts[i]);
174        }
175        Xpp3Dom leaf = new Xpp3Dom(keyParts[keyParts.length - 1]);
176        leaf.setValue(value);
177        node.addChild(leaf);
178        return this;
179      }
180    
181      private static Xpp3Dom getOrCreateChild(Xpp3Dom node, String key) {
182        Xpp3Dom child = node.getChild(key);
183        if (child == null) {
184          child = new Xpp3Dom(key);
185          node.addChild(child);
186        }
187        return child;
188      }
189    
190      /**
191       * Remove a parameter from the maven plugin based on its key
192       *
193       * @param key the param key
194       */
195      public void removeParameter(String key) {
196        Xpp3Dom node = findNodeWith(key);
197        if (node != null) {
198          remove(node);
199        }
200      }
201    
202      private Xpp3Dom findNodeWith(String key) {
203        checkKeyArgument(key);
204        String[] keyParts = key.split("/");
205        Xpp3Dom node = configuration;
206        for (String keyPart : keyParts) {
207          node = node.getChild(keyPart);
208          if (node == null) {
209            return null;
210          }
211        }
212        return node;
213      }
214    
215      private static void remove(Xpp3Dom node) {
216        Xpp3Dom parent = node.getParent();
217        for (int i = 0; i < parent.getChildCount(); i++) {
218          Xpp3Dom child = parent.getChild(i);
219          if (child.equals(node)) {
220            parent.removeChild(i);
221            break;
222          }
223        }
224      }
225    
226      /**
227       * @return whether the maven plugin has got configuration 
228       */
229      public boolean hasConfiguration() {
230        return configuration.getChildCount()>0;
231      }
232    
233      private static void checkKeyArgument(String key) {
234        if (key == null) {
235          throw new IllegalArgumentException("Parameter 'key' should not be null.");
236        }
237      }
238    
239      /**
240       * Registers a plugin in a project pom
241       * <p/>
242       * <p>Adds the plugin if it does not exist or amend its version if it does exist and specified</p>
243       *
244       * @param pom the project pom
245       * @param groupId the plugin group id
246       * @param artifactId the plugin artifact id
247       * @param version the plugin version
248       * @param overrideVersion whether to override the version if the plugin is already registered
249       * @return the registered plugin
250       */
251      public static MavenPlugin registerPlugin(MavenProject pom, String groupId, String artifactId, String version, boolean overrideVersion) {
252        MavenPlugin plugin = getPlugin(pom, groupId, artifactId);
253        if (plugin == null) {
254          plugin = new MavenPlugin(groupId, artifactId, version);
255    
256        } else if (overrideVersion) {
257          plugin.setVersion(version);
258        }
259    
260        // remove from pom
261        unregisterPlugin(pom, groupId, artifactId);
262    
263        // register
264        pom.getBuild().addPlugin(plugin.getPlugin());
265    
266        return plugin;
267      }
268    
269      /**
270       * Returns a plugin from a pom based on its group id and artifact id
271       * <p/>
272       * <p>It searches in the build section, then the reporting section and finally the pluginManagement section</p>
273       * 
274       * @param pom the project pom
275       * @param groupId the plugin group id
276       * @param artifactId the plugin artifact id
277       * @return the plugin if it exists, null otherwise
278       */
279      public static MavenPlugin getPlugin(MavenProject pom, String groupId, String artifactId) {
280        if (pom == null) {
281          return null;
282        }
283        // look for plugin in <build> section
284        Plugin plugin = null;
285        if (pom.getBuildPlugins() != null) {
286          plugin = getPlugin(pom.getBuildPlugins(), groupId, artifactId);
287        }
288    
289        // look for plugin in <report> section
290        if (plugin == null && pom.getReportPlugins() != null) {
291          plugin = getReportPlugin(pom.getReportPlugins(), groupId, artifactId);
292        }
293    
294        // look for plugin in <pluginManagement> section
295        if (pom.getPluginManagement() != null) {
296          Plugin pluginManagement = getPlugin(pom.getPluginManagement().getPlugins(), groupId, artifactId);
297          if (plugin == null) {
298            plugin = pluginManagement;
299    
300          } else if (pluginManagement != null) {
301            if (pluginManagement.getConfiguration() != null) {
302              if (plugin.getConfiguration() == null) {
303                plugin.setConfiguration(pluginManagement.getConfiguration());
304              } else {
305                Xpp3Dom.mergeXpp3Dom((Xpp3Dom) plugin.getConfiguration(), (Xpp3Dom) pluginManagement.getConfiguration());
306              }
307            }
308            if (plugin.getDependencies() == null && pluginManagement.getDependencies() != null) {
309              plugin.setDependencies(pluginManagement.getDependencies());
310            }
311            if (plugin.getVersion() == null) {
312              plugin.setVersion(pluginManagement.getVersion());
313            }
314          }
315        }
316    
317        if (plugin != null) {
318          return new MavenPlugin(plugin);
319        }
320        return null;
321      }
322    
323      private static Plugin getPlugin(Collection<Plugin> plugins, String groupId, String artifactId) {
324        if (plugins == null) {
325          return null;
326        }
327    
328        for (Plugin plugin : plugins) {
329          if (MavenUtils.equals(plugin, groupId, artifactId)) {
330            return plugin;
331          }
332        }
333        return null;
334      }
335    
336      private static Plugin getReportPlugin(Collection<ReportPlugin> plugins, String groupId, String artifactId) {
337        if (plugins == null) {
338          return null;
339        }
340    
341        for (ReportPlugin plugin : plugins) {
342          if (MavenUtils.equals(plugin, groupId, artifactId)) {
343            return cloneReportPluginToPlugin(plugin);
344          }
345        }
346        return null;
347      }
348    
349      private static Plugin cloneReportPluginToPlugin(ReportPlugin reportPlugin) {
350        Plugin plugin = new Plugin();
351        plugin.setGroupId(reportPlugin.getGroupId());
352        plugin.setArtifactId(reportPlugin.getArtifactId());
353        plugin.setVersion(reportPlugin.getVersion());
354        plugin.setConfiguration(reportPlugin.getConfiguration());
355        return plugin;
356      }
357    
358      private static void unregisterPlugin(MavenProject pom, String groupId, String artifactId) {
359        if (pom.getPluginManagement() != null && pom.getPluginManagement().getPlugins() != null) {
360          unregisterPlugin(pom.getPluginManagement().getPlugins(), groupId, artifactId);
361        }
362        if (pom.getBuildPlugins() != null && pom.getBuildPlugins() != null) {
363          unregisterPlugin(pom.getBuildPlugins(), groupId, artifactId);
364        }
365        if (pom.getReportPlugins() != null) {
366          unregisterReportPlugin(pom.getReportPlugins(), groupId, artifactId);
367        }
368      }
369    
370      private static void unregisterPlugin(List<Plugin> plugins, String groupId, String artifactId) {
371        for (Iterator<Plugin> iterator = plugins.iterator(); iterator.hasNext();) {
372          Plugin p = iterator.next();
373          if (MavenUtils.equals(p, groupId, artifactId)) {
374            iterator.remove();
375          }
376        }
377      }
378    
379      private static void unregisterReportPlugin(List<ReportPlugin> plugins, String groupId, String artifactId) {
380        for (Iterator<ReportPlugin> iterator = plugins.iterator(); iterator.hasNext();) {
381          ReportPlugin p = iterator.next();
382          if (MavenUtils.equals(p, groupId, artifactId)) {
383            iterator.remove();
384          }
385        }
386      }
387    
388    
389      @Override
390      public String toString() {
391        return new ToStringBuilder(this)
392            .append("groupId", plugin.getGroupId())
393            .append("artifactId", plugin.getArtifactId())
394            .append("version", plugin.getVersion())
395            .toString();
396      }
397    }