Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 25250701 authored by Stefan Niedermann's avatar Stefan Niedermann Committed by Niedermann IT-Dienstleistungen
Browse files

Enhance testability by using Singleton pattern for ApiProvider

parent fbaf9386
Loading
Loading
Loading
Loading
+0 −4
Original line number Diff line number Diff line
@@ -112,10 +112,6 @@ dependencies {
    // Testing
    testImplementation 'junit:junit:4.13.2'
    testImplementation 'org.mockito:mockito-core:3.10.0'
    def powermockVersion = "2.0.9"
    testImplementation "org.powermock:powermock-core:$powermockVersion"
    testImplementation "org.powermock:powermock-module-junit4:$powermockVersion"
    testImplementation "org.powermock:powermock-api-mockito2:$powermockVersion"
    testImplementation 'org.robolectric:robolectric:4.5.1'
    testImplementation 'androidx.test:core:1.3.0'
    testImplementation 'androidx.test.ext:junit:1.1.2'
+1 −1
Original line number Diff line number Diff line
@@ -121,7 +121,7 @@ public class ImportAccountActivity extends AppCompatActivity {
                        });
                    } catch (Throwable t) {
                        t.printStackTrace();
                        ApiProvider.invalidateAPICache(ssoAccount);
                        ApiProvider.getInstance().invalidateAPICache(ssoAccount);
                        SingleAccountHelper.setCurrentAccount(this, null);
                        runOnUiThread(() -> {
                            restoreCleanState();
+1 −1
Original line number Diff line number Diff line
@@ -674,7 +674,7 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A
                                    }
                                });
                            } catch (Throwable e) {
                                ApiProvider.invalidateAPICache(ssoAccount);
                                ApiProvider.getInstance().invalidateAPICache(ssoAccount);
                                // Happens when importing an already existing account the second time
                                if (e instanceof TokenMismatchException && mainViewModel.getLocalAccountByAccountName(ssoAccount.name) != null) {
                                    Log.w(TAG, "Received " + TokenMismatchException.class.getSimpleName() + " and the given ssoAccount.name (" + ssoAccount.name + ") does already exist in the database. Assume that this account has already been imported.");
+23 −10
Original line number Diff line number Diff line
@@ -34,19 +34,32 @@ import retrofit2.Retrofit;
@WorkerThread
public class ApiProvider {

    private static final String TAG = ApiProvider.class.getSimpleName();
    private static ApiProvider instance;

    private static final String API_ENDPOINT_OCS = "/ocs/v2.php/cloud/";
    private final static String TAG = ApiProvider.class.getSimpleName();

    private static final Map<String, NextcloudAPI> API_CACHE = new HashMap<>();
    private final static String API_ENDPOINT_OCS = "/ocs/v2.php/cloud/";

    private static final Map<String, OcsAPI> API_CACHE_OCS = new HashMap<>();
    private static final Map<String, NotesAPI> API_CACHE_NOTES = new HashMap<>();
    private final Map<String, NextcloudAPI> API_CACHE = new HashMap<>();

    private final Map<String, OcsAPI> API_CACHE_OCS = new HashMap<>();
    private final Map<String, NotesAPI> API_CACHE_NOTES = new HashMap<>();

    public static synchronized ApiProvider getInstance() {
        if (instance == null) {
            instance = new ApiProvider();
        }
        return instance;
    }

    private ApiProvider() {
        // Singleton
    }

    /**
     * An {@link OcsAPI} currently shares the {@link Gson} configuration with the {@link NotesAPI} and therefore divides all {@link Calendar} milliseconds by 1000 while serializing and multiplies values by 1000 during deserialization.
     */
    public static synchronized OcsAPI getOcsAPI(@NonNull Context context, @NonNull SingleSignOnAccount ssoAccount) {
    public synchronized OcsAPI getOcsAPI(@NonNull Context context, @NonNull SingleSignOnAccount ssoAccount) {
        if (API_CACHE_OCS.containsKey(ssoAccount.name)) {
            return API_CACHE_OCS.get(ssoAccount.name);
        }
@@ -58,7 +71,7 @@ public class ApiProvider {
    /**
     * In case the {@param preferredApiVersion} changes, call {@link #invalidateAPICache(SingleSignOnAccount)} or {@link #invalidateAPICache()} to make sure that this call returns a {@link NotesAPI} that uses the correct compatibility layer.
     */
    public static synchronized NotesAPI getNotesAPI(@NonNull Context context, @NonNull SingleSignOnAccount ssoAccount, @Nullable ApiVersion preferredApiVersion) {
    public synchronized NotesAPI getNotesAPI(@NonNull Context context, @NonNull SingleSignOnAccount ssoAccount, @Nullable ApiVersion preferredApiVersion) {
        if (API_CACHE_NOTES.containsKey(ssoAccount.name)) {
            return API_CACHE_NOTES.get(ssoAccount.name);
        }
@@ -67,7 +80,7 @@ public class ApiProvider {
        return notesAPI;
    }

    private static synchronized NextcloudAPI getNextcloudAPI(@NonNull Context context, @NonNull SingleSignOnAccount ssoAccount) {
    private synchronized NextcloudAPI getNextcloudAPI(@NonNull Context context, @NonNull SingleSignOnAccount ssoAccount) {
        if (API_CACHE.containsKey(ssoAccount.name)) {
            return API_CACHE.get(ssoAccount.name);
        } else {
@@ -104,7 +117,7 @@ public class ApiProvider {
     *
     * @param ssoAccount the ssoAccount for which the API cache should be cleared.
     */
    public static synchronized void invalidateAPICache(@NonNull SingleSignOnAccount ssoAccount) {
    public synchronized void invalidateAPICache(@NonNull SingleSignOnAccount ssoAccount) {
        Log.v(TAG, "Invalidating API cache for " + ssoAccount.name);
        if (API_CACHE.containsKey(ssoAccount.name)) {
            final NextcloudAPI nextcloudAPI = API_CACHE.get(ssoAccount.name);
@@ -120,7 +133,7 @@ public class ApiProvider {
    /**
     * Invalidates the whole API cache for all accounts
     */
    public static synchronized void invalidateAPICache() {
    public synchronized void invalidateAPICache() {
        for (String key : API_CACHE.keySet()) {
            Log.v(TAG, "Invalidating API cache for " + key);
            if (API_CACHE.containsKey(key)) {
+2 −2
Original line number Diff line number Diff line
@@ -27,7 +27,7 @@ public class CapabilitiesClient {

    @WorkerThread
    public static Capabilities getCapabilities(@NonNull Context context, @NonNull SingleSignOnAccount ssoAccount, @Nullable String lastETag) throws Throwable {
        final OcsAPI ocsAPI = ApiProvider.getOcsAPI(context, ssoAccount);
        final OcsAPI ocsAPI = ApiProvider.getInstance().getOcsAPI(context, ssoAccount);
        try {
            final ParsedResponse<OcsResponse<Capabilities>> response = ocsAPI.getCapabilities(lastETag).blockingSingle();
            final Capabilities capabilities = response.getResponse().ocs.data;
@@ -51,7 +51,7 @@ public class CapabilitiesClient {
    @WorkerThread
    @Nullable
    public static String getDisplayName(@NonNull Context context, @NonNull SingleSignOnAccount ssoAccount) {
        final OcsAPI ocsAPI = ApiProvider.getOcsAPI(context, ssoAccount);
        final OcsAPI ocsAPI = ApiProvider.getInstance().getOcsAPI(context, ssoAccount);
        try {
            final Response<OcsResponse<OcsUser>> userResponse = ocsAPI.getUser(ssoAccount.userId).execute();
            if (userResponse.isSuccessful()) {
Loading