Skip to content

Commit 946b234

Browse files
authored
Merge pull request #25 from stanwood/develop
Master merge for 1.2.0 release
2 parents 0afd9d8 + 9a85200 commit 946b234

File tree

35 files changed

+178
-102
lines changed

35 files changed

+178
-102
lines changed

README.md

Lines changed: 69 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
[![Release](https://jitpack.io/v/stanwood/framework-network-android.svg?style=flat-square)](https://jitpack.io/#stanwood/framework-network-android)
22
[![Build Status](https://www.bitrise.io/app/983e6342cc5e0e24/status.svg?token=QtXUf2lbVhJrANROaTkluQ)](https://www.bitrise.io/app/983e6342cc5e0e24)
3+
[![Maintainability](https://api.codeclimate.com/v1/badges/eeed4b740670c5753217/maintainability)](https://codeclimate.com/github/stanwood/framework-network-android/maintainability)
34

45
# stanwood Network Utilities (Android)
56

67
A set of hopefully useful classes for common networking use cases.
78

89
## Import
910

10-
The stanwood Network Utilities are hosted on JitPack. Therefore you can simply import them by adding
11+
The stanwood Network Utilities are hosted on JitPack. Therefore you can simply
12+
import them by adding
1113

1214
```groovy
1315
allprojects {
@@ -30,7 +32,8 @@ dependencies {
3032

3133
## Usage
3234

33-
Refer to the extensive javadoc of the provided classes for details on how to use them. Right now there are solutions for the following use cases:
35+
Refer to the extensive javadoc of the provided classes for details on how to
36+
use them. Right now there are solutions for the following use cases:
3437

3538
- handle offline situations and caching when using OkHttp (`cache` package)
3639
- generic token based authentication handling with OkHttp (`auth` package)
@@ -41,18 +44,23 @@ TODO
4144

4245
### auth
4346

44-
The `auth` package contains classes for handling token based authentication with OkHttp. Generally this
45-
is done via Authenticators and Interceptors.
47+
The `auth` package contains classes for handling token based authentication
48+
with OkHttp. Generally this is done via Authenticators and Interceptors.
4649

47-
Integration into both existing means of token retrieval as well as from scratch is simple.
50+
Integration into both existing means of token retrieval as well as from scratch
51+
is simple.
4852

49-
First you need to implement both `TokenReaderWriter` and `AuthenticationProvider`.
50-
The first is used for reading and writing tokens from/to requests.
51-
The second provides means to get authentication data (such as tokens and sign-in status).
52-
Refer to the javadoc for more details on how to implement these interfaces.
53-
In the future optional modules will provide implementations for common use cases.
53+
First you need to implement both `TokenReaderWriter` and
54+
`AuthenticationProvider`. The first is used for reading and writing tokens
55+
from/to requests. The second provides means to get authentication data (such as
56+
tokens and sign-in status). Refer to the javadoc for more details on how to
57+
implement these interfaces.
58+
59+
In the future optional modules will provide implementations for common use
60+
cases.
5461

5562
Then create an instance of `io.stanwood.framework.network.auth.Authenticator`:
63+
5664
```java
5765
Authenticator authenticator = new Authenticator(
5866
authenticationProvider,
@@ -62,6 +70,7 @@ Authenticator authenticator = new Authenticator(
6270
```
6371

6472
And an instance of `AuthInterceptor`:
73+
6574
```java
6675
AuthInterceptor authInterceptor = new AuthInterceptor(
6776
appContext,
@@ -71,46 +80,67 @@ AuthInterceptor authInterceptor = new AuthInterceptor(
7180
```
7281

7382
Construct an `OkHttpClient` and pass the interceptor and the authenticator:
83+
7484
```java
7585
new OkHttpClient.Builder()
7686
.authenticator(authenticator)
7787
.addInterceptor(authInterceptor)
7888
.build();
7989
```
8090

81-
That's it. When using this `OkHttpClient` instance you'll benefit from fully transparent token handling.
82-
83-
__Hint 1:__ *If your app uses multiple authentication methods make sure to implement an own subclass of `AuthenticationProvider` for each method and use an own `OkHttpClient` for each!*
84-
85-
__Hint 2:__ *In case you are using OkHttp/Retrofit to retrieve tokens: As the `Authenticator` locks all other `Authenticators` and `AuthInterceptors` with the same `AuthenticationProvider` it makes sense to provide an own `OkHttpClient` instance (and thus also an own Retrofit instance if you use it) for all calls you need to receive new tokens. If try to serve all calls with the same client instance, it may happen that you run out of connections/threads while trying to get a token because there might be a whole slew of requests already waiting for that token call to succeed. Alternatively you can also try to increase the executor pool size, but this is not recommended as you never know for sure how many requests are executed at a given point in time - and you definitely always want a thread ready for your token request.*
91+
That's it. When using this `OkHttpClient` instance you'll benefit from fully
92+
transparent token handling.
93+
94+
__Hint 1:__ *If your app uses multiple authentication methods make sure to
95+
implement an own subclass of `AuthenticationProvider` for each method and use
96+
an own `OkHttpClient` for each!*
97+
98+
__Hint 2:__ *In case you are using OkHttp/Retrofit to retrieve tokens: As the
99+
`Authenticator` locks all other `Authenticators` and `AuthInterceptors` with
100+
the same `AuthenticationProvider` it makes sense to provide an own
101+
`OkHttpClient` instance (and thus also an own Retrofit instance if you use it)
102+
for all calls you need to receive new tokens. If try to serve all calls with
103+
the same client instance, it may happen that you run out of connections/threads
104+
while trying to get a token because there might be a whole slew of requests
105+
already waiting for that token call to succeed. Alternatively you can also try
106+
to increase the executor pool size, but this is not recommended as you never
107+
know for sure how many requests are executed at a given point in time - and you
108+
definitely always want a thread ready for your token request.*
86109

87110
#### A note on authentication exception handling
88111

89-
The library provides an own exception class called `AuthenticationException`. You can listen for this
90-
class in your Retrofit `Callback.onFailure(Call, Throwable)` to check for authentication related
112+
The library provides an own exception class called `AuthenticationException`.
113+
You can listen for this class in your Retrofit
114+
`Callback.onFailure(Call, Throwable)` to check for authentication related
91115
errors.
92116

93-
However up until now we are not able to fire this exception everywhere - especially the
94-
`Authenticator` suffers from a likely [okhttp bug](https://github.com/square/okhttp/issues/3872)
95-
which prevents us from firing exceptions there. In case of errors you will receive a `NullPointerException`
96-
instead which probably won't help you much for automated handling as this exception is basically
97-
caused by every interceptor/authenticator returning `null` for the expected Request/Response.
98-
99-
For the time being we recommend to take a best effort approach here and additionally check for 401 response code
100-
in Retrofit's `Callback.onSuccess()` for when an issue in the Authenticator occured (if there was no
101-
issue you won't get a 401 propagated to `Callback.onSuccess()` as in case of successful authentication
102-
after receiving a 401 for the initial request your callback will get the response code of the following
103-
originally intended request).
104-
105-
If you're having problems retrieving a token in the `AuthenticationProvider` (e.g. due to an invalid
106-
refresh token) always try to resolve those issues there as well if possible. Throwing an
107-
`AuthenticationException` should just be a last resort.
117+
However up until now we are not able to fire this exception everywhere -
118+
especially the `Authenticator` suffers from a likely
119+
[okhttp bug](https://github.com/square/okhttp/issues/3872) which prevents us
120+
from firing exceptions there. In case of errors you will receive a
121+
`NullPointerException` instead which probably won't help you much for automated
122+
handling as this exception is basically caused by every
123+
interceptor/authenticator returning `null` for the expected Request/Response.
124+
125+
For the time being we recommend to take a best effort approach here and
126+
additionally check for 401 response code in Retrofit's `Callback.onSuccess()`
127+
for when an issue in the Authenticator occured (if there was no issue you won't
128+
get a 401 propagated to `Callback.onSuccess()` as in case of successful
129+
authentication after receiving a 401 for the initial request your callback will
130+
get the response code of the following originally intended request).
131+
132+
If you're having problems retrieving a token in the `AuthenticationProvider`
133+
(e.g. due to an invalid refresh token) always try to resolve those issues there
134+
as well if possible. Throwing an `AuthenticationException` should just be a
135+
last resort.
108136

109137
Alternatively you can also subclass the `Authenticator` class and override
110-
`onAuthenticationFailed()` if you want to trigger special handling for failed authentication from
111-
which we couldn't recover with our default handling. This usually tends to be a bit harder to get
112-
right as it expects you to modify the failed request directly without any means of intercepting the
113-
response. Thus handling token retrieval issues should preferably handled in the `AuthenticationProvider`
114-
as explained above.
115-
116-
We're looking forward to streamlining this as soon as the okhttp bug has been resolved.
138+
`onAuthenticationFailed()` if you want to trigger special handling for failed
139+
authentication from which we couldn't recover with our default handling. This
140+
usually tends to be a bit harder to get right as it expects you to modify the
141+
failed request directly without any means of intercepting the response. Thus
142+
handling token retrieval issues should preferably handled in the
143+
`AuthenticationProvider` as explained above.
144+
145+
We're looking forward to streamlining this as soon as the okhttp bug has been
146+
resolved.

app/src/main/java/io/stanwood/framework/network/sample/MainActivity.kt

Lines changed: 0 additions & 12 deletions
This file was deleted.

app/src/main/res/values/strings.xml

Lines changed: 0 additions & 3 deletions
This file was deleted.

build.gradle

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
// Top-level build file where you can add configuration options common to all sub-projects/modules.
22

33
buildscript {
4-
ext.kotlin_version = '1.2.21'
54
repositories {
65
google()
76
jcenter()
87
}
98
dependencies {
10-
classpath 'com.android.tools.build:gradle:3.1.0-beta2'
11-
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
9+
classpath 'com.android.tools.build:gradle:3.1.2'
1210
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'
1311

1412
// NOTE: Do not place your application dependencies here; they belong

network/build.gradle

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
apply plugin: 'com.android.library'
2-
apply plugin: 'kotlin-android'
3-
apply plugin: 'kotlin-kapt'
42
apply plugin: 'com.github.dcendents.android-maven'
53

64
android {
@@ -28,11 +26,10 @@ android {
2826
dependencies {
2927
implementation fileTree(dir: 'libs', include: ['*.jar'])
3028

31-
implementation 'com.android.support:support-annotations:27.0.2'
29+
implementation 'com.android.support:support-annotations:27.1.1'
3230
testImplementation 'junit:junit:4.12'
33-
androidTestImplementation 'com.android.support.test:runner:1.0.1'
34-
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
35-
api 'com.squareup.okhttp3:okhttp:3.9.1'
31+
androidTestImplementation 'com.android.support.test:runner:1.0.2'
32+
api 'com.squareup.okhttp3:okhttp:3.10.0'
3633
}
3734

3835
// build a jar with source files

network/src/main/java/io/stanwood/framework/network/auth/AuthHeaderKeys.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
* as well as their signed-in variants.
66
*/
77
@SuppressWarnings("WeakerAccess")
8-
public abstract class AuthHeaderKeys {
8+
public class AuthHeaderKeys {
9+
10+
private AuthHeaderKeys() {
11+
throw new IllegalStateException("Utility class, not meant to be instantiated");
12+
}
913

1014
/**
1115
* This header is set by the Authenticators / Auth Interceptors to determine when to retry a

network/src/main/java/io/stanwood/framework/network/auth/Authenticator.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,8 @@ private Request retryOrFail(@NonNull Route route, @NonNull Response response) {
111111
.build()
112112
).build()
113113
);
114-
if (request == null) {
115-
if (onAuthenticationFailedListener != null) {
116-
onAuthenticationFailedListener.onAuthenticationFailed(response);
117-
}
114+
if (request == null && onAuthenticationFailedListener != null) {
115+
onAuthenticationFailedListener.onAuthenticationFailed(response);
118116
}
119117
return request;
120118
}

network/src/main/java/io/stanwood/framework/network/cache/CacheHeaderKeys.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@
77
* Add any combination of these headers to your requests and the interceptors will pick them up.
88
*/
99
@SuppressWarnings("WeakerAccess")
10-
public abstract class CacheHeaderKeys {
10+
public class CacheHeaderKeys {
11+
12+
private CacheHeaderKeys() {
13+
throw new IllegalStateException("Utility class, not meant to be instantiated");
14+
}
1115

1216
/**
1317
* Allows caching this request for offline usage. That doesn't mean it is used as online cache.

network/src/main/java/io/stanwood/framework/network/cache/CacheInterceptor.java

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -61,23 +61,21 @@ public Response intercept(@NonNull Chain chain) throws IOException {
6161
Request request = chain.request();
6262

6363
String offlineCacheHeader = request.header(CacheHeaderKeys.APPLY_OFFLINE_CACHE);
64-
if (Boolean.valueOf(offlineCacheHeader)) {
65-
if (!connectionState.isConnected()) {
66-
Request.Builder builder = request.newBuilder();
67-
if (queryAuthParameterKey != null) {
68-
builder.url(request
69-
.url()
70-
.newBuilder()
71-
.removeAllQueryParameters(queryAuthParameterKey)
72-
.build());
73-
}
74-
request = builder
75-
.cacheControl(CacheControl.FORCE_CACHE)
76-
.removeHeader(CacheHeaderKeys.APPLY_OFFLINE_CACHE)
77-
.removeHeader(CacheHeaderKeys.APPLY_RESPONSE_CACHE)
78-
.build();
79-
return chain.proceed(request);
64+
if (Boolean.valueOf(offlineCacheHeader) && !connectionState.isConnected()) {
65+
Request.Builder builder = request.newBuilder();
66+
if (queryAuthParameterKey != null) {
67+
builder.url(request
68+
.url()
69+
.newBuilder()
70+
.removeAllQueryParameters(queryAuthParameterKey)
71+
.build());
8072
}
73+
request = builder
74+
.cacheControl(CacheControl.FORCE_CACHE)
75+
.removeHeader(CacheHeaderKeys.APPLY_OFFLINE_CACHE)
76+
.removeHeader(CacheHeaderKeys.APPLY_RESPONSE_CACHE)
77+
.build();
78+
return chain.proceed(request);
8179
}
8280

8381
String responseCacheHeader = request.header(CacheHeaderKeys.REFRESH);
File renamed without changes.

0 commit comments

Comments
 (0)