+htc #18027 add the missing javadsl.clientLayer and serverLayer

This commit is contained in:
Johannes Rudolph 2015-07-24 10:57:54 +02:00
parent e14773c3d9
commit 8ef7c64886
7 changed files with 110 additions and 10 deletions

View file

@ -62,7 +62,19 @@ as a more general purpose streaming infrastructure feature.
However, akka-stream should soon provide such a feature.
.. _http-client-layer-java:
Stand-Alone HTTP Layer Usage
----------------------------
// TODO
Due to its Reactive-Streams-based nature the Akka HTTP layer is fully detachable from the underlying TCP
interface. While in most applications this "feature" will not be crucial it can be useful in certain cases to be able
to "run" the HTTP layer (and, potentially, higher-layers) against data that do not come from the network but rather
some other source. Potential scenarios where this might be useful include tests, debugging or low-level event-sourcing
(e.g by replaying network traffic).
On the client-side the stand-alone HTTP layer forms a ``BidiFlow<HttpRequest, SslTlsOutbound, SslTlsInbound, HttpResponse, BoxedUnit>``,
that is a stage that "upgrades" a potentially encrypted raw connection to the HTTP level.
You create an instance of the layer by calling one of the two overloads of the ``Http.get(system).clientLayer`` method,
which also allows for varying degrees of configuration.

View file

@ -154,7 +154,15 @@ If defined encryption is enabled on all accepted connections. Otherwise it is di
Stand-Alone HTTP Layer Usage
----------------------------
It is currently only possible to use the HTTP server layer with Scala in a stand-alone fashion.
See :ref:`http-server-layer-scala` and `#18027`_ for the plan to add Java support.
Due to its Reactive-Streams-based nature the Akka HTTP layer is fully detachable from the underlying TCP
interface. While in most applications this "feature" will not be crucial it can be useful in certain cases to be able
to "run" the HTTP layer (and, potentially, higher-layers) against data that do not come from the network but rather
some other source. Potential scenarios where this might be useful include tests, debugging or low-level event-sourcing
(e.g by replaying network traffic).
.. _`#18027`: https://github.com/akka/akka/issues/18027
On the server-side the stand-alone HTTP layer forms a ``BidiFlow<HttpResponse, SslTlsOutbound, SslTlsInbound, HttpRequest, BoxedUnit>``,
that is a stage that "upgrades" a potentially encrypted raw connection to the HTTP level.
You create an instance of the layer by calling one of the two overloads of the ``Http.get(system).serverLayer`` method,
which also allows for varying degrees of configuration. Note, that the returned instance is not reusable and can only
be materialized once.

View file

@ -67,7 +67,7 @@ However, akka-stream should soon provide such a feature.
Stand-Alone HTTP Layer Usage
----------------------------
Due to its Reactive-Stream-based nature the Akka HTTP layer is fully detachable from the underlying TCP
Due to its Reactive-Streams-based nature the Akka HTTP layer is fully detachable from the underlying TCP
interface. While in most applications this "feature" will not be crucial it can be useful in certain cases to be able
to "run" the HTTP layer (and, potentially, higher-layers) against data that do not come from the network but rather
some other source. Potential scenarios where this might be useful include tests, debugging or low-level event-sourcing

View file

@ -155,13 +155,13 @@ If defined encryption is enabled on all accepted connections. Otherwise it is di
Stand-Alone HTTP Layer Usage
----------------------------
Due to its Reactive-Stream-based nature the Akka HTTP layer is fully detachable from the underlying TCP
Due to its Reactive-Streams-based nature the Akka HTTP layer is fully detachable from the underlying TCP
interface. While in most applications this "feature" will not be crucial it can be useful in certain cases to be able
to "run" the HTTP layer (and, potentially, higher-layers) against data that do not come from the network but rather
some other source. Potential scenarios where this might be useful include tests, debugging or low-level event-sourcing
(e.g by replaying network traffic).
On the server-side the stand-alone HTTP layer forms a ``BidiStage`` that is defined like this:
On the server-side the stand-alone HTTP layer forms a ``BidiFlow`` that is defined like this:
.. includecode2:: /../../akka-http-core/src/main/scala/akka/http/scaladsl/Http.scala
:snippet: server-layer

View file

@ -81,7 +81,7 @@ private[http] object JavaMapping {
}
}
/** This trivial mapping isn't enabled by default to prevent it from conflicting with the `Inherited ones `*/
/** This trivial mapping isn't enabled by default to prevent it from conflicting with the `Inherited` ones `*/
def identity[T]: JavaMapping[T, T] =
new JavaMapping[T, T] {
def toJava(scalaObject: T): J = scalaObject
@ -117,6 +117,14 @@ private[http] object JavaMapping {
scaladsl.Flow[JIn].map(inMapping.toScala(_)).viaMat(scalaObject)(scaladsl.Keep.right).map(outMapping.toJava(_))
}
}
def scalaToJavaAdapterFlow[J, S](implicit mapping: JavaMapping[J, S]): scaladsl.Flow[S, J, Unit] =
scaladsl.Flow[S].map(mapping.toJava(_))
def javaToScalaAdapterFlow[J, S](implicit mapping: JavaMapping[J, S]): scaladsl.Flow[J, S, Unit] =
scaladsl.Flow[J].map(mapping.toScala(_))
def adapterBidiFlow[JIn, SIn, SOut, JOut](implicit inMapping: JavaMapping[JIn, SIn], outMapping: JavaMapping[JOut, SOut]): scaladsl.BidiFlow[JIn, SIn, SOut, JOut, Unit] =
scaladsl.BidiFlow.wrap(javaToScalaAdapterFlow(inMapping), scalaToJavaAdapterFlow(outMapping))(scaladsl.Keep.none)
implicit def pairMapping[J1, J2, S1, S2](implicit _1Mapping: JavaMapping[J1, S1], _2Mapping: JavaMapping[J2, S2]): JavaMapping[Pair[J1, J2], (S1, S2)] =
new JavaMapping[Pair[J1, J2], (S1, S2)] {
def toJava(scalaObject: (S1, S2)): J = Pair(_1Mapping.toJava(scalaObject._1), _2Mapping.toJava(scalaObject._2))
@ -165,6 +173,8 @@ private[http] object JavaMapping {
implicit object RemoteAddress extends Inherited[jm.RemoteAddress, sm.RemoteAddress]
implicit object TransferEncoding extends Inherited[jm.TransferEncoding, sm.TransferEncoding]
implicit object HostHeader extends Inherited[jm.headers.Host, sm.headers.Host]
implicit object ByteRange extends Inherited[jm.headers.ByteRange, sm.headers.ByteRange]
implicit object CacheDirective extends Inherited[jm.headers.CacheDirective, sm.headers.CacheDirective]
implicit object ContentDispositionType extends Inherited[jm.headers.ContentDispositionType, sm.headers.ContentDispositionType]

View file

@ -7,6 +7,7 @@ package akka.http.javadsl
import java.lang.{ Iterable JIterable }
import java.net.InetSocketAddress
import akka.http.impl.util.JavaMapping
import akka.stream.io.{ SslTlsInbound, SslTlsOutbound }
import scala.language.implicitConversions
import scala.concurrent.Future
@ -17,7 +18,8 @@ import akka.actor.{ ExtendedActorSystem, ActorSystem, ExtensionIdProvider, Exten
import akka.event.LoggingAdapter
import akka.io.Inet
import akka.stream.Materializer
import akka.stream.javadsl.{ Flow, Source }
import akka.stream.javadsl.{ BidiFlow, Flow, Source }
import akka.http.impl.util.JavaMapping.Implicits._
import akka.http.scaladsl.{ model sm }
import akka.http.javadsl.model._
@ -37,6 +39,42 @@ class Http(system: ExtendedActorSystem) extends akka.actor.Extension {
private implicit def convertHttpsContext(hctx: Option[HttpsContext]) =
hctx.map(_.asInstanceOf[akka.http.scaladsl.HttpsContext])
/**
* Constructs a server layer stage using the configured default [[ServerSettings]]. The returned [[BidiFlow]] isn't
* reusable and can only be materialized once.
*/
def serverLayer(materializer: Materializer): BidiFlow[HttpResponse, SslTlsOutbound, SslTlsInbound, HttpRequest, Unit] =
adaptServerLayer(delegate.serverLayer()(materializer))
/**
* Constructs a server layer stage using the given [[ServerSettings]]. The returned [[BidiFlow]] isn't reusable and
* can only be materialized once.
*/
def serverLayer(settings: ServerSettings,
materializer: Materializer): BidiFlow[HttpResponse, SslTlsOutbound, SslTlsInbound, HttpRequest, Unit] =
adaptServerLayer(delegate.serverLayer(settings)(materializer))
/**
* Constructs a server layer stage using the given [[ServerSettings]]. The returned [[BidiFlow]] isn't reusable and
* can only be materialized once. The `remoteAddress`, if provided, will be added as a header to each [[HttpRequest]]
* this layer produces if the `akka.http.server.remote-address-header` configuration option is enabled.
*/
def serverLayer(settings: ServerSettings,
remoteAddress: Option[InetSocketAddress],
materializer: Materializer): BidiFlow[HttpResponse, SslTlsOutbound, SslTlsInbound, HttpRequest, Unit] =
adaptServerLayer(delegate.serverLayer(settings, remoteAddress.asScala)(materializer))
/**
* Constructs a server layer stage using the given [[ServerSettings]]. The returned [[BidiFlow]] isn't reusable and
* can only be materialized once. The remoteAddress, if provided, will be added as a header to each [[HttpRequest]]
* this layer produces if the `akka.http.server.remote-address-header` configuration option is enabled.
*/
def serverLayer(settings: ServerSettings,
remoteAddress: Option[InetSocketAddress],
log: LoggingAdapter,
materializer: Materializer): BidiFlow[HttpResponse, SslTlsOutbound, SslTlsInbound, HttpRequest, Unit] =
adaptServerLayer(delegate.serverLayer(settings, remoteAddress.asScala, log)(materializer))
/**
* Creates a [[Source]] of [[IncomingConnection]] instances which represents a prospective HTTP server binding
* on the given `endpoint`.
@ -167,6 +205,27 @@ class Http(system: ExtendedActorSystem) extends akka.actor.Extension {
interface, port, settings, httpsContext, parallelism, log)(materializer)
.map(new ServerBinding(_))(ec)
/**
* Constructs a client layer stage using the configured default [[ClientConnectionSettings]].
*/
def clientLayer(hostHeader: headers.Host): BidiFlow[HttpRequest, SslTlsOutbound, SslTlsInbound, HttpResponse, Unit] =
adaptClientLayer(delegate.clientLayer(JavaMapping.toScala(hostHeader)))
/**
* Constructs a client layer stage using the given [[ClientConnectionSettings]].
*/
def clientLayer(hostHeader: headers.Host,
settings: ClientConnectionSettings): BidiFlow[HttpRequest, SslTlsOutbound, SslTlsInbound, HttpResponse, Unit] =
adaptClientLayer(delegate.clientLayer(JavaMapping.toScala(hostHeader), settings))
/**
* Constructs a client layer stage using the given [[ClientConnectionSettings]].
*/
def clientLayer(hostHeader: headers.Host,
settings: ClientConnectionSettings,
log: LoggingAdapter): BidiFlow[HttpRequest, SslTlsOutbound, SslTlsInbound, HttpResponse, Unit] =
adaptClientLayer(delegate.clientLayer(JavaMapping.toScala(hostHeader), settings, log))
/**
* Creates a [[Flow]] representing a prospective HTTP client connection to the given endpoint.
* Every materialization of the produced flow will attempt to establish a new outgoing connection.
@ -468,4 +527,14 @@ class Http(system: ExtendedActorSystem) extends akka.actor.Extension {
implicit val _ = JavaMapping.identity[T]
JavaMapping.toJava(scalaFlow)(JavaMapping.flowMapping[Pair[HttpRequest, T], (scaladsl.model.HttpRequest, T), Pair[Try[HttpResponse], T], (Try[scaladsl.model.HttpResponse], T), Mat])
}
private def adaptServerLayer(serverLayer: scaladsl.Http.ServerLayer): BidiFlow[HttpResponse, SslTlsOutbound, SslTlsInbound, HttpRequest, Unit] =
new BidiFlow(
JavaMapping.adapterBidiFlow[HttpResponse, sm.HttpResponse, sm.HttpRequest, HttpRequest]
.atop(serverLayer))
private def adaptClientLayer(clientLayer: scaladsl.Http.ClientLayer): BidiFlow[HttpRequest, SslTlsOutbound, SslTlsInbound, HttpResponse, Unit] =
new BidiFlow(
JavaMapping.adapterBidiFlow[HttpRequest, sm.HttpRequest, sm.HttpResponse, HttpResponse]
.atop(clientLayer))
}

View file

@ -150,7 +150,8 @@ class HttpExt(config: Config)(implicit system: ActorSystem) extends akka.actor.E
/**
* Constructs a [[ServerLayer]] stage using the given [[ServerSettings]]. The returned [[BidiFlow]] isn't reusable and
* can only be materialized once.
* can only be materialized once. The `remoteAddress`, if provided, will be added as a header to each [[HttpRequest]]
* this layer produces if the `akka.http.server.remote-address-header` configuration option is enabled.
*/
def serverLayer(settings: ServerSettings,
remoteAddress: Option[InetSocketAddress] = None,