From 830db91c114e6b778f1f40f1384fa1b9f0ed3f58 Mon Sep 17 00:00:00 2001 From: Thomas Kountis Date: Wed, 12 May 2021 14:18:27 +0100 Subject: [PATCH] Jersey example with multipart file upload support --- gradle.properties | 2 +- servicetalk-examples/http/jaxrs/build.gradle | 3 +- .../jaxrs/HelloWorldJaxRsApplication.java | 13 +++++-- .../http/jaxrs/HelloWorldJaxRsResource.java | 35 ++++++++++++++++++- 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/gradle.properties b/gradle.properties index fc9ecc707d..5f3bd7e58f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,7 +31,7 @@ javaxJaxbCoreVersion=2.3.0.1 javaxJaxbImplVersion=2.3.3 jaxRsVersion=2.1.6 -jerseyVersion=2.32 +jerseyVersion=2.34 reactiveStreamsVersion=1.0.3 jcToolsVersion=3.3.0 diff --git a/servicetalk-examples/http/jaxrs/build.gradle b/servicetalk-examples/http/jaxrs/build.gradle index 6bf72b58cf..60c3c64354 100644 --- a/servicetalk-examples/http/jaxrs/build.gradle +++ b/servicetalk-examples/http/jaxrs/build.gradle @@ -1,5 +1,5 @@ /* - * Copyright © 2019 Apple Inc. and the ServiceTalk project authors + * Copyright © 2019, 2021 Apple Inc. and the ServiceTalk project authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ dependencies { implementation project(":servicetalk-data-jackson-jersey") implementation project(":servicetalk-http-netty") implementation project(":servicetalk-http-router-jersey") + implementation "org.glassfish.jersey.media:jersey-media-multipart:$jerseyVersion" implementation "org.slf4j:slf4j-api:$slf4jVersion" runtimeOnly "org.apache.logging.log4j:log4j-slf4j-impl:$log4jVersion" diff --git a/servicetalk-examples/http/jaxrs/src/main/java/io/servicetalk/examples/http/jaxrs/HelloWorldJaxRsApplication.java b/servicetalk-examples/http/jaxrs/src/main/java/io/servicetalk/examples/http/jaxrs/HelloWorldJaxRsApplication.java index 9dd0d900f5..b4098fa5d5 100644 --- a/servicetalk-examples/http/jaxrs/src/main/java/io/servicetalk/examples/http/jaxrs/HelloWorldJaxRsApplication.java +++ b/servicetalk-examples/http/jaxrs/src/main/java/io/servicetalk/examples/http/jaxrs/HelloWorldJaxRsApplication.java @@ -1,5 +1,5 @@ /* - * Copyright © 2018 Apple Inc. and the ServiceTalk project authors + * Copyright © 2018, 2021 Apple Inc. and the ServiceTalk project authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,9 +15,14 @@ */ package io.servicetalk.examples.http.jaxrs; +import org.glassfish.jersey.media.multipart.MultiPartFeature; + +import java.util.Collections; +import java.util.HashSet; import java.util.Set; import javax.ws.rs.core.Application; +import static java.util.Arrays.asList; import static java.util.Collections.singleton; /** @@ -26,6 +31,10 @@ public class HelloWorldJaxRsApplication extends Application { @Override public Set> getClasses() { - return singleton(HelloWorldJaxRsResource.class); + return new HashSet<>(asList( + MultiPartFeature.class, + HelloWorldJaxRsResource.class + ) + ); } } diff --git a/servicetalk-examples/http/jaxrs/src/main/java/io/servicetalk/examples/http/jaxrs/HelloWorldJaxRsResource.java b/servicetalk-examples/http/jaxrs/src/main/java/io/servicetalk/examples/http/jaxrs/HelloWorldJaxRsResource.java index 748d60ea3d..b54decbd68 100644 --- a/servicetalk-examples/http/jaxrs/src/main/java/io/servicetalk/examples/http/jaxrs/HelloWorldJaxRsResource.java +++ b/servicetalk-examples/http/jaxrs/src/main/java/io/servicetalk/examples/http/jaxrs/HelloWorldJaxRsResource.java @@ -1,5 +1,5 @@ /* - * Copyright © 2018 Apple Inc. and the ServiceTalk project authors + * Copyright © 2018, 2021 Apple Inc. and the ServiceTalk project authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,10 +17,14 @@ import io.servicetalk.buffer.api.Buffer; import io.servicetalk.buffer.api.BufferAllocator; +import io.servicetalk.buffer.api.CompositeBuffer; import io.servicetalk.concurrent.api.Publisher; import io.servicetalk.concurrent.api.Single; import io.servicetalk.transport.api.ConnectionContext; +import org.glassfish.jersey.media.multipart.FormDataParam; + +import java.io.InputStream; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; @@ -36,10 +40,12 @@ import javax.ws.rs.core.Response; import static io.servicetalk.concurrent.api.Publisher.from; +import static io.servicetalk.concurrent.api.Publisher.fromInputStream; import static java.lang.Math.random; import static java.util.Collections.singletonMap; import static java.util.concurrent.TimeUnit.SECONDS; import static javax.ws.rs.core.MediaType.APPLICATION_JSON; +import static javax.ws.rs.core.MediaType.MULTIPART_FORM_DATA; import static javax.ws.rs.core.MediaType.TEXT_PLAIN; import static javax.ws.rs.core.Response.accepted; import static javax.ws.rs.core.Response.ok; @@ -145,6 +151,33 @@ public Single hello(final Single who, .addBuffer(allocator.fromAscii("!"))); } + /** + * Resource that relies on multi-part file upload on the consume side, and {@link Publisher} with + * operators for processing it on the produce side. + *

+ * Test with: + *

+     * echo "An empty file" > sample.txt && curl -vF "file=@sample.txt" \
+     * http://localhost:8080/greetings/multipart-hello
+     * 
+ * + * @param ctx the {@link ConnectionContext}. + * @param file the multi-part file contents. + * @return greetings as a {@link Single} {@link Buffer}. + */ + @POST + @Path("multipart-hello") + @Consumes(MULTIPART_FORM_DATA) + @Produces(TEXT_PLAIN) + public Single multipartHello(@Context final ConnectionContext ctx, + @FormDataParam("file") InputStream file) { + final BufferAllocator allocator = ctx.executionContext().bufferAllocator(); + return from(allocator.fromAscii("Hello multipart! Content: ")) + .concat(fromInputStream(file).map(allocator::wrap)) + .collect(allocator::newCompositeBuffer, + (collector, item) -> ((CompositeBuffer) collector).addBuffer(item)); + } + /** * Resource that only relies on {@link Single}/{@link Publisher} for consuming and producing data, * and returns a JAX-RS {@link Response} in order to set its status.