From b6f6438e96df8f667cd1e08134983cdc87f64678 Mon Sep 17 00:00:00 2001 From: gosubpl Date: Wed, 6 Jul 2016 23:23:45 +0200 Subject: [PATCH] doc #20466 Java range-directives examples added (#20892) * #20466 Java range-directives examples added * #20466 post-review changes --- .../RangeDirectivesExamplesTest.java | 88 +++++++++++++++++++ .../range-directives/withRangeSupport.rst | 3 +- .../http/javadsl/server/Unmarshaller.scala | 4 +- 3 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 akka-docs/rst/java/code/docs/http/javadsl/server/directives/RangeDirectivesExamplesTest.java diff --git a/akka-docs/rst/java/code/docs/http/javadsl/server/directives/RangeDirectivesExamplesTest.java b/akka-docs/rst/java/code/docs/http/javadsl/server/directives/RangeDirectivesExamplesTest.java new file mode 100644 index 0000000000..69c1358d9c --- /dev/null +++ b/akka-docs/rst/java/code/docs/http/javadsl/server/directives/RangeDirectivesExamplesTest.java @@ -0,0 +1,88 @@ +/** + * Copyright (C) 2016-2016 Lightbend Inc. + */ +package docs.http.javadsl.server.directives; + +import akka.http.javadsl.model.HttpRequest; +import akka.http.javadsl.model.Multipart; +import akka.http.javadsl.model.StatusCodes; +import akka.http.javadsl.model.headers.ByteRange; +import akka.http.javadsl.model.headers.ContentRange; +import akka.http.javadsl.model.headers.Range; +import akka.http.javadsl.model.headers.RangeUnits; +import akka.http.javadsl.server.Route; +import akka.http.javadsl.server.Unmarshaller; +import akka.http.javadsl.testkit.JUnitRouteTest; +import akka.http.javadsl.testkit.TestRouteResult; +import akka.stream.ActorMaterializer; +import akka.util.ByteString; +import com.typesafe.config.Config; +import com.typesafe.config.ConfigFactory; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.TimeUnit; + +public class RangeDirectivesExamplesTest extends JUnitRouteTest { + @Override + public Config additionalConfig() { + return ConfigFactory.parseString("akka.http.routing.range-coalescing-threshold=2"); + } + + @Test + public void testWithRangeSupport() { + //#withRangeSupport + final Route route = withRangeSupport(() -> complete("ABCDEFGH")); + + // test: + final String bytes348Range = ContentRange.create(RangeUnits.BYTES, + akka.http.javadsl.model.ContentRange.create(3, 4, 8)).value(); + final akka.http.javadsl.model.ContentRange bytes028Range = + akka.http.javadsl.model.ContentRange.create(0, 2, 8); + final akka.http.javadsl.model.ContentRange bytes678Range = + akka.http.javadsl.model.ContentRange.create(6, 7, 8); + final ActorMaterializer materializer = systemResource().materializer(); + + testRoute(route).run(HttpRequest.GET("/") + .addHeader(Range.create(RangeUnits.BYTES, ByteRange.createSlice(3, 4)))) + .assertHeaderKindExists("Content-Range") + .assertHeaderExists("Content-Range", bytes348Range) + .assertStatusCode(StatusCodes.PARTIAL_CONTENT) + .assertEntity("DE"); + + // we set "akka.http.routing.range-coalescing-threshold = 2" + // above to make sure we get two BodyParts + final TestRouteResult response = testRoute(route).run(HttpRequest.GET("/") + .addHeader(Range.create(RangeUnits.BYTES, + ByteRange.createSlice(0, 1), ByteRange.createSlice(1, 2), ByteRange.createSlice(6, 7)))); + response.assertHeaderKindNotExists("Content-Range"); + + final CompletionStage> completionStage = + response.entity(Unmarshaller.entityToMultipartByteRanges()).getParts() + .runFold(new ArrayList<>(), (acc, n) -> { + acc.add(n); + return acc; + }, materializer); + try { + final List bodyParts = + completionStage.toCompletableFuture().get(3, TimeUnit.SECONDS); + assertResult(2, bodyParts.toArray().length); + + final Multipart.ByteRanges.BodyPart part1 = bodyParts.get(0); + assertResult(bytes028Range, part1.getContentRange()); + assertResult(ByteString.fromString("ABC"), + part1.toStrict(1000, materializer).toCompletableFuture().get().getEntity().getData()); + + final Multipart.ByteRanges.BodyPart part2 = bodyParts.get(1); + assertResult(bytes678Range, part2.getContentRange()); + assertResult(ByteString.fromString("GH"), + part2.toStrict(1000, materializer).toCompletableFuture().get().getEntity().getData()); + + } catch (Exception e) { + // please handle this in production code + } + //# + } +} diff --git a/akka-docs/rst/java/http/routing-dsl/directives/range-directives/withRangeSupport.rst b/akka-docs/rst/java/http/routing-dsl/directives/range-directives/withRangeSupport.rst index 263d6325d6..4387e7afe6 100644 --- a/akka-docs/rst/java/http/routing-dsl/directives/range-directives/withRangeSupport.rst +++ b/akka-docs/rst/java/http/routing-dsl/directives/range-directives/withRangeSupport.rst @@ -27,4 +27,5 @@ See also: https://tools.ietf.org/html/rfc7233 Example ------- -TODO: Example snippets for JavaDSL are subject to community contributions! Help us complete the docs, read more about it here: `write example snippets for Akka HTTP Java DSL #20466 `_. +.. includecode2:: ../../../../code/docs/http/javadsl/server/directives/RangeDirectivesExamplesTest.java + :snippet: withRangeSupport \ No newline at end of file diff --git a/akka-http/src/main/scala/akka/http/javadsl/server/Unmarshaller.scala b/akka-http/src/main/scala/akka/http/javadsl/server/Unmarshaller.scala index 7d06ea7ff9..82dcc5ab7b 100644 --- a/akka-http/src/main/scala/akka/http/javadsl/server/Unmarshaller.scala +++ b/akka-http/src/main/scala/akka/http/javadsl/server/Unmarshaller.scala @@ -13,10 +13,11 @@ import akka.http.scaladsl.{ marshalling, model, unmarshalling } import akka.util.ByteString import akka.http.scaladsl.util.FastFuture import akka.http.scaladsl.util.FastFuture._ + import scala.concurrent.ExecutionContext import scala.annotation.varargs import akka.http.javadsl.model.HttpEntity -import akka.http.scaladsl.model.{ ContentTypeRange, ContentTypes, FormData } +import akka.http.scaladsl.model.{ ContentTypeRange, ContentTypes, FormData, Multipart } import akka.http.scaladsl import akka.http.javadsl.model.ContentType import akka.http.javadsl.model.HttpRequest @@ -57,6 +58,7 @@ object Unmarshaller { def entityToCharArray: Unmarshaller[HttpEntity, Array[Char]] = unmarshalling.Unmarshaller.charArrayUnmarshaller def entityToString: Unmarshaller[HttpEntity, String] = unmarshalling.Unmarshaller.stringUnmarshaller def entityToUrlEncodedFormData: Unmarshaller[HttpEntity, FormData] = unmarshalling.Unmarshaller.defaultUrlEncodedFormDataUnmarshaller + def entityToMultipartByteRanges: Unmarshaller[HttpEntity, Multipart.ByteRanges] = unmarshalling.MultipartUnmarshallers.defaultMultipartByteRangesUnmarshaller // format: ON val requestToEntity: Unmarshaller[HttpRequest, RequestEntity] =