1 package com.atlassian.maven.plugins.amps;
2
3 import java.io.File;
4 import java.io.FileOutputStream;
5 import java.io.IOException;
6 import java.net.ServerSocket;
7 import java.net.URL;
8 import java.net.URLClassLoader;
9 import java.util.*;
10 import java.util.jar.Manifest;
11 import java.util.regex.Matcher;
12
13 import com.atlassian.core.util.FileUtils;
14 import com.atlassian.maven.plugins.amps.util.PluginXmlUtils;
15 import com.atlassian.maven.plugins.amps.util.VersionUtils;
16
17 import com.sun.jersey.wadl.resourcedoc.ResourceDocletJSON;
18
19 import org.apache.commons.io.IOUtils;
20 import org.apache.commons.lang.StringUtils;
21 import org.apache.maven.artifact.DependencyResolutionRequiredException;
22 import org.apache.maven.model.Plugin;
23 import org.apache.maven.plugin.MojoExecutionException;
24 import org.apache.maven.plugin.logging.Log;
25 import org.apache.maven.project.MavenProject;
26 import org.codehaus.plexus.util.xml.Xpp3Dom;
27 import org.twdata.maven.mojoexecutor.MojoExecutor.Element;
28 import org.twdata.maven.mojoexecutor.MojoExecutor.ExecutionEnvironment;
29
30 import static com.atlassian.maven.plugins.amps.util.FileUtils.fixWindowsSlashes;
31 import static com.atlassian.maven.plugins.amps.util.FileUtils.file;
32 import static org.twdata.maven.mojoexecutor.MojoExecutor.artifactId;
33 import static org.twdata.maven.mojoexecutor.MojoExecutor.configuration;
34 import static org.twdata.maven.mojoexecutor.MojoExecutor.element;
35 import static org.twdata.maven.mojoexecutor.MojoExecutor.executeMojo;
36 import static org.twdata.maven.mojoexecutor.MojoExecutor.goal;
37 import static org.twdata.maven.mojoexecutor.MojoExecutor.groupId;
38 import static org.twdata.maven.mojoexecutor.MojoExecutor.name;
39 import static org.twdata.maven.mojoexecutor.MojoExecutor.plugin;
40 import static org.twdata.maven.mojoexecutor.MojoExecutor.version;
41
42
43
44
45 public class MavenGoals
46 {
47 private final MavenContext ctx;
48
49 private final Log log;
50 private final Map<String, String> pluginArtifactIdToVersionMap;
51
52 private final Map<String, Container> idToContainerMap = new HashMap<String, Container>()
53 {{
54 put("tomcat5x", new Container("tomcat5x", "org.apache.tomcat", "apache-tomcat", "5.5.26"));
55 put("tomcat6x", new Container("tomcat6x", "org.apache.tomcat", "apache-tomcat", "6.0.20"));
56 put("resin3x", new Container("resin3x", "com.caucho", "resin", "3.0.26"));
57 put("jboss42x", new Container("jboss42x", "org.jboss.jbossas", "jbossas", "4.2.3.GA"));
58 put("jetty6x", new Container("jetty6x"));
59 }};
60
61 private final Map<String, String> defaultArtifactIdToVersionMap = new HashMap<String, String>()
62 {{
63 put("maven-cli-plugin", "0.7");
64 put("cargo-maven2-plugin", "1.0-beta-2-db2");
65
66 put("org.codehaus.cargo:cargo-maven2-plugin", "1.1.3");
67 put("atlassian-pdk", "2.3.1");
68 put("maven-archetype-plugin", "2.0-alpha-4");
69 put("maven-bundle-plugin", "2.0.0");
70 put("yuicompressor-maven-plugin", "0.7.1");
71 put("build-helper-maven-plugin", "1.7");
72
73
74
75 put("maven-dependency-plugin", "2.0");
76 put("maven-resources-plugin", "2.3");
77 put("maven-jar-plugin", "2.2");
78 put("maven-surefire-plugin", "2.4.3");
79
80 }};
81
82 public MavenGoals(final MavenContext ctx)
83 {
84 this.ctx = ctx;
85
86 this.log = ctx.getLog();
87
88 this.pluginArtifactIdToVersionMap = Collections.unmodifiableMap(defaultArtifactIdToVersionMap);
89 }
90
91 private ExecutionEnvironment executionEnvironment()
92 {
93 return ctx.getExecutionEnvironment();
94 }
95
96 public MavenProject getContextProject()
97 {
98 return ctx.getProject();
99 }
100
101 public void executeAmpsRecursively(final String ampsVersion, final String ampsGoal, Xpp3Dom cfg) throws MojoExecutionException
102 {
103 executeMojo(
104 plugin(
105 groupId("com.atlassian.maven.plugins"),
106 artifactId("maven-amps-plugin"),
107 version(ampsVersion)
108 ),
109 goal(ampsGoal),
110 cfg,
111 executionEnvironment());
112 }
113
114 public void startCli(final PluginInformation pluginInformation, final int port) throws MojoExecutionException
115 {
116 final String pluginId = pluginInformation.getId();
117
118 final List<Element> configs = new ArrayList<Element>();
119 configs.add(element(name("commands"),
120 element(name("pi"),
121 "resources" + " "
122 + "com.atlassian.maven.plugins:maven-" + pluginId + "-plugin:filter-plugin-descriptor" + " "
123 + "compile" + " "
124 + "com.atlassian.maven.plugins:maven-" + pluginId + "-plugin:copy-bundled-dependencies" + " "
125 + "com.atlassian.maven.plugins:maven-" + pluginId + "-plugin:compress-resources" + " "
126 + "com.atlassian.maven.plugins:maven-" + pluginId + "-plugin:generate-manifest" + " "
127 + "com.atlassian.maven.plugins:maven-" + pluginId + "-plugin:validate-manifest" + " "
128 + "com.atlassian.maven.plugins:maven-" + pluginId + "-plugin:jar" + " "
129 + "com.atlassian.maven.plugins:maven-" + pluginId + "-plugin:install"),
130 element(name("tpi"),
131 "testResources" + " "
132 + "testCompile" + " "
133 + "com.atlassian.maven.plugins:maven-" + pluginId + "-plugin:test-jar" + " "
134 + "com.atlassian.maven.plugins:maven-" + pluginId + "-plugin:test-install"),
135 element(name("package"),
136 "resources" + " "
137 + "com.atlassian.maven.plugins:maven-" + pluginId + "-plugin:filter-plugin-descriptor" + " "
138 + "compile" + " "
139 + "com.atlassian.maven.plugins:maven-" + pluginId + "-plugin:copy-bundled-dependencies" + " "
140 + "com.atlassian.maven.plugins:maven-" + pluginId + "-plugin:generate-manifest" + " "
141 + "com.atlassian.maven.plugins:maven-" + pluginId + "-plugin:jar" + " ")));
142 if (port > 0)
143 {
144 configs.add(element(name("port"), String.valueOf(port)));
145 }
146 executeMojo(
147 plugin(
148 groupId("org.twdata.maven"),
149 artifactId("maven-cli-plugin"),
150 version(pluginArtifactIdToVersionMap.get("maven-cli-plugin"))
151 ),
152 goal("execute"),
153 configuration(configs.toArray(new Element[0])),
154 executionEnvironment());
155 }
156
157 public void createPlugin(final String productId) throws MojoExecutionException
158 {
159 executeMojo(
160 plugin(
161 groupId("org.apache.maven.plugins"),
162 artifactId("maven-archetype-plugin"),
163 version(defaultArtifactIdToVersionMap.get("maven-archetype-plugin"))
164 ),
165 goal("generate"),
166 configuration(
167 element(name("archetypeGroupId"), "com.atlassian.maven.archetypes"),
168 element(name("archetypeArtifactId"), (productId.equals("all") ? "" : productId + "-" ) + "plugin-archetype"),
169 element(name("archetypeVersion"), VersionUtils.getVersion())
170 ),
171 executionEnvironment());
172 }
173
174 public void copyBundledDependencies() throws MojoExecutionException
175 {
176 executeMojo(
177 plugin(
178 groupId("org.apache.maven.plugins"),
179 artifactId("maven-dependency-plugin"),
180 version(defaultArtifactIdToVersionMap.get("maven-dependency-plugin"))
181 ),
182 goal("copy-dependencies"),
183 configuration(
184 element(name("includeScope"), "runtime"),
185 element(name("excludeScope"), "provided"),
186 element(name("excludeScope"), "test"),
187 element(name("includeTypes"), "jar"),
188 element(name("outputDirectory"), "${project.build.outputDirectory}/META-INF/lib")
189 ),
190 executionEnvironment()
191 );
192 }
193
194 public void extractBundledDependencies() throws MojoExecutionException
195 {
196 executeMojo(
197 plugin(
198 groupId("org.apache.maven.plugins"),
199 artifactId("maven-dependency-plugin"),
200 version(defaultArtifactIdToVersionMap.get("maven-dependency-plugin"))
201 ),
202 goal("unpack-dependencies"),
203 configuration(
204 element(name("includeScope"), "runtime"),
205 element(name("excludeScope"), "provided"),
206 element(name("excludeScope"), "test"),
207 element(name("includeTypes"), "jar"),
208 element(name("excludes"), "META-INF/MANIFEST.MF, META-INF/*.DSA, META-INF/*.SF"),
209 element(name("outputDirectory"), "${project.build.outputDirectory}")
210 ),
211 executionEnvironment()
212 );
213 }
214
215 public void compressResources() throws MojoExecutionException
216 {
217 executeMojo(
218 plugin(
219 groupId("net.sf.alchim"),
220 artifactId("yuicompressor-maven-plugin"),
221 version(defaultArtifactIdToVersionMap.get("yuicompressor-maven-plugin"))
222 ),
223 goal("compress"),
224 configuration(
225 element(name("suffix"), "-min"),
226 element(name("jswarn"), "false")
227 ),
228 executionEnvironment()
229 );
230 }
231
232 public void filterPluginDescriptor() throws MojoExecutionException
233 {
234 executeMojo(
235 plugin(
236 groupId("org.apache.maven.plugins"),
237 artifactId("maven-resources-plugin"),
238 version(defaultArtifactIdToVersionMap.get("maven-resources-plugin"))
239 ),
240 goal("copy-resources"),
241 configuration(
242 element(name("encoding"), "UTF-8"),
243 element(name("resources"),
244 element(name("resource"),
245 element(name("directory"), "src/main/resources"),
246 element(name("filtering"), "true"),
247 element(name("includes"),
248 element(name("include"), "atlassian-plugin.xml"))
249 )
250 ),
251 element(name("outputDirectory"), "${project.build.outputDirectory}")
252 ),
253 executionEnvironment()
254 );
255 }
256
257 public void runUnitTests(Map<String, Object> systemProperties) throws MojoExecutionException
258 {
259 final Element systemProps = convertPropsToElements(systemProperties);
260
261 executeMojo(
262 plugin(
263 groupId("org.apache.maven.plugins"),
264 artifactId("maven-surefire-plugin"),
265 version(defaultArtifactIdToVersionMap.get("maven-surefire-plugin"))
266 ),
267 goal("test"),
268 configuration(
269 systemProps,
270 element(name("excludes"),
271 element(name("exclude"), "it/**"),
272 element(name("exclude"), "**/*$*"))
273 ),
274 executionEnvironment()
275 );
276 }
277
278 public File copyWebappWar(final String productId, final File targetDirectory, final ProductArtifact artifact)
279 throws MojoExecutionException
280 {
281 final File webappWarFile = new File(targetDirectory, productId + "-original.war");
282 executeMojo(
283 plugin(
284 groupId("org.apache.maven.plugins"),
285 artifactId("maven-dependency-plugin"),
286 version(defaultArtifactIdToVersionMap.get("maven-dependency-plugin"))
287 ),
288 goal("copy"),
289 configuration(
290 element(name("artifactItems"),
291 element(name("artifactItem"),
292 element(name("groupId"), artifact.getGroupId()),
293 element(name("artifactId"), artifact.getArtifactId()),
294 element(name("type"), "war"),
295 element(name("version"), artifact.getVersion()),
296 element(name("destFileName"), webappWarFile.getName()))),
297 element(name("outputDirectory"), targetDirectory.getPath())
298 ),
299 executionEnvironment()
300 );
301 return webappWarFile;
302 }
303
304 public File copyArtifact(final String targetFileName, final File targetDirectory,
305 final ProductArtifact artifact, String type) throws MojoExecutionException
306 {
307 final File targetFile = new File(targetDirectory, targetFileName);
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("type"), type),
321 element(name("version"), artifact.getVersion()),
322 element(name("destFileName"), targetFile.getName()))),
323 element(name("outputDirectory"), targetDirectory.getPath())
324 ),
325 executionEnvironment()
326 );
327 return targetFile;
328 }
329
330
331
332
333
334
335
336
337
338
339 public void copyPlugins(final File outputDirectory, final List<ProductArtifact> artifacts)
340 throws MojoExecutionException
341 {
342 for (ProductArtifact artifact : artifacts)
343 {
344 final MavenProject artifactReactorProject = getReactorProjectForArtifact(artifact);
345 if (artifactReactorProject != null)
346 {
347
348 log.debug(artifact + " will be copied from reactor project " + artifactReactorProject);
349 final File artifactFile = artifactReactorProject.getArtifact().getFile();
350 if (artifactFile == null)
351 {
352 log.warn("The plugin " + artifact + " is in the reactor but not the file hasn't been attached. Skipping.");
353 }
354 else
355 {
356 log.debug("Copying " + artifactFile + " to " + outputDirectory);
357 try
358 {
359 FileUtils.copyFile(artifactFile, new File(outputDirectory, artifactFile.getName()));
360 }
361 catch (IOException e)
362 {
363 throw new MojoExecutionException("Could not copy " + artifact + " to " + outputDirectory, e);
364 }
365 }
366
367 }
368 else
369 {
370 executeMojo(
371 plugin(
372 groupId("org.apache.maven.plugins"),
373 artifactId("maven-dependency-plugin"),
374 version(defaultArtifactIdToVersionMap.get("maven-dependency-plugin"))
375 ),
376 goal("copy"),
377 configuration(
378 element(name("artifactItems"),
379 element(name("artifactItem"),
380 element(name("groupId"), artifact.getGroupId()),
381 element(name("artifactId"), artifact.getArtifactId()),
382 element(name("version"), artifact.getVersion()))),
383 element(name("outputDirectory"), outputDirectory.getPath())
384 ),
385 executionEnvironment());
386 }
387 }
388 }
389
390 private MavenProject getReactorProjectForArtifact(ProductArtifact artifact)
391 {
392 for (final MavenProject project : ctx.getReactor())
393 {
394 if (project.getGroupId().equals(artifact.getGroupId())
395 && project.getArtifactId().equals(artifact.getArtifactId())
396 && project.getVersion().equals(artifact.getVersion()))
397 {
398 return project;
399 }
400 }
401 return null;
402 }
403
404 private void unpackContainer(final Container container) throws MojoExecutionException
405 {
406 executeMojo(
407 plugin(
408 groupId("org.apache.maven.plugins"),
409 artifactId("maven-dependency-plugin"),
410 version(defaultArtifactIdToVersionMap.get("maven-dependency-plugin"))
411 ),
412 goal("unpack"),
413 configuration(
414 element(name("artifactItems"),
415 element(name("artifactItem"),
416 element(name("groupId"), container.getGroupId()),
417 element(name("artifactId"), container.getArtifactId()),
418 element(name("version"), container.getVersion()),
419 element(name("type"), "zip"))),
420 element(name("outputDirectory"), container.getRootDirectory(getBuildDirectory()))
421 ),
422 executionEnvironment());
423 }
424
425 private String getBuildDirectory()
426 {
427 return ctx.getProject().getBuild().getDirectory();
428 }
429
430 public int startWebapp(final String productInstanceId, final File war, final Map<String, String> systemProperties, final List<ProductArtifact> extraContainerDependencies,
431 final Product webappContext) throws MojoExecutionException
432 {
433 final Container container = findContainer(webappContext.getContainerId());
434 File containerDir = new File(container.getRootDirectory(getBuildDirectory()));
435
436
437 if (!container.isEmbedded())
438 {
439 if (containerDir.exists())
440 {
441 log.info("Reusing unpacked container '" + container.getId() + "' from " + containerDir.getPath());
442 }
443 else
444 {
445 log.info("Unpacking container '" + container.getId() + "' from container artifact: " + container.toString());
446 unpackContainer(container);
447 }
448 }
449
450 final int rmiPort = pickFreePort(0);
451 final int actualHttpPort = pickFreePort(webappContext.getHttpPort());
452 final List<Element> sysProps = new ArrayList<Element>();
453
454 for (final Map.Entry<String, String> entry : systemProperties.entrySet())
455 {
456 sysProps.add(element(name(entry.getKey()), entry.getValue()));
457 }
458 log.info("Starting " + productInstanceId + " on the " + container.getId() + " container on ports "
459 + actualHttpPort + " (http) and " + rmiPort + " (rmi)");
460
461 final String baseUrl = getBaseUrl(webappContext.getServer(), actualHttpPort, webappContext.getContextPath());
462 sysProps.add(element(name("baseurl"), baseUrl));
463
464 final List<Element> deps = new ArrayList<Element>();
465 for (final ProductArtifact dep : extraContainerDependencies)
466 {
467 deps.add(element(name("dependency"),
468 element(name("location"), webappContext.getArtifactRetriever().resolve(dep))
469 ));
470 }
471
472 final List<Element> props = new ArrayList<Element>();
473 for (final Map.Entry<String, String> entry : systemProperties.entrySet())
474 {
475 props.add(element(name(entry.getKey()), entry.getValue()));
476 }
477 props.add(element(name("cargo.servlet.port"), String.valueOf(actualHttpPort)));
478 props.add(element(name("cargo.rmi.port"), String.valueOf(rmiPort)));
479 props.add(element(name("cargo.jvmargs"), webappContext.getJvmArgs()));
480
481 int startupTimeout = webappContext.getStartupTimeout();
482 if (Boolean.FALSE.equals(webappContext.getSynchronousStartup()))
483 {
484 startupTimeout = 0;
485 }
486
487 executeMojo(
488 cargo(webappContext),
489 goal("start"),
490 configuration(
491 element(name("wait"), "false"),
492 element(name("container"),
493 element(name("containerId"), container.getId()),
494 element(name("type"), container.getType()),
495 element(name("home"), container.getInstallDirectory(getBuildDirectory())),
496 element(name("output"), webappContext.getOutput()),
497 element(name("systemProperties"), sysProps.toArray(new Element[sysProps.size()])),
498 element(name("dependencies"), deps.toArray(new Element[deps.size()])),
499 element(name("timeout"), String.valueOf(startupTimeout))
500 ),
501 element(name("configuration"),
502 element(name("home"), container.getConfigDirectory(getBuildDirectory(), productInstanceId)),
503 element(name("type"), "standalone"),
504 element(name("properties"), props.toArray(new Element[props.size()])),
505 element(name("deployables"),
506 element(name("deployable"),
507 element(name("groupId"), "foo"),
508 element(name("artifactId"), "bar"),
509 element(name("type"), "war"),
510 element(name("location"), war.getPath()),
511 element(name("properties"),
512 element(name("context"), webappContext.getContextPath())
513 )
514 )
515 )
516 )
517 ),
518 executionEnvironment()
519 );
520 return actualHttpPort;
521 }
522
523 public void stopWebapp(final String productId, final String containerId, final Product webappContext) throws MojoExecutionException
524 {
525 final Container container = findContainer(containerId);
526
527 String actualShutdownTimeout = webappContext.getSynchronousStartup() ? "0" : String.valueOf(webappContext.getShutdownTimeout());
528
529 executeMojo(
530 cargo(webappContext),
531 goal("stop"),
532 configuration(
533 element(name("container"),
534 element(name("containerId"), container.getId()),
535 element(name("type"), container.getType()),
536 element(name("timeout"), actualShutdownTimeout),
537
538 element(name("home"), container.getInstallDirectory(getBuildDirectory()))
539 ),
540 element(name("configuration"),
541
542 element(name("home"), container.getConfigDirectory(getBuildDirectory(), productId))
543
544
545 )
546 ),
547 executionEnvironment()
548 );
549 }
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568 private Element[] createShutdownPortsPropertiesConfiguration(final Product webappContext)
569 {
570 final List<Element> properties = new ArrayList<Element>();
571 String portUsedToDetermineIfShutdownSucceeded = String.valueOf(webappContext.getHttpPort());
572 properties.add(element(name("cargo.servlet.port"), portUsedToDetermineIfShutdownSucceeded));
573 properties.add(element(name("cargo.rmi.port"), portUsedToDetermineIfShutdownSucceeded));
574 properties.add(element(name("cargo.tomcat.ajp.port"), portUsedToDetermineIfShutdownSucceeded));
575 return properties.toArray(new Element[properties.size()]);
576 }
577
578
579
580
581
582
583
584
585
586
587
588 private Plugin cargo(Product webappContext)
589 {
590 if (Boolean.TRUE.equals(webappContext.getSynchronousStartup()))
591 {
592 return plugin(
593 groupId("org.twdata.maven"),
594 artifactId("cargo-maven2-plugin"),
595 version(pluginArtifactIdToVersionMap.get("cargo-maven2-plugin")));
596 }
597 else
598 {
599 return plugin(
600 groupId("org.codehaus.cargo"),
601 artifactId("cargo-maven2-plugin"),
602 version(pluginArtifactIdToVersionMap.get("org.codehaus.cargo:cargo-maven2-plugin")));
603 }
604 }
605
606 public static String getBaseUrl(final String server, final int actualHttpPort, final String contextPath)
607 {
608 String port = actualHttpPort != 80 ? ":" + actualHttpPort : "";
609 if (server.startsWith("http")) {
610 return server + port + contextPath;
611 } else {
612 return "http://" + server + port + contextPath;
613 }
614 }
615
616 public void runTests(String testGroupId, String containerId, List<String> includes, List<String> excludes, Map<String, Object> systemProperties, final File targetDirectory)
617 throws MojoExecutionException
618 {
619 List<Element> includeElements = new ArrayList<Element>(includes.size());
620 for (String include : includes)
621 {
622 includeElements.add(element(name("include"), include));
623 }
624
625 List<Element> excludeElements = new ArrayList<Element>(excludes.size() + 2);
626 excludeElements.add(element(name("exclude"), "**/*$*"));
627 excludeElements.add(element(name("exclude"), "**/Abstract*"));
628 for (String exclude : excludes)
629 {
630 excludeElements.add(element(name("exclude"), exclude));
631 }
632
633 final String testOutputDir = targetDirectory.getAbsolutePath() + "/" + testGroupId + "/" + containerId + "/surefire-reports";
634 final String reportsDirectory = "reportsDirectory";
635 systemProperties.put(reportsDirectory, testOutputDir);
636
637 final Element systemProps = convertPropsToElements(systemProperties);
638
639
640 executeMojo(
641 plugin(
642 groupId("org.apache.maven.plugins"),
643 artifactId("maven-surefire-plugin"),
644 version(defaultArtifactIdToVersionMap.get("maven-surefire-plugin"))
645 ),
646 goal("test"),
647 configuration(
648 element(name("includes"),
649 includeElements.toArray(new Element[includeElements.size()])
650 ),
651 element(name("excludes"),
652 excludeElements.toArray(new Element[excludeElements.size()])
653 ),
654 systemProps,
655 element(name(reportsDirectory), testOutputDir)
656 ),
657 executionEnvironment()
658 );
659 }
660
661
662
663
664 private Element convertPropsToElements(Map<String, Object> systemProperties)
665 {
666 ArrayList<Element> properties = new ArrayList<Element>();
667
668
669 for (Map.Entry<String, Object> entry: systemProperties.entrySet())
670 {
671 properties.add(
672 element(name("property"),
673 element(name("name"), entry.getKey()),
674 element(name("value"), entry.getValue().toString())));
675 }
676
677 return element(name("systemProperties"), properties.toArray(new Element[properties.size()]));
678 }
679
680 private Container findContainer(final String containerId)
681 {
682 final Container container = idToContainerMap.get(containerId);
683 if (container == null)
684 {
685 throw new IllegalArgumentException("Container " + containerId + " not supported");
686 }
687 return container;
688 }
689
690 int pickFreePort(final int requestedPort)
691 {
692 ServerSocket socket = null;
693 try
694 {
695 socket = new ServerSocket(requestedPort);
696 return requestedPort > 0 ? requestedPort : socket.getLocalPort();
697 }
698 catch (final IOException e)
699 {
700
701 ServerSocket zeroSocket = null;
702 try
703 {
704 zeroSocket = new ServerSocket(0);
705 return zeroSocket.getLocalPort();
706 }
707 catch (final IOException ex)
708 {
709 throw new RuntimeException("Error opening socket", ex);
710 }
711 finally
712 {
713 closeSocket(zeroSocket);
714 }
715 }
716 finally
717 {
718 closeSocket(socket);
719 }
720 }
721
722 private void closeSocket(ServerSocket socket)
723 {
724 if (socket != null)
725 {
726 try
727 {
728 socket.close();
729 }
730 catch (final IOException e)
731 {
732 throw new RuntimeException("Error closing socket", e);
733 }
734 }
735 }
736
737 public void installPlugin(PdkParams pdkParams)
738 throws MojoExecutionException
739 {
740 final String baseUrl = getBaseUrl(pdkParams.getServer(), pdkParams.getPort(), pdkParams.getContextPath());
741 executeMojo(
742 plugin(
743 groupId("com.atlassian.maven.plugins"),
744 artifactId("atlassian-pdk"),
745 version(pluginArtifactIdToVersionMap.get("atlassian-pdk"))
746 ),
747 goal("install"),
748 configuration(
749 element(name("pluginFile"), pdkParams.getPluginFile()),
750 element(name("username"), pdkParams.getUsername()),
751 element(name("password"), pdkParams.getPassword()),
752 element(name("serverUrl"), baseUrl),
753 element(name("pluginKey"), pdkParams.getPluginKey())
754 ),
755 executionEnvironment()
756 );
757 }
758
759 public void uninstallPlugin(final String pluginKey, final String server, final int port, final String contextPath)
760 throws MojoExecutionException
761 {
762 final String baseUrl = getBaseUrl(server, port, contextPath);
763 executeMojo(
764 plugin(
765 groupId("com.atlassian.maven.plugins"),
766 artifactId("atlassian-pdk"),
767 version(pluginArtifactIdToVersionMap.get("atlassian-pdk"))
768 ),
769 goal("uninstall"),
770 configuration(
771 element(name("username"), "admin"),
772 element(name("password"), "admin"),
773 element(name("serverUrl"), baseUrl),
774 element(name("pluginKey"), pluginKey)
775 ),
776 executionEnvironment()
777 );
778 }
779
780 public void installIdeaPlugin() throws MojoExecutionException
781 {
782 executeMojo(
783 plugin(
784 groupId("org.twdata.maven"),
785 artifactId("maven-cli-plugin"),
786 version(pluginArtifactIdToVersionMap.get("maven-cli-plugin"))
787 ),
788 goal("idea"),
789 configuration(),
790 executionEnvironment()
791 );
792 }
793
794 public File copyDist(final File targetDirectory, final ProductArtifact artifact) throws MojoExecutionException
795 {
796 return copyZip(targetDirectory, artifact, "test-dist.zip");
797 }
798
799 public File copyHome(final File targetDirectory, final ProductArtifact artifact) throws MojoExecutionException
800 {
801 return copyZip(targetDirectory, artifact, artifact.getArtifactId() + ".zip");
802 }
803
804 public File copyZip(final File targetDirectory, final ProductArtifact artifact, final String localName) throws MojoExecutionException
805 {
806 final File artifactZip = new File(targetDirectory, localName);
807 executeMojo(
808 plugin(
809 groupId("org.apache.maven.plugins"),
810 artifactId("maven-dependency-plugin"),
811 version(defaultArtifactIdToVersionMap.get("maven-dependency-plugin"))
812 ),
813 goal("copy"),
814 configuration(
815 element(name("artifactItems"),
816 element(name("artifactItem"),
817 element(name("groupId"), artifact.getGroupId()),
818 element(name("artifactId"), artifact.getArtifactId()),
819 element(name("type"), "zip"),
820 element(name("version"), artifact.getVersion()),
821 element(name("destFileName"), artifactZip.getName()))),
822 element(name("outputDirectory"), artifactZip.getParent())
823 ),
824 executionEnvironment()
825 );
826 return artifactZip;
827 }
828
829 public void generateBundleManifest(final Map<String, String> instructions, final Map<String, String> basicAttributes) throws MojoExecutionException
830 {
831 final List<Element> instlist = new ArrayList<Element>();
832 for (final Map.Entry<String, String> entry : instructions.entrySet())
833 {
834 instlist.add(element(entry.getKey(), entry.getValue()));
835 }
836 for (final Map.Entry<String, String> entry : basicAttributes.entrySet())
837 {
838 instlist.add(element(entry.getKey(), entry.getValue()));
839 }
840 executeMojo(
841 plugin(
842 groupId("org.apache.felix"),
843 artifactId("maven-bundle-plugin"),
844 version(defaultArtifactIdToVersionMap.get("maven-bundle-plugin"))
845 ),
846 goal("manifest"),
847 configuration(
848 element(name("supportedProjectTypes"),
849 element(name("supportedProjectType"), "jar"),
850 element(name("supportedProjectType"), "bundle"),
851 element(name("supportedProjectType"), "war"),
852 element(name("supportedProjectType"), "atlassian-plugin")),
853 element(name("instructions"), instlist.toArray(new Element[instlist.size()]))
854 ),
855 executionEnvironment()
856 );
857 }
858
859 public void generateMinimalManifest(final Map<String, String> basicAttributes) throws MojoExecutionException
860 {
861 File metaInf = file(ctx.getProject().getBuild().getOutputDirectory(), "META-INF");
862 if (!metaInf.exists())
863 {
864 metaInf.mkdirs();
865 }
866 File mf = file(ctx.getProject().getBuild().getOutputDirectory(), "META-INF", "MANIFEST.MF");
867 Manifest m = new Manifest();
868 m.getMainAttributes().putValue("Manifest-Version", "1.0");
869 for (Map.Entry<String, String> entry : basicAttributes.entrySet())
870 {
871 m.getMainAttributes().putValue(entry.getKey(), entry.getValue());
872 }
873 FileOutputStream fos = null;
874 try
875 {
876 fos = new FileOutputStream(mf);
877 m.write(fos);
878 }
879 catch (IOException e)
880 {
881 throw new MojoExecutionException("Unable to create manifest", e);
882 }
883 finally
884 {
885 IOUtils.closeQuietly(fos);
886 }
887 }
888
889 public void jarWithOptionalManifest(final boolean manifestExists) throws MojoExecutionException
890 {
891 Element[] archive = new Element[0];
892 if (manifestExists)
893 {
894 archive = new Element[]{element(name("manifestFile"), "${project.build.outputDirectory}/META-INF/MANIFEST.MF")};
895 }
896
897 executeMojo(
898 plugin(
899 groupId("org.apache.maven.plugins"),
900 artifactId("maven-jar-plugin"),
901 version(defaultArtifactIdToVersionMap.get("maven-jar-plugin"))
902 ),
903 goal("jar"),
904 configuration(
905 element(name("archive"), archive)
906 ),
907 executionEnvironment()
908 );
909 }
910
911 public void jarTests(String finalName) throws MojoExecutionException
912 {
913 executeMojo(
914 plugin(
915 groupId("org.apache.maven.plugins"),
916 artifactId("maven-jar-plugin"),
917 version(defaultArtifactIdToVersionMap.get("maven-jar-plugin"))
918 ),
919 goal("test-jar"),
920 configuration(
921 element(name("finalName"), finalName),
922 element(name("archive"),
923 element(name("manifestFile"), "${project.build.testOutputDirectory}/META-INF/MANIFEST.MF"))
924 ),
925 executionEnvironment()
926 );
927 }
928
929 public void generateObrXml(File dep, File obrXml) throws MojoExecutionException
930 {
931 executeMojo(
932 plugin(
933 groupId("org.apache.felix"),
934 artifactId("maven-bundle-plugin"),
935 version(defaultArtifactIdToVersionMap.get("maven-bundle-plugin"))
936 ),
937 goal("install-file"),
938 configuration(
939 element(name("obrRepository"), obrXml.getPath()),
940
941
942 element(name("groupId"), "doesntmatter"),
943 element(name("artifactId"), "doesntmatter"),
944 element(name("version"), "doesntmatter"),
945
946 element(name("packaging"), "jar"),
947 element(name("file"), dep.getPath())
948
949 ),
950 executionEnvironment()
951 );
952 }
953
954
955
956
957
958
959
960
961
962
963
964 public void attachArtifact(File file, String type) throws MojoExecutionException
965 {
966
967 executeMojo(
968 plugin(
969 groupId("org.codehaus.mojo"),
970 artifactId("build-helper-maven-plugin"),
971 version(defaultArtifactIdToVersionMap.get("build-helper-maven-plugin"))
972 ),
973 goal("attach-artifact"),
974 configuration(
975 element(name("artifacts"),
976 element(name("artifact"),
977 element(name("file"), file.getAbsolutePath()),
978 element(name("type"), type)
979 )
980 )
981 ),
982 executionEnvironment());
983
984 }
985
986 public void release(String mavenArgs) throws MojoExecutionException
987 {
988 String args = "";
989
990 if(StringUtils.isNotBlank(mavenArgs)) {
991 args = mavenArgs;
992 }
993
994 executeMojo(
995 plugin(
996 groupId("org.apache.maven.plugins"),
997 artifactId("maven-release-plugin"),
998 version(defaultArtifactIdToVersionMap.get("maven-release-plugin"))
999 ),
1000 goal("prepare"),
1001 configuration(
1002 element(name("arguments"), args)
1003 ),
1004 executionEnvironment()
1005 );
1006
1007 executeMojo(
1008 plugin(
1009 groupId("org.apache.maven.plugins"),
1010 artifactId("maven-release-plugin"),
1011 version(defaultArtifactIdToVersionMap.get("maven-release-plugin"))
1012 ),
1013 goal("perform"),
1014 configuration(
1015 element(name("arguments"), args)
1016 ),
1017 executionEnvironment()
1018 );
1019 }
1020
1021 public void generateRestDocs() throws MojoExecutionException
1022 {
1023 MavenProject prj = ctx.getProject();
1024 StringBuffer packagesPath = new StringBuffer();
1025 List<PluginXmlUtils.RESTModuleInfo> restModules = PluginXmlUtils.getRestModules(ctx);
1026
1027 for(PluginXmlUtils.RESTModuleInfo moduleInfo : restModules)
1028 {
1029 List<String> packageList = moduleInfo.getPackagesToScan();
1030
1031 for(String packageToScan : packageList)
1032 {
1033 if(packagesPath.length() > 0)
1034 {
1035 packagesPath.append(File.pathSeparator);
1036 }
1037
1038 String filePath = prj.getBuild().getSourceDirectory() + File.separator + packageToScan.replaceAll("\\.", Matcher.quoteReplacement(File.separator));
1039 packagesPath.append(filePath);
1040 }
1041 }
1042
1043 if(!restModules.isEmpty() && packagesPath.length() > 0)
1044 {
1045 Set<String> docletPaths = new HashSet<String>();
1046 StringBuffer docletPath = new StringBuffer(":" + prj.getBuild().getOutputDirectory());
1047 String resourcedocPath = fixWindowsSlashes(prj.getBuild().getOutputDirectory() + File.separator + "resourcedoc.xml");
1048
1049 PluginXmlUtils.PluginInfo pluginInfo = PluginXmlUtils.getPluginInfo(ctx);
1050
1051 try
1052 {
1053 docletPaths.addAll(prj.getCompileClasspathElements());
1054 docletPaths.addAll(prj.getRuntimeClasspathElements());
1055 docletPaths.addAll(prj.getSystemClasspathElements());
1056
1057
1058 URL[] pluginUrls = ((URLClassLoader)Thread.currentThread().getContextClassLoader()).getURLs();
1059 for(URL pluginUrl : pluginUrls)
1060 {
1061 docletPaths.add(pluginUrl.getFile());
1062 }
1063
1064 for(String path : docletPaths) {
1065 docletPath.append(File.pathSeparator);
1066 docletPath.append(path);
1067 }
1068
1069 } catch (DependencyResolutionRequiredException e)
1070 {
1071 throw new MojoExecutionException("Dependencies must be resolved", e);
1072 }
1073
1074 executeMojo(
1075 plugin(
1076 groupId("org.apache.maven.plugins"),
1077 artifactId("maven-javadoc-plugin"),
1078 version("2.8.1")
1079 ),
1080 goal("javadoc"),
1081 configuration(
1082 element(name("maxmemory"),"1024m"),
1083 element(name("sourcepath"),packagesPath.toString()),
1084 element(name("doclet"), ResourceDocletJSON.class.getName()),
1085 element(name("docletPath"), docletPath.toString()),
1086 element(name("docletArtifacts"),
1087 element(name("docletArtifact"),
1088 element(name("groupId"),"xerces"),
1089 element(name("artifactId"),"xercesImpl"),
1090 element(name("version"),"2.9.1")
1091 ),
1092 element(name("docletArtifact"),
1093 element(name("groupId"),"commons-lang"),
1094 element(name("artifactId"),"commons-lang"),
1095 element(name("version"),"2.6")
1096 )
1097 ),
1098 element(name("additionalparam"),"-output \"" + resourcedocPath + "\""),
1099 element(name("useStandardDocletOptions"),"false")
1100 ),
1101 executionEnvironment()
1102 );
1103
1104 try {
1105
1106 File userAppDocs = new File(prj.getBuild().getOutputDirectory(),"application-doc.xml");
1107 if(!userAppDocs.exists())
1108 {
1109 String appDocText = FileUtils.getResourceContent("application-doc.xml");
1110 appDocText = StringUtils.replace(appDocText, "${rest.doc.title}", pluginInfo.getName());
1111 appDocText = StringUtils.replace(appDocText,"${rest.doc.description}",pluginInfo.getDescription());
1112 File appDocFile = new File(prj.getBuild().getOutputDirectory(), "application-doc.xml");
1113
1114 FileUtils.saveTextFile(appDocText, appDocFile);
1115 log.info("Wrote " + appDocFile.getAbsolutePath());
1116 }
1117
1118 File userGrammars = new File(prj.getBuild().getOutputDirectory(),"application-grammars.xml");
1119 if(!userGrammars.exists())
1120 {
1121 String grammarText = FileUtils.getResourceContent("application-grammars.xml");
1122 File grammarFile = new File(prj.getBuild().getOutputDirectory(), "application-grammars.xml");
1123
1124 FileUtils.saveTextFile(grammarText, grammarFile);
1125
1126 log.info("Wrote " + grammarFile.getAbsolutePath());
1127 }
1128
1129 } catch (Exception e)
1130 {
1131 throw new MojoExecutionException("Error writing REST application xml files",e);
1132 }
1133 }
1134 }
1135
1136 private static class Container extends ProductArtifact
1137 {
1138 private final String id;
1139 private final String type;
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149 public Container(final String id, final String groupId, final String artifactId, final String version)
1150 {
1151 super(groupId, artifactId, version);
1152 this.id = id;
1153 this.type = "installed";
1154 }
1155
1156
1157
1158
1159
1160
1161 public Container(final String id)
1162 {
1163 this.id = id;
1164 this.type = "embedded";
1165 }
1166
1167
1168
1169
1170 public String getId()
1171 {
1172 return id;
1173 }
1174
1175
1176
1177
1178 public String getType()
1179 {
1180 return type;
1181 }
1182
1183
1184
1185
1186 public boolean isEmbedded()
1187 {
1188 return "embedded".equals(type);
1189 }
1190
1191
1192
1193
1194
1195 public String getRootDirectory(String buildDir)
1196 {
1197 return buildDir + File.separator + "container" + File.separator + getId();
1198 }
1199
1200
1201
1202
1203
1204 public String getInstallDirectory(String buildDir)
1205 {
1206 return getRootDirectory(buildDir) + File.separator + getArtifactId() + "-" + getVersion();
1207 }
1208
1209
1210
1211
1212
1213
1214 public String getConfigDirectory(String buildDir, String productId)
1215 {
1216 return getRootDirectory(buildDir) + File.separator + "cargo-" + productId + "-home";
1217 }
1218 }
1219 }