/atlassian-plugins-webresource-rest/src/main/java/com/atlassian/webresource/plugin/rest/one/zero/PhasesUnawareResources.java
Java | 159 lines | 123 code | 10 blank | 26 comment | 2 complexity | 6428bc43433a17443877848aee34fbea MD5 | raw file
- package com.atlassian.webresource.plugin.rest.one.zero;
- import com.atlassian.annotations.VisibleForTesting;
- import com.atlassian.plugin.webresource.models.Requestable;
- import com.atlassian.plugin.webresource.models.WebResourceContextKey;
- import com.atlassian.plugin.webresource.models.WebResourceKey;
- import com.atlassian.plugins.rest.common.security.AnonymousAllowed;
- import com.atlassian.webresource.api.assembler.resource.ResourcePhase;
- import com.atlassian.webresource.plugin.async.AsyncWebResourceLoader;
- import com.atlassian.webresource.plugin.rest.one.zero.model.ResolveResourcesJson;
- import com.atlassian.webresource.plugin.rest.one.zero.model.ResourcesAndData;
- import io.swagger.v3.oas.annotations.OpenAPIDefinition;
- import io.swagger.v3.oas.annotations.Operation;
- import io.swagger.v3.oas.annotations.Parameter;
- import io.swagger.v3.oas.annotations.info.Info;
- import io.swagger.v3.oas.annotations.media.Content;
- import io.swagger.v3.oas.annotations.media.Schema;
- import io.swagger.v3.oas.annotations.responses.ApiResponse;
- import javax.annotation.Nullable;
- import javax.ws.rs.Consumes;
- import javax.ws.rs.GET;
- import javax.ws.rs.POST;
- import javax.ws.rs.Path;
- import javax.ws.rs.Produces;
- import javax.ws.rs.QueryParam;
- import java.io.IOException;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import java.util.function.Function;
- import java.util.stream.Collectors;
- import static io.swagger.v3.oas.annotations.enums.Explode.FALSE;
- import static io.swagger.v3.oas.annotations.enums.ParameterStyle.FORM;
- import static java.util.Arrays.asList;
- import static java.util.Collections.emptyList;
- import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
- /**
- * REST endpoint for retrieving resolved of JS, CSS (and more) resources
- *
- * @since v3.0
- */
- @AnonymousAllowed
- @OpenAPIDefinition(
- info = @Info(
- title = "Web Resource Manager",
- version = "1.0",
- description = "This is a draft of the proposed APIs to support retrieving of all forms of resources."
- )
- )
- @Path("resources")
- @Consumes({APPLICATION_JSON})
- @Produces({APPLICATION_JSON})
- public class PhasesUnawareResources {
- private final AsyncWebResourceLoader asyncWebResourceLoader;
- public PhasesUnawareResources(AsyncWebResourceLoader asyncWebResourceLoader) {
- this.asyncWebResourceLoader = asyncWebResourceLoader;
- }
- @VisibleForTesting
- protected static <T extends Requestable> Set<T> mapsStringsToRequestables(
- Collection<String> rawStrings,
- Function<String, T> constructor
- ) {
- return rawStrings.stream().map(constructor).collect(Collectors.toSet());
- }
- @VisibleForTesting
- protected static <T extends Requestable> Map<ResourcePhase, Set<T>> withDefaultPhase(
- Set<T> requestables
- ) {
- return requestables.isEmpty() ? Collections.emptyMap() : Collections.singletonMap(ResourcePhase.defaultPhase(), requestables);
- }
- /**
- * HTTP GET version of {@link #post} allowing parameters to be supplied via the URL.
- * <p>
- * Avoid this in favour of the POST form when you risk exceeding the maximum URL length supported by browsers. For
- * example when you expect to have a large number of requires or exclusions (e.g. in development mode where
- * resources are not batched).
- *
- * @param webResources Comma separated list of IDs of resources to require. Can have a phase separated by a
- * semi-colon
- * @param contexts Comma separated list of IDs of contexts to require. Can have a phase separated by a
- * semi-colon
- * @param excludeResources Comma separated list of IDs of resources to exclude.
- * @param excludeContexts Comma separated list of IDs of contexts to exclude.f
- * @deprecated Use the {@link #post} version to avoid URL length issues
- */
- @Deprecated
- @GET
- @Produces({APPLICATION_JSON})
- @Operation(summary = "Retrieve resolved resources", tags = {"resources"})
- @ApiResponse(responseCode = "200", description = "Successful operation", content = @Content(schema =
- @Schema(implementation = ResourcesAndData.class)))
- public ResourcesAndData get(
- @Parameter(description = "Comma-separated list of phase aware WebResources wanted. Phases are " +
- "prepended, followed by by a semi-colon to separate it from the key of the WebResource",
- example = "interactive;com.atlassian:web-resource-key-1,render;com.atlassian:web-resource-key-2",
- style = FORM, explode = FALSE)
- @QueryParam("r")
- String webResources,
- @Parameter(description = "Comma-separated list of phase aware WebResourceContexts wanted. Phases are " +
- "prepended, followed by by a semi-colon to separate it from the key of the WebResourceContext",
- example = "interactive;com.atlassian:context-key-1,render;com.atlassian:context-key-2",
- style = FORM, explode = FALSE)
- @QueryParam("c")
- String contexts,
- @Parameter(description = "Comma-separated list of WebResources not wanted.",
- example = "com.atlassian:excluded-web-resource-key-1,com.atlassian:excluded-web-resource-key-2",
- style = FORM, explode = FALSE)
- @QueryParam("xr")
- String excludeResources,
- @Parameter(description = "Comma-separated list of WebResourceContexts not wanted.",
- example = "com.atlassian:excluded-context-key-1,com.atlassian:excluded-context-key-2",
- style = FORM, explode = FALSE)
- @QueryParam("xc")
- String excludeContexts
- ) throws IOException {
- return new ResourcesAndData(asyncWebResourceLoader.resolve(
- withDefaultPhase(mapsStringsToRequestables(splitQueryParam(webResources), WebResourceKey::new)),
- withDefaultPhase(mapsStringsToRequestables(splitQueryParam(contexts), WebResourceContextKey::new)),
- mapsStringsToRequestables(splitQueryParam(excludeResources), WebResourceKey::new),
- mapsStringsToRequestables(splitQueryParam(excludeContexts), WebResourceContextKey::new)
- ));
- }
- /**
- * Calculate the missing JS, CSS and extra data required by the client, taking into consider exclusions (which
- * are what the client already has).
- *
- * @param request The resources and contexts to include and exclude.
- */
- @POST
- @Consumes({APPLICATION_JSON})
- @Produces({APPLICATION_JSON})
- @Operation(summary = "Retrieve resolved resources", tags = {"resources"})
- @ApiResponse(responseCode = "200", description = "Successful operation", content = @Content(schema =
- @Schema(implementation = ResourcesAndData.class)))
- public ResourcesAndData post(
- @Parameter(required = true) ResolveResourcesJson request
- ) throws IOException {
- return new ResourcesAndData(asyncWebResourceLoader.resolve(
- withDefaultPhase(mapsStringsToRequestables(request.getResources(), WebResourceKey::new)),
- withDefaultPhase(mapsStringsToRequestables(request.getContexts(), WebResourceContextKey::new)),
- mapsStringsToRequestables(request.getExcludeResources(), WebResourceKey::new),
- mapsStringsToRequestables(request.getExcludeContexts(), WebResourceContextKey::new)
- ));
- }
- private static List<String> splitQueryParam(@Nullable final String queryParam) {
- return (queryParam == null || queryParam.isEmpty()) ? emptyList() : asList(queryParam.split(","));
- }
- }