diff --git a/docs/src/test/scala/docs/ApiMayChangeDocCheckerSpec.scala b/docs/src/test/scala/docs/ApiMayChangeDocCheckerSpec.scala index d2be06ea76..e459f38d9d 100644 --- a/docs/src/test/scala/docs/ApiMayChangeDocCheckerSpec.scala +++ b/docs/src/test/scala/docs/ApiMayChangeDocCheckerSpec.scala @@ -33,9 +33,9 @@ class ApiMayChangeDocCheckerSpec extends AnyWordSpec with Matchers { clazz.getCanonicalName.replaceAll("\\$minus", "-").split("\\$")(0) } - // As Specs, Directives and HttpApp inherit get all directives methods, we skip those as they are not really bringing any extra info + // As Specs and Directives inherit get all directives methods, we skip those as they are not really bringing any extra info def removeClassesToIgnore(method: Method): Boolean = { - Seq("Spec", ".Directives", ".HttpApp").exists(method.getDeclaringClass.getCanonicalName.contains) + Seq("Spec", ".Directives").exists(method.getDeclaringClass.getCanonicalName.contains) } def collectMissing(docPage: Seq[String])(set: Set[String], name: String): Set[String] = { diff --git a/http-tests/src/test/java/org/apache/pekko/http/javadsl/server/MinimalHttpApp.java b/http-tests/src/test/java/org/apache/pekko/http/javadsl/server/MinimalHttpApp.java deleted file mode 100644 index 4da7e9d2ea..0000000000 --- a/http-tests/src/test/java/org/apache/pekko/http/javadsl/server/MinimalHttpApp.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * license agreements; and to You under the Apache License, version 2.0: - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * This file is part of the Apache Pekko project, which was derived from Akka. - */ - -/* - * Copyright (C) 2009-2022 Lightbend Inc. - */ - -package org.apache.pekko.http.javadsl.server; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import org.apache.pekko.Done; -import org.apache.pekko.actor.ActorSystem; -import org.apache.pekko.http.javadsl.ServerBinding; - -public class MinimalHttpApp extends HttpApp { - - CompletableFuture shutdownTrigger = new CompletableFuture<>(); - CompletableFuture bindingPromise = new CompletableFuture<>(); - - public void shutdown() { - shutdownTrigger.complete(Done.getInstance()); - } - - @Override - protected Route routes() { - return path("foo", () -> complete("bar")); - } - - @Override - protected void postHttpBinding(ServerBinding binding) { - super.postHttpBinding(binding); - bindingPromise.complete(binding); - } - - @Override - protected void postHttpBindingFailure(Throwable cause) { - super.postHttpBindingFailure(cause); - bindingPromise.completeExceptionally(cause); - } - - @Override - protected CompletionStage waitForShutdownSignal(ActorSystem system) { - return shutdownTrigger; - } -} diff --git a/http-tests/src/test/java/org/apache/pekko/http/javadsl/server/SneakHttpApp.java b/http-tests/src/test/java/org/apache/pekko/http/javadsl/server/SneakHttpApp.java deleted file mode 100644 index 962a334144..0000000000 --- a/http-tests/src/test/java/org/apache/pekko/http/javadsl/server/SneakHttpApp.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * license agreements; and to You under the Apache License, version 2.0: - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * This file is part of the Apache Pekko project, which was derived from Akka. - */ - -/* - * Copyright (C) 2009-2022 Lightbend Inc. - */ - -package org.apache.pekko.http.javadsl.server; - -import java.util.Optional; -import java.util.concurrent.atomic.AtomicBoolean; -import org.apache.pekko.actor.ActorSystem; -import org.apache.pekko.http.javadsl.ServerBinding; - -public class SneakHttpApp extends MinimalHttpApp { - - AtomicBoolean postServerShutdownCalled = new AtomicBoolean(false); - AtomicBoolean postBindingCalled = new AtomicBoolean(false); - AtomicBoolean postBindingFailureCalled = new AtomicBoolean(false); - - @Override - protected void postServerShutdown(Optional failure, ActorSystem system) { - postServerShutdownCalled.set(true); - } - - @Override - protected void postHttpBinding(ServerBinding binding) { - postBindingCalled.set(true); - bindingPromise.complete(binding); - } - - @Override - protected void postHttpBindingFailure(Throwable cause) { - postBindingFailureCalled.set(true); - } -} diff --git a/http-tests/src/test/scala/org/apache/pekko/http/javadsl/server/HttpAppSpec.scala b/http-tests/src/test/scala/org/apache/pekko/http/javadsl/server/HttpAppSpec.scala deleted file mode 100644 index 52cfc3526c..0000000000 --- a/http-tests/src/test/scala/org/apache/pekko/http/javadsl/server/HttpAppSpec.scala +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * license agreements; and to You under the Apache License, version 2.0: - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * This file is part of the Apache Pekko project, which was derived from Akka. - */ - -/* - * Copyright (C) 2009-2022 Lightbend Inc. - */ - -package org.apache.pekko.http.javadsl.server - -import java.net.InetSocketAddress -import java.net.ServerSocket -import java.net.SocketException -import java.util.concurrent.{ TimeUnit, TimeoutException } - -import scala.concurrent.{ Await, Future } -import scala.concurrent.duration.Duration - -import org.apache.pekko -import pekko.Done -import pekko.http.impl.util.PekkoSpecWithMaterializer -import pekko.http.javadsl.ServerBinding -import pekko.http.javadsl.settings.ServerSettings -import pekko.http.scaladsl.Http -import pekko.http.scaladsl.client.RequestBuilding -import pekko.http.scaladsl.model.{ HttpRequest, StatusCodes } -import pekko.testkit.EventFilter - -import org.scalatest.concurrent.Eventually - -import com.typesafe.config.ConfigFactory - -class HttpAppSpec extends PekkoSpecWithMaterializer with RequestBuilding with Eventually { - import system.dispatcher - - def withMinimal(testCode: MinimalHttpApp => Any): Unit = { - val minimal = new MinimalHttpApp() - try testCode(minimal) - finally { - if (!minimal.shutdownTrigger.isDone) minimal.shutdownTrigger.complete(Done) - } - } - - def withSneaky(testCode: SneakHttpApp => Any): Unit = { - val sneaky = new SneakHttpApp() - try testCode(sneaky) - finally { - if (!sneaky.shutdownTrigger.isDone) sneaky.shutdownTrigger.complete(Done) - } - } - - "HttpApp Java" should { - - "start only with host and port" in withMinimal { minimal => - val server = Future { - minimal.startServer("localhost", 0) - } - - val binding = minimal.bindingPromise.get(5, TimeUnit.SECONDS) - - // Checking server is up and running - callAndVerify(binding, "foo") - - // Requesting the server to shutdown - minimal.shutdown() - Await.ready(server, Duration(1, TimeUnit.SECONDS)) - server.isCompleted should ===(true) - - } - - "start without ActorSystem" in withMinimal { minimal => - val server = Future { - minimal.startServer("localhost", 0, ServerSettings.create(ConfigFactory.load)) - } - - val binding = minimal.bindingPromise.get(5, TimeUnit.SECONDS) - - // Checking server is up and running - callAndVerify(binding, "foo") - - // Requesting the server to shutdown - minimal.shutdown() - - Await.ready(server, Duration(1, TimeUnit.SECONDS)) - server.isCompleted should ===(true) - - } - - "start providing an ActorSystem" in withMinimal { minimal => - val server = Future { - log.debug("Before startServer 1") - val res = minimal.startServer("localhost", 0, system) - log.debug("After startServer 1") - res - }(system.dispatchers.lookup("pekko.actor.default-blocking-io-dispatcher")) - - val binding = - try minimal.bindingPromise.get(2, TimeUnit.SECONDS) - catch { - case e: TimeoutException => - java.lang.management.ManagementFactory.getThreadMXBean.dumpAllThreads(true, true).foreach(println) - throw e - } - - // Checking server is up and running - callAndVerify(binding, "foo") - - // Requesting the server to shutdown - minimal.shutdown() - - Await.ready(server, Duration(1, TimeUnit.SECONDS)) - server.isCompleted should ===(true) - system.whenTerminated.isCompleted should ===(false) - - } - - "start providing an ActorSystem and Settings" in withMinimal { minimal => - val server = Future { - log.debug("Before startServer 2") - val res = minimal.startServer("localhost", 0, ServerSettings.create(system), system) - log.debug("After startServer 2") - res - }(system.dispatchers.lookup("pekko.actor.default-blocking-io-dispatcher")) - - val binding = - try minimal.bindingPromise.get(2, TimeUnit.SECONDS) - catch { - case e: TimeoutException => - java.lang.management.ManagementFactory.getThreadMXBean.dumpAllThreads(true, true).foreach(println) - throw e - } - - // Checking server is up and running - callAndVerify(binding, "foo") - - // Requesting the server to shutdown - minimal.shutdown() - - Await.ready(server, Duration(1, TimeUnit.SECONDS)) - server.isCompleted should ===(true) - system.whenTerminated.isCompleted should ===(false) - - } - - "provide binding if available" in withMinimal { minimal => - intercept[IllegalStateException] { - minimal.binding() - } - - val server = Future { - minimal.startServer("127.0.0.1", 0, ServerSettings.create(ConfigFactory.load)) - } - - val binding = minimal.bindingPromise.get(5, TimeUnit.SECONDS) - - minimal.binding().localAddress.getAddress.getHostAddress should ===("127.0.0.1") - - // Checking server is up and running - callAndVerify(binding, "foo") - - // Requesting the server to shutdown - minimal.shutdown() - Await.ready(server, Duration(1, TimeUnit.SECONDS)) - server.isCompleted should ===(true) - - } - - "notify" when { - - "shutting down" in withSneaky { sneaky => - val server = Future { - sneaky.startServer("localhost", 0, ServerSettings.create(ConfigFactory.load)) - } - - sneaky.postServerShutdownCalled.get() should ===(false) - - val binding = sneaky.bindingPromise.get(5, TimeUnit.SECONDS) - - // Checking server is up and running - callAndVerify(binding, "foo") - - // Requesting the server to shutdown - sneaky.shutdown() - Await.ready(server, Duration(1, TimeUnit.SECONDS)) - server.isCompleted should ===(true) - eventually { - sneaky.postServerShutdownCalled.get() should ===(true) - } - - } - - "after binding is successful" in withSneaky { sneaky => - val server = Future { - sneaky.startServer("localhost", 0, ServerSettings.create(ConfigFactory.load)) - } - - val binding = sneaky.bindingPromise.get(5, TimeUnit.SECONDS) - - sneaky.postBindingCalled.get() should ===(true) - - // Checking server is up and running - callAndVerify(binding, "foo") - - // Requesting the server to shutdown - sneaky.shutdown() - Await.ready(server, Duration(1, TimeUnit.SECONDS)) - server.isCompleted should ===(true) - - } - - "after binding is unsuccessful" in withSneaky { sneaky => - val serverSocket = new ServerSocket() - serverSocket.bind(new InetSocketAddress("127.0.0.1", 0)) - val port = serverSocket.getLocalPort - - try { - EventFilter[SocketException](pattern = ".*Address already in use.*", occurrences = 1).intercept { - sneaky.startServer("localhost", port, system) - } - - eventually { - sneaky.postBindingFailureCalled.get() should ===(true) - } - } finally serverSocket.close() - } - - } - - } - - private def callAndVerify(binding: ServerBinding, path: String) = { - - val host = binding.localAddress.getHostString - val port = binding.localAddress.getPort - - val request = HttpRequest(uri = s"http://$host:$port/$path") - val response = Http().singleRequest(request) - response.futureValue.status should ===(StatusCodes.OK) - } - -} diff --git a/http-tests/src/test/scala/org/apache/pekko/http/scaladsl/server/HttpAppSpec.scala b/http-tests/src/test/scala/org/apache/pekko/http/scaladsl/server/HttpAppSpec.scala deleted file mode 100644 index e196f84a93..0000000000 --- a/http-tests/src/test/scala/org/apache/pekko/http/scaladsl/server/HttpAppSpec.scala +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * license agreements; and to You under the Apache License, version 2.0: - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * This file is part of the Apache Pekko project, which was derived from Akka. - */ - -/* - * Copyright (C) 2009-2022 Lightbend Inc. - */ - -package org.apache.pekko.http.scaladsl.server - -import java.net.InetSocketAddress -import java.net.ServerSocket -import java.net.SocketException -import java.util.concurrent.TimeUnit -import java.util.concurrent.atomic.AtomicBoolean - -import scala.concurrent.{ Await, ExecutionContext, Future, Promise } -import scala.concurrent.duration.Duration -import scala.util.Try - -import org.apache.pekko -import pekko.Done -import pekko.actor.ActorSystem -import pekko.http.impl.util.PekkoSpecWithMaterializer -import pekko.http.scaladsl.Http -import pekko.http.scaladsl.Http.ServerBinding -import pekko.http.scaladsl.client.RequestBuilding -import pekko.http.scaladsl.model.{ HttpRequest, StatusCodes } -import pekko.http.scaladsl.settings.ServerSettings -import pekko.testkit.EventFilter - -import org.scalatest.concurrent.Eventually - -import com.typesafe.config.ConfigFactory - -class HttpAppSpec extends PekkoSpecWithMaterializer with RequestBuilding with Eventually { - import system.dispatcher - - class MinimalApp extends HttpApp { - - val shutdownPromise = Promise[Done]() - val bindingPromise = Promise[ServerBinding]() - - def shutdownServer(): Unit = shutdownPromise.success(Done) - - override protected def routes: Route = - path("foo") { - complete("bar") - } - - override protected def postHttpBinding(binding: ServerBinding): Unit = { - super.postHttpBinding(binding) - bindingPromise.success(binding) - } - - override protected def waitForShutdownSignal(system: ActorSystem)(implicit ec: ExecutionContext): Future[Done] = { - shutdownPromise.future - } - } - - class SneakyServer extends MinimalApp { - - val postBindingCalled = new AtomicBoolean(false) - val postBindingFailureCalled = new AtomicBoolean(false) - val postShutdownCalled = new AtomicBoolean(false) - - override protected def postHttpBindingFailure(cause: Throwable): Unit = postBindingFailureCalled.set(true) - - override protected def postHttpBinding(binding: ServerBinding): Unit = { - postBindingCalled.set(true) - bindingPromise.success(binding) - } - - override protected def postServerShutdown(attempt: Try[Done], system: ActorSystem): Unit = - postShutdownCalled.set(true) - } - - def withMinimal(testCode: MinimalApp => Any): Unit = { - val minimal = new MinimalApp() - try testCode(minimal) - finally { - if (!minimal.shutdownPromise.isCompleted) minimal.shutdownPromise.success(Done) - } - } - - def withSneaky(testCode: SneakyServer => Any): Unit = { - val sneaky = new SneakyServer() - try testCode(sneaky) - finally { - if (!sneaky.shutdownPromise.isCompleted) sneaky.shutdownPromise.success(Done) - } - } - - "HttpApp" should { - - "start only with host and port" in withMinimal { minimal => - val server = Future { - minimal.startServer("localhost", 0) - } - - val binding = Await.result(minimal.bindingPromise.future, Duration(5, TimeUnit.SECONDS)) - - // Checking server is up and running - callAndVerify(binding, "foo") - - // Requesting the server to shutdown - minimal.shutdownServer() - Await.ready(server, Duration(1, TimeUnit.SECONDS)) - server.isCompleted should ===(true) - } - - "start without ActorSystem" in withMinimal { minimal => - val server = Future { - minimal.startServer("localhost", 0, ServerSettings(ConfigFactory.load)) - } - - val binding = Await.result(minimal.bindingPromise.future, Duration(5, TimeUnit.SECONDS)) - - // Checking server is up and running - callAndVerify(binding, "foo") - - // Requesting the server to shutdown - minimal.shutdownServer() - Await.ready(server, Duration(1, TimeUnit.SECONDS)) - server.isCompleted should ===(true) - - } - - "start providing an ActorSystem" in withMinimal { minimal => - val server = Future { - minimal.startServer("localhost", 0, system) - } - - val binding = Await.result(minimal.bindingPromise.future, Duration(5, TimeUnit.SECONDS)) - - // Checking server is up and running - callAndVerify(binding, "foo") - - // Requesting the server to shutdown - minimal.shutdownServer() - Await.ready(server, Duration(1, TimeUnit.SECONDS)) - server.isCompleted should ===(true) - system.whenTerminated.isCompleted should ===(false) - - } - - "start providing an ActorSystem and Settings" in withMinimal { minimal => - val server = Future { - minimal.startServer("localhost", 0, ServerSettings(system), system) - } - - val binding = Await.result(minimal.bindingPromise.future, Duration(5, TimeUnit.SECONDS)) - - // Checking server is up and running - callAndVerify(binding, "foo") - - // Requesting the server to shutdown - minimal.shutdownServer() - Await.ready(server, Duration(1, TimeUnit.SECONDS)) - server.isCompleted should ===(true) - system.whenTerminated.isCompleted should ===(false) - - } - - "provide binding if available" in withMinimal { minimal => - minimal.binding().isFailure should ===(true) - - val server = Future { - minimal.startServer("127.0.0.1", 0, ServerSettings(ConfigFactory.load)) - } - - val binding = Await.result(minimal.bindingPromise.future, Duration(5, TimeUnit.SECONDS)) - - minimal.binding().isSuccess should ===(true) - minimal.binding().get.localAddress.getAddress.getHostAddress should ===("127.0.0.1") - - // Checking server is up and running - callAndVerify(binding, "foo") - - // Requesting the server to shutdown - minimal.shutdownServer() - Await.ready(server, Duration(1, TimeUnit.SECONDS)) - server.isCompleted should ===(true) - - } - - "notify" when { - - "shutting down" in withSneaky { sneaky => - val server = Future { - sneaky.startServer("localhost", 0, ServerSettings(ConfigFactory.load)) - } - - val binding = Await.result(sneaky.bindingPromise.future, Duration(5, TimeUnit.SECONDS)) - - sneaky.postShutdownCalled.get() should ===(false) - - // Checking server is up and running - callAndVerify(binding, "foo") - - // Requesting the server to shutdown - sneaky.shutdownServer() - Await.ready(server, Duration(1, TimeUnit.SECONDS)) - server.isCompleted should ===(true) - eventually { - sneaky.postShutdownCalled.get() should ===(true) - } - - } - - "after binding is successful" in withSneaky { sneaky => - val server = Future { - sneaky.startServer("localhost", 0, ServerSettings(ConfigFactory.load)) - } - - val binding = Await.result(sneaky.bindingPromise.future, Duration(5, TimeUnit.SECONDS)) - - sneaky.postBindingCalled.get() should ===(true) - - // Checking server is up and running - callAndVerify(binding, "foo") - - // Requesting the server to shutdown - sneaky.shutdownServer() - Await.ready(server, Duration(1, TimeUnit.SECONDS)) - server.isCompleted should ===(true) - - } - - "after binding is unsuccessful" in withSneaky { sneaky => - val serverSocket = new ServerSocket() - serverSocket.bind(new InetSocketAddress("127.0.0.1", 0)) - val port = serverSocket.getLocalPort - - try { - EventFilter[SocketException](pattern = ".*Address already in use.*", occurrences = 1).intercept { - sneaky.startServer("localhost", port, system) - } - - eventually { - sneaky.postBindingFailureCalled.get() should ===(true) - } - } finally serverSocket.close() - } - - } - - } - - private def callAndVerify(binding: ServerBinding, path: String) = { - val host = binding.localAddress.getHostString - val port = binding.localAddress.getPort - - val request = HttpRequest(uri = s"http://$host:$port/$path") - val response = Http().singleRequest(request) - response.futureValue.status should ===(StatusCodes.OK) - } -} diff --git a/http/src/main/java/org/apache/pekko/http/javadsl/server/HttpApp.java b/http/src/main/java/org/apache/pekko/http/javadsl/server/HttpApp.java deleted file mode 100644 index 58f57451a1..0000000000 --- a/http/src/main/java/org/apache/pekko/http/javadsl/server/HttpApp.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * license agreements; and to You under the Apache License, version 2.0: - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * This file is part of the Apache Pekko project, which was derived from Akka. - */ - -/* - * Copyright (C) 2009-2022 Lightbend Inc. - */ - -package org.apache.pekko.http.javadsl.server; - -import com.typesafe.config.ConfigFactory; -import java.io.IOException; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.pekko.Done; -import org.apache.pekko.actor.ActorSystem; -import org.apache.pekko.event.Logging; -import org.apache.pekko.http.javadsl.Http; -import org.apache.pekko.http.javadsl.ServerBinding; -import org.apache.pekko.http.javadsl.settings.ServerSettings; - -/** - * DEPRECATED, consider https://github.com/apache/pekko-http-quickstart-java.g8 instead - * - *

Bootstrap trait for Http Server. It helps booting up a pekko-http server by only defining the - * desired routes. It offers additional hooks to modify the default behavior. - * - * @deprecated HttpApp this doesn't reflect the latest APIs, since Akka HTTP 10.2.0 - */ -@Deprecated(since = "Akka HTTP 10.2.0") -public abstract class HttpApp extends AllDirectives { - - private AtomicReference serverBinding = new AtomicReference<>(); - - /** - * Holds a reference to the {@link ActorSystem} used to start this server. Stopping this system - * will interfere with the proper functioning condition of the server. - */ - protected AtomicReference systemReference = new AtomicReference<>(); - - /** Start a server on the specified host and port. Note that this method is blocking. */ - public void startServer(String host, int port) throws ExecutionException, InterruptedException { - startServer(host, port, ServerSettings.create(ConfigFactory.load())); - } - - /** - * Start a server on the specified host and port, using the provided [[ActorSystem]] Note that - * this method is blocking. - * - * @param system ActorSystem to use for starting the app, if null is passed in a new default - * ActorSystem will be created instead, which will be terminated when the server is stopped. - */ - public void startServer(String host, int port, ActorSystem system) - throws ExecutionException, InterruptedException { - startServer(host, port, ServerSettings.create(system), Optional.ofNullable(system)); - } - - /** - * Start a server on the specified host and port, using the provided settings. Note that this - * method is blocking. - */ - public void startServer(String host, int port, ServerSettings settings) - throws ExecutionException, InterruptedException { - startServer(host, port, settings, Optional.empty()); - } - - /** - * Start a server on the specified host and port, using the provided settings and [[ActorSystem]]. - * Note that this method is blocking. - * - * @param system ActorSystem to use for starting the app, if null is passed in a new default - * ActorSystem will be created instead, which will be terminated when the server is stopped. - */ - public void startServer(String host, int port, ServerSettings settings, ActorSystem system) - throws ExecutionException, InterruptedException { - startServer(host, port, settings, Optional.ofNullable(system)); - } - - /** - * Start a server on the specified host and port, using the provided settings and [[ActorSystem]] - * if present. Note that this method is blocking. This method may throw an {@link - * ExecutionException} or {@link InterruptedException} if the future that signals that the server - * should shutdown is interrupted or cancelled. - * - * @param system ActorSystem to use for starting the app, if an empty Optional is passed in a new - * default ActorSystem will be created instead, which will be terminated when the server is - * stopped. - */ - public void startServer( - String host, int port, ServerSettings settings, Optional system) - throws ExecutionException, InterruptedException { - - final ActorSystem theSystem = - system.orElseGet(() -> ActorSystem.create(Logging.simpleName(this).replaceAll("\\$", ""))); - systemReference.set(theSystem); - - CompletionStage bindingFuture = - Http.get(theSystem).newServerAt(host, port).withSettings(settings).bind(routes()); - - bindingFuture.handle( - (binding, exception) -> { - if (exception != null) { - postHttpBindingFailure(exception); - } else { - // setting the server binding for possible future uses in the client - serverBinding.set(binding); - postHttpBinding(binding); - } - return null; - }); - - try { - bindingFuture - .thenCompose( - ignore -> waitForShutdownSignal(theSystem)) // chaining both futures to fail fast - .toCompletableFuture() - .exceptionally( - ignored -> Done.getInstance()) // If the future fails, we want to complete normally - .get(); // It's waiting forever because maybe there is never a shutdown signal - } finally { - bindingFuture - .thenCompose(ServerBinding::unbind) - .handle( - (success, exception) -> { - postServerShutdown(Optional.ofNullable(exception), theSystem); - if (system.isEmpty()) { - // we created the system. we should cleanup! - theSystem.terminate(); - } - return null; - }); - } - } - - /** - * It tries to retrieve the {@link ServerBinding} if the server has been successfully started. It - * throws an {@link IllegalStateException} otherwise. You can use this method to attempt to - * retrieve the {@link ServerBinding} at any point in time to, for example, stop the server due to - * unexpected circumstances. - */ - ServerBinding binding() { - if (serverBinding.get() == null) - throw new IllegalStateException("Binding not yet stored. Have you called startServer?"); - return serverBinding.get(); - } - - /** - * Hook that will be called just after the server termination. Override this method if you want to - * perform some cleanup actions after the server is stopped. The {@code failure} parameter - * contains a {@link Throwable} only if there has been a problem shutting down the server. - */ - protected void postServerShutdown(Optional failure, ActorSystem system) { - systemReference.get().log().info("Shutting down the server"); - } - - /** - * Hook that will be called just after the Http server binding is done. Override this method if - * you want to perform some actions after the server is up. - */ - protected void postHttpBinding(ServerBinding binding) { - systemReference - .get() - .log() - .info( - "Server online at http://" - + binding.localAddress().getHostName() - + ":" - + binding.localAddress().getPort() - + "/"); - } - - /** - * Hook that will be called in case the Http server binding fails. Override this method if you - * want to perform some actions after the server binding failed. - */ - protected void postHttpBindingFailure(Throwable cause) { - systemReference.get().log().error(cause, "Error starting the server: " + cause.getMessage()); - } - - /** - * Hook that lets the user specify the future that will signal the shutdown of the server whenever - * completed. - */ - protected CompletionStage waitForShutdownSignal(ActorSystem system) { - final CompletableFuture promise = new CompletableFuture<>(); - Runtime.getRuntime().addShutdownHook(new Thread(() -> promise.complete(Done.getInstance()))); - CompletableFuture.runAsync( - () -> { - System.out.println("Press RETURN to stop..."); - try { - if (System.in.read() >= 0) promise.complete(Done.getInstance()); - } catch (IOException e) { - systemReference.get().log().error(e, "Problem occurred! " + e.getMessage()); - } - }); - return promise; - } - - /** Override to implement the route that will be served by this http server. */ - protected abstract Route routes(); -} diff --git a/http/src/main/mima-filters/2.0.x.backwards.excludes/remove-deprecated-methods.excludes b/http/src/main/mima-filters/2.0.x.backwards.excludes/remove-deprecated-methods.excludes index 6375262da2..f52fa35a4d 100644 --- a/http/src/main/mima-filters/2.0.x.backwards.excludes/remove-deprecated-methods.excludes +++ b/http/src/main/mima-filters/2.0.x.backwards.excludes/remove-deprecated-methods.excludes @@ -95,3 +95,7 @@ ProblemFilters.exclude[DirectMissingMethodProblem]("org.apache.pekko.http.scalad ProblemFilters.exclude[DirectMissingMethodProblem]("org.apache.pekko.http.scaladsl.unmarshalling.sse.EventStreamUnmarshalling.maxEventSize") ProblemFilters.exclude[DirectMissingMethodProblem]("org.apache.pekko.http.scaladsl.unmarshalling.sse.EventStreamUnmarshalling.fromEventStream") ProblemFilters.exclude[DirectMissingMethodProblem]("org.apache.pekko.http.scaladsl.unmarshalling.sse.EventStreamUnmarshalling.$init$") + +# Remove deprecated HttpApp (since Akka HTTP 10.2.0) +ProblemFilters.exclude[MissingClassProblem]("org.apache.pekko.http.scaladsl.server.HttpApp") +ProblemFilters.exclude[MissingClassProblem]("org.apache.pekko.http.javadsl.server.HttpApp") diff --git a/http/src/main/scala/org/apache/pekko/http/scaladsl/server/HttpApp.scala b/http/src/main/scala/org/apache/pekko/http/scaladsl/server/HttpApp.scala deleted file mode 100644 index aa9f8f8273..0000000000 --- a/http/src/main/scala/org/apache/pekko/http/scaladsl/server/HttpApp.scala +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * license agreements; and to You under the Apache License, version 2.0: - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * This file is part of the Apache Pekko project, which was derived from Akka. - */ - -/* - * Copyright (C) 2009-2022 Lightbend Inc. - */ - -package org.apache.pekko.http.scaladsl.server - -import java.util.concurrent.atomic.AtomicReference - -import scala.concurrent.{ blocking, Await, ExecutionContext, ExecutionContextExecutor, Future, Promise } -import scala.concurrent.duration.Duration -import scala.io.StdIn -import scala.util.{ Failure, Success, Try } - -import org.apache.pekko -import pekko.Done -import pekko.actor.ActorSystem -import pekko.event.Logging -import pekko.http.scaladsl.Http -import pekko.http.scaladsl.Http.ServerBinding -import pekko.http.scaladsl.settings.ServerSettings - -import com.typesafe.config.ConfigFactory - -/** - * DEPRECATED, consider https://github.com/apache/pekko-http-quickstart-scala.g8 instead - * - * Bootstrap trait for Http Server. It helps booting up a pekko-http server by only defining the desired routes. - * It offers additional hooks to modify the default behavior. - */ -@deprecated("HttpApp this doesn't reflect the latest APIs", "Akka HTTP 10.2.0") -abstract class HttpApp extends Directives { - - private val serverBinding = new AtomicReference[ServerBinding]() - - /** - * [[ActorSystem]] used to start this server. Stopping this system will interfere with the proper functioning condition of the server. - */ - protected val systemReference = new AtomicReference[ActorSystem]() - - /** - * Start a server on the specified host and port. - * Note that this method is blocking - */ - def startServer(host: String, port: Int): Unit = { - startServer(host, port, ServerSettings(ConfigFactory.load)) - } - - /** - * Start a server on the specified host and port, using the provided [[ActorSystem]]. - * Note that this method is blocking - * - * @param system ActorSystem to use for starting the app, - * if `null` is passed in a new default ActorSystem will be created instead, which will - * be terminated when the server is stopped. - */ - def startServer(host: String, port: Int, system: ActorSystem): Unit = { - startServer(host, port, ServerSettings(system), Option(system)) - } - - /** - * Start a server on the specified host and port, using the provided settings. - * Note that this method is blocking. - */ - def startServer(host: String, port: Int, settings: ServerSettings): Unit = { - startServer(host, port, settings, None) - } - - /** - * Start a server on the specified host and port, using the provided settings and [[ActorSystem]]. - * Note that this method is blocking. - * - * @param system ActorSystem to use for starting the app, - * if `null` is passed in a new default ActorSystem will be created instead, which will - * be terminated when the server is stopped. - */ - def startServer(host: String, port: Int, settings: ServerSettings, system: ActorSystem): Unit = { - startServer(host, port, settings, Option(system)) - } - - /** - * Start a server on the specified host and port, using the provided settings and [[ActorSystem]] if present. - * Note that this method is blocking. - * - * @param system ActorSystem to use for starting the app, - * if `None` is passed in a new default ActorSystem will be created instead, which will - * be terminated when the server is stopped. - */ - def startServer(host: String, port: Int, settings: ServerSettings, system: Option[ActorSystem]): Unit = { - implicit val theSystem = system.getOrElse(ActorSystem(Logging.simpleName(this).replaceAll("\\$", ""))) - systemReference.set(theSystem) - implicit val executionContext: ExecutionContextExecutor = theSystem.dispatcher - - val bindingFuture = - Http().newServerAt(host, port) - .withSettings(settings) - .bind(routes) - - bindingFuture.onComplete { - case Success(binding) => - // setting the server binding for possible future uses in the client - serverBinding.set(binding) - postHttpBinding(binding) - case Failure(cause) => - postHttpBindingFailure(cause) - } - - Await.ready( - bindingFuture.flatMap(_ => waitForShutdownSignal(theSystem)), // chaining both futures to fail fast - Duration.Inf) // It's waiting forever because maybe there is never a shutdown signal - - bindingFuture - .flatMap(_.unbind()) - .onComplete(attempt => { - postServerShutdown(attempt, theSystem) - // we created the system. we should cleanup! - if (system.isEmpty) theSystem.terminate() - }) - } - - /** - * It tries to retrieve the [[ServerBinding]] if the server has been successfully started. It fails otherwise. - * You can use this method to attempt to retrieve the [[ServerBinding]] at any point in time to, for example, stop the server due to unexpected circumstances. - */ - def binding(): Try[ServerBinding] = { - if (serverBinding.get() == null) - Failure(new IllegalStateException("Binding not yet stored. Have you called startServer?")) - else Success(serverBinding.get()) - } - - /** - * Hook that will be called just after the server termination. Override this method if you want to perform some cleanup actions after the server is stopped. - * The `attempt` parameter is represented with a [[Try]] type that is successful only if the server was successfully shut down. - */ - protected def postServerShutdown(attempt: Try[Done], system: ActorSystem): Unit = { - systemReference.get().log.info("Shutting down the server") - } - - /** - * Hook that will be called just after the Http server binding is done. Override this method if you want to perform some actions after the server is up. - */ - protected def postHttpBinding(binding: Http.ServerBinding): Unit = { - systemReference.get().log.info( - s"Server online at http://${binding.localAddress.getHostName}:${binding.localAddress.getPort}/") - } - - /** - * Hook that will be called in case the Http server binding fails. Override this method if you want to perform some actions after the server binding failed. - */ - protected def postHttpBindingFailure(cause: Throwable): Unit = { - systemReference.get().log.error(cause, s"Error starting the server ${cause.getMessage}") - } - - /** - * Hook that lets the user specify the future that will signal the shutdown of the server whenever completed. - */ - protected def waitForShutdownSignal(system: ActorSystem)(implicit ec: ExecutionContext): Future[Done] = { - val promise = Promise[Done]() - sys.addShutdownHook { - promise.trySuccess(Done) - } - Future { - blocking { - if (StdIn.readLine("Press RETURN to stop...\n") != null) - promise.trySuccess(Done) - } - } - promise.future - } - - /** - * Override to implement the routes that will be served by this http server. - */ - protected def routes: Route -}