PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://bitbucket.org/atlassian/atlassian-plugins-webresource
Java | 159 lines | 123 code | 10 blank | 26 comment | 2 complexity | 6428bc43433a17443877848aee34fbea MD5 | raw file
  1. package com.atlassian.webresource.plugin.rest.one.zero;
  2. import com.atlassian.annotations.VisibleForTesting;
  3. import com.atlassian.plugin.webresource.models.Requestable;
  4. import com.atlassian.plugin.webresource.models.WebResourceContextKey;
  5. import com.atlassian.plugin.webresource.models.WebResourceKey;
  6. import com.atlassian.plugins.rest.common.security.AnonymousAllowed;
  7. import com.atlassian.webresource.api.assembler.resource.ResourcePhase;
  8. import com.atlassian.webresource.plugin.async.AsyncWebResourceLoader;
  9. import com.atlassian.webresource.plugin.rest.one.zero.model.ResolveResourcesJson;
  10. import com.atlassian.webresource.plugin.rest.one.zero.model.ResourcesAndData;
  11. import io.swagger.v3.oas.annotations.OpenAPIDefinition;
  12. import io.swagger.v3.oas.annotations.Operation;
  13. import io.swagger.v3.oas.annotations.Parameter;
  14. import io.swagger.v3.oas.annotations.info.Info;
  15. import io.swagger.v3.oas.annotations.media.Content;
  16. import io.swagger.v3.oas.annotations.media.Schema;
  17. import io.swagger.v3.oas.annotations.responses.ApiResponse;
  18. import javax.annotation.Nullable;
  19. import javax.ws.rs.Consumes;
  20. import javax.ws.rs.GET;
  21. import javax.ws.rs.POST;
  22. import javax.ws.rs.Path;
  23. import javax.ws.rs.Produces;
  24. import javax.ws.rs.QueryParam;
  25. import java.io.IOException;
  26. import java.util.Collection;
  27. import java.util.Collections;
  28. import java.util.List;
  29. import java.util.Map;
  30. import java.util.Set;
  31. import java.util.function.Function;
  32. import java.util.stream.Collectors;
  33. import static io.swagger.v3.oas.annotations.enums.Explode.FALSE;
  34. import static io.swagger.v3.oas.annotations.enums.ParameterStyle.FORM;
  35. import static java.util.Arrays.asList;
  36. import static java.util.Collections.emptyList;
  37. import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
  38. /**
  39. * REST endpoint for retrieving resolved of JS, CSS (and more) resources
  40. *
  41. * @since v3.0
  42. */
  43. @AnonymousAllowed
  44. @OpenAPIDefinition(
  45. info = @Info(
  46. title = "Web Resource Manager",
  47. version = "1.0",
  48. description = "This is a draft of the proposed APIs to support retrieving of all forms of resources."
  49. )
  50. )
  51. @Path("resources")
  52. @Consumes({APPLICATION_JSON})
  53. @Produces({APPLICATION_JSON})
  54. public class PhasesUnawareResources {
  55. private final AsyncWebResourceLoader asyncWebResourceLoader;
  56. public PhasesUnawareResources(AsyncWebResourceLoader asyncWebResourceLoader) {
  57. this.asyncWebResourceLoader = asyncWebResourceLoader;
  58. }
  59. @VisibleForTesting
  60. protected static <T extends Requestable> Set<T> mapsStringsToRequestables(
  61. Collection<String> rawStrings,
  62. Function<String, T> constructor
  63. ) {
  64. return rawStrings.stream().map(constructor).collect(Collectors.toSet());
  65. }
  66. @VisibleForTesting
  67. protected static <T extends Requestable> Map<ResourcePhase, Set<T>> withDefaultPhase(
  68. Set<T> requestables
  69. ) {
  70. return requestables.isEmpty() ? Collections.emptyMap() : Collections.singletonMap(ResourcePhase.defaultPhase(), requestables);
  71. }
  72. /**
  73. * HTTP GET version of {@link #post} allowing parameters to be supplied via the URL.
  74. * <p>
  75. * Avoid this in favour of the POST form when you risk exceeding the maximum URL length supported by browsers. For
  76. * example when you expect to have a large number of requires or exclusions (e.g. in development mode where
  77. * resources are not batched).
  78. *
  79. * @param webResources Comma separated list of IDs of resources to require. Can have a phase separated by a
  80. * semi-colon
  81. * @param contexts Comma separated list of IDs of contexts to require. Can have a phase separated by a
  82. * semi-colon
  83. * @param excludeResources Comma separated list of IDs of resources to exclude.
  84. * @param excludeContexts Comma separated list of IDs of contexts to exclude.f
  85. * @deprecated Use the {@link #post} version to avoid URL length issues
  86. */
  87. @Deprecated
  88. @GET
  89. @Produces({APPLICATION_JSON})
  90. @Operation(summary = "Retrieve resolved resources", tags = {"resources"})
  91. @ApiResponse(responseCode = "200", description = "Successful operation", content = @Content(schema =
  92. @Schema(implementation = ResourcesAndData.class)))
  93. public ResourcesAndData get(
  94. @Parameter(description = "Comma-separated list of phase aware WebResources wanted. Phases are " +
  95. "prepended, followed by by a semi-colon to separate it from the key of the WebResource",
  96. example = "interactive;com.atlassian:web-resource-key-1,render;com.atlassian:web-resource-key-2",
  97. style = FORM, explode = FALSE)
  98. @QueryParam("r")
  99. String webResources,
  100. @Parameter(description = "Comma-separated list of phase aware WebResourceContexts wanted. Phases are " +
  101. "prepended, followed by by a semi-colon to separate it from the key of the WebResourceContext",
  102. example = "interactive;com.atlassian:context-key-1,render;com.atlassian:context-key-2",
  103. style = FORM, explode = FALSE)
  104. @QueryParam("c")
  105. String contexts,
  106. @Parameter(description = "Comma-separated list of WebResources not wanted.",
  107. example = "com.atlassian:excluded-web-resource-key-1,com.atlassian:excluded-web-resource-key-2",
  108. style = FORM, explode = FALSE)
  109. @QueryParam("xr")
  110. String excludeResources,
  111. @Parameter(description = "Comma-separated list of WebResourceContexts not wanted.",
  112. example = "com.atlassian:excluded-context-key-1,com.atlassian:excluded-context-key-2",
  113. style = FORM, explode = FALSE)
  114. @QueryParam("xc")
  115. String excludeContexts
  116. ) throws IOException {
  117. return new ResourcesAndData(asyncWebResourceLoader.resolve(
  118. withDefaultPhase(mapsStringsToRequestables(splitQueryParam(webResources), WebResourceKey::new)),
  119. withDefaultPhase(mapsStringsToRequestables(splitQueryParam(contexts), WebResourceContextKey::new)),
  120. mapsStringsToRequestables(splitQueryParam(excludeResources), WebResourceKey::new),
  121. mapsStringsToRequestables(splitQueryParam(excludeContexts), WebResourceContextKey::new)
  122. ));
  123. }
  124. /**
  125. * Calculate the missing JS, CSS and extra data required by the client, taking into consider exclusions (which
  126. * are what the client already has).
  127. *
  128. * @param request The resources and contexts to include and exclude.
  129. */
  130. @POST
  131. @Consumes({APPLICATION_JSON})
  132. @Produces({APPLICATION_JSON})
  133. @Operation(summary = "Retrieve resolved resources", tags = {"resources"})
  134. @ApiResponse(responseCode = "200", description = "Successful operation", content = @Content(schema =
  135. @Schema(implementation = ResourcesAndData.class)))
  136. public ResourcesAndData post(
  137. @Parameter(required = true) ResolveResourcesJson request
  138. ) throws IOException {
  139. return new ResourcesAndData(asyncWebResourceLoader.resolve(
  140. withDefaultPhase(mapsStringsToRequestables(request.getResources(), WebResourceKey::new)),
  141. withDefaultPhase(mapsStringsToRequestables(request.getContexts(), WebResourceContextKey::new)),
  142. mapsStringsToRequestables(request.getExcludeResources(), WebResourceKey::new),
  143. mapsStringsToRequestables(request.getExcludeContexts(), WebResourceContextKey::new)
  144. ));
  145. }
  146. private static List<String> splitQueryParam(@Nullable final String queryParam) {
  147. return (queryParam == null || queryParam.isEmpty()) ? emptyList() : asList(queryParam.split(","));
  148. }
  149. }