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