com.ruesga.rview.misc.CacheHelper.java Source code

Java tutorial

Introduction

Here is the source code for com.ruesga.rview.misc.CacheHelper.java

Source

/*
 * Copyright (C) 2016 Jorge Ruesga
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.ruesga.rview.misc;

import android.annotation.SuppressLint;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;

import com.ruesga.rview.attachments.Attachment;
import com.ruesga.rview.attachments.EmptyMetadataException;
import com.ruesga.rview.gerrit.NoConnectivityException;
import com.ruesga.rview.model.Account;
import com.ruesga.rview.preferences.Preferences;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import androidx.core.content.FileProvider;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;

public class CacheHelper {

    public static final long MAX_AGE_CACHE = 60 * 60 * 24 * 5L;
    public static final long MAX_DISK_CACHE = 50 * 1024 * 1024L;

    private static final String IMAGES_CACHE_FOLDER = "images";
    private static final String AVATARS_CACHE_FOLDER = "avatars";
    private static final String DIFF_CACHE_FOLDER = "diff";
    private static final String ATTACHMENT_CACHE_FOLDER = "attachments";

    public static final String CACHE_CHANGE_JSON = "change.json";
    public static final String CACHE_FILES_JSON = "files.json";
    public static final String CACHE_FILES_INFO_JSON = "files_info.json";
    public static final String CACHE_DIFF_JSON = "diff.json";
    public static final String CACHE_COMMENTS_JSON = "comments.json";
    public static final String CACHE_DRAFT_JSON = "drafts.json";
    public static final String CACHE_CONTENT = "content";
    public static final String CACHE_BLAME = "blame";
    public static final String CACHE_PARENT = "parent";

    public static final String CACHE_TRENDING_JSON = "trending.json";
    public static final String CACHE_PLUGINS_JSON = "plugins.json";

    public static Response.Builder addCacheControl(Response.Builder builder) {
        return builder.header("Cache-Control", "max-age=" + MAX_AGE_CACHE);
    }

    @SuppressWarnings("ResultOfMethodCallIgnored")
    public static File getImagesCacheDir(Context context) {
        File cacheDir = new File(context.getCacheDir(), IMAGES_CACHE_FOLDER);
        if (!cacheDir.exists()) {
            cacheDir.mkdir();
        }
        return cacheDir;
    }

    @SuppressWarnings("ResultOfMethodCallIgnored")
    public static File getAvatarsCacheDir(Context context) {
        File cacheDir = new File(context.getCacheDir(), AVATARS_CACHE_FOLDER);
        if (!cacheDir.exists()) {
            cacheDir.mkdir();
        }
        return cacheDir;
    }

    public static Uri createNewTemporaryFileUri(Context context, String suffix) throws IOException {
        File temp = createNewTemporaryFile(context, suffix);
        if (temp != null) {
            return FileProvider.getUriForFile(context, "com.ruesga.rview.content", temp);
        }
        return null;
    }

    public static File createNewTemporaryFile(Context context, String suffix) throws IOException {
        String ts = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
        File storageDir = context.getFilesDir();
        if (storageDir.exists() || storageDir.mkdirs()) {
            File file = new File(storageDir.getAbsolutePath(), ts + suffix);
            if (file.createNewFile()) {
                return new File(storageDir.getAbsolutePath(), ts + suffix);
            }
        }
        return null;
    }

    public static File getAccountCacheDir(Context context) {
        return getAccountCacheDir(context, Preferences.getAccount(context));
    }

    public static File getAccountCacheDir(Context context, Account account) {
        return new File(context.getCacheDir(), account.getAccountHash());
    }

    public static boolean createAccountCacheDir(Context context) {
        return createAccountCacheDir(context, Preferences.getAccount(context));
    }

    public static boolean createAccountCacheDir(Context context, Account account) {
        final File cacheDir = getAccountCacheDir(context, account);
        return cacheDir.exists() || cacheDir.mkdirs();
    }

    public static void removeAccountCacheDir(Context context) {
        removeAccountCacheDir(context, Preferences.getAccount(context));
    }

    public static void removeAccountCacheDir(Context context, Account account) {
        final File cacheDir = getAccountCacheDir(context, account);
        if (cacheDir.exists()) {
            try {
                FileUtils.deleteDirectory(cacheDir);
            } catch (IOException ex) {
                // Ignore
            }
        }
    }

    public static File getAccountDiffCacheDir(Context context) {
        return getAccountDiffCacheDir(context, Preferences.getAccount(context));
    }

    @SuppressWarnings("ResultOfMethodCallIgnored")
    public static File getAccountDiffCacheDir(Context context, Account account) {
        createAccountCacheDir(context, account);
        File cacheDir = new File(getAccountCacheDir(context, account), DIFF_CACHE_FOLDER);
        if (!cacheDir.exists()) {
            cacheDir.mkdir();
        }
        return cacheDir;
    }

    public static void removeAccountDiffCacheDir(Context context) {
        removeAccountDiffCacheDir(context, Preferences.getAccount(context));
    }

    public static void removeAccountDiffCacheDir(Context context, Account account) {
        final File cacheDir = getAccountDiffCacheDir(context, account);
        if (cacheDir.exists()) {
            try {
                FileUtils.deleteDirectory(cacheDir);
            } catch (IOException ex) {
                // Ignore
            }
        }
    }

    public static boolean hasAccountDiffCache(Context context, String name) {
        return hasAccountDiffCache(context, Preferences.getAccount(context), name);
    }

    public static boolean hasAccountDiffCache(Context context, Account account, String name) {
        return new File(getAccountDiffCacheDir(context, account), name).exists();
    }

    public static byte[] readAccountDiffCacheFile(Context context, String name) throws IOException {
        return readAccountDiffCacheFile(context, Preferences.getAccount(context), name);
    }

    public static byte[] readAccountDiffCacheFile(Context context, Account account, String name)
            throws IOException {
        return FileUtils.readFileToByteArray(new File(getAccountDiffCacheDir(context, account), name));
    }

    public static void writeAccountDiffCacheFile(Context context, String name, byte[] data) throws IOException {
        writeAccountDiffCacheFile(context, Preferences.getAccount(context), name, data);
    }

    public static void writeAccountDiffCacheFile(Context context, Account account, String name, byte[] data)
            throws IOException {
        FileUtils.writeByteArrayToFile(new File(getAccountDiffCacheDir(context, account), name), data);
    }

    public static void removeAccountDiffCacheFile(Context context, String name) {
        removeAccountDiffCacheFile(context, Preferences.getAccount(context), name);
    }

    @SuppressWarnings("ResultOfMethodCallIgnored")
    public static void removeAccountDiffCacheFile(Context context, Account account, String name) {
        final File cacheDir = getAccountDiffCacheDir(context, account);
        if (cacheDir.exists()) {
            new File(getAccountDiffCacheDir(context, account), name).delete();
        }
    }

    public static long getFileCacheAge(Context context, Account account, String name) {
        File file = new File(getAccountCacheDir(context, account), name);
        if (file.exists()) {
            return file.lastModified();
        }
        return 0;
    }

    public static byte[] readFileCache(Context context, Account account, String name) throws IOException {
        File file = new File(getAccountCacheDir(context, account), name);
        if (file.exists()) {
            return FileUtils.readFileToByteArray(file);
        }
        return null;
    }

    @SuppressWarnings("ResultOfMethodCallIgnored")
    public static void writeFileCache(Context context, Account account, String name, byte[] data)
            throws IOException {
        File file = new File(getAccountCacheDir(context, account), name);
        file.getParentFile().mkdirs();
        FileUtils.writeByteArrayToFile(file, data);
    }

    @SuppressWarnings("ResultOfMethodCallIgnored")
    public static void removeFileCache(Context context, Account account, String name) {
        File file = new File(getAccountCacheDir(context, account), name);
        if (file.exists()) {
            file.delete();
        }
    }

    @SuppressWarnings("ResultOfMethodCallIgnored")
    public static File getAttachmentCacheDir(Context context) {
        File cacheDir = new File(context.getCacheDir(), ATTACHMENT_CACHE_FOLDER);
        if (!cacheDir.exists()) {
            cacheDir.mkdir();
        }
        return cacheDir;
    }

    @SuppressWarnings("ConstantConditions")
    public static File getAttachmentFile(Context context, Attachment attachment) {
        String fileName = Preferences.getAccount(context).getAccountHash() + "_" + attachment.mMessageId + "_"
                + attachment.mName;
        return new File(getAttachmentCacheDir(context), fileName);
    }

    public static boolean hasAttachmentFile(Context context, Attachment attachment) {
        return getAttachmentFile(context, attachment).exists();
    }

    @SuppressLint("Deprecated")
    public static void downloadAttachmentFile(Context context, Attachment attachment) throws IOException {
        OkHttpClient client = NetworkingHelper.createNetworkClient().addNetworkInterceptor(chain -> {
            Response originalResponse = chain.proceed(chain.request());
            return CacheHelper.addCacheControl(originalResponse.newBuilder()).build();
        }).readTimeout(20000, java.util.concurrent.TimeUnit.MILLISECONDS).followRedirects(true)
                .followSslRedirects(true).addInterceptor(chain -> {
                    ConnectivityManager cm = (ConnectivityManager) context
                            .getSystemService(Context.CONNECTIVITY_SERVICE);
                    if (cm != null) {
                        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
                        if (activeNetwork != null && activeNetwork.isConnectedOrConnecting()) {
                            return chain.proceed(chain.request());
                        }
                    }
                    throw new NoConnectivityException();
                }).build();

        Request request = new Request.Builder().url(attachment.mUrl).build();
        Response response = client.newCall(request).execute();
        ResponseBody body = response.body();
        if (body == null) {
            throw new IOException("body was null");
        }
        try {
            if (!response.isSuccessful()) {
                throw new IOException("failed to download file: " + response.code());
            }
            if (body.contentLength() == 0) {
                throw new EmptyMetadataException(attachment.mUrl);
            }

            InputStream is = body.byteStream();
            OutputStream os = new BufferedOutputStream(new FileOutputStream(getAttachmentFile(context, attachment)),
                    4096);
            try {
                IOUtils.copy(is, os, 4096);
            } finally {
                IOUtils.closeQuietly(is);
                IOUtils.closeQuietly(os);
                response.close();
            }
        } finally {
            try {
                response.close();
            } catch (Exception ex) {
                // Ignore
            }
        }
    }
}