diff --git a/app/src/main/java/com/matsyuk/authcase/MyApplication.java b/app/src/main/java/com/matsyuk/authcase/MyApplication.java index 5977ca3..bf32f64 100644 --- a/app/src/main/java/com/matsyuk/authcase/MyApplication.java +++ b/app/src/main/java/com/matsyuk/authcase/MyApplication.java @@ -12,7 +12,7 @@ public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); - ComponentManager.getInstance().initMainComponent(); + ComponentManager.getInstance().initAppComponent(); } } diff --git a/app/src/main/java/com/matsyuk/authcase/data/auth/AuthHolder.java b/app/src/main/java/com/matsyuk/authcase/data/auth/AuthHolder.java index 6076eab..e26be22 100644 --- a/app/src/main/java/com/matsyuk/authcase/data/auth/AuthHolder.java +++ b/app/src/main/java/com/matsyuk/authcase/data/auth/AuthHolder.java @@ -1,23 +1,38 @@ package com.matsyuk.authcase.data.auth; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; + +import com.matsyuk.authcase.data.common_network.CommonApi; + +import io.reactivex.Single; /** * @author e.matsyuk */ public class AuthHolder { - @Nullable - private String token; + private CommonApi commonApi; - public void setToken(@NonNull String token) { - this.token = token; + @NonNull + private volatile String token = "StartToken"; + + public AuthHolder(CommonApi commonApi) { + this.commonApi = commonApi; } - @Nullable + @NonNull public String getToken() { return token; } + public void refresh() { + updateToken().blockingGet(); + } + + private Single updateToken() { + return commonApi.updateToken() + .singleOrError() + .doOnSuccess(newToken -> token = newToken); + } + } diff --git a/app/src/main/java/com/matsyuk/authcase/data/network/SomeApi.java b/app/src/main/java/com/matsyuk/authcase/data/auth_network/AuthApi.java similarity index 73% rename from app/src/main/java/com/matsyuk/authcase/data/network/SomeApi.java rename to app/src/main/java/com/matsyuk/authcase/data/auth_network/AuthApi.java index 384f9c0..14790bb 100644 --- a/app/src/main/java/com/matsyuk/authcase/data/network/SomeApi.java +++ b/app/src/main/java/com/matsyuk/authcase/data/auth_network/AuthApi.java @@ -1,4 +1,4 @@ -package com.matsyuk.authcase.data.network; +package com.matsyuk.authcase.data.auth_network; import com.matsyuk.authcase.domain.main.SomeModel; @@ -8,7 +8,7 @@ /** * @author e.matsyuk */ -public interface SomeApi { +public interface AuthApi { @GET("/api/get") Observable getData(); diff --git a/app/src/main/java/com/matsyuk/authcase/data/auth_network/MainAuthenticator.java b/app/src/main/java/com/matsyuk/authcase/data/auth_network/MainAuthenticator.java new file mode 100644 index 0000000..ac3329d --- /dev/null +++ b/app/src/main/java/com/matsyuk/authcase/data/auth_network/MainAuthenticator.java @@ -0,0 +1,46 @@ +package com.matsyuk.authcase.data.auth_network; + +import android.support.annotation.Nullable; + +import com.matsyuk.authcase.data.auth.AuthHolder; + +import java.io.IOException; + +import okhttp3.Authenticator; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.Route; + +/** + * @author e.matsyuk + */ +public class MainAuthenticator implements Authenticator { + + private static final String ACCESS_TOKEN_HEADER = "Access-Token"; + + private AuthHolder authHolder; + + public MainAuthenticator(AuthHolder authHolder) { + this.authHolder = authHolder; + } + + @Nullable + @Override + public synchronized Request authenticate(Route route, Response response) throws IOException { + String storedToken = authHolder.getToken(); + String requestToken = response.request().header(ACCESS_TOKEN_HEADER); + + Request.Builder requestBuilder = response.request().newBuilder(); + + if (storedToken.equals(requestToken)) { + authHolder.refresh(); + } + + return buildRequest(requestBuilder); + } + + private Request buildRequest(Request.Builder requestBuilder) { + return requestBuilder.header(ACCESS_TOKEN_HEADER, authHolder.getToken()).build(); + } + +} diff --git a/app/src/main/java/com/matsyuk/authcase/data/network/MainInterceptor.java b/app/src/main/java/com/matsyuk/authcase/data/auth_network/MainInterceptor.java similarity index 94% rename from app/src/main/java/com/matsyuk/authcase/data/network/MainInterceptor.java rename to app/src/main/java/com/matsyuk/authcase/data/auth_network/MainInterceptor.java index 42695d2..8965996 100644 --- a/app/src/main/java/com/matsyuk/authcase/data/network/MainInterceptor.java +++ b/app/src/main/java/com/matsyuk/authcase/data/auth_network/MainInterceptor.java @@ -1,4 +1,4 @@ -package com.matsyuk.authcase.data.network; +package com.matsyuk.authcase.data.auth_network; import com.matsyuk.authcase.data.auth.AuthHolder; @@ -13,9 +13,10 @@ */ public class MainInterceptor implements Interceptor { - private AuthHolder authHolder; private static final String ACCESS_TOKEN_HEADER = "Access-Token"; + private AuthHolder authHolder; + public MainInterceptor(AuthHolder authHolder) { this.authHolder = authHolder; } diff --git a/app/src/main/java/com/matsyuk/authcase/data/auth_network/TestInterceptor.java b/app/src/main/java/com/matsyuk/authcase/data/auth_network/TestInterceptor.java new file mode 100644 index 0000000..c653a92 --- /dev/null +++ b/app/src/main/java/com/matsyuk/authcase/data/auth_network/TestInterceptor.java @@ -0,0 +1,347 @@ +package com.matsyuk.authcase.data.auth_network; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.HttpRetryException; +import java.net.ProtocolException; +import java.net.Proxy; +import java.net.SocketTimeoutException; +import java.security.cert.CertificateException; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSocketFactory; +import okhttp3.Address; +import okhttp3.CertificatePinner; +import okhttp3.Connection; +import okhttp3.HttpUrl; +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.Route; +import okhttp3.internal.connection.RouteException; +import okhttp3.internal.connection.StreamAllocation; +import okhttp3.internal.http.HttpMethod; +import okhttp3.internal.http.RealInterceptorChain; +import okhttp3.internal.http.UnrepeatableRequestBody; +import okhttp3.internal.http2.ConnectionShutdownException; + +import static java.net.HttpURLConnection.HTTP_CLIENT_TIMEOUT; +import static java.net.HttpURLConnection.HTTP_MOVED_PERM; +import static java.net.HttpURLConnection.HTTP_MOVED_TEMP; +import static java.net.HttpURLConnection.HTTP_MULT_CHOICE; +import static java.net.HttpURLConnection.HTTP_PROXY_AUTH; +import static java.net.HttpURLConnection.HTTP_SEE_OTHER; +import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; +import static okhttp3.internal.Util.closeQuietly; +import static okhttp3.internal.http.StatusLine.HTTP_PERM_REDIRECT; +import static okhttp3.internal.http.StatusLine.HTTP_TEMP_REDIRECT; + +public class TestInterceptor implements Interceptor { + /** + * How many redirects and auth challenges should we attempt? Chrome follows 21 redirects; Firefox, + * curl, and wget follow 20; Safari follows 16; and HTTP/1.0 recommends 5. + */ + private static final int MAX_FOLLOW_UPS = 20; + + private final OkHttpClient client; + private final boolean forWebSocket; + private StreamAllocation streamAllocation; + private Object callStackTrace; + private volatile boolean canceled; + + public TestInterceptor(OkHttpClient client, boolean forWebSocket) { + this.client = client; + this.forWebSocket = forWebSocket; + } + + /** + * Immediately closes the socket connection if it's currently held. Use this to interrupt an + * in-flight request from any thread. It's the caller's responsibility to close the request body + * and response body streams; otherwise resources may be leaked. + * + *

This method is safe to be called concurrently, but provides limited guarantees. If a + * transport layer connection has been established (such as a HTTP/2 stream) that is terminated. + * Otherwise if a socket connection is being established, that is terminated. + */ + public void cancel() { + canceled = true; + StreamAllocation streamAllocation = this.streamAllocation; + if (streamAllocation != null) streamAllocation.cancel(); + } + + public boolean isCanceled() { + return canceled; + } + + public void setCallStackTrace(Object callStackTrace) { + this.callStackTrace = callStackTrace; + } + + public StreamAllocation streamAllocation() { + return streamAllocation; + } + + @Override public Response intercept(Chain chain) throws IOException { + Request request = chain.request(); + + streamAllocation = new StreamAllocation( + client.connectionPool(), createAddress(request.url()), callStackTrace); + + int followUpCount = 0; + Response priorResponse = null; + while (true) { + if (canceled) { + streamAllocation.release(); + throw new IOException("Canceled"); + } + + Response response = null; + boolean releaseConnection = true; + try { + response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null); + releaseConnection = false; + } catch (RouteException e) { + // The attempt to connect via a route failed. The request will not have been sent. + if (!recover(e.getLastConnectException(), false, request)) { + throw e.getLastConnectException(); + } + releaseConnection = false; + continue; + } catch (IOException e) { + // An attempt to communicate with a server failed. The request may have been sent. + boolean requestSendStarted = !(e instanceof ConnectionShutdownException); + if (!recover(e, requestSendStarted, request)) throw e; + releaseConnection = false; + continue; + } finally { + // We're throwing an unchecked exception. Release any resources. + if (releaseConnection) { + streamAllocation.streamFailed(null); + streamAllocation.release(); + } + } + + // Attach the prior response if it exists. Such responses never have a body. + if (priorResponse != null) { + response = response.newBuilder() + .priorResponse(priorResponse.newBuilder() + .body(null) + .build()) + .build(); + } + + Request followUp = followUpRequest(response); + + if (followUp == null) { + if (!forWebSocket) { + streamAllocation.release(); + } + return response; + } + + closeQuietly(response.body()); + + if (++followUpCount > MAX_FOLLOW_UPS) { + streamAllocation.release(); + throw new ProtocolException("Too many follow-up requests: " + followUpCount); + } + + if (followUp.body() instanceof UnrepeatableRequestBody) { + streamAllocation.release(); + throw new HttpRetryException("Cannot retry streamed HTTP body", response.code()); + } + + if (!sameConnection(response, followUp.url())) { + streamAllocation.release(); + streamAllocation = new StreamAllocation( + client.connectionPool(), createAddress(followUp.url()), callStackTrace); + } else if (streamAllocation.codec() != null) { + throw new IllegalStateException("Closing the body of " + response + + " didn't close its backing stream. Bad interceptor?"); + } + + request = followUp; + priorResponse = response; + } + } + + private Address createAddress(HttpUrl url) { + SSLSocketFactory sslSocketFactory = null; + HostnameVerifier hostnameVerifier = null; + CertificatePinner certificatePinner = null; + if (url.isHttps()) { + sslSocketFactory = client.sslSocketFactory(); + hostnameVerifier = client.hostnameVerifier(); + certificatePinner = client.certificatePinner(); + } + + return new Address(url.host(), url.port(), client.dns(), client.socketFactory(), + sslSocketFactory, hostnameVerifier, certificatePinner, client.proxyAuthenticator(), + client.proxy(), client.protocols(), client.connectionSpecs(), client.proxySelector()); + } + + /** + * Report and attempt to recover from a failure to communicate with a server. Returns true if + * {@code e} is recoverable, or false if the failure is permanent. Requests with a body can only + * be recovered if the body is buffered or if the failure occurred before the request has been + * sent. + */ + private boolean recover(IOException e, boolean requestSendStarted, Request userRequest) { + streamAllocation.streamFailed(e); + + // The application layer has forbidden retries. + if (!client.retryOnConnectionFailure()) return false; + + // We can't send the request body again. + if (requestSendStarted && userRequest.body() instanceof UnrepeatableRequestBody) return false; + + // This exception is fatal. + if (!isRecoverable(e, requestSendStarted)) return false; + + // No more routes to attempt. + if (!streamAllocation.hasMoreRoutes()) return false; + + // For failure recovery, use the same route selector with a new connection. + return true; + } + + private boolean isRecoverable(IOException e, boolean requestSendStarted) { + // If there was a protocol problem, don't recover. + if (e instanceof ProtocolException) { + return false; + } + + // If there was an interruption don't recover, but if there was a timeout connecting to a route + // we should try the next route (if there is one). + if (e instanceof InterruptedIOException) { + return e instanceof SocketTimeoutException && !requestSendStarted; + } + + // Look for known client-side or negotiation errors that are unlikely to be fixed by trying + // again with a different route. + if (e instanceof SSLHandshakeException) { + // If the problem was a CertificateException from the X509TrustManager, + // do not retry. + if (e.getCause() instanceof CertificateException) { + return false; + } + } + if (e instanceof SSLPeerUnverifiedException) { + // e.g. a certificate pinning error. + return false; + } + + // An example of one we might want to retry with a different route is a problem connecting to a + // proxy and would manifest as a standard IOException. Unless it is one we know we should not + // retry, we return true and try a new route. + return true; + } + + /** + * Figures out the HTTP request to make in response to receiving {@code userResponse}. This will + * either add authentication headers, follow redirects or handle a client request timeout. If a + * follow-up is either unnecessary or not applicable, this returns null. + */ + private Request followUpRequest(Response userResponse) throws IOException { + if (userResponse == null) throw new IllegalStateException(); + Connection connection = streamAllocation.connection(); + Route route = connection != null + ? connection.route() + : null; + int responseCode = userResponse.code(); + + final String method = userResponse.request().method(); + switch (responseCode) { + case HTTP_PROXY_AUTH: + Proxy selectedProxy = route != null + ? route.proxy() + : client.proxy(); + if (selectedProxy.type() != Proxy.Type.HTTP) { + throw new ProtocolException("Received HTTP_PROXY_AUTH (407) code while not using proxy"); + } + return client.proxyAuthenticator().authenticate(route, userResponse); + + case HTTP_UNAUTHORIZED: + return client.authenticator().authenticate(route, userResponse); + + case HTTP_PERM_REDIRECT: + case HTTP_TEMP_REDIRECT: + // "If the 307 or 308 status code is received in response to a request other than GET + // or HEAD, the user agent MUST NOT automatically redirect the request" + if (!method.equals("GET") && !method.equals("HEAD")) { + return null; + } + // fall-through + case HTTP_MULT_CHOICE: + case HTTP_MOVED_PERM: + case HTTP_MOVED_TEMP: + case HTTP_SEE_OTHER: + // Does the client allow redirects? + if (!client.followRedirects()) return null; + + String location = userResponse.header("Location"); + if (location == null) return null; + HttpUrl url = userResponse.request().url().resolve(location); + + // Don't follow redirects to unsupported protocols. + if (url == null) return null; + + // If configured, don't follow redirects between SSL and non-SSL. + boolean sameScheme = url.scheme().equals(userResponse.request().url().scheme()); + if (!sameScheme && !client.followSslRedirects()) return null; + + // Most redirects don't include a request body. + Request.Builder requestBuilder = userResponse.request().newBuilder(); + if (HttpMethod.permitsRequestBody(method)) { + final boolean maintainBody = HttpMethod.redirectsWithBody(method); + if (HttpMethod.redirectsToGet(method)) { + requestBuilder.method("GET", null); + } else { + RequestBody requestBody = maintainBody ? userResponse.request().body() : null; + requestBuilder.method(method, requestBody); + } + if (!maintainBody) { + requestBuilder.removeHeader("Transfer-Encoding"); + requestBuilder.removeHeader("Content-Length"); + requestBuilder.removeHeader("Content-Type"); + } + } + + // When redirecting across hosts, drop all authentication headers. This + // is potentially annoying to the application layer since they have no + // way to retain them. + if (!sameConnection(userResponse, url)) { + requestBuilder.removeHeader("Authorization"); + } + + return requestBuilder.url(url).build(); + + case HTTP_CLIENT_TIMEOUT: + // 408's are rare in practice, but some servers like HAProxy use this response code. The + // spec says that we may repeat the request without modifications. Modern browsers also + // repeat the request (even non-idempotent ones.) + if (userResponse.request().body() instanceof UnrepeatableRequestBody) { + return null; + } + + return userResponse.request(); + + default: + return null; + } + } + + /** + * Returns true if an HTTP request for {@code followUp} can reuse the connection used by this + * engine. + */ + private boolean sameConnection(Response response, HttpUrl followUp) { + HttpUrl url = response.request().url(); + return url.host().equals(followUp.host()) + && url.port() == followUp.port() + && url.scheme().equals(followUp.scheme()); + } +} diff --git a/app/src/main/java/com/matsyuk/authcase/data/common_network/CommonApi.java b/app/src/main/java/com/matsyuk/authcase/data/common_network/CommonApi.java new file mode 100644 index 0000000..9dec64c --- /dev/null +++ b/app/src/main/java/com/matsyuk/authcase/data/common_network/CommonApi.java @@ -0,0 +1,14 @@ +package com.matsyuk.authcase.data.common_network; + +import io.reactivex.Observable; +import retrofit2.http.GET; + +/** + * @author e.matsyuk + */ +public interface CommonApi { + + @GET("/api/get/token") + Observable updateToken(); + +} diff --git a/app/src/main/java/com/matsyuk/authcase/di/ComponentManager.java b/app/src/main/java/com/matsyuk/authcase/di/ComponentManager.java index e615be4..6f160e4 100644 --- a/app/src/main/java/com/matsyuk/authcase/di/ComponentManager.java +++ b/app/src/main/java/com/matsyuk/authcase/di/ComponentManager.java @@ -1,7 +1,7 @@ package com.matsyuk.authcase.di; -import com.matsyuk.authcase.di.main.DaggerMainComponent; -import com.matsyuk.authcase.di.main.MainComponent; +import com.matsyuk.authcase.di.app.AppComponent; +import com.matsyuk.authcase.di.app.DaggerAppComponent; /** * @author e.matsyuk @@ -9,7 +9,7 @@ public class ComponentManager { private static volatile ComponentManager instance; - private MainComponent mainComponent; + private AppComponent appComponent; public static ComponentManager getInstance() { if (instance == null) { @@ -24,12 +24,12 @@ public static ComponentManager getInstance() { private ComponentManager() {} - public void initMainComponent() { - mainComponent = DaggerMainComponent.builder().build(); + public void initAppComponent() { + appComponent = DaggerAppComponent.builder().build(); } - public MainComponent getMainComponent() { - return mainComponent; + public AppComponent getAppComponent() { + return appComponent; } } diff --git a/app/src/main/java/com/matsyuk/authcase/di/main/MainComponent.java b/app/src/main/java/com/matsyuk/authcase/di/app/AppComponent.java similarity index 53% rename from app/src/main/java/com/matsyuk/authcase/di/main/MainComponent.java rename to app/src/main/java/com/matsyuk/authcase/di/app/AppComponent.java index 13ef416..f1999c9 100644 --- a/app/src/main/java/com/matsyuk/authcase/di/main/MainComponent.java +++ b/app/src/main/java/com/matsyuk/authcase/di/app/AppComponent.java @@ -1,4 +1,4 @@ -package com.matsyuk.authcase.di.main; +package com.matsyuk.authcase.di.app; import com.matsyuk.authcase.presentation.main.MainActivity; @@ -10,7 +10,7 @@ * @author e.matsyuk */ @Singleton -@Component(modules = {MainModule.class, NetworkModule.class, AuthModule.class}) -public interface MainComponent { +@Component(modules = {AppModule.class, AuthNetworkModule.class, AuthModule.class, CommonNetworkModule.class}) +public interface AppComponent { void inject(MainActivity mainActivity); } diff --git a/app/src/main/java/com/matsyuk/authcase/di/app/AppModule.java b/app/src/main/java/com/matsyuk/authcase/di/app/AppModule.java new file mode 100644 index 0000000..3fb6fc5 --- /dev/null +++ b/app/src/main/java/com/matsyuk/authcase/di/app/AppModule.java @@ -0,0 +1,24 @@ +package com.matsyuk.authcase.di.app; + +import com.matsyuk.authcase.data.auth_network.AuthApi; +import com.matsyuk.authcase.repositories.main.AuthRepository; +import com.matsyuk.authcase.repositories.main.AuthRepositoryImpl; + +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; + +/** + * @author e.matsyuk + */ +@Module +public class AppModule { + + @Singleton + @Provides + public AuthRepository provideSomeRepository(AuthApi authApi) { + return new AuthRepositoryImpl(authApi); + } + +} diff --git a/app/src/main/java/com/matsyuk/authcase/di/main/AuthModule.java b/app/src/main/java/com/matsyuk/authcase/di/app/AuthModule.java similarity index 53% rename from app/src/main/java/com/matsyuk/authcase/di/main/AuthModule.java rename to app/src/main/java/com/matsyuk/authcase/di/app/AuthModule.java index 0595b2f..272f303 100644 --- a/app/src/main/java/com/matsyuk/authcase/di/main/AuthModule.java +++ b/app/src/main/java/com/matsyuk/authcase/di/app/AuthModule.java @@ -1,8 +1,7 @@ -package com.matsyuk.authcase.di.main; - -import android.support.annotation.NonNull; +package com.matsyuk.authcase.di.app; import com.matsyuk.authcase.data.auth.AuthHolder; +import com.matsyuk.authcase.data.common_network.CommonApi; import javax.inject.Singleton; @@ -16,10 +15,9 @@ public class AuthModule { @Provides - @NonNull @Singleton - public AuthHolder provideAuthHolder() { - return new AuthHolder(); + public AuthHolder provideAuthHolder(CommonApi commonApi) { + return new AuthHolder(commonApi); } } diff --git a/app/src/main/java/com/matsyuk/authcase/di/app/AuthNetworkModule.java b/app/src/main/java/com/matsyuk/authcase/di/app/AuthNetworkModule.java new file mode 100644 index 0000000..dfe5b53 --- /dev/null +++ b/app/src/main/java/com/matsyuk/authcase/di/app/AuthNetworkModule.java @@ -0,0 +1,65 @@ +package com.matsyuk.authcase.di.app; + +import com.matsyuk.authcase.data.auth.AuthHolder; +import com.matsyuk.authcase.data.auth_network.AuthApi; +import com.matsyuk.authcase.data.auth_network.MainAuthenticator; +import com.matsyuk.authcase.data.auth_network.MainInterceptor; + +import java.util.concurrent.Executors; + +import javax.inject.Named; +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; +import okhttp3.Authenticator; +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import retrofit2.Retrofit; + +/** + * @author e.matsyuk + */ +@Module +public class AuthNetworkModule { + + @Provides + @Singleton + public Interceptor provideInterceptor(AuthHolder authHolder) { + return new MainInterceptor(authHolder); + } + + @Provides + @Singleton + public Authenticator provideAuthenticator(AuthHolder authHolder) { + return new MainAuthenticator(authHolder); + } + + @Provides + @Singleton + @Named("auth") + public OkHttpClient provideOkHttpClient(Interceptor interceptor, Authenticator authenticator) { + return new OkHttpClient.Builder() + .addInterceptor(interceptor) + .authenticator(authenticator) + .build(); + } + + @Provides + @Singleton + @Named("auth") + public Retrofit provideRetrofit(@Named("auth") OkHttpClient okHttpClient) { + return new Retrofit.Builder() + .baseUrl("some_url") + .client(okHttpClient) + .callbackExecutor(Executors.newFixedThreadPool(3)) + .build(); + } + + @Provides + @Singleton + public AuthApi provideAuthApi(@Named("auth") Retrofit retrofit) { + return retrofit.create(AuthApi.class); + } + +} diff --git a/app/src/main/java/com/matsyuk/authcase/di/app/CommonNetworkModule.java b/app/src/main/java/com/matsyuk/authcase/di/app/CommonNetworkModule.java new file mode 100644 index 0000000..ccaf389 --- /dev/null +++ b/app/src/main/java/com/matsyuk/authcase/di/app/CommonNetworkModule.java @@ -0,0 +1,46 @@ +package com.matsyuk.authcase.di.app; + +import com.matsyuk.authcase.data.common_network.CommonApi; + +import java.util.concurrent.Executors; + +import javax.inject.Named; +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; +import okhttp3.OkHttpClient; +import retrofit2.Retrofit; + +/** + * @author e.matsyuk + */ +@Module +public class CommonNetworkModule { + + @Provides + @Singleton + @Named("common") + public OkHttpClient provideOkHttpClient() { + return new OkHttpClient.Builder() + .build(); + } + + @Provides + @Singleton + @Named("common") + public Retrofit provideRetrofit(@Named("common") OkHttpClient okHttpClient) { + return new Retrofit.Builder() + .baseUrl("some_url") + .client(okHttpClient) + .callbackExecutor(Executors.newFixedThreadPool(3)) + .build(); + } + + @Provides + @Singleton + public CommonApi provideCommonApi(@Named("common") Retrofit retrofit) { + return retrofit.create(CommonApi.class); + } + +} diff --git a/app/src/main/java/com/matsyuk/authcase/di/main/MainModule.java b/app/src/main/java/com/matsyuk/authcase/di/main/MainModule.java deleted file mode 100644 index 1ae7c6b..0000000 --- a/app/src/main/java/com/matsyuk/authcase/di/main/MainModule.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.matsyuk.authcase.di.main; - -import com.matsyuk.authcase.data.network.SomeApi; -import com.matsyuk.authcase.repositories.main.SomeRepository; -import com.matsyuk.authcase.repositories.main.SomeRepositoryImpl; - -import javax.inject.Singleton; - -import dagger.Module; -import dagger.Provides; - -/** - * @author e.matsyuk - */ -@Module -public class MainModule { - - @Singleton - @Provides - public SomeRepository provideSomeRepository(SomeApi someApi) { - return new SomeRepositoryImpl(someApi); - } - -} diff --git a/app/src/main/java/com/matsyuk/authcase/di/main/NetworkModule.java b/app/src/main/java/com/matsyuk/authcase/di/main/NetworkModule.java deleted file mode 100644 index 27a11e3..0000000 --- a/app/src/main/java/com/matsyuk/authcase/di/main/NetworkModule.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.matsyuk.authcase.di.main; - -import android.support.annotation.NonNull; - -import com.matsyuk.authcase.data.auth.AuthHolder; -import com.matsyuk.authcase.data.network.MainInterceptor; -import com.matsyuk.authcase.data.network.SomeApi; - -import javax.inject.Named; -import javax.inject.Singleton; - -import dagger.Module; -import dagger.Provides; -import okhttp3.Interceptor; -import okhttp3.OkHttpClient; -import retrofit2.Retrofit; - -/** - * @author e.matsyuk - */ -@Module -public class NetworkModule { - - @Provides - @NonNull - @Singleton - public Interceptor provideInterceptor(AuthHolder authHolder) { - return new MainInterceptor(authHolder); - } - - @Provides - @NonNull - @Singleton - public OkHttpClient provideOkHttpClient(Interceptor interceptor) { - return new OkHttpClient.Builder() - .addInterceptor(interceptor) - .build(); - } - - @Provides - @NonNull - @Singleton - public Retrofit provideRetrofit(OkHttpClient okHttpClient) { - return new Retrofit.Builder() - .baseUrl("some_url") - .client(okHttpClient) - .build(); - } - - @Provides - @NonNull - @Singleton - public SomeApi provideAccountService(@NonNull Retrofit retrofit) { - return retrofit.create(SomeApi.class); - } - -} diff --git a/app/src/main/java/com/matsyuk/authcase/presentation/main/MainActivity.java b/app/src/main/java/com/matsyuk/authcase/presentation/main/MainActivity.java index dd6d2d8..5435fe7 100644 --- a/app/src/main/java/com/matsyuk/authcase/presentation/main/MainActivity.java +++ b/app/src/main/java/com/matsyuk/authcase/presentation/main/MainActivity.java @@ -5,19 +5,19 @@ import com.matsyuk.authcase.R; import com.matsyuk.authcase.di.ComponentManager; -import com.matsyuk.authcase.repositories.main.SomeRepository; +import com.matsyuk.authcase.repositories.main.AuthRepository; import javax.inject.Inject; public class MainActivity extends AppCompatActivity { @Inject - SomeRepository someRepository; + AuthRepository authRepository; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - ComponentManager.getInstance().getMainComponent().inject(this); + ComponentManager.getInstance().getAppComponent().inject(this); setContentView(R.layout.activity_main); } } diff --git a/app/src/main/java/com/matsyuk/authcase/repositories/main/SomeRepository.java b/app/src/main/java/com/matsyuk/authcase/repositories/main/AuthRepository.java similarity index 85% rename from app/src/main/java/com/matsyuk/authcase/repositories/main/SomeRepository.java rename to app/src/main/java/com/matsyuk/authcase/repositories/main/AuthRepository.java index 6429fbe..3990478 100644 --- a/app/src/main/java/com/matsyuk/authcase/repositories/main/SomeRepository.java +++ b/app/src/main/java/com/matsyuk/authcase/repositories/main/AuthRepository.java @@ -7,6 +7,6 @@ /** * @author e.matsyuk */ -public interface SomeRepository { +public interface AuthRepository { Single getData(); } diff --git a/app/src/main/java/com/matsyuk/authcase/repositories/main/AuthRepositoryImpl.java b/app/src/main/java/com/matsyuk/authcase/repositories/main/AuthRepositoryImpl.java new file mode 100644 index 0000000..106ae7c --- /dev/null +++ b/app/src/main/java/com/matsyuk/authcase/repositories/main/AuthRepositoryImpl.java @@ -0,0 +1,24 @@ +package com.matsyuk.authcase.repositories.main; + +import com.matsyuk.authcase.data.auth_network.AuthApi; +import com.matsyuk.authcase.domain.main.SomeModel; + +import io.reactivex.Single; + +/** + * @author e.matsyuk + */ +public class AuthRepositoryImpl implements AuthRepository { + + private AuthApi authApi; + + public AuthRepositoryImpl(AuthApi authApi) { + this.authApi = authApi; + } + + @Override + public Single getData() { + return authApi.getData().singleOrError(); + } + +} diff --git a/app/src/main/java/com/matsyuk/authcase/repositories/main/SomeRepositoryImpl.java b/app/src/main/java/com/matsyuk/authcase/repositories/main/SomeRepositoryImpl.java deleted file mode 100644 index b9eaebb..0000000 --- a/app/src/main/java/com/matsyuk/authcase/repositories/main/SomeRepositoryImpl.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.matsyuk.authcase.repositories.main; - -import com.matsyuk.authcase.data.network.SomeApi; -import com.matsyuk.authcase.domain.main.SomeModel; - -import io.reactivex.Single; - -/** - * @author e.matsyuk - */ -public class SomeRepositoryImpl implements SomeRepository { - - private SomeApi someApi; - - public SomeRepositoryImpl(SomeApi someApi) { - this.someApi = someApi; - } - - @Override - public Single getData() { - return someApi.getData().singleOrError(); - } - -}