PageRenderTime 39ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/amps-maven-plugin/src/main/java/com/atlassian/maven/plugins/amps/product/CtkServerProductHandler.java

https://bitbucket.org/atlassian/amps
Java | 249 lines | 196 code | 32 blank | 21 comment | 17 complexity | 17aefa4d070bc5b0c948aa59df3c7ea1 MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause
  1. package com.atlassian.maven.plugins.amps.product;
  2. import com.atlassian.maven.plugins.amps.MavenContext;
  3. import com.atlassian.maven.plugins.amps.MavenGoals;
  4. import com.atlassian.maven.plugins.amps.Node;
  5. import com.atlassian.maven.plugins.amps.Product;
  6. import com.atlassian.maven.plugins.amps.ProductArtifact;
  7. import com.atlassian.maven.plugins.amps.util.ProjectUtils;
  8. import com.atlassian.maven.plugins.amps.util.ant.AntJavaExecutorThread;
  9. import com.atlassian.maven.plugins.amps.util.ant.JavaTaskFactory;
  10. import org.apache.maven.plugin.MojoExecutionException;
  11. import org.apache.maven.plugin.logging.Log;
  12. import org.apache.tools.ant.taskdefs.Java;
  13. import javax.annotation.Nonnull;
  14. import javax.annotation.ParametersAreNonnullByDefault;
  15. import java.io.File;
  16. import java.io.IOException;
  17. import java.net.HttpURLConnection;
  18. import java.net.URL;
  19. import java.util.Arrays;
  20. import java.util.HashMap;
  21. import java.util.List;
  22. import java.util.Map;
  23. import java.util.Optional;
  24. import static com.atlassian.maven.plugins.amps.util.ZipUtils.unzip;
  25. import static com.atlassian.maven.plugins.amps.util.ant.JavaTaskFactory.output;
  26. import static java.lang.String.format;
  27. import static java.net.HttpURLConnection.HTTP_OK;
  28. import static java.util.Collections.emptyList;
  29. import static java.util.Collections.singletonList;
  30. import static java.util.Optional.empty;
  31. /**
  32. * The Atlassian Federated API CTK Server.
  33. */
  34. @ParametersAreNonnullByDefault
  35. public class CtkServerProductHandler implements ProductHandler {
  36. private static final String CTK_SERVER_ARTIFACT_MATCHER = "federated-api-ctk-server-.*\\.jar";
  37. private final MavenContext context;
  38. private final MavenGoals goals;
  39. private final JavaTaskFactory javaTaskFactory;
  40. private final Log log;
  41. public CtkServerProductHandler(final MavenContext context, final MavenGoals goals) {
  42. this.context = context;
  43. this.goals = goals;
  44. this.javaTaskFactory = new JavaTaskFactory(context.getLog());
  45. this.log = context.getLog();
  46. }
  47. @Nonnull
  48. @Override
  49. public String getId() {
  50. return ProductHandlerFactory.CTK_SERVER;
  51. }
  52. @Override
  53. public int getDefaultHttpPort() {
  54. return 8990;
  55. }
  56. @Override
  57. public int getDefaultHttpsPort() {
  58. return 8448;
  59. }
  60. @Nonnull
  61. @Override
  62. public ProductArtifact getArtifact() {
  63. throw new UnsupportedOperationException("Not implemented");
  64. }
  65. @Nonnull
  66. @Override
  67. public Optional<ProductArtifact> getTestResourcesArtifact() {
  68. return empty();
  69. }
  70. @Override
  71. @Nonnull
  72. public String getDefaultContextPath() {
  73. return "/";
  74. }
  75. @Override
  76. @Nonnull
  77. public List<Node> start(final Product product) throws MojoExecutionException {
  78. unpackContainer(product);
  79. return startContainer(product);
  80. }
  81. @Override
  82. public void stop(final Product product) throws MojoExecutionException {
  83. try {
  84. stopContainer(product);
  85. } catch (IOException e) {
  86. throw new MojoExecutionException("Failed to send stop command to CTK server", e);
  87. }
  88. }
  89. @Override
  90. @Nonnull
  91. public String getDefaultContainerId() {
  92. return "ctk-server";
  93. }
  94. @Override
  95. @Nonnull
  96. public String getDefaultContainerId(Product product) {
  97. return getDefaultContainerId();
  98. }
  99. @Override
  100. @Nonnull
  101. public List<File> getSnapshotDirectories(@Nonnull final Product product) {
  102. return singletonList(getBaseDirectory(product));
  103. }
  104. /**
  105. * @param product the current product configuration
  106. * @return the server is stateless, so no separate home directory
  107. */
  108. @Override
  109. @Nonnull
  110. public List<File> getHomeDirectories(@Nonnull final Product product) {
  111. return singletonList(getBaseDirectory(product));
  112. }
  113. /**
  114. * The server itself is stateless, so multiple running instances of the same version share the same base directory.
  115. *
  116. * @param product the current product configuration
  117. * @return the directory containing the CTK server jar files and its dependencies (for the configured product
  118. * version).
  119. */
  120. @Override
  121. @Nonnull
  122. public File getBaseDirectory(@Nonnull final Product product) {
  123. return ProjectUtils.createDirectory(new File(context.getProject().getBuild().getDirectory(), "ctk-server-" + product.getVersion()));
  124. }
  125. @Override
  126. public void createHomeZip(@Nonnull final File homeDirectory, @Nonnull final File targetZip, @Nonnull final Product product) {
  127. throw new UnsupportedOperationException();
  128. }
  129. private void unpackContainer(final Product product) throws MojoExecutionException {
  130. final File baseDirectory = getBaseDirectory(product);
  131. final String[] directoryContents = baseDirectory.list();
  132. if (directoryContents == null || directoryContents.length == 0) {
  133. final File serverDistributionArtifactFile = copyServerArtifactToOutputDirectory(product);
  134. unpackServerArtifact(serverDistributionArtifactFile, baseDirectory);
  135. deleteServerArtifact(serverDistributionArtifactFile);
  136. } else {
  137. log.debug("CTK Server " + product.getVersion() + " already unpacked.");
  138. }
  139. }
  140. private File copyServerArtifactToOutputDirectory(final Product product) throws MojoExecutionException {
  141. final File buildDirectory = new File(context.getProject().getBuild().getDirectory());
  142. final ProductArtifact artifact = getServerDistributionArtifact(product);
  143. final String filename = format("%s-%s.%s", artifact.getArtifactId(), artifact.getVersion(), artifact.getType());
  144. return goals.copyZip(buildDirectory, artifact, filename);
  145. }
  146. private void unpackServerArtifact(final File serverDistributionArtifactFile, final File serverDirectory)
  147. throws MojoExecutionException {
  148. try {
  149. unzip(serverDistributionArtifactFile, serverDirectory.getPath(), 0);
  150. } catch (final IOException ex) {
  151. throw new MojoExecutionException("Unable to extract CTK server distribution: " + serverDistributionArtifactFile, ex);
  152. }
  153. }
  154. private void deleteServerArtifact(final File artifactFile) {
  155. log.debug("Deleting CTK server distribution artifact: " + artifactFile.getPath());
  156. if (!artifactFile.delete()) {
  157. log.warn("Failed to delete CTK server distribution artifact: " + artifactFile.getPath());
  158. }
  159. }
  160. private List<Node> startContainer(final Product product) {
  161. final Map<String, String> systemProperties = getSystemProperties(product);
  162. final Java java = javaTaskFactory.newJavaTask(output(product.getOutput()).systemProperties(systemProperties).
  163. jvmArgs(product.getJvmArgs() + product.getSingleNodeDebugArgs()));
  164. java.setDir(getBaseDirectory(product));
  165. java.setJar(findServerJar(product));
  166. java.createArg().setValue("--host");
  167. java.createArg().setValue(product.getServer());
  168. java.createArg().setValue("--port");
  169. java.createArg().setValue(Integer.toString(product.getSingleNodeWebPort()));
  170. final AntJavaExecutorThread javaThread = new AntJavaExecutorThread(java);
  171. javaThread.start();
  172. return product.getNodes();
  173. }
  174. private ProductArtifact getServerDistributionArtifact(final Product product) {
  175. return new ProductArtifact("com.atlassian.federation", "federated-api-ctk-server-distribution",
  176. product.getVersion(), "zip");
  177. }
  178. private Map<String, String> getSystemProperties(final Product product) {
  179. final Map<String, String> map = new HashMap<>();
  180. for (Map.Entry<String, Object> entry : product.getSystemPropertyVariables().entrySet()) {
  181. map.put(entry.getKey(), (String) entry.getValue());
  182. }
  183. return map;
  184. }
  185. private File findServerJar(final Product product) {
  186. final File baseDirectory = getBaseDirectory(product);
  187. final File[] files = baseDirectory.listFiles((dir, name) -> name.matches(CTK_SERVER_ARTIFACT_MATCHER));
  188. if (files == null || files.length == 0) {
  189. throw new IllegalStateException("CTK Server JAR file not found in: " + baseDirectory +
  190. " (expected a file matching " + CTK_SERVER_ARTIFACT_MATCHER + ")");
  191. } else if (files.length == 1) {
  192. return files[0];
  193. } else {
  194. throw new IllegalStateException(
  195. "Found too many CTK Server JAR files, expected only one: " + Arrays.toString(files));
  196. }
  197. }
  198. /**
  199. * Send a <code>DELETE</code> request to the server to indicate it should stop serving content and shut down.
  200. *
  201. * @param product the current product
  202. * @throws IOException if there's an I/O error
  203. * @throws MojoExecutionException if there's an error stopping the container
  204. */
  205. private void stopContainer(final Product product) throws IOException, MojoExecutionException {
  206. final URL url = new URL(
  207. product.getProtocol(), product.getServer(), product.getSingleNodeWebPort(), product.getContextPath());
  208. final HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
  209. httpConnection.setConnectTimeout(product.getShutdownTimeout());
  210. httpConnection.setRequestMethod("DELETE");
  211. final int responseCode = httpConnection.getResponseCode();
  212. if (responseCode != HTTP_OK) {
  213. throw new MojoExecutionException(
  214. "CTK server didn't understand stop command; received HTTP response code: " + responseCode);
  215. }
  216. }
  217. }