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 ability to generalize over a HTTP request being async or not. #347

Merged
merged 7 commits into from
Sep 28, 2017

Conversation

tcard
Copy link
Contributor

@tcard tcard commented Aug 31, 2017

This was something I had done in the push, but is independent of it.

Move AsyncHttp to CallbackfulHttp, and instead of inheriting from
ThreadPoolExecutor, take any Executor as a parameter. Then, have
both AsyncHttp and SyncHttp inheriting from it. AsyncHttp injects a
ThreadPoolExecutor, as before, while SyncHttp injects an Executor
that just executes Runnables right away, in the current thread.
Thus, SyncHttp exposes an “asynchronous” (callbackful) interface
while behaving synchronously.

By using CallbackfulHttp, we can abstract over whether an operation
is executed synchronously or asynchronously.

To make this more user-friendly, AnySyncHttp wraps both a SyncHttp
and an AsyncHttp, and lets you specify how to execute (class Execute) a
request (class Request) and then getting its result synchronously or
asynchronously (in another thread), as a method call result or passed
to a callback, with the sync and async methods respectively.

This design should make the Http class obsolete, once/if all the code
that uses it is ported. It could also be left as a proxy to SyncHttp.

(I did this after I renamed something in a foo method but forgot to
do the same in a fooAsync method, causing a bug that was reported by
a user.)

As an example, I've refactored Channel.publish(Message[]). Luckily, I've found an instance of the class of errors this is supposed to fix: RTL6g3 was implemented for publish, but not for publishAsync. Now, as they share their code, is implemented by both.

tcard added 3 commits August 31, 2017 22:06
Move AsyncHttp to CallbackfulHttp, and instead of inheriting from
ThreadPoolExecutor, take any Executor as a parameter. Then, have
both AsyncHttp and SyncHttp inheriting from it. AsyncHttp injects a
ThreadPoolExecutor, as before, while SyncHttp injects an Executor
that just executes Runnables right away, in the current thread.
Thus, SyncHttp exposes an “asynchronous” (callbackful) interface
while behaving synchronously.

By using CallbackfulHttp, we can abstract over whether an operation
is executed synchronously or asynchronously.

To make this more user-friendly, AnySyncHttp wraps both a SyncHttp
and an AsyncHttp, and lets you specify how to execute (class Execute) a
request (class Request) and then getting its result synchronously or
asynchronously (in another thread), as a method call result or passed
to a callback, with the `sync` and `async` methods respectively.

This design should make the Http class obsolete, once/if all the code
that uses it is ported. It could also be left as a proxy to SyncHttp.

(I did this after I renamed something in a `foo` method but forgot to
do the same in a `fooAsync` method, causing a bug that was reported by
a user.)
Plus, fix bug by which RTL6g3 was not implemented for the async version.
@tcard tcard requested a review from paddybyers August 31, 2017 20:22
Copy link
Member

@mattheworiordan mattheworiordan left a comment

Choose a reason for hiding this comment

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

Few small comments in regards to naming & code comments, but otherwise looks good to me. Caveat is that I don't really know the Java code base that well so can't really comment on the overall design and how it fits in.

* Created by tcard on 28/04/2017.
*/

public class AnySyncHttp {
Copy link
Member

Choose a reason for hiding this comment

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

Should we perhaps add a brief comment as to the purpose of this class for future us?

* Created by tcard on 31/8/17.
*/

public class CallbackfulHttp<Executor extends java.util.concurrent.Executor> {
Copy link
Member

Choose a reason for hiding this comment

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

What is CallbackfulHttp i.e. I am not clear on what the ful after Callback implies. Perhaps a high level comment on what this does is needed.

@paddybyers
Copy link
Member

Overall I like this as a way of rationalising the duplication we had but my reservations at the moment are:

  1. names .. I don't like CallbackfulHttp, AnySyncHttp, publishAnySync etc - I'm trying renaming a few things to see how it looks.

  2. I would really like to see the migration from Http to SyncHttp completed and AblyRest.http removed. That can be part of a follow-up PR but we should do it now instead of later.

  3. I don't like the passing of results back in array members in

    final Object[] result = new Object[1];
    , and especially the fact that it's an untyped Object and there need to be unchecked casts. There's surely enough generics to avoid this.

I'll be back with a few naming suggestions.

@tcard
Copy link
Contributor Author

tcard commented Sep 1, 2017

If we get rid of Http, CallbackfulHttp can be just Http (or AbstractHttp for extra Javaness). CallbackfulHttp is named that way as opposed to "callbackless" Http, because that's the difference between them.

I also don't love AnySyncHttp. I've thought about HttpProxy, because it's just a GoF proxy for AsyncHttp and SyncHttp, but it could be confused with an HTTP proxy in the network sense. HttpRequester maybe?

@tcard
Copy link
Contributor Author

tcard commented Sep 1, 2017

f782a9e addresses @paddybyers 's point 3.

this.syncHttp = syncHttp;
}

public static class Request<Result> {
Copy link
Member

Choose a reason for hiding this comment

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

I don't see why this is static and yet it has a anySyncHttp member. I think you can remove that member and remove the static declaration.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done at 08f3c98.

}

public Result sync() throws AblyException {
final SyncExecuteResult<Result> result = new SyncExecuteResult<>();
Copy link
Member

Choose a reason for hiding this comment

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

Yes, I was looking at just having syncResult and syncErr members in the Result type, instead of a new type to hold them, but what you have is a bit cleaner.

@paddybyers
Copy link
Member

OK, I think we're heading towards a messy state where the existing Http class is a mixture of various configuration options, some ancillary classes (RequestBody etc) and some of the request primitives that are used elsewhere in the API. I think we should be refactoring that into something like HttpOptions or HttpConfig which contains the options-derived state (hosts etc); and separate out the ancillary types into a separate class (or an http.types package) and the lower primitives can either be removed to eliminate layer duplication, or we can rename that class as HttpImpl or HttpEngine or something.

That will potentially free up the Http name for something that actually represents the API that the rest of the library uses.

Doing that refactor isn't trivial because we also have a lot of tests that rely on those primitive APIs.

Anyway, if we're not doing that yet, how about renaming things as:

CallbackfulHttp -> AbstractHttpExecutor

AsyncHttp, SyncHttp can stay the same or be renamed AsyncHttpExecutor, SyncHttpExecutor

AnySyncExecutor -> HttpExecutor maybe.

publishAnySync -> executePublish or publishImpl maybe.

}

public interface Execute<Result> {
public void execute(CallbackfulHttp http, Callback<Result> callback) throws AblyException;
Copy link
Member

Choose a reason for hiding this comment

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

I've getting a raw types warning here and elsewhere; it should be CallbackfulHttp<? extends Executor> http.

The old Http class has been split up. We have now:

* HttpCore implements the core primitives to do Ably-ready requests, ie.
  HTTP requests on the current thread that implement Ably auth, know how
  to reauthorize, and interpret Ably's error responses as ErrorInfos.
  It also has ancillary inner classes like Response, BodyHandler. 
* HttpScheduler, that implements operations on top of a HttpCore
  scheduled to an Executor. The API is asynchronous, but the underlying
  Executor may make its behaviour synchronous. We have both
  SyncHttpScheduler and AsyncHttpScheduler subclasses.
* Http, which offers a higher level API to SyncHttpScheduler and 
  AsyncHttpScheduler to help expose a synchronous or asynchronous API
  out of HTTP operations without duplicating code.
* HttpHelpers, for helper methods used primarily in tests. It's also
  used in some non-test places that don't need the sync/async
  unification so I didn't bother converting them to use Http, which
  would make them more complex.
* HttpConstants to hold constants like method names, header names, etc.

PaginatedQuery/Result and AsyncPaginatedQuery/Result have now unified
implementations too. Now both wrap BasePaginatedQuery/Result. To make
this user-friendly some internal bridging classes boilerplate had to be
added, unfortunately, but the end result should be simple enough.

Tests have not been converted yet.
@tcard
Copy link
Contributor Author

tcard commented Sep 5, 2017

@paddybyers PTAL. I should have split 080a386 in at least a couple of steps but unfortunately I didn't, and since renaming and refactoring went hand in hand it's impossible to do after the fact.

See the comments in 080a386 's commit message.

@paddybyers
Copy link
Member

This looks very good, thanks.

Are you planning to update the tests in this PR?

@tcard
Copy link
Contributor Author

tcard commented Sep 20, 2017

@paddybyers Yes, I'll do that tomorrow.

@tcard
Copy link
Contributor Author

tcard commented Sep 28, 2017

There are some test that are failing, but I took a look and they didn't seem related to these changes. I'm raising an issue to fix them and merging this PR.

@tcard tcard merged commit b3c8862 into master Sep 28, 2017
@tcard tcard deleted the any-sync-http branch September 28, 2017 17:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants