PageRenderTime 49ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/atlassian-plugins-webresource-rest/src/main/java/com/atlassian/webresource/plugin/rest/one/zero/CrossTenantCdnResource.java

https://bitbucket.org/atlassian/atlassian-plugins-webresource
Java | 195 lines | 155 code | 23 blank | 17 comment | 3 complexity | f6be975b407432ff9d8d2aec20029b74 MD5 | raw file
  1. package com.atlassian.webresource.plugin.rest.one.zero;
  2. import com.atlassian.plugin.webresource.PluginResourceLocator;
  3. import com.atlassian.plugin.webresource.WebResourceIntegration;
  4. import com.atlassian.plugin.webresource.cdn.mapper.Mapping;
  5. import com.atlassian.plugin.webresource.cdn.mapper.WebResourceMapper;
  6. import com.atlassian.plugin.webresource.impl.config.Config;
  7. import com.atlassian.plugin.webresource.prebake.PrebakeConfig;
  8. import com.atlassian.plugins.rest.common.security.AnonymousAllowed;
  9. import org.apache.commons.lang3.exception.ExceptionUtils;
  10. import org.slf4j.Logger;
  11. import org.slf4j.LoggerFactory;
  12. import javax.ws.rs.DefaultValue;
  13. import javax.ws.rs.GET;
  14. import javax.ws.rs.PUT;
  15. import javax.ws.rs.Path;
  16. import javax.ws.rs.Produces;
  17. import javax.ws.rs.QueryParam;
  18. import javax.ws.rs.core.MediaType;
  19. import javax.ws.rs.core.Response;
  20. import java.util.List;
  21. import java.util.Map;
  22. import java.util.Optional;
  23. import java.util.function.Supplier;
  24. import java.util.stream.Collectors;
  25. import java.util.stream.StreamSupport;
  26. import static javax.ws.rs.core.Response.ok;
  27. import static javax.ws.rs.core.Response.status;
  28. /**
  29. * REST end-point providing CT-CDN diagnostics.
  30. *
  31. * @since v3.5.7
  32. */
  33. @AnonymousAllowed
  34. @Path("ct-cdn")
  35. public class CrossTenantCdnResource {
  36. private static final Logger log = LoggerFactory.getLogger(CrossTenantCdnResource.class);
  37. private final WebResourceIntegration webResourceIntegration;
  38. private final Config config;
  39. @SuppressWarnings("deprecation")
  40. public CrossTenantCdnResource(
  41. final WebResourceIntegration webResourceIntegration,
  42. final PluginResourceLocator pluginResourceLocator) {
  43. this.webResourceIntegration = webResourceIntegration;
  44. this.config = pluginResourceLocator.temporaryWayToGetGlobalsDoNotUseIt().getConfig();
  45. }
  46. /**
  47. * Returns a JSON with information about the current status of CT-CDN.
  48. *
  49. * @param includeMappings Includes the full loaded mappings in the JSON when true.
  50. */
  51. @Path("status")
  52. @GET
  53. @Produces({MediaType.APPLICATION_JSON})
  54. public Response healthInfo(@QueryParam("includeMappings") @DefaultValue("true") final boolean includeMappings) {
  55. log.debug("Collection general info about CT-CDN");
  56. final String hash = config.computeGlobalStateHash();
  57. final WebResourceMapper wrm = config.getWebResourceMapper();
  58. final Optional<PrebakeConfig> prebakeConfig = webResourceIntegration.getCDNStrategy() != null ?
  59. webResourceIntegration.getCDNStrategy().getPrebakeConfig() : Optional.empty();
  60. final Map<String, List<String>> simpleMappings = StreamSupport
  61. .stream(wrm.mappings().all().spliterator(), false)
  62. .collect(Collectors.toMap(Mapping::originalResource, Mapping::mappedResources));
  63. final Info.WebResourceMapper wrmInfo = new Info.WebResourceMapper(
  64. includeMappings ? simpleMappings : null,
  65. simpleMappings.size(),
  66. simpleMappings.values().stream().mapToInt(List::size).sum(),
  67. wrm.getClass().getName());
  68. return ok(new Info(
  69. new Info.State(config.getCtCdnBaseUrl(), hash, webResourceIntegration.isCtCdnMappingEnabled()),
  70. new Info.PreBaker(config.isPreBakeEnabled()),
  71. new Info.PrebakeConfig(
  72. prebakeConfig.map(PrebakeConfig::getPattern).orElse("[EMPTY]"),
  73. prebakeConfig.map(pc -> pc.getMappingLocation(hash).getAbsolutePath()).orElse("[EMPTY]"),
  74. prebakeConfig.map(pc -> pc.getMappingLocation(hash).exists()).orElse(false)),
  75. wrmInfo
  76. )).build();
  77. }
  78. /**
  79. * Tries to reload mappings using the current configuration.
  80. * It was not design for production but testing and diagnostic purposes.
  81. * An error is returned if CT-CDN is disabled by the product through {@link PrebakeConfig}.
  82. *
  83. * @return Result of the reload, including the stack trace in case of error.
  84. */
  85. @Path("mappings")
  86. @PUT
  87. @Produces({MediaType.APPLICATION_JSON})
  88. public final Response reloadMappings() {
  89. return whenPreBakeIsEnabled(() -> {
  90. log.info("Trying to reload WebResourceMapper");
  91. try {
  92. config.reloadWebResourceMapper();
  93. return ok(new ReloadStatus("Mappings were reloaded",
  94. config.getWebResourceMapper().mappings().size(), null)).build();
  95. } catch (Exception e) {
  96. log.warn(e.getMessage(), e);
  97. return ok(new ReloadStatus(e.getMessage(), config.getWebResourceMapper().mappings().size(),
  98. ExceptionUtils.getStackTrace(e))).build();
  99. }
  100. });
  101. }
  102. private Response whenPreBakeIsEnabled(Supplier<Response> normalResponse) {
  103. if (config.isPreBakeEnabled()) {
  104. return normalResponse.get();
  105. } else {
  106. log.warn("Pre-baking called but feature is not enabled!");
  107. return status(Response.Status.FORBIDDEN).build();
  108. }
  109. }
  110. public static class ReloadStatus {
  111. public String status;
  112. public int size;
  113. public String exception;
  114. public ReloadStatus(final String status, final int size, final String exception) {
  115. this.status = status;
  116. this.size = size;
  117. this.exception = exception;
  118. }
  119. }
  120. public static class Info {
  121. public State state;
  122. public PreBaker preBaker;
  123. public PrebakeConfig prebakeConfig;
  124. public WebResourceMapper webResourceMapper;
  125. public Info(final State state, final PreBaker preBaker, final PrebakeConfig prebakeConfig,
  126. final WebResourceMapper webResourceMapper) {
  127. this.state = state;
  128. this.preBaker = preBaker;
  129. this.prebakeConfig = prebakeConfig;
  130. this.webResourceMapper = webResourceMapper;
  131. }
  132. public static class State {
  133. public String baseUrl;
  134. public String productStateHash;
  135. public boolean enabled;
  136. public State(final String baseUrl, final String productStateHash, final boolean enabled) {
  137. this.baseUrl = baseUrl;
  138. this.productStateHash = productStateHash;
  139. this.enabled = enabled;
  140. }
  141. }
  142. public static class PreBaker {
  143. public boolean enabled;
  144. public PreBaker(boolean enabled) {
  145. this.enabled = enabled;
  146. }
  147. }
  148. public static class PrebakeConfig {
  149. public String mappingFilePattern;
  150. public String mappingFileLocation;
  151. public boolean fileExists;
  152. public PrebakeConfig(final String mappingFilePattern, final String mappingFileLocation, boolean fileExists) {
  153. this.mappingFilePattern = mappingFilePattern;
  154. this.mappingFileLocation = mappingFileLocation;
  155. this.fileExists = fileExists;
  156. }
  157. }
  158. public static class WebResourceMapper {
  159. public String implementationClass;
  160. public int numberOfEntries;
  161. public int countOfValues;
  162. public Map<String, List<String>> mappings;
  163. public WebResourceMapper(final Map<String, List<String>> mappings, final int numberOfEntries,
  164. final int countOfValues, final String implementationClass) {
  165. this.mappings = mappings;
  166. this.numberOfEntries = numberOfEntries;
  167. this.countOfValues = countOfValues;
  168. this.implementationClass = implementationClass;
  169. }
  170. }
  171. }
  172. }