Related: #85
This commit contains a lot of changes. I'll group them into several pairs of
motivations and modifications.
Use the Reactive Streams API to support HTTP content streaming
Motivation:
Reactive Streams API is the de-facto standard API for implementing object
streaming these days; RxJava, gRPC, Akka and Project Reactor are the notable
adoptors.
Modifications:
- Add RichPublisher and its subtypes to provide the foundation for streaming
HTTP content
- See the com.linecorp.armeria.common.reactivestreams package, most notably:
- RichPublisher and Writer
- QueueBasedPublisher
Decouple the core API from Netty API
Motivation:
Armeria is meant to be used by an application developer. Exposing too much
detail to him or her is not the best idea.
Modifications:
- Hide all Netty HTTP types under Armeria's own HTTP/2-centric message types
- HttpObject
- HttpHeaders
- HttpData
- HttpMethod
- HttpStatus
- HttpStatusClass
- HttpHeaderNames
- Introduce HttpRequest and HttpResponse whose content is a RichPublisher, our
reactive streams API
- Add AggregatedHttpMessage which is the FullHttpMessage counterpart
- Add HttpRequest/ResponseWriter for easier composition of an HTTP message
- Do not expose ByteBuf in the user-facing API
- Use CompletableFuture instead of Netty Future/Promise
- Note that we still use Netty's AsciiString as header names because it's
generic enough
Redefine Client, Service and their context API
Motivation:
Previously, we shared one context type for both client and server side:
ServiceInvocationContext. This is potentially confusing and both client and
server sides had to shoehorn their models into the common model provided by
ServiceInvocationContext.
Also, ServiceInvocationContext assumed that a request is fully available when
context is created. However, this is not true anymore with content streaming.
Modifications:
- Replace ServiceInvocationContext with RequestContext
- Add ClientRequestContext and ServiceRequestContext
- All timeout settings, maximum allowed content length and custom HTTP header
options are now overridable via the setters of the context.
- Only expose the information that could be available when a request has just
started rather than when a full request is ready.
- Add RequestLog and ResponseLog so that a client or a service fills the
properties as they are available. A user will be notified via
requestLogFuture() and responseLogFuture() when all necessary information
is ready.
- For example, RequestContext.method() property always returns the method at
the session layer. That is, in a Thrift-over-HTTP call, ctx.method() will
return "POST" rather than "someThriftMethod". It is because such information
is available only when the full request has been received. You can get the
Thrift method name from RequestLog once it's ready.
- See LoggingClient/Server and MetricCollectingClient/Server for code example
- Remove ClientCodec, RemoteInvoker, ServiceCodec, ServiceInvocationHandler,
because they are all merged into Client or Service
Overall reorganization of session layer implementation
Motivation:
Our code layout is too HTTP-centric and this will eventually make it hard to
add other session protocols.
Modifications:
- Move HTTP-specific code to com.linecorp.armeria.{server,client}.http
- Move the internal classes that could be shared between client and server to
com.linecorp.armeria.internal.*
Implement HTTP content streaming at the session layer
Modifications:
- Use Armeria's own HTTP/2 centric streaming-aware API instead of aggregating
an HTTP/1 or 2 request into a full HTTP/1 request
- See Http1/2RequestDecoder, HttpResponseSubscriber and HttpServerHandler to
learn how this works on the server side
- Start from Http1/2RequestDecoder to HttpServerHandler.handleRequest()
- See Http1/2ResponseDecoder, HttpRequestSubscriber and HttpSessionHandler to
learn how this works on the client side
- Start from HttpSessionHandler.invoke()
Revamp HttpService, ThriftService and other services with the new core API
Motivation:
HttpService and ThriftService assumes a request is fully received when it is
invoked, which is not true anymore. Also, they are split into two components,
ServiceCodec and ServiceInvocationHandler, and they are gone now.
Modifications:
- HttpService is now an interface.
- Add AbstractHttpService which replaces the old HttpService class
- ThriftService is now THttpService.
- ThriftService is split into two parts: THttpService and ThriftCallService.
- THttpService translates an HTTP request into a ThriftCall and
a ThriftReply into an HTTP response. (similar to ServiceCodec)
- ThriftCallService delegates a ThriftCall to a stub implementation.
(similar to ServiceInvocationHandler)
- Deprecate ThriftService
- Other service implementations underwent similar changes to work with the new
API.
Revamp client-side service composition and decoration
Motivation:
Previous client composition and decoration was based on the assumption that
the full request content is available upon its invocation, which isn't true
anymore.
Modifications:
- Replace the option 'DECORATOR' with 'DECORATION' whose value type is
'ClientDecorations'
- A user is now expected to specify the type of the request and response he
or she desires to intercept, and the ClientFactory will apply the decorator
at the right place in the invocation chain.
- builder.add(ThriftCall.class, ThriftReply.class, thriftCallDecorator);
- builder.add(HttpRequest.class, HttpResponse.class, httpDecorator);
Write new HTTP client API
Motivation:
SimpleHttpClient exposes Netty API and it's not powerful enough.
Modifications:
- Add HttpClient which replaces SimpleHttpClient
- Deprecate SimpleHttpClient
Merge ThriftFunction and ThriftMethod
Motivation:
They basically do the same job slightly differently.
Modifications:
- Merge them into one implementation and move to the internal package.
- See com.linecorp.armeria.internal.thrift.{ThriftFunction,ThriftServiceMetadata}
Provide a way to add a decorator to all services
Motivation:
Some decorators are often meant to be added to all services in a server or in a
VirtualHost.
Modifications:
- Add ServerBuilder.decorator() that adds a decorator to all services in a
server
- Add VirtualHostBuilder.decorator() that adds a decorator too all services in
a VirtualHost
Rename RemoteInvokerFactory to ClientFactory
Motivation:
RemoteInvoker is now gone. ClientFactory sounds better in my opinion.
Modification:
- Rename/replace RemoteInvoker to/with ClientFactory
- Add HttpClientFactory and ThriftClientFactory
- Add AllInOneClientFactory that supports both HTTP and Thrift-over-HTTP via
the two ClientFactories above
- Rename RemoveInvokerOption and its related classes to SessionOption
Refactor LoggingClient/Service and MetricCollectingClient/Service
- Rename MetricConsumer to MessageLogConsumer
- Move the classes in the 'metrics' package to the 'logging' package
- Add LogCollectingClient/Service
- LoggingClient/Service and MetricCollectingClient/Service extends
LogCollectingClient/Service
- Rename MetricCollectingClient/Service to
DropwizardMetricCollectingClient/Service because a user can use
LogCollectingClient/Service to support his/her favorite metric
collecting library
Result
- HTTP content streaming works.
- Frequently used service implementations such as ThriftService, TomcatService,
JettyService and HttpFileService works without modifying user code.
- Frequently used client implementations such as SimpleHttpClient and usual
Thrift client stub generation works as before.
new feature