PageRenderTime 40ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://bitbucket.org/atlassian/amps
Java | 245 lines | 211 code | 21 blank | 13 comment | 4 complexity | 43f28f0a4c98c797a79ff8ee7468591b 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.Product;
  5. import com.atlassian.maven.plugins.amps.ProductArtifact;
  6. import com.atlassian.maven.plugins.amps.product.manager.WebAppManager;
  7. import com.google.common.collect.ImmutableMap;
  8. import org.apache.commons.io.FileUtils;
  9. import org.apache.maven.artifact.resolver.ArtifactResolver;
  10. import org.apache.maven.plugin.MojoExecutionException;
  11. import org.apache.maven.repository.RepositorySystem;
  12. import javax.annotation.Nonnull;
  13. import java.io.File;
  14. import java.io.IOException;
  15. import java.net.URI;
  16. import java.net.URISyntaxException;
  17. import java.util.ArrayList;
  18. import java.util.Arrays;
  19. import java.util.Collection;
  20. import java.util.List;
  21. import java.util.Map;
  22. import java.util.Optional;
  23. import static com.atlassian.maven.plugins.amps.product.ProductHandlerFactory.CROWD;
  24. import static com.atlassian.maven.plugins.amps.util.ConfigFileUtils.replaceAll;
  25. import static com.atlassian.maven.plugins.amps.util.ConfigFileUtils.updateProperties;
  26. import static java.util.Collections.singleton;
  27. public class CrowdProductHandler extends AbstractWebappProductHandler {
  28. private static final String LOCAL_CROWD_CONFIG = "crowd.cfg.xml";
  29. private static final String SHARED_CROWD_CONFIG = "shared/crowd.cfg.xml";
  30. public CrowdProductHandler(final MavenContext context, final MavenGoals goals,
  31. final RepositorySystem repositorySystem, final ArtifactResolver artifactResolver,
  32. final WebAppManager webAppManager) {
  33. super(context, goals, new CrowdPluginProvider(), repositorySystem, artifactResolver, webAppManager);
  34. }
  35. @Nonnull
  36. @Override
  37. public String getId() {
  38. return CROWD;
  39. }
  40. @Nonnull
  41. @Override
  42. public ProductArtifact getArtifact() {
  43. return new ProductArtifact("com.atlassian.crowd", "crowd-web-app", "RELEASE");
  44. }
  45. @Nonnull
  46. @Override
  47. public Optional<ProductArtifact> getTestResourcesArtifact() {
  48. return Optional.of(new ProductArtifact("com.atlassian.crowd.distribution", "crowd-plugin-test-resources"));
  49. }
  50. @Override
  51. public int getDefaultHttpPort() {
  52. return 4990;
  53. }
  54. @Override
  55. public int getDefaultHttpsPort() {
  56. return 8444;
  57. }
  58. @Override
  59. @Nonnull
  60. protected Map<String, String> getProductSpecificSystemProperties(final Product product, final int nodeIndex) {
  61. final ImmutableMap.Builder<String, String> systemProperties = ImmutableMap.builder();
  62. systemProperties.put("cargo.servlet.uriencoding", "UTF-8");
  63. final List<File> homeDirectories = getHomeDirectories(product);
  64. // Use the first node's shared home as the cluster's shared home (it already exists in ZIP files)
  65. final File sharedHome = new File(homeDirectories.get(0), "shared");
  66. final String homeDirectory = homeDirectories.get(nodeIndex).getPath();
  67. // Crowd's DefaultHomeLocator reads this property
  68. systemProperties.put("crowd.home", homeDirectory);
  69. // Crowd's HomeDirectoryServiceImpl reads this property
  70. systemProperties.put("crowd.shared.home", sharedHome.getPath());
  71. // Synthesise a node name (read in Crowd by NodeDataProvider#getNodeName)
  72. systemProperties.put("cluster.node.name", product.getInstanceId() + "-" + nodeIndex);
  73. return systemProperties.build();
  74. }
  75. @Nonnull
  76. @Override
  77. public Optional<File> getUserInstalledPluginsDirectory(
  78. final Product product, final File webappDir, final File homeDir) {
  79. final File sharedHomeDir = new File(homeDir, "shared");
  80. if (sharedHomeDir.exists()) {
  81. return Optional.of(new File(sharedHomeDir, "plugins"));
  82. } else {
  83. return Optional.of(new File(homeDir, "plugins"));
  84. }
  85. }
  86. @Override
  87. @Nonnull
  88. public List<ProductArtifact> getExtraContainerDependencies() {
  89. return Arrays.asList(
  90. new ProductArtifact("hsqldb", "hsqldb", "1.8.0.7"),
  91. new ProductArtifact("javax.transaction", "jta", "1.1"),
  92. new ProductArtifact("javax.mail", "mail", "1.4"),
  93. new ProductArtifact("javax.activation", "activation", "1.0.2")
  94. );
  95. }
  96. @Nonnull
  97. @Override
  98. protected Collection<String> getExtraJarsToSkipWhenScanningForTldsAndWebFragments() {
  99. // AMPS-1524: mail-1.4.jar has `activation.jar` in its Class-Path manifest header, not activation-1.0.2.jar
  100. return singleton("mail-*.jar");
  101. }
  102. @Override
  103. @Nonnull
  104. public File getBundledPluginPath(Product product, File productDir) {
  105. return new File(productDir, "WEB-INF/classes/atlassian-bundled-plugins.zip");
  106. }
  107. @Override
  108. public void processHomeDirectory(final Product product, final int nodeIndex, final File homeDir)
  109. throws MojoExecutionException {
  110. super.processHomeDirectory(product, nodeIndex, homeDir);
  111. try {
  112. updateLicenseInSharedConfig(homeDir, product);
  113. updateClusteringEnabledFlag(homeDir, product);
  114. updateHsqlUrlInCrowdConfig(homeDir);
  115. updateCrowdDotProperties(product, nodeIndex, homeDir);
  116. } catch (final IOException e) {
  117. throw new MojoExecutionException(e.getMessage());
  118. }
  119. }
  120. @Override
  121. protected boolean useBackdoorToInstallLicense() {
  122. // Crowd reads certain license attributes at startup, so using the plugin is too late. We therefore apply the
  123. // user-provided license before startup, see updateLicenseInSharedConfig below.
  124. return false;
  125. }
  126. /*
  127. Because Crowd's NodeDataProvider memoizes whether clustering is enabled at startup time, using the license
  128. backdoor plugin to replace the license later cannot enable DC mode. We therefore have to put the user-provided
  129. license into the Crowd configuration before the product starts up.
  130. */
  131. private void updateLicenseInSharedConfig(final File homeDir, final Product product) throws MojoExecutionException {
  132. final Optional<String> license = product.getUserConfiguredLicense();
  133. if (license.isPresent()) { // no ifPresent lambda because exception thrown below
  134. replaceAll(new File(homeDir, SHARED_CROWD_CONFIG),
  135. "(<property name=\"license\">).+(</property>)", "$1" + license.get() + "$2");
  136. }
  137. }
  138. private void updateClusteringEnabledFlag(final File homeDir, final Product product)
  139. throws MojoExecutionException {
  140. if (product.isMultiNode()) {
  141. replaceAll(new File(homeDir, SHARED_CROWD_CONFIG),
  142. "crowd.clustering.enabled\">false<", "crowd.clustering.enabled\">true<");
  143. }
  144. }
  145. // Crowd still uses HSQLDB as of 4.3.0
  146. private void updateHsqlUrlInCrowdConfig(final File homeDir) throws IOException, MojoExecutionException {
  147. final String jdbcDir = homeDir.getCanonicalPath().replace("\\", "/");
  148. final String hsqldbUrl = "jdbc:hsqldb:" + jdbcDir + "/database/defaultdb";
  149. replaceAll(new File(homeDir, SHARED_CROWD_CONFIG),
  150. "jdbc:hsqldb:.*/(crowd-)?home/database/defaultdb",
  151. hsqldbUrl);
  152. replaceAll(new File(homeDir, LOCAL_CROWD_CONFIG),
  153. "jdbc:hsqldb:.*/(crowd-)?home/database/defaultdb",
  154. hsqldbUrl);
  155. }
  156. private void updateCrowdDotProperties(final Product product, final int nodeIndex, final File homeDir)
  157. throws MojoExecutionException {
  158. final String baseUrl = getBaseUrl(product, nodeIndex);
  159. final Map<String, String> newProperties = ImmutableMap.of(
  160. "crowd.server.url", baseUrl + "/services",
  161. "application.login.url", baseUrl
  162. );
  163. updateProperties(new File(homeDir, "crowd.properties"), newProperties);
  164. }
  165. private String getBaseUrl(final Product product, final int nodeIndex) throws MojoExecutionException {
  166. // Crowd connects back to itself; use 'localhost' rather than the hostname an external client would see
  167. try {
  168. return withLocalhostAsHostname(product.getBaseUrlForNode(nodeIndex));
  169. } catch (URISyntaxException e) {
  170. throw new MojoExecutionException("Unable to process Crowd service URL", e);
  171. }
  172. }
  173. static String withLocalhostAsHostname(@Nonnull final String uri) throws URISyntaxException {
  174. final URI base = new URI(uri);
  175. final URI baseWithLocalhost = new URI(
  176. base.getScheme(),
  177. base.getUserInfo(),
  178. "localhost",
  179. base.getPort(),
  180. base.getPath(),
  181. base.getQuery(),
  182. base.getFragment());
  183. return baseWithLocalhost.toString();
  184. }
  185. private static class CrowdPluginProvider extends AbstractPluginProvider {
  186. @Override
  187. protected Collection<ProductArtifact> getSalArtifacts(final String salVersion) {
  188. return Arrays.asList(
  189. new ProductArtifact("com.atlassian.sal", "sal-api", salVersion),
  190. new ProductArtifact("com.atlassian.sal", "sal-crowd-plugin", salVersion));
  191. }
  192. @Override
  193. protected Collection<ProductArtifact> getPdkInstallArtifacts(final String pdkInstallVersion) {
  194. final List<ProductArtifact> plugins = new ArrayList<>(super.getPdkInstallArtifacts(pdkInstallVersion));
  195. plugins.add(new ProductArtifact("commons-fileupload", "commons-fileupload", "1.2.1"));
  196. return plugins;
  197. }
  198. }
  199. @Override
  200. protected void cleanupProductHomeForZip(@Nonnull final Product product, @Nonnull final File homeDirectory)
  201. throws MojoExecutionException, IOException {
  202. super.cleanupProductHomeForZip(product, homeDirectory);
  203. FileUtils.deleteQuietly(new File(homeDirectory, "caches"));
  204. FileUtils.deleteQuietly(new File(homeDirectory, "logs"));
  205. }
  206. @Nonnull
  207. @Override
  208. protected List<File> getConfigFiles(@Nonnull final Product product, @Nonnull final File snapshotDir) {
  209. final List<File> configFiles = super.getConfigFiles(product, snapshotDir);
  210. configFiles.add(new File(snapshotDir, "database.log"));
  211. configFiles.add(new File(snapshotDir, LOCAL_CROWD_CONFIG));
  212. configFiles.add(new File(snapshotDir, SHARED_CROWD_CONFIG));
  213. configFiles.add(new File(snapshotDir, "crowd.properties"));
  214. return configFiles;
  215. }
  216. }