Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a simpler way to decorate a client / Enrich ClientBuilder #93

Merged
merged 2 commits into from
Jan 25, 2016

Conversation

trustin
Copy link
Member

@trustin trustin commented Jan 20, 2016

Motivation:

When a user attempts to decorate a client, it is much more verbose than
decorating a service. A user should be given with a simpler way to
configure a client when using ClientBuilder.

Modifications:

  • Add a new interface 'Client' which is a client-side counterpart of
    'Service'
    • Add SimpleClient and DecoratingClient
  • Add various setter methods incloding decorator() to ClientBuilder
  • Add LoggingClient and hide LoggingClientCodec
  • Remove the ability to decorate an InvocationHandler, because it
    seems that RemoteInvoker decorators can do the exact same job.
  • Miscellaneous:
    • Make LoggingClientCodec extend DecoratingClientCodec
    • Make AbstractOptions and its subtypes accept
      Iterable as well

Result:

A user can build a client in a more fluent and less verbose way:

  builder.decorator(LoggingClient::new)
         .decorator(MyDecorator::new)
         .build();

@trustin trustin added this to the 0.8.0.Final milestone Jan 20, 2016
@trustin
Copy link
Member Author

trustin commented Jan 20, 2016

@inch772 @synk @anuraaga PTAL

* {@link Client} with the specified {@code handlerDecorator}.
*/
default <T extends RemoteInvoker, U extends RemoteInvoker>
Client decorateInvoker(Function<T, U> handlerDecorator) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think invokerDecorator is better than handlerDecorator here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, copy & paste cruft! Fixed. :-)

@SuppressWarnings("unchecked")
final Client newClient = decorator.apply(this);

if (newClient != null) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would it be null? If a decorator wanted to not decorate for some reason, it could just return the input client.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wanted to yield the same behavior with the server side, but yeah, we shouldn't do this on both sides. Let me fix this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thin we still need to check if a decorator returns null to generate more meaningful message (e.g. you screwed up, not Armeria did)

@trustin
Copy link
Member Author

trustin commented Jan 25, 2016

@anuraaga Addressed the comments. Anything else?

default Client decorate(Function<Client, Client> decorator) {
@SuppressWarnings("unchecked")
final Client newClient = decorator.apply(this);
if (newClient == null) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

requireNonNull?

@anuraaga
Copy link
Collaborator

LGTM - guess we only use requireNonNull on parameters, but just checking

@synk
Copy link
Contributor

synk commented Jan 25, 2016

LGTM

@trustin
Copy link
Member Author

trustin commented Jan 25, 2016

@anuraaga Ah, I should use it for checking return values.

@trustin
Copy link
Member Author

trustin commented Jan 25, 2016

@anuraaga But we are using dynamically generated exception messages in this case, so I'd like to leave them as they are.

@trustin
Copy link
Member Author

trustin commented Jan 25, 2016

@synk Please merge when you're ready. :-) I did not squash the commits because they are different.

Motivation:

When a user attempts to decorate a client, it is much more verbose than
decorating a service. A user should be given with a simpler way to
configure a client when using ClientBuilder.

Modifications:

- Add a new interface 'Client' which is a client-side counterpart of
  'Service'
  - Add SimpleClient and DecoratingClient
- Add various setter methods incloding decorator() to ClientBuilder
- Add LoggingClient and hide LoggingClientCodec
- Remove the ability to decorate an InvocationHandler, because it
  seems that RemoteInvoker decorators can do the exact same job.
- Miscellaneous:
  - Make LoggingClientCodec extend DecoratingClientCodec
  - Make AbstractOptions and its subtypes accept
    Iterable<AbstractOption> as well

Result:

A user can build a client in a more fluent and less verbose way:

  builder.decorator(LoggingClient::new)
         .decorator(MyDecorator::new)
         .build();
- Disallow null in AbstractOptions for clarity
- Disallow returning null in decorator.apply() for clarity
synk added a commit that referenced this pull request Jan 25, 2016
Add a simpler way to decorate a client / Enrich ClientBuilder
@synk synk merged commit c8c7d52 into line:master Jan 25, 2016
@synk
Copy link
Contributor

synk commented Jan 25, 2016

Merged!

@trustin trustin deleted the more_client_builder_methods branch January 27, 2016 06:52
@trustin
Copy link
Member Author

trustin commented Jan 27, 2016

@synk Thanks! :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants