ProcessLock.java

/*
 * Decompiled with CFR 0_132.
 * 
 * Could not load the following classes:
 *  android.text.TextUtils
 */
package org.xutils.common.util;

import android.text.TextUtils;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.text.DecimalFormat;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.xutils.common.util.DoubleKeyValueMap;
import org.xutils.common.util.IOUtil;
import org.xutils.common.util.LogUtil;
import org.xutils.x;

public final class ProcessLock
implements Closeable {
    private final String mLockName;
    private final FileLock mFileLock;
    private final File mFile;
    private final Closeable mStream;
    private final boolean mWriteMode;
    private static final String LOCK_FILE_DIR = "process_lock";
    private static final DoubleKeyValueMap<String, Integer, ProcessLock> LOCK_MAP = new DoubleKeyValueMap();
    private static final DecimalFormat FORMAT;

    private ProcessLock(String lockName, File file, FileLock fileLock, Closeable stream, boolean writeMode) {
        this.mLockName = lockName;
        this.mFileLock = fileLock;
        this.mFile = file;
        this.mStream = stream;
        this.mWriteMode = writeMode;
    }

    public static ProcessLock tryLock(String lockName, boolean writeMode) {
        return ProcessLock.tryLockInternal(lockName, ProcessLock.customHash(lockName), writeMode);
    }

    public static ProcessLock tryLock(String lockName, boolean writeMode, long maxWaitTimeMillis) throws InterruptedException {
        ProcessLock lock = null;
        long expiryTime = System.currentTimeMillis() + maxWaitTimeMillis;
        String hash = ProcessLock.customHash(lockName);
        while (System.currentTimeMillis() < expiryTime && (lock = ProcessLock.tryLockInternal(lockName, hash, writeMode)) == null) {
            try {
                Thread.sleep(1L);
            }
            catch (InterruptedException iex2) {
                throw iex2;
            }
            catch (Throwable iex2) {
            }
        }
        return lock;
    }

    public boolean isValid() {
        return ProcessLock.isValid(this.mFileLock);
    }

    public void release() {
        ProcessLock.release(this.mLockName, this.mFileLock, this.mFile, this.mStream);
    }

    @Override
    public void close() throws IOException {
        this.release();
    }

    private static boolean isValid(FileLock fileLock) {
        return fileLock != null && fileLock.isValid();
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private static void release(String lockName, FileLock fileLock, File file, Closeable stream) {
        DoubleKeyValueMap<String, Integer, ProcessLock> doubleKeyValueMap = LOCK_MAP;
        synchronized (doubleKeyValueMap) {
            if (fileLock != null) {
                try {
                    LOCK_MAP.remove(lockName, fileLock.hashCode());
                    ConcurrentHashMap<Integer, ProcessLock> locks = LOCK_MAP.get(lockName);
                    if (locks == null || locks.isEmpty()) {
                        IOUtil.deleteFileOrDir(file);
                    }
                    if (fileLock.channel().isOpen()) {
                        fileLock.release();
                    }
                }
                catch (Throwable ex) {
                    LogUtil.e(ex.getMessage(), ex);
                }
                finally {
                    IOUtil.closeQuietly(fileLock.channel());
                }
            }
            IOUtil.closeQuietly(stream);
        }
    }

    private static String customHash(String str) {
        if (TextUtils.isEmpty((CharSequence)str)) {
            return "0";
        }
        double hash = 0.0;
        byte[] bytes = str.getBytes();
        for (int i = 0; i < str.length(); ++i) {
            hash = (255.0 * hash + (double)bytes[i]) * 0.005;
        }
        return FORMAT.format(hash);
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private static ProcessLock tryLockInternal(String lockName, String hash, boolean writeMode) {
        DoubleKeyValueMap<String, Integer, ProcessLock> doubleKeyValueMap = LOCK_MAP;
        synchronized (doubleKeyValueMap) {
            block14 : {
                ConcurrentHashMap<Integer, ProcessLock> locks = LOCK_MAP.get(lockName);
                if (locks != null && !locks.isEmpty()) {
                    Iterator<Map.Entry<Integer, ProcessLock>> itr = locks.entrySet().iterator();
                    while (itr.hasNext()) {
                        Map.Entry<Integer, ProcessLock> entry = itr.next();
                        ProcessLock value = entry.getValue();
                        if (value != null) {
                            if (!value.isValid()) {
                                itr.remove();
                                continue;
                            }
                            if (writeMode) {
                                return null;
                            }
                            if (!value.mWriteMode) continue;
                            return null;
                        }
                        itr.remove();
                    }
                }
                FileChannel channel = null;
                Closeable stream = null;
                try {
                    File file = new File(x.app().getDir(LOCK_FILE_DIR, 0), hash);
                    if (!file.exists() && !file.createNewFile()) break block14;
                    if (writeMode) {
                        FileOutputStream out = new FileOutputStream(file, false);
                        channel = out.getChannel();
                        stream = out;
                    } else {
                        FileInputStream in = new FileInputStream(file);
                        channel = in.getChannel();
                        stream = in;
                    }
                    if (channel != null) {
                        FileLock fileLock = channel.tryLock(0L, Long.MAX_VALUE, !writeMode);
                        if (ProcessLock.isValid(fileLock)) {
                            ProcessLock result = new ProcessLock(lockName, file, fileLock, stream, writeMode);
                            LOCK_MAP.put(lockName, fileLock.hashCode(), result);
                            return result;
                        }
                        ProcessLock.release(lockName, fileLock, file, stream);
                        break block14;
                    }
                    throw new IOException("can not get file channel:" + file.getAbsolutePath());
                }
                catch (Throwable ignored) {
                    LogUtil.d("tryLock: " + lockName + ", " + ignored.getMessage());
                    IOUtil.closeQuietly(stream);
                    IOUtil.closeQuietly(channel);
                }
            }
        }
        return null;
    }

    public String toString() {
        return this.mLockName + ": " + this.mFile.getName();
    }

    protected void finalize() throws Throwable {
        super.finalize();
        this.release();
    }

    static {
        File dir = x.app().getDir(LOCK_FILE_DIR, 0);
        IOUtil.deleteFileOrDir(dir);
        FORMAT = new DecimalFormat("0.##################");
    }
}