├── .gitignore
├── .idea
├── .name
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── dictionaries
│ └── victor.xml
├── gradle.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── README.md
├── RestAPIParseAuthCleanAndroid.iml
├── build.gradle
├── data
├── .gitignore
├── build.gradle
├── data.iml
├── proguard-rules.pro
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ ├── entities
│ │ │ └── Credentials.java
│ │ ├── internal
│ │ │ └── di
│ │ │ │ ├── DataComponent.java
│ │ │ │ └── DataModule.java
│ │ ├── net
│ │ │ ├── ConfigEndpoints.java
│ │ │ ├── Endpoints.java
│ │ │ └── RestApi.java
│ │ ├── repositories
│ │ │ └── SessionDataRepository.java
│ │ └── storage
│ │ │ └── Persistence.java
│ └── res
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ ├── net
│ └── RestApiTest.java
│ ├── repositories
│ └── SessionDataRepositoryTest.java
│ └── storage
│ └── PersistenceTest.java
├── domain
├── .gitignore
├── build.gradle
├── domain.iml
└── src
│ ├── main
│ └── java
│ │ ├── entities
│ │ └── User.java
│ │ ├── interactors
│ │ ├── GetUserUseCase.java
│ │ ├── LoginUseCase.java
│ │ ├── LogoutUseCase.java
│ │ ├── SessionUseCase.java
│ │ ├── SignUpUseCase.java
│ │ └── UpdateUserCase.java
│ │ ├── presenters
│ │ ├── GetUserPresenter.java
│ │ ├── LaunchPresenter.java
│ │ ├── LoginPresenter.java
│ │ ├── LogoutPresenter.java
│ │ ├── Presenter.java
│ │ ├── SignUpPresenter.java
│ │ ├── UpdateUserPresenter.java
│ │ └── subscribers
│ │ │ ├── BaseCredentialsSubscriber.java
│ │ │ ├── BaseProfileSubscriber.java
│ │ │ └── BaseUseCaseSubscriber.java
│ │ ├── respositories
│ │ └── SessionRepository.java
│ │ ├── schedulers
│ │ ├── ObserveOn.java
│ │ └── SubscribeOn.java
│ │ └── views
│ │ ├── CredentialsView.java
│ │ ├── GetUserView.java
│ │ ├── LaunchView.java
│ │ ├── LoginView.java
│ │ ├── LogoutView.java
│ │ ├── ProfileView.java
│ │ ├── SignUpView.java
│ │ ├── UpdateUserView.java
│ │ └── View.java
│ └── test
│ └── java
│ ├── interactors
│ ├── BaseSessionUseCaseTest.java
│ ├── GetUserUseCaseTest.java
│ ├── LoginUseCaseTest.java
│ ├── LogoutUseCaseTest.java
│ ├── SessionUseCaseTest.java
│ ├── SignUpUseCaseTest.java
│ └── UpdateUserUseCaseTest.java
│ └── presenters
│ ├── BasePresenterTest.java
│ ├── GetUserPresenterTest.java
│ ├── LaunchPresenterTest.java
│ ├── LoginPresenterTest.java
│ ├── LogoutPresenterTest.java
│ ├── SignUpPresenterTest.java
│ └── UpdateUserPresenterTest.java
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── presentation
├── .gitignore
├── build.gradle
├── presentation.iml
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── ConnectionTest.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ ├── activities
│ │ ├── BaseActivity.java
│ │ ├── CredentialsActivity.java
│ │ ├── LaunchActivity.java
│ │ └── ProfileActivity.java
│ ├── fragments
│ │ ├── BaseFragment.java
│ │ ├── FragmentLogin.java
│ │ ├── FragmentLogout.java
│ │ ├── FragmentProfile.java
│ │ └── FragmentSignUp.java
│ ├── internal
│ │ └── di
│ │ │ ├── ApplicationComponent.java
│ │ │ └── ApplicationModule.java
│ ├── navigation
│ │ └── Navigator.java
│ └── utilities
│ │ └── AndroidApplication.java
│ └── res
│ ├── layout
│ ├── connect_activity.xml
│ ├── fragment_login.xml
│ ├── fragment_logout.xml
│ ├── fragment_profile.xml
│ ├── fragment_sign_up.xml
│ └── profile_activity.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── settings.gradle
└── store
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | .DS_Store
6 | /build
7 | /captures
8 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | RestAPIParseAuthCleanAndroid
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/dictionaries/victor.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | unsubscribed
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
20 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | Android Lint
39 |
40 |
41 | General
42 |
43 |
44 | Maven
45 |
46 |
47 |
48 |
49 | Android
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | 1.7
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RestAPIParseAuthCleanAndroid
2 | An android implementation of an authentication system based on the Parse Api using the design patterns suggested by Robert C. Martin (aka Uncle Bob) on his “clean architecture”.
3 |
4 | # Technologies:
5 | Dagger 2, AndroidAnnotations, Retrofit, Mockito, Roboelectric, Robotium, RXJava, MVP, Dependency inversion, Dependency Injection
6 |
--------------------------------------------------------------------------------
/RestAPIParseAuthCleanAndroid.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.3.0'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | ext {
22 | compileSdkVersion = 22
23 | buildToolsVersion = "22.0.1"
24 |
25 | //Libraries
26 | daggerVersion = '2.0.1'
27 | rxJavaVersion = '1.0.14'
28 | rxAndroidVersion = '1.0.1'
29 | javaxAnnotationVersion = "10.0-b28"
30 | androidannotationsVersion = '3.3.2'
31 | supportAppCompatVersion = '22.2.1'
32 | gsonVersion = "1.7.2"
33 | retrofitVersion = "1.9.0"
34 |
35 | //Unit testing
36 | jUnitVersion = "4.12"
37 | mockitoVersion = "1.10.19"
38 | hamcrestVersion = "1.1"
39 | robolectricVersion = "3.0"
40 |
41 | //Integration testing
42 | supportTestRunnerVersion = "0.3"
43 | supportTestRulesVersion = "0.3"
44 | robotiumVersion = "5.3.1"
45 |
46 | domainDependencies = [
47 | daggerCompiler: "com.google.dagger:dagger-compiler:${daggerVersion}",
48 | dagger: "com.google.dagger:dagger:${daggerVersion}",
49 | rxJava: "io.reactivex:rxjava:${rxJavaVersion}",
50 | javaxAnnotation: "org.glassfish:javax.annotation:${javaxAnnotationVersion}"
51 | ]
52 |
53 | domainTestDependencies = [
54 | junit: "junit:junit:${jUnitVersion}",
55 | mockito: "org.mockito:mockito-core:${mockitoVersion}",
56 | hamcrest: "org.hamcrest:hamcrest-library:${hamcrestVersion}"
57 | ]
58 |
59 | dataDependencies = [
60 | retrofit: "com.squareup.retrofit:retrofit:${retrofitVersion}",
61 | daggerCompiler: "com.google.dagger:dagger-compiler:${daggerVersion}",
62 | dagger: "com.google.dagger:dagger:${daggerVersion}",
63 | rxJava: "io.reactivex:rxjava:${rxJavaVersion}",
64 | javaxAnnotation: "org.glassfish:javax.annotation:${javaxAnnotationVersion}",
65 | supportAppCompat: "com.android.support:appcompat-v7:${supportAppCompatVersion}"
66 | ]
67 |
68 | dataTestDependencies = [
69 | junit: "junit:junit:${jUnitVersion}",
70 | mockito: "org.mockito:mockito-core:${mockitoVersion}",
71 | hamcrest: "org.hamcrest:hamcrest-library:${hamcrestVersion}",
72 | robolectric: "org.robolectric:robolectric:${robolectricVersion}"
73 | ]
74 |
75 | presentationDependencies = [
76 | daggerCompiler: "com.google.dagger:dagger-compiler:${daggerVersion}",
77 | dagger: "com.google.dagger:dagger:${daggerVersion}",
78 | rxJava: "io.reactivex:rxjava:${rxJavaVersion}",
79 | rxAndroid: "io.reactivex:rxandroid:${rxAndroidVersion}",
80 | javaxAnnotation: "org.glassfish:javax.annotation:${javaxAnnotationVersion}",
81 | androidannotations: "org.androidannotations:androidannotations-api:${androidannotationsVersion}",
82 | androidannotationsCompiler: "org.androidannotations:androidannotations:${androidannotationsVersion}",
83 | supportAppCompat: "com.android.support:appcompat-v7:${supportAppCompatVersion}"
84 | ]
85 |
86 | presentationTestDependencies = [
87 | supportTestRunner: "com.android.support.test:runner:${supportTestRunnerVersion}",
88 | supportTestRules: "com.android.support.test:rules:${supportTestRulesVersion}",
89 | robotiumVersion: "com.jayway.android.robotium:robotium-solo:${robotiumVersion}"
90 | ]
91 | }
92 |
--------------------------------------------------------------------------------
/data/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/data/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'android-apt'
3 |
4 | buildscript {
5 | repositories {
6 | jcenter()
7 | }
8 |
9 | dependencies {
10 | classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
11 | }
12 | }
13 | android {
14 | compileSdkVersion 22
15 | buildToolsVersion "22.0.1"
16 |
17 | defaultConfig {
18 | minSdkVersion 16
19 | targetSdkVersion 22
20 | versionCode 1
21 | versionName "1.0"
22 | }
23 |
24 | buildTypes {
25 | debug {
26 | testCoverageEnabled = true
27 | }
28 | release {
29 | minifyEnabled false
30 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
31 | }
32 | }
33 | compileOptions {
34 | sourceCompatibility JavaVersion.VERSION_1_7
35 | targetCompatibility JavaVersion.VERSION_1_7
36 | }
37 | }
38 |
39 | apt {
40 | arguments {
41 | androidManifestFile variant.outputs[0].processResources.manifestFile
42 | resourcePackageName "edu.victoralbertos.restapiparseauthcleanandroid"
43 | }
44 | }
45 |
46 | dependencies {
47 | compile fileTree(dir: 'libs', include: ['*.jar'])
48 | compile project(':domain')
49 |
50 |
51 | def dataDependencies = rootProject.ext.dataDependencies
52 |
53 | compile dataDependencies.retrofit
54 |
55 | apt dataDependencies.daggerCompiler
56 | compile dataDependencies.dagger
57 | provided dataDependencies.javaxAnnotation
58 |
59 | compile dataDependencies.rxJava
60 |
61 | compile dataDependencies.supportAppCompat
62 |
63 |
64 | def dataTestDependencies = rootProject.ext.dataTestDependencies
65 |
66 | testCompile dataTestDependencies.junit
67 | testCompile dataTestDependencies.mockito
68 | testCompile dataTestDependencies.hamcrest
69 | testCompile dataTestDependencies.robolectric
70 | }
71 |
--------------------------------------------------------------------------------
/data/data.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | generateDebugAndroidTestSources
19 | generateDebugSources
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/data/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/victor/Documents/AndroidStudio/android_sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/data/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/data/src/main/java/entities/Credentials.java:
--------------------------------------------------------------------------------
1 | package entities;
2 |
3 | public class Credentials {
4 | private String sessionToken, objectId;
5 |
6 | public String getSessionToken() {
7 | return sessionToken;
8 | }
9 |
10 | public String getObjectId() {
11 | return objectId;
12 | }
13 | }
--------------------------------------------------------------------------------
/data/src/main/java/internal/di/DataComponent.java:
--------------------------------------------------------------------------------
1 | package internal.di;
2 |
3 | import net.Endpoints;
4 |
5 | import dagger.Component;
6 |
7 | @Component(modules = DataModule.class)
8 | public interface DataComponent {
9 | Endpoints endpoints();
10 | }
11 |
--------------------------------------------------------------------------------
/data/src/main/java/internal/di/DataModule.java:
--------------------------------------------------------------------------------
1 | package internal.di;
2 |
3 | import com.google.gson.JsonObject;
4 |
5 | import net.ConfigEndpoints;
6 | import net.Endpoints;
7 |
8 | import dagger.Module;
9 | import dagger.Provides;
10 | import retrofit.ErrorHandler;
11 | import retrofit.RestAdapter;
12 | import retrofit.RetrofitError;
13 |
14 | @Module
15 | public class DataModule {
16 | @Provides Endpoints provideEndpoints() {
17 | return new RestAdapter.Builder()
18 | .setEndpoint(ConfigEndpoints.URL_BASE)
19 | .setErrorHandler(new ErrorHandler() {
20 | @Override public Throwable handleError(RetrofitError cause) {
21 | JsonObject jsonObject = (JsonObject) cause.getBodyAs(JsonObject.class);
22 | String message = jsonObject.get("error").getAsString();
23 | return new RuntimeException(message);
24 | }
25 | }).build().create(Endpoints.class);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/data/src/main/java/net/ConfigEndpoints.java:
--------------------------------------------------------------------------------
1 | package net;
2 |
3 | public interface ConfigEndpoints {
4 | String URL_BASE = "https://api.parse.com/1";
5 | String HEADER_APP_ID = "X-Parse-Application-Id: KuDgG8xELX1anJVIG3igMOpzbt7pVEDml09R2Yow";
6 | String HEADER_REST_API_KEY = "X-Parse-REST-API-Key: V2V9SyIMqgXrSL03pVuzDLlIH6z9nmBVHHjDMrh1";
7 | }
8 |
--------------------------------------------------------------------------------
/data/src/main/java/net/Endpoints.java:
--------------------------------------------------------------------------------
1 | package net;
2 |
3 | import com.google.gson.JsonObject;
4 |
5 | import entities.Credentials;
6 | import entities.User;
7 | import retrofit.http.Body;
8 | import retrofit.http.GET;
9 | import retrofit.http.Header;
10 | import retrofit.http.Headers;
11 | import retrofit.http.POST;
12 | import retrofit.http.PUT;
13 | import retrofit.http.Path;
14 | import retrofit.http.Query;
15 | import rx.Observable;
16 |
17 | public interface Endpoints {
18 | @Headers({ConfigEndpoints.HEADER_APP_ID, ConfigEndpoints.HEADER_REST_API_KEY})
19 | @GET("/login")
20 | Observable login(@Query("username") String username, @Query("password") String password);
21 |
22 | @Headers({ConfigEndpoints.HEADER_APP_ID, ConfigEndpoints.HEADER_REST_API_KEY})
23 | @POST("/users")
24 | Observable signUp(@Body User user);
25 |
26 | @Headers({ConfigEndpoints.HEADER_APP_ID, ConfigEndpoints.HEADER_REST_API_KEY})
27 | @GET("/users/me")
28 | Observable currentSession(@Header("X-Parse-Session-Token") String token);
29 |
30 | @Headers({ConfigEndpoints.HEADER_APP_ID, ConfigEndpoints.HEADER_REST_API_KEY})
31 | @PUT("/users/{objectId}")
32 | Observable update(@Header("X-Parse-Session-Token") String token,
33 | @Path("objectId") String objectId, @Body User user);
34 | }
35 |
--------------------------------------------------------------------------------
/data/src/main/java/net/RestApi.java:
--------------------------------------------------------------------------------
1 | package net;
2 |
3 | import com.google.gson.JsonObject;
4 |
5 | import javax.inject.Inject;
6 |
7 | import entities.Credentials;
8 | import entities.User;
9 | import rx.Observable;
10 |
11 | public class RestApi {
12 | private final Endpoints endpoints;
13 |
14 | @Inject public RestApi(Endpoints endpoints) {
15 | this.endpoints = endpoints;
16 | }
17 |
18 | public Observable login(String username, String password) {
19 | return endpoints.login(username, password);
20 | }
21 |
22 | public Observable signUp(User user) {
23 | return endpoints.signUp(user);
24 | }
25 |
26 | public Observable currentSession(String token) {
27 | return endpoints.currentSession(token);
28 | }
29 |
30 | public Observable update(String token, String objectId, User user) {
31 | return endpoints.update(token, objectId, user);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/data/src/main/java/repositories/SessionDataRepository.java:
--------------------------------------------------------------------------------
1 | package repositories;
2 |
3 | import android.content.Context;
4 |
5 | import com.google.gson.JsonObject;
6 |
7 | import net.RestApi;
8 |
9 | import javax.inject.Inject;
10 |
11 | import edu.victoralbertos.data.R;
12 | import entities.Credentials;
13 | import entities.User;
14 | import respositories.SessionRepository;
15 | import rx.Observable;
16 | import rx.Subscriber;
17 | import rx.functions.Func1;
18 | import storage.Persistence;
19 |
20 | public class SessionDataRepository implements SessionRepository {
21 | private final RestApi restApi;
22 | private final Persistence persistence;
23 | private final Context context;
24 |
25 | @Inject public SessionDataRepository(Context context, RestApi restApi, Persistence persistence) {
26 | this.context = context;
27 | this.restApi = restApi;
28 | this.persistence = persistence;
29 | }
30 |
31 | @Override public Observable askForLogin(String username, String password) {
32 | return restApi.login(username, password).map(new Func1() {
33 | @Override public String call(Credentials credentials) {
34 | persistence.save(Credentials.class.getName(), credentials);
35 | return context.getString(R.string.success);
36 | }
37 | });
38 | }
39 |
40 | @Override public Observable askForUserLogged() {
41 | Credentials credentials = persistence.retrieve(Credentials.class.getName(), Credentials.class);
42 | if (credentials == null) return notLoggedUserError();
43 |
44 | return restApi.currentSession(credentials.getSessionToken());
45 | }
46 |
47 | @Override public Observable askForUpdateLoggedUser(User user) {
48 | Credentials credentials = persistence.retrieve(Credentials.class.getName(), Credentials.class);
49 | if (credentials == null) return notLoggedUserError();
50 |
51 | String token = credentials.getSessionToken();
52 | String objectId = credentials.getObjectId();
53 |
54 | return restApi.update(token, objectId, user).map(new Func1() {
55 | @Override public String call(JsonObject jsonObject) {
56 | return context.getString(R.string.success);
57 | }
58 | });
59 | }
60 |
61 | @Override public Observable askForSignUp(User user) {
62 | return restApi.signUp(user).map(new Func1() {
63 | @Override public String call(Credentials credentials) {
64 | persistence.save(Credentials.class.getName(), credentials);
65 | return context.getString(R.string.success);
66 | }
67 | });
68 | }
69 |
70 | @Override public Observable askForLogout() {
71 | Credentials credentials = persistence.retrieve(Credentials.class.getName(), Credentials.class);
72 | if (credentials == null) return notLoggedUserError();
73 |
74 | persistence.delete(Credentials.class.getName());
75 | return Observable.just(context.getString(R.string.success));
76 | }
77 |
78 | private Observable notLoggedUserError() {
79 | return Observable.create(new Observable.OnSubscribe() {
80 | @Override
81 | public void call(Subscriber super T> subscriber) {
82 | subscriber.onError(new RuntimeException(context.getString(R.string.not_user_logged)));
83 | }
84 | });
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/data/src/main/java/storage/Persistence.java:
--------------------------------------------------------------------------------
1 | package storage;
2 |
3 | import android.content.Context;
4 | import android.support.annotation.Nullable;
5 |
6 | import com.google.gson.Gson;
7 |
8 | import java.io.BufferedReader;
9 | import java.io.File;
10 | import java.io.FileReader;
11 | import java.io.FileWriter;
12 |
13 | import javax.inject.Inject;
14 |
15 | public class Persistence {
16 | private final Context context;
17 |
18 | @Inject public Persistence(Context context) {
19 | this.context = context;
20 | }
21 |
22 | public boolean save(String key, Object data) {
23 | String wrapperJSONSerialized = new Gson().toJson(data);
24 | try {
25 | File file = new File(context.getFilesDir(), key);
26 |
27 | FileWriter fileWriter = new FileWriter(file, false);
28 | fileWriter.write(wrapperJSONSerialized);
29 | fileWriter.flush();
30 | fileWriter.close();
31 | return true;
32 | } catch (Exception e) {
33 | e.printStackTrace();
34 | return false;
35 | }
36 | }
37 |
38 | public boolean delete(String key) {
39 | File file = new File(context.getFilesDir(), key);
40 | return file.delete();
41 | }
42 |
43 | @Nullable public T retrieve(String key, Class clazz) {
44 | try {
45 | File file = new File(context.getFilesDir(), key);
46 | BufferedReader bufferedReader = new BufferedReader(new FileReader(file.getAbsoluteFile()));
47 | return new Gson().fromJson(bufferedReader, clazz);
48 | } catch (Exception e) {
49 | e.printStackTrace();
50 | return null;
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/data/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Data
3 | Good!
4 | Not good!
5 | Nor user logged!
6 |
7 |
--------------------------------------------------------------------------------
/data/src/test/java/net/RestApiTest.java:
--------------------------------------------------------------------------------
1 | package net;
2 |
3 | import com.google.gson.JsonObject;
4 |
5 | import org.junit.Before;
6 | import org.junit.FixMethodOrder;
7 | import org.junit.Test;
8 | import org.junit.runners.MethodSorters;
9 |
10 | import entities.Credentials;
11 | import entities.User;
12 | import internal.di.DaggerDataComponent;
13 | import rx.observers.TestSubscriber;
14 |
15 | import static org.hamcrest.MatcherAssert.assertThat;
16 | import static org.hamcrest.Matchers.is;
17 |
18 | @FixMethodOrder(MethodSorters.NAME_ASCENDING)
19 | public class RestApiTest {
20 | private RestApi restApi;
21 |
22 | @Before public void setUp() {
23 | Endpoints endpoints = DaggerDataComponent.create().endpoints();
24 | restApi = new RestApi(endpoints);
25 | }
26 |
27 | @Test public void first_When_Sign_Up_With_Valid_Inputs_Then_Get_Credentials() {
28 | TestSubscriber subscriber = new TestSubscriber<>();
29 | restApi.signUp(makeValidUser()).subscribe(subscriber);
30 |
31 | subscriber.awaitTerminalEvent();
32 | credentials = subscriber.getOnNextEvents().get(0);
33 | assertThat(subscriber.getOnNextEvents().size(), is(1));
34 | }
35 |
36 | @Test public void first_When_Sign_Up_With_Invalid_Inputs_Then_Throw_An_ExceptionOnSubscriber() {
37 | TestSubscriber subscriber = new TestSubscriber<>();
38 | restApi.signUp(makeInvalidUser()).subscribe(subscriber);
39 |
40 | subscriber.awaitTerminalEvent();
41 | assertThat(subscriber.getOnErrorEvents().size(), is(1));
42 | }
43 |
44 | @Test public void second_When_Update_With_Valid_Inputs_Then_User_Is_Updated() {
45 | TestSubscriber subscriber = new TestSubscriber<>();
46 | restApi.update(credentials.getSessionToken(), credentials.getObjectId(), makeValidUser()).subscribe(subscriber);
47 |
48 | subscriber.awaitTerminalEvent();
49 | assertThat(subscriber.getOnNextEvents().size(), is(1));
50 | }
51 |
52 | @Test public void second_When_Update_With_Invalid_Inputs_Then_User_Is_Not_Updated() {
53 | TestSubscriber subscriber = new TestSubscriber<>();
54 | restApi.update("anInvalidToken", "anObjectId", makeInvalidUser()).subscribe(subscriber);
55 |
56 | subscriber.awaitTerminalEvent();
57 | assertThat(subscriber.getOnErrorEvents().size(), is(1));
58 | }
59 |
60 | @Test public void third_When_Ask_For_User_With_Valid_Inputs_Then_Get_User() {
61 | TestSubscriber subscriber = new TestSubscriber<>();
62 | restApi.currentSession(credentials.getSessionToken()).subscribe(subscriber);
63 |
64 | subscriber.awaitTerminalEvent();
65 | assertThat(subscriber.getOnNextEvents().size(), is(1));
66 | }
67 |
68 | @Test public void third_When_Ask_For_User_With_Invalid_Inputs_Then_Throw_An_Exception_On_Subscriber() {
69 | TestSubscriber subscriber = new TestSubscriber<>();
70 | restApi.currentSession("anInvalidToken").subscribe(subscriber);
71 |
72 | subscriber.awaitTerminalEvent();
73 | assertThat(subscriber.getOnErrorEvents().size(), is(1));
74 | }
75 |
76 | @Test public void fourth_When_Login_With_Valid_Inputs_Then_Get_Credentials() {
77 | TestSubscriber subscriber = new TestSubscriber<>();
78 | restApi.login(makeValidUser().getUsername(), makeValidUser().getPassword()).subscribe(subscriber);
79 |
80 | subscriber.awaitTerminalEvent();
81 | assertThat(subscriber.getOnNextEvents().size(), is(1));
82 | }
83 |
84 | @Test public void fourth_When_Login_With_Invalid_Inputs_Then_Throw_An_ExceptionOnSubscriber() {
85 | TestSubscriber subscriber = new TestSubscriber<>();
86 | restApi.login("anInvalidUsername", "anInvalidPassword").subscribe(subscriber);
87 |
88 | subscriber.awaitTerminalEvent();
89 | assertThat(subscriber.getOnErrorEvents().size(), is(1));
90 | }
91 |
92 | private User makeInvalidUser() {
93 | return new User();
94 | }
95 |
96 | private static Credentials credentials;
97 | private static User user;
98 | private static User makeValidUser() {
99 | if (user != null) return user;
100 |
101 | long time = System.currentTimeMillis();
102 | String username = "ut" + time;
103 | String email = "et@" + time + "t.com";
104 | String phone = "pht" + time;
105 | String password = "pat" + time;
106 | return user = new User(username, email, phone, password);
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/data/src/test/java/repositories/SessionDataRepositoryTest.java:
--------------------------------------------------------------------------------
1 | package repositories;
2 |
3 | import android.content.Context;
4 |
5 | import com.google.gson.JsonObject;
6 |
7 | import net.RestApi;
8 |
9 | import org.junit.Before;
10 | import org.junit.Test;
11 | import org.mockito.Mock;
12 | import org.mockito.MockitoAnnotations;
13 |
14 | import entities.Credentials;
15 | import entities.User;
16 | import rx.Observable;
17 | import rx.Subscriber;
18 | import rx.observers.TestSubscriber;
19 | import storage.Persistence;
20 |
21 | import static org.hamcrest.MatcherAssert.assertThat;
22 | import static org.hamcrest.Matchers.is;
23 | import static org.mockito.Matchers.any;
24 | import static org.mockito.Matchers.eq;
25 | import static org.mockito.Mockito.verify;
26 | import static org.mockito.Mockito.verifyZeroInteractions;
27 | import static org.mockito.Mockito.when;
28 |
29 | public class SessionDataRepositoryTest {
30 | @Mock private RestApi restApi;
31 | @Mock private Persistence persistence;
32 | @Mock private Context context;
33 | private SessionDataRepository sessionDataRepository;
34 |
35 | @Before public void setUp() {
36 | MockitoAnnotations.initMocks(this);
37 | sessionDataRepository = new SessionDataRepository(context, restApi, persistence);
38 | }
39 |
40 | @Test public void when_Login_With_Valid_Inputs_Then_Get_Credentials_And_Saved_It() {
41 | when(restApi.login(any(String.class), any(String.class))).thenReturn(Observable.just(new Credentials()));
42 |
43 | TestSubscriber subscriber = new TestSubscriber<>();
44 | sessionDataRepository.askForLogin("username", "password").subscribe(subscriber);
45 | subscriber.awaitTerminalEvent();
46 |
47 | assertThat(subscriber.getOnNextEvents().size(), is(1));
48 | verify(persistence).save(any(String.class), any(Object.class));
49 | }
50 |
51 | @Test public void when_Login_With_Invalid_Inputs_Then_Credentials_Is_Not_Saved() {
52 | when(restApi.login(any(String.class), any(String.class))).thenReturn(Observable.create(
53 | new Observable.OnSubscribe() {
54 | @Override
55 | public void call(Subscriber super Credentials> subscriber) {
56 | subscriber.onError(new RuntimeException("Not Great"));
57 | }
58 | })
59 | );
60 |
61 | TestSubscriber subscriber = new TestSubscriber<>();
62 | sessionDataRepository.askForLogin("username", "password").subscribe(subscriber);
63 | subscriber.awaitTerminalEvent();
64 |
65 | assertThat(subscriber.getOnErrorEvents().size(), is(1));
66 | verifyZeroInteractions(persistence);
67 | }
68 |
69 | @Test public void when_Get_User_Being_Logged_Then_Get_User() {
70 | Credentials credentials = new Credentials();
71 |
72 | when(persistence.retrieve(any(String.class), eq(Credentials.class))).thenReturn(credentials);
73 | when(restApi.currentSession(null)).thenReturn(Observable.just(new User()));
74 |
75 | TestSubscriber subscriber = new TestSubscriber<>();
76 | sessionDataRepository.askForUserLogged().subscribe(subscriber);
77 | subscriber.awaitTerminalEvent();
78 |
79 | assertThat(subscriber.getOnNextEvents().size(), is(1));
80 | }
81 |
82 | @Test public void when_Get_User_Not_Being_Logged_Then_Throw_Exception_On_Subscribe() {
83 | TestSubscriber subscriber = new TestSubscriber<>();
84 | sessionDataRepository.askForUserLogged().subscribe(subscriber);
85 | subscriber.awaitTerminalEvent();
86 |
87 | assertThat(subscriber.getOnErrorEvents().size(), is(1));
88 | }
89 |
90 | @Test public void when_Update_User_Being_Logged_Then_Get_User() {
91 | Credentials credentials = new Credentials();
92 |
93 | when(persistence.retrieve(any(String.class), eq(Credentials.class))).thenReturn(credentials);
94 | when(restApi.update(any(String.class), any(String.class), any(User.class))).thenReturn(Observable.just(new JsonObject()));
95 |
96 | TestSubscriber subscriber = new TestSubscriber<>();
97 | sessionDataRepository.askForUpdateLoggedUser(new User()).subscribe(subscriber);
98 | subscriber.awaitTerminalEvent();
99 |
100 | assertThat(subscriber.getOnNextEvents().size(), is(1));
101 | }
102 |
103 | @Test public void when_Update_User_Not_Being_Logged_Then_Throw_Exception_On_Subscribe() {
104 | TestSubscriber subscriber = new TestSubscriber<>();
105 | sessionDataRepository.askForUpdateLoggedUser(new User()).subscribe(subscriber);
106 | subscriber.awaitTerminalEvent();
107 |
108 | assertThat(subscriber.getOnErrorEvents().size(), is(1));
109 | }
110 |
111 | @Test public void when_Sign_Up_With_Valid_Inputs_Then_Get_Credentials_And_Saved_It() {
112 | when(restApi.signUp(any(User.class))).thenReturn(Observable.just(new Credentials()));
113 |
114 | TestSubscriber subscriber = new TestSubscriber<>();
115 | sessionDataRepository.askForSignUp(new User()).subscribe(subscriber);
116 | subscriber.awaitTerminalEvent();
117 |
118 | assertThat(subscriber.getOnNextEvents().size(), is(1));
119 | verify(persistence).save(any(String.class), any(Object.class));
120 | }
121 |
122 | @Test public void when_Sign_Up_With_Invalid_Inputs_Then_Credentials_Is_Not_Saved() {
123 | when(restApi.signUp(null)).thenReturn(Observable.create(
124 | new Observable.OnSubscribe() {
125 | @Override
126 | public void call(Subscriber super Credentials> subscriber) {
127 | subscriber.onError(new RuntimeException("Not Great"));
128 | }
129 | })
130 | );
131 |
132 | TestSubscriber subscriber = new TestSubscriber<>();
133 | sessionDataRepository.askForSignUp(null).subscribe(subscriber);
134 | subscriber.awaitTerminalEvent();
135 |
136 | assertThat(subscriber.getOnErrorEvents().size(), is(1));
137 | verifyZeroInteractions(persistence);
138 | }
139 |
140 | @Test public void when_Logout_With_Active_Session_Then_Get_A_Response_As_String() {
141 | when(persistence.retrieve(any(String.class), eq(Credentials.class))).thenReturn(new Credentials());
142 |
143 | TestSubscriber subscriber = new TestSubscriber<>();
144 | sessionDataRepository.askForLogout().subscribe(subscriber);
145 | subscriber.awaitTerminalEvent();
146 |
147 | verify(persistence).delete(Credentials.class.getName());
148 | assertThat(subscriber.getOnNextEvents().size(), is(1));
149 | }
150 |
151 | @Test public void when_Logout_Without_Active_Session_Then_Throw_An_Exception_On_Subscriber() {
152 | when(persistence.retrieve(any(String.class), eq(Credentials.class))).thenReturn(null);
153 |
154 | TestSubscriber subscriber = new TestSubscriber<>();
155 | sessionDataRepository.askForLogout().subscribe(subscriber);
156 | subscriber.awaitTerminalEvent();
157 |
158 | assertThat(subscriber.getOnErrorEvents().size(), is(1));
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/data/src/test/java/storage/PersistenceTest.java:
--------------------------------------------------------------------------------
1 | package storage;
2 |
3 | import org.junit.Before;
4 | import org.junit.Test;
5 | import org.junit.runner.RunWith;
6 | import org.robolectric.RobolectricGradleTestRunner;
7 | import org.robolectric.RuntimeEnvironment;
8 | import org.robolectric.annotation.Config;
9 |
10 | import edu.victoralbertos.data.BuildConfig;
11 |
12 | import static org.hamcrest.MatcherAssert.assertThat;
13 | import static org.hamcrest.core.Is.is;
14 | import static org.hamcrest.core.IsNot.not;
15 |
16 | @RunWith(RobolectricGradleTestRunner.class)
17 | @Config(constants = BuildConfig.class, sdk = 21)
18 | public class PersistenceTest {
19 | private Persistence persistence;
20 | private final static String KEY = "store";
21 | private final static String VALUE = "dummy";
22 |
23 | @Before public void setUp() {
24 | persistence = new Persistence(RuntimeEnvironment.application);
25 | }
26 |
27 | @Test public void when_A_Valid_Pair_Is_Supplied_Then_Get_True() {
28 | boolean result = persistence.save(KEY, VALUE);
29 | assertThat(result, is(true));
30 | }
31 |
32 | @Test public void when_An_Invalid_Pair_Is_Supplied_Then_Get_False() {
33 | boolean result = persistence.save(null, null);
34 | assertThat(result, is(not(true)));
35 | }
36 |
37 | @Test public void when_A_Valid_Pair_Is_Supplied_And_Retrieve_Then_Get_It() {
38 | persistence.save(KEY, VALUE);
39 |
40 | String result = persistence.retrieve(KEY, String.class);
41 | assertThat(result, is(VALUE));
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/domain/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/domain/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 |
3 | sourceCompatibility = 1.7
4 | targetCompatibility = 1.7
5 |
6 | configurations {
7 | provided
8 | }
9 |
10 | sourceSets {
11 | main {
12 | compileClasspath += configurations.provided
13 | }
14 | }
15 |
16 | dependencies {
17 | compile fileTree(dir: 'libs', include: ['*.jar'])
18 |
19 | def domainDependencies = rootProject.ext.domainDependencies
20 |
21 | compile domainDependencies.dagger
22 | provided domainDependencies.daggerCompiler
23 | provided domainDependencies.javaxAnnotation
24 |
25 | compile domainDependencies.rxJava
26 |
27 | def domainTestDependencies = rootProject.ext.domainTestDependencies
28 |
29 | testCompile domainTestDependencies.junit
30 | testCompile domainTestDependencies.mockito
31 | testCompile domainTestDependencies.hamcrest
32 | }
--------------------------------------------------------------------------------
/domain/domain.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/domain/src/main/java/entities/User.java:
--------------------------------------------------------------------------------
1 | package entities;
2 |
3 | public class User {
4 | private String username, email, phone, password;
5 |
6 | public User() {}
7 |
8 | public User(String username, String email, String phone, String password) {
9 | this.username = username;
10 | this.email = email;
11 | this.phone = phone;
12 | this.password = password;
13 | }
14 |
15 | public User(String username, String email, String phone) {
16 | this.username = username;
17 | this.email = email;
18 | this.phone = phone;
19 | }
20 |
21 | public String getUsername() {
22 | return username;
23 | }
24 |
25 | public String getPassword() {
26 | return password;
27 | }
28 |
29 | public String getEmail() {
30 | return email;
31 | }
32 |
33 | public String getPhone() {
34 | return phone;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/domain/src/main/java/interactors/GetUserUseCase.java:
--------------------------------------------------------------------------------
1 | package interactors;
2 |
3 | import javax.inject.Inject;
4 |
5 | import entities.User;
6 | import schedulers.ObserveOn;
7 | import schedulers.SubscribeOn;
8 | import respositories.SessionRepository;
9 | import rx.Observable;
10 |
11 | public class GetUserUseCase extends SessionUseCase {
12 | @Inject public GetUserUseCase(SessionRepository sessionRepository, SubscribeOn subscribeOn, ObserveOn observeOn) {
13 | super(sessionRepository, subscribeOn, observeOn);
14 | }
15 |
16 | @Override protected Observable buildUseCaseObservable() {
17 | return sessionRepository.askForUserLogged();
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/domain/src/main/java/interactors/LoginUseCase.java:
--------------------------------------------------------------------------------
1 | package interactors;
2 |
3 | import javax.inject.Inject;
4 |
5 | import schedulers.ObserveOn;
6 | import schedulers.SubscribeOn;
7 | import respositories.SessionRepository;
8 | import rx.Observable;
9 |
10 | public class LoginUseCase extends SessionUseCase {
11 | private String username, password;
12 |
13 | @Inject public LoginUseCase(SessionRepository sessionRepository, SubscribeOn subscribeOn, ObserveOn observeOn) {
14 | super(sessionRepository, subscribeOn, observeOn);
15 | }
16 |
17 | public void doLogin(String username, String password) {
18 | this.username = username;
19 | this.password = password;
20 | }
21 |
22 | @Override protected Observable buildUseCaseObservable() {
23 | return sessionRepository.askForLogin(username, password);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/domain/src/main/java/interactors/LogoutUseCase.java:
--------------------------------------------------------------------------------
1 | package interactors;
2 |
3 | import javax.inject.Inject;
4 |
5 | import schedulers.ObserveOn;
6 | import schedulers.SubscribeOn;
7 | import respositories.SessionRepository;
8 | import rx.Observable;
9 |
10 | public class LogoutUseCase extends SessionUseCase {
11 |
12 | @Inject public LogoutUseCase(SessionRepository sessionRepository, SubscribeOn subscribeOn, ObserveOn observeOn) {
13 | super(sessionRepository, subscribeOn, observeOn);
14 | }
15 |
16 | @Override protected Observable buildUseCaseObservable() {
17 | return sessionRepository.askForLogout();
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/domain/src/main/java/interactors/SessionUseCase.java:
--------------------------------------------------------------------------------
1 | package interactors;
2 |
3 | import schedulers.ObserveOn;
4 | import schedulers.SubscribeOn;
5 | import respositories.SessionRepository;
6 | import rx.Observable;
7 | import rx.Subscriber;
8 | import rx.Subscription;
9 | import rx.subscriptions.Subscriptions;
10 |
11 | public abstract class SessionUseCase {
12 | protected final SessionRepository sessionRepository;
13 | private final SubscribeOn subscribeOn;
14 | private final ObserveOn observeOn;
15 | private Subscription subscription = Subscriptions.empty();
16 |
17 | protected SessionUseCase(SessionRepository sessionRepository, SubscribeOn subscribeOn, ObserveOn observeOn) {
18 | this.sessionRepository = sessionRepository;
19 | this.subscribeOn = subscribeOn;
20 | this.observeOn = observeOn;
21 | }
22 |
23 | public void execute(Subscriber subscriber) {
24 | subscription = buildUseCaseObservable()
25 | .subscribeOn(subscribeOn.getScheduler())
26 | .observeOn(observeOn.getScheduler())
27 | .subscribe(subscriber);
28 | }
29 |
30 | public void unsubscribe() {
31 | if (!subscription.isUnsubscribed()) {
32 | subscription.unsubscribe();
33 | }
34 | }
35 |
36 | protected abstract Observable buildUseCaseObservable();
37 | }
38 |
--------------------------------------------------------------------------------
/domain/src/main/java/interactors/SignUpUseCase.java:
--------------------------------------------------------------------------------
1 | package interactors;
2 |
3 | import javax.inject.Inject;
4 |
5 | import entities.User;
6 | import schedulers.ObserveOn;
7 | import schedulers.SubscribeOn;
8 | import respositories.SessionRepository;
9 | import rx.Observable;
10 |
11 | public class SignUpUseCase extends SessionUseCase {
12 | private User user;
13 |
14 | @Inject public SignUpUseCase(SessionRepository sessionRepository, SubscribeOn subscribeOn, ObserveOn observeOn) {
15 | super(sessionRepository, subscribeOn, observeOn);
16 | }
17 |
18 | public void setUser(User user) {
19 | this.user = user;
20 | }
21 |
22 | @Override protected Observable buildUseCaseObservable() {
23 | return sessionRepository.askForSignUp(user);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/domain/src/main/java/interactors/UpdateUserCase.java:
--------------------------------------------------------------------------------
1 | package interactors;
2 |
3 | import javax.inject.Inject;
4 |
5 | import entities.User;
6 | import schedulers.ObserveOn;
7 | import schedulers.SubscribeOn;
8 | import respositories.SessionRepository;
9 | import rx.Observable;
10 |
11 | public class UpdateUserCase extends SessionUseCase {
12 | private User user;
13 |
14 | @Inject public UpdateUserCase(SessionRepository sessionRepository, SubscribeOn subscribeOn, ObserveOn observeOn) {
15 | super(sessionRepository, subscribeOn, observeOn);
16 | }
17 |
18 | public void setUserToUpdate(User user) {
19 | this.user = user;
20 | }
21 |
22 | @Override protected Observable buildUseCaseObservable() {
23 | return sessionRepository.askForUpdateLoggedUser(user);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/domain/src/main/java/presenters/GetUserPresenter.java:
--------------------------------------------------------------------------------
1 | package presenters;
2 |
3 | import javax.inject.Inject;
4 |
5 | import entities.User;
6 | import interactors.GetUserUseCase;
7 | import presenters.subscribers.BaseProfileSubscriber;
8 | import views.GetUserView;
9 |
10 | public class GetUserPresenter implements Presenter {
11 | private final GetUserUseCase getUserUseCase;
12 |
13 | @Inject public GetUserPresenter(GetUserUseCase getUserUseCase) {
14 | this.getUserUseCase = getUserUseCase;
15 | }
16 |
17 | @Override public void attachView(GetUserView getUserView) {
18 | getUserUseCase.execute(new BaseProfileSubscriber(getUserView) {
19 | @Override public void onNext(User user) {
20 | profileView.hideProgress();
21 | profileView.onSuccess(user);
22 | }
23 | });
24 | }
25 |
26 | @Override public void destroy() {
27 | getUserUseCase.unsubscribe();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/domain/src/main/java/presenters/LaunchPresenter.java:
--------------------------------------------------------------------------------
1 | package presenters;
2 |
3 | import javax.inject.Inject;
4 |
5 | import entities.User;
6 | import interactors.GetUserUseCase;
7 | import presenters.subscribers.BaseUseCaseSubscriber;
8 | import views.LaunchView;
9 |
10 | public class LaunchPresenter implements Presenter {
11 | private final GetUserUseCase getUserUseCase;
12 |
13 | @Inject public LaunchPresenter(GetUserUseCase getUserUseCase) {
14 | this.getUserUseCase = getUserUseCase;
15 | }
16 |
17 | @Override public void attachView(LaunchView launchView) {
18 | getUserUseCase.execute(new LaunchSubscriber(launchView));
19 | }
20 |
21 | @Override public void destroy() {
22 | getUserUseCase.unsubscribe();
23 | }
24 |
25 | private static class LaunchSubscriber extends BaseUseCaseSubscriber {
26 | private final LaunchView launchView;
27 |
28 | public LaunchSubscriber(LaunchView launchView) {
29 | this.launchView = launchView;
30 | }
31 |
32 | @Override public void onError(Throwable e) {
33 | launchView.goToCredentials();
34 | }
35 |
36 | @Override public void onNext(User user) {
37 | launchView.goToProfile();
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/domain/src/main/java/presenters/LoginPresenter.java:
--------------------------------------------------------------------------------
1 | package presenters;
2 |
3 | import javax.inject.Inject;
4 |
5 | import interactors.LoginUseCase;
6 | import presenters.subscribers.BaseCredentialsSubscriber;
7 | import views.LoginView;
8 |
9 | public class LoginPresenter implements Presenter {
10 | private final LoginUseCase loginUseCase;
11 | private LoginView loginView;
12 |
13 | @Inject public LoginPresenter(LoginUseCase loginUseCase) {
14 | this.loginUseCase = loginUseCase;
15 | }
16 |
17 | @Override public void attachView(LoginView loginView) {
18 | this.loginView = loginView;
19 | }
20 |
21 | public void doLogin(String username, String password) {
22 | loginUseCase.doLogin(username, password);
23 | loginUseCase.execute(new BaseCredentialsSubscriber(loginView) {});
24 | }
25 |
26 | @Override public void destroy() {
27 | loginUseCase.unsubscribe();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/domain/src/main/java/presenters/LogoutPresenter.java:
--------------------------------------------------------------------------------
1 | package presenters;
2 |
3 | import javax.inject.Inject;
4 |
5 | import interactors.LogoutUseCase;
6 | import presenters.subscribers.BaseProfileSubscriber;
7 | import views.LogoutView;
8 |
9 | public class LogoutPresenter implements Presenter {
10 | private final LogoutUseCase logoutUseCase;
11 | private LogoutView logoutView;
12 |
13 | @Inject public LogoutPresenter(LogoutUseCase logoutUseCase) {
14 | this.logoutUseCase = logoutUseCase;
15 | }
16 |
17 | @Override public void attachView(LogoutView logoutView) {
18 | this.logoutView = logoutView;
19 | }
20 |
21 | public void doLogout() {
22 | logoutUseCase.execute(new BaseProfileSubscriber(logoutView) {
23 | @Override public void onNext(String message) {
24 | profileView.hideProgress();
25 | profileView.onSuccess(message);
26 | profileView.toCredentials();
27 | }
28 | });
29 | }
30 |
31 | @Override public void destroy() {
32 | logoutUseCase.unsubscribe();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/domain/src/main/java/presenters/Presenter.java:
--------------------------------------------------------------------------------
1 | package presenters;
2 |
3 | import views.View;
4 |
5 | public interface Presenter {
6 | void attachView(T view);
7 | void destroy();
8 | }
9 |
--------------------------------------------------------------------------------
/domain/src/main/java/presenters/SignUpPresenter.java:
--------------------------------------------------------------------------------
1 | package presenters;
2 |
3 | import javax.inject.Inject;
4 |
5 | import entities.User;
6 | import interactors.SignUpUseCase;
7 | import presenters.subscribers.BaseCredentialsSubscriber;
8 | import views.SignUpView;
9 |
10 | public class SignUpPresenter implements Presenter {
11 | private final SignUpUseCase singUpUseCase;
12 | private SignUpView signUpView;
13 |
14 | @Inject public SignUpPresenter(SignUpUseCase singUpUseCase) {
15 | this.singUpUseCase = singUpUseCase;
16 | }
17 |
18 | @Override public void attachView(SignUpView signUpView) {
19 | this.signUpView = signUpView;
20 | }
21 |
22 | @Override public void destroy() {
23 | singUpUseCase.unsubscribe();
24 | }
25 |
26 | public void doSignUp(User user) {
27 | singUpUseCase.setUser(user);
28 | singUpUseCase.execute(new BaseCredentialsSubscriber(signUpView){});
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/domain/src/main/java/presenters/UpdateUserPresenter.java:
--------------------------------------------------------------------------------
1 | package presenters;
2 |
3 | import javax.inject.Inject;
4 |
5 | import entities.User;
6 | import interactors.UpdateUserCase;
7 | import presenters.subscribers.BaseProfileSubscriber;
8 | import views.UpdateUserView;
9 |
10 | public class UpdateUserPresenter implements Presenter {
11 | private final UpdateUserCase updateUserCase;
12 | private UpdateUserView updateUserView;
13 |
14 | @Inject public UpdateUserPresenter(UpdateUserCase updateUserCase) {
15 | this.updateUserCase = updateUserCase;
16 | }
17 |
18 | @Override public void attachView(UpdateUserView updateUserView) {
19 | this.updateUserView = updateUserView;
20 | }
21 |
22 | public void doUpdateUser(User user) {
23 | updateUserCase.setUserToUpdate(user);
24 | updateUserCase.execute(new BaseProfileSubscriber(updateUserView) {
25 | @Override public void onNext(String message) {
26 | profileView.hideProgress();
27 | profileView.onSuccess(message);
28 | }
29 | });
30 | }
31 |
32 | @Override public void destroy() {
33 | updateUserCase.unsubscribe();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/domain/src/main/java/presenters/subscribers/BaseCredentialsSubscriber.java:
--------------------------------------------------------------------------------
1 | package presenters.subscribers;
2 |
3 | import views.CredentialsView;
4 |
5 | public abstract class BaseCredentialsSubscriber extends BaseUseCaseSubscriber {
6 | private final View credentialsView;
7 |
8 | public BaseCredentialsSubscriber(View credentialsView) {
9 | this.credentialsView = credentialsView;
10 | }
11 |
12 | @Override public void onStart() {
13 | credentialsView.showProgress();
14 | }
15 |
16 | @Override public void onError(Throwable e) {
17 | credentialsView.hideProgress();
18 | credentialsView.onError(e.getMessage());
19 | }
20 |
21 | @Override public void onNext(String response) {
22 | credentialsView.hideProgress();
23 | credentialsView.onSuccess(response);
24 | credentialsView.goToProfile();
25 | }
26 | }
--------------------------------------------------------------------------------
/domain/src/main/java/presenters/subscribers/BaseProfileSubscriber.java:
--------------------------------------------------------------------------------
1 | package presenters.subscribers;
2 |
3 | import views.ProfileView;
4 |
5 | public abstract class BaseProfileSubscriber extends BaseUseCaseSubscriber {
6 | protected final View profileView;
7 |
8 | public BaseProfileSubscriber(View profileView) {
9 | this.profileView = profileView;
10 | }
11 |
12 | @Override public void onStart() {
13 | profileView.showProgress();
14 | }
15 |
16 | @Override public void onError(Throwable e) {
17 | profileView.hideProgress();
18 | profileView.onError(e.getMessage());
19 | }
20 | }
--------------------------------------------------------------------------------
/domain/src/main/java/presenters/subscribers/BaseUseCaseSubscriber.java:
--------------------------------------------------------------------------------
1 | package presenters.subscribers;
2 |
3 | import rx.Subscriber;
4 |
5 | public abstract class BaseUseCaseSubscriber extends Subscriber {
6 | @Override public void onCompleted() {}
7 |
8 | @Override public void onError(Throwable e) {}
9 |
10 | @Override public void onNext(T t) {}
11 | }
12 |
--------------------------------------------------------------------------------
/domain/src/main/java/respositories/SessionRepository.java:
--------------------------------------------------------------------------------
1 | package respositories;
2 |
3 | import entities.User;
4 | import rx.Observable;
5 |
6 | public interface SessionRepository {
7 | Observable askForLogin(String username, String password);
8 | Observable askForSignUp(User user);
9 | Observable askForUserLogged();
10 | Observable askForUpdateLoggedUser(User user);
11 | Observable askForLogout();
12 | }
--------------------------------------------------------------------------------
/domain/src/main/java/schedulers/ObserveOn.java:
--------------------------------------------------------------------------------
1 | package schedulers;
2 |
3 | import rx.Scheduler;
4 |
5 | public interface ObserveOn {
6 | Scheduler getScheduler();
7 | }
8 |
--------------------------------------------------------------------------------
/domain/src/main/java/schedulers/SubscribeOn.java:
--------------------------------------------------------------------------------
1 | package schedulers;
2 |
3 | import rx.Scheduler;
4 |
5 | public interface SubscribeOn {
6 | Scheduler getScheduler();
7 | }
8 |
--------------------------------------------------------------------------------
/domain/src/main/java/views/CredentialsView.java:
--------------------------------------------------------------------------------
1 | package views;
2 |
3 | public interface CredentialsView extends View {
4 | void showProgress();
5 | void hideProgress();
6 | void onError(String message);
7 | void onSuccess(String message);
8 | void goToProfile();
9 | }
10 |
--------------------------------------------------------------------------------
/domain/src/main/java/views/GetUserView.java:
--------------------------------------------------------------------------------
1 | package views;
2 |
3 | import entities.User;
4 |
5 | public interface GetUserView extends ProfileView {
6 | void onSuccess(User user);
7 | }
8 |
--------------------------------------------------------------------------------
/domain/src/main/java/views/LaunchView.java:
--------------------------------------------------------------------------------
1 | package views;
2 |
3 | public interface LaunchView extends View {
4 | void goToCredentials();
5 | void goToProfile();
6 | }
7 |
--------------------------------------------------------------------------------
/domain/src/main/java/views/LoginView.java:
--------------------------------------------------------------------------------
1 | package views;
2 |
3 | public interface LoginView extends CredentialsView {
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/domain/src/main/java/views/LogoutView.java:
--------------------------------------------------------------------------------
1 | package views;
2 |
3 | public interface LogoutView extends ProfileView {
4 | void onSuccess(String message);
5 | void toCredentials();
6 | }
7 |
--------------------------------------------------------------------------------
/domain/src/main/java/views/ProfileView.java:
--------------------------------------------------------------------------------
1 | package views;
2 |
3 | public interface ProfileView extends View {
4 | void showProgress();
5 | void hideProgress();
6 | void onError(String message);
7 | }
8 |
--------------------------------------------------------------------------------
/domain/src/main/java/views/SignUpView.java:
--------------------------------------------------------------------------------
1 | package views;
2 |
3 | public interface SignUpView extends CredentialsView {
4 | }
5 |
--------------------------------------------------------------------------------
/domain/src/main/java/views/UpdateUserView.java:
--------------------------------------------------------------------------------
1 | package views;
2 |
3 | public interface UpdateUserView extends ProfileView {
4 | void onSuccess(String message);
5 | }
6 |
--------------------------------------------------------------------------------
/domain/src/main/java/views/View.java:
--------------------------------------------------------------------------------
1 | package views;
2 |
3 | public interface View {
4 | }
5 |
--------------------------------------------------------------------------------
/domain/src/test/java/interactors/BaseSessionUseCaseTest.java:
--------------------------------------------------------------------------------
1 | package interactors;
2 |
3 |
4 | import org.junit.Before;
5 | import org.mockito.Mock;
6 | import org.mockito.MockitoAnnotations;
7 |
8 | import schedulers.ObserveOn;
9 | import schedulers.SubscribeOn;
10 | import rx.schedulers.Schedulers;
11 |
12 | import static org.mockito.Mockito.when;
13 |
14 | public abstract class BaseSessionUseCaseTest {
15 | @Mock protected ObserveOn observeOn;
16 | @Mock protected SubscribeOn subscribeOn;
17 |
18 | @Before public void setUp() {
19 | MockitoAnnotations.initMocks(this);
20 | when(observeOn.getScheduler()).thenReturn(Schedulers.newThread());
21 | when(subscribeOn.getScheduler()).thenReturn(Schedulers.newThread());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/domain/src/test/java/interactors/GetUserUseCaseTest.java:
--------------------------------------------------------------------------------
1 | package interactors;
2 |
3 | import org.junit.Test;
4 | import org.mockito.Mock;
5 |
6 | import entities.User;
7 | import respositories.SessionRepository;
8 | import rx.Observable;
9 | import rx.Subscriber;
10 | import rx.observers.TestSubscriber;
11 |
12 | import static org.hamcrest.MatcherAssert.assertThat;
13 | import static org.hamcrest.Matchers.is;
14 | import static org.mockito.Mockito.when;
15 |
16 | public class GetUserUseCaseTest extends BaseSessionUseCaseTest {
17 | private GetUserUseCase getUserUseCase;
18 | @Mock private SessionRepository sessionRepository;
19 |
20 | @Override public void setUp() {
21 | super.setUp();
22 | getUserUseCase = new GetUserUseCase(sessionRepository, subscribeOn, observeOn);
23 | }
24 |
25 | @Test public void when_There_Is_A_User_Logged_Then_Get_User() {
26 | when(sessionRepository.askForUserLogged()).thenReturn(Observable.just(new User()));
27 |
28 | TestSubscriber subscriber = new TestSubscriber<>();
29 | getUserUseCase.execute(subscriber);
30 | subscriber.awaitTerminalEvent();
31 |
32 | assertThat(subscriber.getOnNextEvents().size(), is(1));;
33 | }
34 |
35 | @Test public void when_There_Is_Not_A_User_Logged_Then_Throw_An_Exception_On_Subscriber() {
36 | when(sessionRepository.askForUserLogged()).thenReturn(Observable.create(new Observable.OnSubscribe() {
37 | @Override
38 | public void call(Subscriber super User> subscriber) {
39 | subscriber.onError(new RuntimeException("Not User"));
40 | }
41 | }));
42 |
43 | TestSubscriber subscriber = new TestSubscriber<>();
44 | getUserUseCase.execute(subscriber);
45 | subscriber.awaitTerminalEvent();
46 |
47 | assertThat(subscriber.getOnErrorEvents().size(), is(1));
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/domain/src/test/java/interactors/LoginUseCaseTest.java:
--------------------------------------------------------------------------------
1 | package interactors;
2 |
3 | import org.junit.Test;
4 | import org.mockito.Mock;
5 |
6 | import respositories.SessionRepository;
7 | import rx.Observable;
8 | import rx.Subscriber;
9 | import rx.observers.TestSubscriber;
10 |
11 | import static org.hamcrest.MatcherAssert.assertThat;
12 | import static org.hamcrest.Matchers.is;
13 | import static org.mockito.Mockito.when;
14 |
15 | public class LoginUseCaseTest extends BaseSessionUseCaseTest {
16 | private final static String A_VALID_USERNAME = "aValidUsername", A_VALID_PASSWORD = "aValidPassword",
17 | AN_INVALID_USERNAME = "anInvalidUsername", AN_INVALID_PASSWORD = "anInvalidPassword";
18 | private LoginUseCase loginUseCase;
19 | @Mock private SessionRepository sessionRepository;
20 |
21 | @Override public void setUp() {
22 | super.setUp();
23 | loginUseCase = new LoginUseCase(sessionRepository, subscribeOn, observeOn);
24 |
25 | when(sessionRepository.askForLogin(A_VALID_USERNAME, A_VALID_PASSWORD)).thenReturn(Observable.just("Great"));
26 | when(sessionRepository.askForLogin(AN_INVALID_USERNAME, AN_INVALID_PASSWORD)).thenReturn(Observable.create(
27 | new Observable.OnSubscribe() {
28 | @Override
29 | public void call(Subscriber super String> subscriber) {
30 | subscriber.onError(new RuntimeException("Not Great"));
31 | }
32 | })
33 | );
34 | }
35 |
36 | @Test public void when_Login_With_Valid_Inputs_Then_Get_A_Response_As_String() {
37 | loginUseCase.doLogin(A_VALID_USERNAME, A_VALID_PASSWORD);
38 | subscribe_To_Login_And_Wait_Until_Observable_Is_Completed(0, 1);
39 | }
40 |
41 | @Test public void when_Login_With_Invalid_Inputs_Then_Throw_An_Exception_On_Subscriber() {
42 | loginUseCase.doLogin(AN_INVALID_USERNAME, AN_INVALID_PASSWORD);
43 | subscribe_To_Login_And_Wait_Until_Observable_Is_Completed(1, 0);
44 | }
45 |
46 | private void subscribe_To_Login_And_Wait_Until_Observable_Is_Completed(int expectedErrors, int expectedEvents) {
47 | TestSubscriber subscriber = new TestSubscriber<>();
48 | loginUseCase.execute(subscriber);
49 | subscriber.awaitTerminalEvent();
50 |
51 | assertThat(subscriber.getOnErrorEvents().size(), is(expectedErrors));
52 | assertThat(subscriber.getOnNextEvents().size(), is(expectedEvents));
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/domain/src/test/java/interactors/LogoutUseCaseTest.java:
--------------------------------------------------------------------------------
1 | package interactors;
2 |
3 | import org.junit.Test;
4 | import org.mockito.Mock;
5 |
6 | import respositories.SessionRepository;
7 | import rx.Observable;
8 | import rx.Subscriber;
9 | import rx.observers.TestSubscriber;
10 |
11 | import static org.hamcrest.MatcherAssert.assertThat;
12 | import static org.hamcrest.Matchers.is;
13 | import static org.mockito.Mockito.when;
14 |
15 | public class LogoutUseCaseTest extends BaseSessionUseCaseTest {
16 | private LogoutUseCase logoutUseCase;
17 | @Mock private SessionRepository sessionRepository;
18 |
19 | @Override public void setUp() {
20 | super.setUp();
21 | logoutUseCase = new LogoutUseCase(sessionRepository, subscribeOn, observeOn);
22 | }
23 |
24 | @Test public void when_Logout_With_Active_Session_Then_Get_A_Response_As_String() {
25 | when(sessionRepository.askForLogout()).thenReturn(Observable.just("Great!"));
26 |
27 | TestSubscriber subscriber = new TestSubscriber<>();
28 | logoutUseCase.execute(subscriber);
29 | subscriber.awaitTerminalEvent();
30 |
31 | assertThat(subscriber.getOnNextEvents().size(), is(1));
32 | }
33 |
34 | @Test public void when_Logout_Without_Active_Session_Then_Throw_An_Exception_On_Subscriber() {
35 | when(sessionRepository.askForLogout()).thenReturn(Observable.create(
36 | new Observable.OnSubscribe() {
37 | @Override public void call(Subscriber super String> subscriber) {
38 | subscriber.onError(new RuntimeException("Not Great"));
39 | }
40 | })
41 | );
42 |
43 | TestSubscriber subscriber = new TestSubscriber<>();
44 | logoutUseCase.execute(subscriber);
45 | subscriber.awaitTerminalEvent();
46 |
47 | assertThat(subscriber.getOnErrorEvents().size(), is(1));
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/domain/src/test/java/interactors/SessionUseCaseTest.java:
--------------------------------------------------------------------------------
1 | package interactors;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.junit.runners.Parameterized;
6 |
7 | import java.util.Arrays;
8 | import java.util.Collection;
9 |
10 | import entities.User;
11 | import respositories.SessionRepository;
12 | import rx.Observable;
13 | import rx.observers.TestSubscriber;
14 |
15 | import static org.hamcrest.MatcherAssert.assertThat;
16 | import static org.hamcrest.Matchers.is;
17 | import static org.mockito.Mockito.mock;
18 |
19 | @RunWith(Parameterized.class)
20 | public class SessionUseCaseTest extends BaseSessionUseCaseTest {
21 | private SessionUseCase sessionUseCase;
22 |
23 | @Parameterized.Parameter(value = 0) public Observable observable;
24 | @Parameterized.Parameter(value = 1) public int expectedEvents;
25 |
26 | @Override public void setUp() {
27 | super.setUp();
28 | sessionUseCase = new SessionUseCaseTestClass();
29 | }
30 |
31 | @Parameterized.Parameters public static Collection