com.limegroup.gnutella.licenses.LicenseCache.java Source code

Java tutorial

Introduction

Here is the source code for com.limegroup.gnutella.licenses.LicenseCache.java

Source

package com.limegroup.gnutella.licenses;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.URI;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.limewire.io.IOUtils;
import org.limewire.service.ErrorService;
import org.limewire.util.CommonUtils;
import org.limewire.util.GenericsUtils;

import com.google.inject.Singleton;
import com.limegroup.gnutella.URN;

/**
 * A repository of licenses.
 */
@Singleton
public class LicenseCache {

    private static final Log LOG = LogFactory.getLog(LicenseCache.class);

    /**
     * The amount of time to keep a license in the cache.
     */
    private static final long EXPIRY_TIME = 7 * 24 * 60 * 60 * 1000; // one week.    

    /**
     * File where the licenses are serialized.
     */
    private final File CACHE_FILE = new File(CommonUtils.getUserSettingsDir(), "licenses.cache");

    /**
     * A map of Licenses.  One License per URI.
     */
    private Map<URI, License> licenses;

    /**
     * An extra map of data that Licenses can use
     * to cache info.  This information lasts forever.
     */
    private Map<Object, Object> data;

    /**
     * Whether or not data is dirty since the last time we wrote to disk.
     */
    private boolean dirty = false;

    LicenseCache() {
        // TODO move this out of construction
        deserialize();
    }

    /**
     * Adds a verified license.
     */
    synchronized void addVerifiedLicense(License license) {
        licenses.put(license.getLicenseURI(), license);
        dirty = true;
    }

    /**
     * Adds data.
     */
    synchronized void addData(Object key, Object value) {
        data.put(key, value);
        dirty = true;
    }

    /**
     * Retrieves the cached license for the specified URI, substituting
     * the license string for a new one.
     */
    synchronized License getLicense(String licenseString, URI licenseURI) {
        License license = licenses.get(licenseURI);
        if (license != null)
            return license.copy(licenseString, licenseURI);
        else
            return null;
    }

    /**
     * Gets details.
     */
    synchronized Object getData(Object key) {
        return data.get(key);
    }

    /**
     * Determines if the license is verified for the given URN and URI.
     */
    synchronized boolean isVerifiedAndValid(URN urn, URI uri) {
        License license = licenses.get(uri);
        return license != null && license.isValid(urn);
    }

    /**
      * Loads values from cache file, if available
      */
    private void deserialize() {
        ObjectInputStream ois = null;
        try {
            if (!CACHE_FILE.exists()) {
                // finally-block will initialize maps
                return;
            }
            ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(CACHE_FILE)));
            Object o = ois.readObject();
            if (o != null)
                licenses = GenericsUtils.scanForMap(o, URI.class, License.class, GenericsUtils.ScanMode.REMOVE);
            o = ois.readObject();
            if (o != null)
                data = GenericsUtils.scanForMap(o, Object.class, Object.class, GenericsUtils.ScanMode.REMOVE);
            removeOldEntries();
        } catch (Throwable t) {
            LOG.error("Can't read licenses", t);
        } finally {
            IOUtils.close(ois);

            if (licenses == null)
                licenses = new HashMap<URI, License>();
            if (data == null)
                data = new HashMap<Object, Object>();
        }
    }

    /**
      * Removes any stale entries from the map so that they will automatically
      * be replaced.
      */
    private void removeOldEntries() {
        long cutoff = System.currentTimeMillis() - EXPIRY_TIME;

        // discard outdated info
        for (Iterator<License> i = licenses.values().iterator(); i.hasNext();) {
            License license = i.next();
            if (license.getLastVerifiedTime() < cutoff) {
                dirty = true;
                i.remove();
            }
        }
    }

    /**
     * Write cache so that we only have to calculate them once.
     */
    public synchronized void persistCache() {
        if (!dirty)
            return;

        ObjectOutputStream oos = null;
        try {
            oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(CACHE_FILE)));
            oos.writeObject(licenses);
            oos.writeObject(data);
            oos.flush();
        } catch (IOException e) {
            ErrorService.error(e);
        } finally {
            IOUtils.close(oos);
        }

        dirty = false;
    }
}