1   package com.atlassian.maven.plugins.amps;
2   
3   import com.atlassian.core.util.FileUtils;
4   import com.atlassian.maven.plugins.amps.util.VersionUtils;
5   import com.atlassian.maven.plugins.amps.util.ZipUtils;
6   import org.apache.maven.execution.MavenSession;
7   import org.apache.maven.plugin.MojoExecutionException;
8   import org.apache.maven.plugin.PluginManager;
9   import org.apache.maven.plugin.logging.Log;
10  import org.apache.maven.project.MavenProject;
11  
12  import java.io.File;
13  import java.io.IOException;
14  import java.net.ServerSocket;
15  import java.util.ArrayList;
16  import java.util.Collections;
17  import java.util.HashMap;
18  import java.util.List;
19  import java.util.Map;
20  
21  import static org.twdata.maven.mojoexecutor.MojoExecutor.*;
22  
23  /**
24   * Executes specific maven goals
25   */
26  public class MavenGoals
27  {
28      private final MavenProject project;
29      private final List<MavenProject> reactor;
30      private final MavenSession session;
31      private final PluginManager pluginManager;
32      private final Log log;
33      private final Map<String, String> pluginArtifactIdToVersionMap;
34  
35      private final Map<String, Container> idToContainerMap = new HashMap<String, Container>()
36      {{
37              put("tomcat5x", new Container("tomcat5x", "org.apache.tomcat", "apache-tomcat", "5.5.26"));
38              put("tomcat6x", new Container("tomcat6x", "org.apache.tomcat", "apache-tomcat", "6.0.20"));
39              put("resin3x", new Container("resin3x", "com.caucho", "resin", "3.0.26"));
40              put("jboss42x", new Container("jboss42x", "org.jboss.jbossas", "jbossas", "4.2.3.GA"));
41              put("jetty6x", new Container("jetty6x"));
42          }};
43  
44      private final Map<String, String> defaultArtifactIdToVersionMap = new HashMap<String, String>()
45      {{
46              put("maven-cli-plugin", "0.7");
47              put("cargo-maven2-plugin", "1.0-beta-2-db2");
48              put("atlassian-pdk", "2.1.6");
49              put("maven-archetype-plugin", "2.0-alpha-4");
50              put("maven-bundle-plugin", "2.0.0");
51              put("yuicompressor-maven-plugin", "0.7.1");
52  
53              // You can't actually override the version a plugin if defined in the project, so these don't actually do
54              // anything, since the super pom already defines versions.
55              put("maven-dependency-plugin", "2.0");
56              put("maven-resources-plugin", "2.3");
57              put("maven-jar-plugin", "2.2");
58              put("maven-surefire-plugin", "2.4.3");
59  
60          }};
61  
62      public MavenGoals(final MavenContext ctx)
63      {
64          this(ctx, Collections.<String, String>emptyMap());
65      }
66  
67      public MavenGoals(final MavenContext ctx, final Map<String, String> pluginToVersionMap)
68      {
69          this.project = ctx.getProject();
70          this.reactor = ctx.getReactor();
71          this.session = ctx.getSession();
72          this.pluginManager = ctx.getPluginManager();
73          this.log = ctx.getLog();
74  
75          final Map<String, String> map = new HashMap<String, String>(defaultArtifactIdToVersionMap);
76          map.putAll(pluginToVersionMap);
77          this.pluginArtifactIdToVersionMap = Collections.unmodifiableMap(map);
78  
79      }
80  
81      public void startCli(final PluginInformation pluginInformation, final int port) throws MojoExecutionException
82      {
83          final String pluginId = pluginInformation.getId();
84  
85          final List<Element> configs = new ArrayList<Element>();
86          configs.add(element(name("commands"),
87                  element(name("pi"), new StringBuilder()
88                          .append("resources").append(" ")
89                          .append("com.atlassian.maven.plugins:maven-").append(pluginId).append("-plugin:filter-plugin-descriptor").append(" ")
90                          .append("compile").append(" ")
91                          .append("com.atlassian.maven.plugins:maven-").append(pluginId).append("-plugin:copy-bundled-dependencies").append(" ")
92                          .append("com.atlassian.maven.plugins:maven-").append(pluginId).append("-plugin:compress-resources").append(" ")
93                          .append("com.atlassian.maven.plugins:maven-").append(pluginId).append("-plugin:generate-manifest").append(" ")
94                          .append("com.atlassian.maven.plugins:maven-").append(pluginId).append("-plugin:validate-manifest").append(" ")
95                          .append("com.atlassian.maven.plugins:maven-").append(pluginId).append("-plugin:jar").append(" ")
96                          .append("com.atlassian.maven.plugins:maven-").append(pluginId).append("-plugin:install").toString()),
97                  element(name("tpi"), new StringBuilder()
98                          .append("testResources").append(" ")
99                          .append("testCompile").append(" ")
100                         .append("com.atlassian.maven.plugins:maven-").append(pluginId).append("-plugin:test-jar").append(" ")
101                         .append("com.atlassian.maven.plugins:maven-").append(pluginId).append("-plugin:test-install").toString()),
102                 element(name("package"), new StringBuilder()
103                         .append("resources").append(" ")
104                         .append("com.atlassian.maven.plugins:maven-").append(pluginId).append("-plugin:filter-plugin-descriptor").append(" ")
105                         .append("compile").append(" ")
106                         .append("com.atlassian.maven.plugins:maven-").append(pluginId).append("-plugin:copy-bundled-dependencies").append(" ")
107                         .append("com.atlassian.maven.plugins:maven-").append(pluginId).append("-plugin:generate-manifest").append(" ")
108                         .append("com.atlassian.maven.plugins:maven-").append(pluginId).append("-plugin:jar").append(" ").toString())));
109         if (port > 0)
110         {
111             configs.add(element(name("port"), String.valueOf(port)));
112         }
113         executeMojo(
114                 plugin(
115                         groupId("org.twdata.maven"),
116                         artifactId("maven-cli-plugin"),
117                         version(pluginArtifactIdToVersionMap.get("maven-cli-plugin"))
118                 ),
119                 goal("execute"),
120                 configuration(configs.toArray(new Element[0])),
121                 executionEnvironment(project, session, pluginManager));
122     }
123 
124     public void createPlugin(final String productId) throws MojoExecutionException
125     {
126         executeMojo(
127                 plugin(
128                         groupId("org.apache.maven.plugins"),
129                         artifactId("maven-archetype-plugin"),
130                         version(defaultArtifactIdToVersionMap.get("maven-archetype-plugin"))
131                 ),
132                 goal("generate"),
133                 configuration(
134                         element(name("archetypeGroupId"), "com.atlassian.maven.archetypes"),
135                         element(name("archetypeArtifactId"), productId + "-plugin-archetype"),
136                         element(name("archetypeVersion"), VersionUtils.getVersion())
137                 ),
138                 executionEnvironment(project, session, pluginManager));
139     }
140 
141     public void copyBundledDependencies() throws MojoExecutionException
142     {
143         executeMojo(
144                 plugin(
145                         groupId("org.apache.maven.plugins"),
146                         artifactId("maven-dependency-plugin"),
147                         version(defaultArtifactIdToVersionMap.get("maven-dependency-plugin"))
148                 ),
149                 goal("copy-dependencies"),
150                 configuration(
151                         element(name("includeScope"), "runtime"),
152                         element(name("excludeScope"), "provided"),
153                         element(name("excludeScope"), "test"),
154                         element(name("includeTypes"), "jar"),
155                         element(name("outputDirectory"), "${project.build.outputDirectory}/META-INF/lib")
156                 ),
157                 executionEnvironment(project, session, pluginManager)
158         );
159     }
160 
161     public void extractBundledDependencies() throws MojoExecutionException
162     {
163          executeMojo(
164                  plugin(
165                         groupId("org.apache.maven.plugins"),
166                         artifactId("maven-dependency-plugin"),
167                         version(defaultArtifactIdToVersionMap.get("maven-dependency-plugin"))
168                 ),
169                 goal("unpack-dependencies"),
170                 configuration(
171                         element(name("includeScope"), "runtime"),
172                         element(name("excludeScope"), "provided"),
173                         element(name("excludeScope"), "test"),
174                         element(name("includeTypes"), "jar"),
175                         element(name("excludes"), "META-INF/MANIFEST.MF, META-INF/*.DSA, META-INF/*.SF"),
176                         element(name("outputDirectory"), "${project.build.outputDirectory}")
177                 ),
178                 executionEnvironment(project, session, pluginManager)
179         );
180     }
181     
182     public void compressResources() throws MojoExecutionException
183     {
184         executeMojo(
185                 plugin(
186                         groupId("net.sf.alchim"),
187                         artifactId("yuicompressor-maven-plugin"),
188                         version(defaultArtifactIdToVersionMap.get("yuicompressor-maven-plugin"))
189                 ),
190                 goal("compress"),
191                 configuration(
192                         element(name("suffix"), "-min"),
193                         element(name("jswarn"), "false")
194                 ),
195                 executionEnvironment(project, session, pluginManager)
196         );
197     }
198 
199     public void filterPluginDescriptor() throws MojoExecutionException
200     {
201         executeMojo(
202                 plugin(
203                         groupId("org.apache.maven.plugins"),
204                         artifactId("maven-resources-plugin"),
205                         version(defaultArtifactIdToVersionMap.get("maven-resources-plugin"))
206                 ),
207                 goal("copy-resources"),
208                 configuration(
209                         element(name("encoding"), "UTF-8"),
210                         element(name("resources"),
211                                 element(name("resource"),
212                                         element(name("directory"), "src/main/resources"),
213                                         element(name("filtering"), "true"),
214                                         element(name("includes"),
215                                                 element(name("include"), "atlassian-plugin.xml"))
216                                 )
217                         ),
218                         element(name("outputDirectory"), "${project.build.outputDirectory}")
219                 ),
220                 executionEnvironment(project, session, pluginManager)
221         );
222     }
223 
224     public void runUnitTests() throws MojoExecutionException
225     {
226         executeMojo(
227                 plugin(
228                         groupId("org.apache.maven.plugins"),
229                         artifactId("maven-surefire-plugin"),
230                         version(defaultArtifactIdToVersionMap.get("maven-surefire-plugin"))
231                 ),
232                 goal("test"),
233                 configuration(
234                         element(name("excludes"),
235                                 element(name("exclude"), "it/**"),
236                                 element(name("exclude"), "**/*$*"))
237                 ),
238                 executionEnvironment(project, session, pluginManager)
239         );
240     }
241 
242     public File copyWebappWar(final String productId, final File targetDirectory, final ProductArtifact artifact)
243             throws MojoExecutionException
244     {
245         final File webappWarFile = new File(targetDirectory, productId + "-original.war");
246         executeMojo(
247                 plugin(
248                         groupId("org.apache.maven.plugins"),
249                         artifactId("maven-dependency-plugin"),
250                         version(defaultArtifactIdToVersionMap.get("maven-dependency-plugin"))
251                 ),
252                 goal("copy"),
253                 configuration(
254                         element(name("artifactItems"),
255                                 element(name("artifactItem"),
256                                         element(name("groupId"), artifact.getGroupId()),
257                                         element(name("artifactId"), artifact.getArtifactId()),
258                                         element(name("type"), "war"),
259                                         element(name("version"), artifact.getVersion()),
260                                         element(name("destFileName"), webappWarFile.getName()))),
261                         element(name("outputDirectory"), targetDirectory.getPath())
262                 ),
263                 executionEnvironment(project, session, pluginManager)
264         );
265         return webappWarFile;
266     }
267 
268     /**
269      * Copies {@code artifacts} to the {@code outputDirectory}. Artifacts are looked up in order: <ol> <li>in the maven
270      * reactor</li> <li>in the maven repositories</li> </ol> This can't be used in a goal that happens before the
271      * <em>package</em> phase as artifacts in the reactor will be not be packaged (and therefore 'copiable') until this
272      * phase.
273      *
274      * @param outputDirectory the directory to copy artifacts to
275      * @param artifacts       the list of artifact to copy to the given directory
276      */
277     public void copyPlugins(final File outputDirectory, final List<ProductArtifact> artifacts)
278             throws MojoExecutionException
279     {
280         for (ProductArtifact artifact : artifacts)
281         {
282             final MavenProject artifactReactorProject = getReactorProjectForArtifact(artifact);
283             if (artifactReactorProject != null)
284             {
285 
286                 log.debug(artifact + " will be copied from reactor project " + artifactReactorProject);
287                 final File artifactFile = artifactReactorProject.getArtifact().getFile();
288                 if (artifactFile == null)
289                 {
290                     log.warn("The plugin " + artifact + " is in the reactor but not the file hasn't been attached.  Skipping.");
291                 }
292                 else
293                 {
294                     log.debug("Copying " + artifactFile + " to " + outputDirectory);
295                     try
296                     {
297                         FileUtils.copyFile(artifactFile, new File(outputDirectory, artifactFile.getName()));
298                     }
299                     catch (IOException e)
300                     {
301                         throw new MojoExecutionException("Could not copy " + artifact + " to " + outputDirectory, e);
302                     }
303                 }
304 
305             }
306             else
307             {
308                 executeMojo(
309                         plugin(
310                                 groupId("org.apache.maven.plugins"),
311                                 artifactId("maven-dependency-plugin"),
312                                 version(defaultArtifactIdToVersionMap.get("maven-dependency-plugin"))
313                         ),
314                         goal("copy"),
315                         configuration(
316                                 element(name("artifactItems"),
317                                         element(name("artifactItem"),
318                                                 element(name("groupId"), artifact.getGroupId()),
319                                                 element(name("artifactId"), artifact.getArtifactId()),
320                                                 element(name("version"), artifact.getVersion()))),
321                                 element(name("outputDirectory"), outputDirectory.getPath())
322                         ),
323                         executionEnvironment(project, session, pluginManager));
324             }
325         }
326     }
327 
328     private MavenProject getReactorProjectForArtifact(ProductArtifact artifact)
329     {
330         for (final MavenProject project : reactor)
331         {
332             if (project.getGroupId().equals(artifact.getGroupId())
333                     && project.getArtifactId().equals(artifact.getArtifactId())
334                     && project.getVersion().equals(artifact.getVersion()))
335             {
336                 return project;
337             }
338         }
339         return null;
340     }
341 
342     private void unpackContainer(final Container container) throws MojoExecutionException
343     {
344         executeMojo(
345                 plugin(
346                         groupId("org.apache.maven.plugins"),
347                         artifactId("maven-dependency-plugin"),
348                         version(defaultArtifactIdToVersionMap.get("maven-dependency-plugin"))
349                 ),
350                 goal("unpack"),
351                 configuration(
352                         element(name("artifactItems"),
353                                 element(name("artifactItem"),
354                                         element(name("groupId"), container.getGroupId()),
355                                         element(name("artifactId"), container.getArtifactId()),
356                                         element(name("version"), container.getVersion()),
357                                         element(name("type"), "zip"))),
358                         element(name("outputDirectory"), container.getRootDirectory(getBuildDirectory()))
359                 ),
360                 executionEnvironment(project, session, pluginManager));
361     }
362 
363     private String getBuildDirectory()
364     {
365         return project.getBuild().getDirectory();
366     }
367 
368     public int startWebapp(final String productInstanceId, final File war, final Map<String, String> systemProperties, final List<ProductArtifact> extraContainerDependencies,
369                            final Product webappContext) throws MojoExecutionException
370     {
371         final Container container = findContainer(webappContext.getContainerId());
372         File containerDir = new File(container.getRootDirectory(getBuildDirectory()));
373 
374         // retrieve non-embedded containers
375         if (!container.isEmbedded())
376         {
377             if (containerDir.exists())
378             {
379                 log.info("Reusing unpacked container '" + container.getId() + "' from " + containerDir.getPath());
380             }
381             else
382             {
383                 log.info("Unpacking container '" + container.getId() + "' from container artifact: " + container.toString());
384                 unpackContainer(container);
385             }
386         }
387 
388         final int rmiPort = pickFreePort(0);
389         final int actualHttpPort = pickFreePort(webappContext.getHttpPort());
390         final List<Element> sysProps = new ArrayList<Element>();
391         if (webappContext.getJvmArgs() == null)
392         {
393             webappContext.setJvmArgs("-Xmx512m -XX:MaxPermSize=160m");
394         }
395 
396         for (final Map.Entry<String, String> entry : systemProperties.entrySet())
397         {
398             webappContext.setJvmArgs(webappContext.getJvmArgs() + " -D" + entry.getKey() + "=\"" + entry.getValue() + "\"");
399             sysProps.add(element(name(entry.getKey()), entry.getValue()));
400         }
401         log.info("Starting " + productInstanceId + " on the " + container.getId() + " container on ports "
402                 + actualHttpPort + " (http) and " + rmiPort + " (rmi)");
403 
404         final String baseUrl = getBaseUrl(webappContext.getServer(), actualHttpPort, webappContext.getContextPath());
405         sysProps.add(element(name("baseurl"), baseUrl));
406 
407         final List<Element> deps = new ArrayList<Element>();
408         for (final ProductArtifact dep : extraContainerDependencies)
409 
410         {
411             deps.add(element(name("dependency"),
412                     element(name("location"), webappContext.getArtifactRetriever().resolve(dep))
413             ));
414         }
415 
416         final List<Element> props = new ArrayList<Element>();
417         for (final Map.Entry<String, String> entry : systemProperties.entrySet())
418         {
419             props.add(element(name(entry.getKey()), entry.getValue()));
420         }
421         props.add(element(name("cargo.servlet.port"), String.valueOf(actualHttpPort)));
422         props.add(element(name("cargo.rmi.port"), String.valueOf(rmiPort)));
423         props.add(element(name("cargo.jvmargs"), webappContext.getJvmArgs()));
424 
425         executeMojo(
426                 plugin(
427                         groupId("org.twdata.maven"),
428                         artifactId("cargo-maven2-plugin"),
429                         version(pluginArtifactIdToVersionMap.get("cargo-maven2-plugin"))
430                 ),
431                 goal("start"),
432                 configuration(
433                         element(name("wait"), "false"),
434                         element(name("container"),
435                                 element(name("containerId"), container.getId()),
436                                 element(name("type"), container.getType()),
437                                 element(name("home"), container.getInstallDirectory(getBuildDirectory())),
438                                 element(name("output"), webappContext.getOutput()),
439                                 element(name("systemProperties"), sysProps.toArray(new Element[sysProps.size()])),
440                                 element(name("dependencies"), deps.toArray(new Element[deps.size()]))
441                         ),
442                         element(name("configuration"),
443                                 element(name("home"), container.getConfigDirectory(getBuildDirectory(), productInstanceId)),
444                                 element(name("type"), "standalone"),
445                                 element(name("properties"), props.toArray(new Element[props.size()])),
446                                 element(name("deployables"),
447                                         element(name("deployable"),
448                                                 element(name("groupId"), "foo"),
449                                                 element(name("artifactId"), "bar"),
450                                                 element(name("type"), "war"),
451                                                 element(name("location"), war.getPath()),
452                                                 element(name("properties"),
453                                                         element(name("context"), webappContext.getContextPath())
454                                                 )
455                                         )
456                                 )
457                         )
458                 ),
459                 executionEnvironment(project, session, pluginManager)
460         );
461         return actualHttpPort;
462     }
463 
464     static String getBaseUrl(final String server, final int actualHttpPort, final String contextPath)
465     {
466         return "http://" + server + ":" + actualHttpPort + contextPath;
467     }
468 
469     public void runTests(String productId, String containerId, List<String> includes, List<String> excludes, Map<String, Object> systemProperties, final File targetDirectory)
470     		throws MojoExecutionException
471 	{
472     	List<Element> includeElements = new ArrayList<Element>(includes.size());
473     	for (String include : includes)
474     	{
475     		includeElements.add(element(name("include"), include));
476     	}
477 
478         List<Element> excludeElements = new ArrayList<Element>(excludes.size() + 2);
479         excludeElements.add(element(name("exclude"), "**/*$*"));
480         excludeElements.add(element(name("exclude"), "**/Abstract*"));
481         for (String exclude : excludes)
482         {
483         	excludeElements.add(element(name("exclude"), exclude));
484         }
485 
486         final String testOutputDir = targetDirectory.getAbsolutePath() + "/" + productId + "/" + containerId + "/surefire-reports";
487         final String reportsDirectory = "reportsDirectory";
488         systemProperties.put(reportsDirectory, testOutputDir);
489         
490         final Element systemProps = convertPropsToElements(systemProperties);
491 
492 
493         executeMojo(
494                 plugin(
495                         groupId("org.apache.maven.plugins"),
496                         artifactId("maven-surefire-plugin"),
497                         version(defaultArtifactIdToVersionMap.get("maven-surefire-plugin"))
498                 ),
499                 goal("test"),
500                 configuration(
501                         element(name("includes"),
502                         		includeElements.toArray(new Element[includeElements.size()])
503                         ),
504                         element(name("excludes"),
505                                 excludeElements.toArray(new Element[excludeElements.size()])
506                         ),
507                         systemProps,
508                         element(name(reportsDirectory), testOutputDir)
509                 ),
510                 executionEnvironment(project, session, pluginManager)
511         );
512 	}
513     
514     /**
515      * Converts a map of System properties to maven config elements
516      */
517     private Element convertPropsToElements(Map<String, Object> systemProperties)
518     {
519         ArrayList<Element> properties = new ArrayList<Element>();
520 
521         // add extra system properties... overwriting any of the hard coded values above.
522         for (Map.Entry<String, Object> entry: systemProperties.entrySet())
523         {
524             properties.add(
525                     element(name("property"),
526                             element(name("name"), entry.getKey()),
527                             element(name("value"), entry.getValue().toString())));
528         }
529 
530         return element(name("systemProperties"), properties.toArray(new Element[properties.size()]));
531     }
532 
533     private Container findContainer(final String containerId)
534     {
535         final Container container = idToContainerMap.get(containerId);
536         if (container == null)
537         {
538             throw new IllegalArgumentException("Container " + containerId + " not supported");
539         }
540         return container;
541     }
542 
543     int pickFreePort(final int requestedPort)
544     {
545         ServerSocket socket = null;
546         try
547         {
548             socket = new ServerSocket(requestedPort);
549             return requestedPort > 0 ? requestedPort : socket.getLocalPort();
550         }
551         catch (final IOException e)
552         {
553             // happens if the requested port is taken, so we need to pick a new one
554             ServerSocket zeroSocket = null;
555             try
556             {
557                 zeroSocket = new ServerSocket(0);
558                 return zeroSocket.getLocalPort();
559             }
560             catch (final IOException ex)
561             {
562                 throw new RuntimeException("Error opening socket", ex);
563             }
564             finally
565             {
566                 closeSocket(zeroSocket);
567             }
568         }
569         finally
570         {
571             closeSocket(socket);
572         }
573     }
574 
575     private void closeSocket(ServerSocket socket)
576     {
577         if (socket != null)
578         {
579             try
580             {
581                 socket.close();
582             }
583             catch (final IOException e)
584             {
585                 throw new RuntimeException("Error closing socket", e);
586             }
587         }
588     }
589 
590     public void stopWebapp(final String productId, final String containerId) throws MojoExecutionException
591     {
592         final Container container = findContainer(containerId);
593         executeMojo(
594                 plugin(
595                         groupId("org.twdata.maven"),
596                         artifactId("cargo-maven2-plugin"),
597                         version(pluginArtifactIdToVersionMap.get("cargo-maven2-plugin"))
598                 ),
599                 goal("stop"),
600                 configuration(
601                         element(name("container"),
602                                 element(name("containerId"), container.getId()),
603                                 element(name("type"), container.getType())
604                         ),
605                         element(name("configuration"),
606                                 element(name("home"), container.getConfigDirectory(getBuildDirectory(), productId))
607                         )
608                 ),
609                 executionEnvironment(project, session, pluginManager)
610         );
611     }
612 
613     public void installPlugin(PdkParams pdkParams)
614             throws MojoExecutionException
615     {
616         final String baseUrl = getBaseUrl(pdkParams.getServer(), pdkParams.getPort(), pdkParams.getContextPath());
617         executeMojo(
618                 plugin(
619                         groupId("com.atlassian.maven.plugins"),
620                         artifactId("atlassian-pdk"),
621                         version(pluginArtifactIdToVersionMap.get("atlassian-pdk"))
622                 ),
623                 goal("install"),
624                 configuration(
625                         element(name("pluginFile"), pdkParams.getPluginFile()),
626                         element(name("username"), pdkParams.getUsername()),
627                         element(name("password"), pdkParams.getPassword()),
628                         element(name("serverUrl"), baseUrl),
629                         element(name("pluginKey"), pdkParams.getPluginKey())
630                 ),
631                 executionEnvironment(project, session, pluginManager)
632         );
633     }
634 
635     public void uninstallPlugin(final String pluginKey, final String server, final int port, final String contextPath)
636             throws MojoExecutionException
637     {
638         final String baseUrl = getBaseUrl(server, port, contextPath);
639         executeMojo(
640                 plugin(
641                         groupId("com.atlassian.maven.plugins"),
642                         artifactId("atlassian-pdk"),
643                         version(pluginArtifactIdToVersionMap.get("atlassian-pdk"))
644                 ),
645                 goal("uninstall"),
646                 configuration(
647                         element(name("username"), "admin"),
648                         element(name("password"), "admin"),
649                         element(name("serverUrl"), baseUrl),
650                         element(name("pluginKey"), pluginKey)
651                 ),
652                 executionEnvironment(project, session, pluginManager)
653         );
654     }
655 
656     public void installIdeaPlugin() throws MojoExecutionException
657     {
658         executeMojo(
659                 plugin(
660                         groupId("org.twdata.maven"),
661                         artifactId("maven-cli-plugin"),
662                         version(pluginArtifactIdToVersionMap.get("maven-cli-plugin"))
663                 ),
664                 goal("idea"),
665                 configuration(),
666                 executionEnvironment(project, session, pluginManager)
667         );
668     }
669 
670     public File copyDist(final File targetDirectory, final ProductArtifact artifact) throws MojoExecutionException
671     {
672         return copyZip(targetDirectory, artifact, "test-dist.zip");
673     }
674 
675     public File copyHome(final File targetDirectory, final ProductArtifact artifact) throws MojoExecutionException
676     {
677         return copyZip(targetDirectory, artifact, "test-resources.zip");
678     }
679 
680     public File copyZip(final File targetDirectory, final ProductArtifact artifact, final String localName) throws MojoExecutionException
681     {
682         final File artifactZip = new File(targetDirectory, localName);
683         executeMojo(
684                 plugin(
685                         groupId("org.apache.maven.plugins"),
686                         artifactId("maven-dependency-plugin"),
687                         version(defaultArtifactIdToVersionMap.get("maven-dependency-plugin"))
688                 ),
689                 goal("copy"),
690                 configuration(
691                         element(name("artifactItems"),
692                                 element(name("artifactItem"),
693                                         element(name("groupId"), artifact.getGroupId()),
694                                         element(name("artifactId"), artifact.getArtifactId()),
695                                         element(name("type"), "zip"),
696                                         element(name("version"), artifact.getVersion()),
697                                         element(name("destFileName"), artifactZip.getName()))),
698                         element(name("outputDirectory"), artifactZip.getParent())
699                 ),
700                 executionEnvironment(project, session, pluginManager)
701         );
702         return artifactZip;
703     }
704 
705     public void generateManifest(final Map<String, String> instructions) throws MojoExecutionException
706     {
707         final List<Element> instlist = new ArrayList<Element>();
708         for (final Map.Entry<String, String> entry : instructions.entrySet())
709         {
710             instlist.add(element(entry.getKey(), entry.getValue()));
711         }
712         executeMojo(
713                 plugin(
714                         groupId("org.apache.felix"),
715                         artifactId("maven-bundle-plugin"),
716                         version(defaultArtifactIdToVersionMap.get("maven-bundle-plugin"))
717                 ),
718                 goal("manifest"),
719                 configuration(
720                         element(name("supportedProjectTypes"),
721                                 element(name("supportedProjectType"), "jar"),
722                                 element(name("supportedProjectType"), "bundle"),
723                                 element(name("supportedProjectType"), "war"),
724                                 element(name("supportedProjectType"), "atlassian-plugin")),
725                         element(name("instructions"), instlist.toArray(new Element[instlist.size()]))
726                 ),
727                 executionEnvironment(project, session, pluginManager)
728         );
729     }
730 
731     public void jarWithOptionalManifest(final boolean manifestExists) throws MojoExecutionException
732     {
733         Element[] archive = new Element[0];
734         if (manifestExists)
735         {
736             archive = new Element[]{element(name("manifestFile"), "${project.build.outputDirectory}/META-INF/MANIFEST.MF")};
737         }
738 
739         executeMojo(
740                 plugin(
741                         groupId("org.apache.maven.plugins"),
742                         artifactId("maven-jar-plugin"),
743                         version(defaultArtifactIdToVersionMap.get("maven-jar-plugin"))
744                 ),
745                 goal("jar"),
746                 configuration(
747                         element(name("archive"), archive)
748                 ),
749                 executionEnvironment(project, session, pluginManager)
750         );
751     }
752 
753     public void jarTests(String finalName) throws MojoExecutionException
754     {
755         executeMojo(
756                 plugin(
757                         groupId("org.apache.maven.plugins"),
758                         artifactId("maven-jar-plugin"),
759                         version(defaultArtifactIdToVersionMap.get("maven-jar-plugin"))
760                 ),
761                 goal("test-jar"),
762                 configuration(
763                         element(name("finalName"), finalName),
764                         element(name("archive"),
765                             element(name("manifestFile"), "${project.build.testOutputDirectory}/META-INF/MANIFEST.MF"))
766                 ),
767                 executionEnvironment(project, session, pluginManager)
768         );
769     }
770 
771     public void generateObrXml(File dep, File obrXml) throws MojoExecutionException
772     {
773         executeMojo(
774                 plugin(
775                         groupId("org.apache.felix"),
776                         artifactId("maven-bundle-plugin"),
777                         version(defaultArtifactIdToVersionMap.get("maven-bundle-plugin"))
778                 ),
779                 goal("install-file"),
780                 configuration(
781                         element(name("obrRepository"), obrXml.getPath()),
782 
783                         // the following three settings are required but not really used
784                         element(name("groupId"), "doesntmatter"),
785                         element(name("artifactId"), "doesntmatter"),
786                         element(name("version"), "doesntmatter"),
787 
788                         element(name("packaging"), "jar"),
789                         element(name("file"), dep.getPath())
790 
791                 ),
792                 executionEnvironment(project, session, pluginManager)
793         );
794     }
795 
796     /**
797      * Copies and creates a zip file of the previous run's home directory minus any installed plugins.
798      *
799      * @param homeDirectory The path to the previous run's home directory.
800      * @param targetZip     The path to the final zip file.
801      * @param productId     The name of the product.
802      *
803      * @since 3.1-m3
804      */
805     public void createHomeResourcesZip(final File homeDirectory, final File targetZip, final String productId)
806     {
807         if (homeDirectory == null || !homeDirectory.exists())
808         {
809             String homePath = "null";
810             if(homeDirectory != null) {
811                 homePath = homeDirectory.getAbsolutePath();
812             }
813             log.info("home directory doesn't exist, skipping. [" + homePath + "]");
814             return;
815         }
816 
817         final File appDir = new File(project.getBuild().getDirectory(), productId);
818         final File tmpDir = new File(appDir, "tmp-resources");
819         final File genDir = new File(tmpDir, "generated-home");
820         final String entryBase = "generated-resources/" + productId + "-home";
821 
822         if (genDir.exists())
823         {
824             FileUtils.deleteDir(genDir);
825         }
826 
827         genDir.mkdirs();
828 
829         try
830         {
831             FileUtils.copyDirectory(homeDirectory, genDir, true);
832 
833             //we want to get rid of the plugins folders.
834             File homePlugins = new File(genDir, "plugins");
835             File bundledPlugins = new File(genDir, "bundled-plugins");
836 
837             if (homePlugins.exists())
838             {
839                 FileUtils.deleteDir(homePlugins);
840             }
841 
842             if (bundledPlugins.exists())
843             {
844                 FileUtils.deleteDir(bundledPlugins);
845             }
846 
847             ZipUtils.zipDir(targetZip, genDir, entryBase);
848         } catch (IOException e)
849         {
850             throw new RuntimeException("Error zipping home directory", e);
851         }
852 
853 
854     }
855 
856     private static class Container extends ProductArtifact
857     {
858         private final String id;
859         private final String type;
860 
861         /**
862          * Installable container that can be downloaded by Maven.
863          *
864          * @param id         identifier of container, eg. "tomcat5x".
865          * @param groupId    groupId of container.
866          * @param artifactId artifactId of container.
867          * @param version    version number of container.
868          */
869         public Container(final String id, final String groupId, final String artifactId, final String version)
870         {
871             super(groupId, artifactId, version);
872             this.id = id;
873             this.type = "installed";
874         }
875 
876         /**
877          * Embedded container packaged with Cargo.
878          *
879          * @param id identifier of container, eg. "jetty6x".
880          */
881         public Container(final String id)
882         {
883             this.id = id;
884             this.type = "embedded";
885         }
886 
887         /**
888          * @return identifier of container.
889          */
890         public String getId()
891         {
892             return id;
893         }
894 
895         /**
896          * @return "installed" or "embedded".
897          */
898         public String getType()
899         {
900             return type;
901         }
902 
903         /**
904          * @return <code>true</code> if the container type is "embedded".
905          */
906         public boolean isEmbedded()
907         {
908             return "embedded".equals(type);
909         }
910 
911         /**
912          * @param buildDir project.build.directory.
913          * @return root directory of the container that will house the container installation and configuration.
914          */
915         public String getRootDirectory(String buildDir)
916         {
917             return buildDir + File.separator + "container" + File.separator + getId();
918         }
919 
920         /**
921          * @param buildDir project.build.directory.
922          * @return directory housing the installed container.
923          */
924         public String getInstallDirectory(String buildDir)
925         {
926             return getRootDirectory(buildDir) + File.separator + getArtifactId() + "-" + getVersion();
927         }
928 
929         /**
930          * @param buildDir  project.build.directory.
931          * @param productId product name.
932          * @return directory to house the container configuration for the specified product.
933          */
934         public String getConfigDirectory(String buildDir, String productId)
935         {
936             return getRootDirectory(buildDir) + File.separator + "cargo-" + productId + "-home";
937         }
938     }
939 }