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