diff --git a/http-tests/src/test/java/org/apache/pekko/http/javadsl/server/RouteFlowMaterializerTest.java b/http-tests/src/test/java/org/apache/pekko/http/javadsl/server/RouteFlowMaterializerTest.java new file mode 100644 index 000000000..9b51bf7c9 --- /dev/null +++ b/http-tests/src/test/java/org/apache/pekko/http/javadsl/server/RouteFlowMaterializerTest.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.pekko.http.javadsl.server; + +import static org.apache.pekko.http.javadsl.server.Directives.complete; +import static org.apache.pekko.http.javadsl.server.Directives.extractMaterializer; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.concurrent.CompletionStage; +import java.util.concurrent.TimeUnit; +import org.apache.pekko.NotUsed; +import org.apache.pekko.http.javadsl.model.HttpRequest; +import org.apache.pekko.http.javadsl.model.HttpResponse; +import org.apache.pekko.http.javadsl.testkit.JUnitJupiterRouteTest; +import org.apache.pekko.stream.Materializer; +import org.apache.pekko.stream.SystemMaterializer; +import org.apache.pekko.stream.javadsl.Flow; +import org.apache.pekko.stream.javadsl.Sink; +import org.apache.pekko.stream.javadsl.Source; +import org.junit.jupiter.api.Test; + +public class RouteFlowMaterializerTest extends JUnitJupiterRouteTest { + + private final Route route = + extractMaterializer(m -> complete(String.valueOf(System.identityHashCode(m)))); + + private String runFlow(Flow flow, Materializer mat) + throws Exception { + CompletionStage response = + Source.single(HttpRequest.GET("/")).via(flow).runWith(Sink.head(), mat); + return response + .toCompletableFuture() + .get(5, TimeUnit.SECONDS) + .entity() + .toStrict(5000, mat) + .toCompletableFuture() + .get(5, TimeUnit.SECONDS) + .getData() + .utf8String(); + } + + @Test + public void flowUsesTheGivenMaterializer() throws Exception { + Materializer custom = Materializer.createMaterializer(system()); + try { + assertEquals( + String.valueOf(System.identityHashCode(custom)), + runFlow(route.flow(system(), custom), custom)); + } finally { + custom.shutdown(); + } + } + + @Test + public void flowWithoutMaterializerUsesTheSystemMaterializer() throws Exception { + Materializer systemMaterializer = SystemMaterializer.get(system()).materializer(); + assertEquals( + String.valueOf(System.identityHashCode(systemMaterializer)), + runFlow(route.flow(system()), systemMaterializer)); + } +} diff --git a/http/src/main/scala/org/apache/pekko/http/javadsl/server/directives/RouteAdapter.scala b/http/src/main/scala/org/apache/pekko/http/javadsl/server/directives/RouteAdapter.scala index 206c90a42..4b381224d 100644 --- a/http/src/main/scala/org/apache/pekko/http/javadsl/server/directives/RouteAdapter.scala +++ b/http/src/main/scala/org/apache/pekko/http/javadsl/server/directives/RouteAdapter.scala @@ -45,8 +45,8 @@ final class RouteAdapter(val delegate: pekko.http.scaladsl.server.Route) extends } private def scalaFlow(system: ActorSystem, materializer: Materializer): Flow[HttpRequest, HttpResponse, NotUsed] = { - implicit val s: ActorSystem = system - Flow[HttpRequest].map(_.asScala).via(delegate).map(_.asJava) + val scalaFunction = scaladsl.server.Route.toFunction(delegate, materializer)(system) + Flow[HttpRequest].mapAsync(1)(request => scalaFunction(request.asScala)).map(_.asJava) } override def orElse(alternative: Route): Route = diff --git a/http/src/main/scala/org/apache/pekko/http/scaladsl/server/Route.scala b/http/src/main/scala/org/apache/pekko/http/scaladsl/server/Route.scala index bbd20d423..f3c7ad544 100644 --- a/http/src/main/scala/org/apache/pekko/http/scaladsl/server/Route.scala +++ b/http/src/main/scala/org/apache/pekko/http/scaladsl/server/Route.scala @@ -18,6 +18,7 @@ import scala.concurrent.{ ExecutionContextExecutor, Future } import org.apache.pekko import pekko.NotUsed import pekko.actor.ClassicActorSystemProvider +import pekko.annotation.InternalApi import pekko.http.scaladsl.model.{ HttpRequest, HttpResponse } import pekko.http.scaladsl.server.directives.BasicDirectives import pekko.http.scaladsl.settings.{ ParserSettings, RoutingSettings } @@ -69,7 +70,17 @@ object Route { def toFlow(route: Route)(implicit system: ClassicActorSystemProvider): Flow[HttpRequest, HttpResponse, NotUsed] = Flow[HttpRequest].mapAsync(1)(toFunction(route)) - def toFunction(route: Route)(implicit system: ClassicActorSystemProvider): HttpRequest => Future[HttpResponse] = { + def toFunction(route: Route)(implicit system: ClassicActorSystemProvider): HttpRequest => Future[HttpResponse] = + toFunction(route, SystemMaterializer(system).materializer) + + /** + * INTERNAL API + * + * Same as `toFunction` but runs the route with the given [[Materializer]] instead of the system materializer. + */ + @InternalApi + private[pekko] def toFunction(route: Route, materializer: Materializer)( + implicit system: ClassicActorSystemProvider): HttpRequest => Future[HttpResponse] = { val routingLog = RoutingLog(system.classicSystem.log) val routingSettings = RoutingSettings(system) val parserSettings = ParserSettings.forServer @@ -82,7 +93,7 @@ object Route { } createAsyncHandler(sealedRoute, routingLog, routingSettings, parserSettings)(system.classicSystem.dispatcher, - SystemMaterializer(system).materializer) + materializer) } private[pekko] def createAsyncHandler(sealedRoute: Route, routingLog: RoutingLog, routingSettings: RoutingSettings,