io.nuclei.splice.internal.FileManager.java Source code

Java tutorial

Introduction

Here is the source code for io.nuclei.splice.internal.FileManager.java

Source

/**
 * Copyright 2015 Kyle J Brock
 *
 * 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 io.nuclei.splice.internal;

import android.content.Context;
import android.net.Uri;
import android.os.Environment;
import android.support.annotation.VisibleForTesting;
import android.support.v4.util.ArrayMap;
import android.support.v4.util.AtomicFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import java.util.concurrent.locks.ReentrantLock;

import io.nuclei.splice.service.Source;

public class FileManager {

    public static final int TYPE_CACHE_FILE = 1;
    public static final int TYPE_LOCAL_FILE = 2;
    public static final int TYPE_EXTERNAL_FILE = 3;

    static final ArrayMap<FileRef, ReentrantLock> sLocks = new ArrayMap<>();

    public static ReentrantLock lock(FileRef ref) {
        ReentrantLock lock;
        boolean locked;
        synchronized (sLocks) {
            lock = sLocks.get(ref);
            if (lock == null) {
                lock = new ReentrantLock();
                sLocks.put(ref, lock);
            }
            locked = lock.tryLock();
        }
        if (!locked) {
            while (true) {
                synchronized (sLocks) {
                    try {
                        sLocks.wait();
                    } catch (InterruptedException ignore) {
                    }
                    if (lock.tryLock()) {
                        ReentrantLock newLock = sLocks.get(ref);
                        if (newLock == null) {
                            sLocks.put(ref, lock);
                            break;
                        } else if (newLock != lock) {
                            lock.unlock();
                            lock = newLock;
                            if (lock.tryLock()) {
                                break;
                            }
                        } else {
                            break;
                        }
                    }
                }
            }
        }
        return lock;
    }

    public static void unlock(FileRef ref) {
        synchronized (sLocks) {
            ReentrantLock lock = sLocks.get(ref);
            sLocks.remove(ref);
            lock.unlock();
            sLocks.notifyAll();
        }
    }

    static final String DIR = ".splice";

    private static File getBaseFile(Context context, int type) throws IOException {
        File base = null;
        if (type == TYPE_EXTERNAL_FILE && Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
            base = new File(context.getExternalFilesDir(null), DIR);
        else if (type == TYPE_CACHE_FILE)
            base = new File(context.getCacheDir(), DIR);
        else if (type == TYPE_LOCAL_FILE)
            base = new File(context.getFilesDir(), DIR);
        if (base == null)
            throw new IOException("Couldn't access directory type: " + type);
        if (!base.exists() && !base.mkdirs())
            throw new IOException("Couldn't create directory: " + base);
        return base;
    }

    @VisibleForTesting
    public static AtomicFile getAtomicFile(Context context, FileRef ref) throws IOException {
        File base = getBaseFile(context, ref.type);
        if (base == null)
            throw new IOException("Unable to read/write to type: " + ref.type);
        return new AtomicFile(new File(base, ref.id));
    }

    @VisibleForTesting
    public static File getFile(Context context, FileRef ref) throws IOException {
        File base = getBaseFile(context, ref.type);
        if (base == null)
            throw new IOException("Unable to read/write to type: " + ref.type);
        return new File(base, ref.id);
    }

    public static Uri newUri(Context context, String id) throws IOException {
        FileRef ref = newRef(id);
        return newUri(context, ref);
    }

    public static Uri newUri(Context context, FileRef ref) throws IOException {
        File base = getBaseFile(context, ref.type);
        if (base == null)
            throw new IOException("Unable to read/write to type: " + ref.type);
        return Uri.fromFile(new File(base, ref.id));
    }

    public static FileRef newRef(int type) {
        String id = UUID.randomUUID().toString();
        return new FileRef(id, type);
    }

    public static FileRef newRef(String id) {
        return new FileRef(id);
    }

    public static InputStream open(Context context, FileRef ref) throws IOException {
        return getAtomicFile(context, ref).openRead();
    }

    public static void delete(Context context, FileRef ref) throws IOException {
        getAtomicFile(context, ref).delete();
    }

    public static void copy(Context context, FileRef ref, OutputStream out) throws IOException {
        AtomicFile file = getAtomicFile(context, ref);
        FileInputStream in = file.openRead();
        try {
            copy(in, out);
        } finally {
            in.close();
        }
    }

    public static void copy(Context context, FileRef ref, InputStream in) throws IOException {
        AtomicFile file = getAtomicFile(context, ref);
        FileOutputStream out = file.startWrite();
        try {
            copy(in, out);
        } finally {
            file.finishWrite(out);
        }
    }

    public static void copy(Context context, DbRef ref, Source source) throws IOException {
        AtomicFile file = getAtomicFile(context, ref.ref);
        FileOutputStream out = file.startWrite();
        try {
            source.process(context, ref, out);
        } finally {
            file.finishWrite(out);
        }
    }

    public static void copy(InputStream in, OutputStream out) throws IOException {
        byte[] buf = ByteArrayPool.get().getBuf(4096);
        try {
            int n;
            while (-1 != (n = in.read(buf))) {
                out.write(buf, 0, n);
            }
        } finally {
            ByteArrayPool.get().returnBuf(buf);
        }
    }

}