All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jxmapviewer.cache.FileBasedLocalCache Maven / Gradle / Ivy

There is a newer version: 2.8
Show newest version
package org.jxmapviewer.cache;

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.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * A file/folder-based cache
 */
public class FileBasedLocalCache implements LocalCache {

    private static final Log log = LogFactory.getLog(FileBasedLocalCache.class);

    private final File cacheDir;
    private final boolean checkForUpdates;

    /**
     * @param cacheDir the root cache folder
     * @param checkForUpdates true, if the remote URL should be checked for updates first
     */
    public FileBasedLocalCache(File cacheDir, boolean checkForUpdates) {
        this.cacheDir = cacheDir;
        if (!cacheDir.exists())
        {
            cacheDir.mkdirs();
        }
        this.checkForUpdates = checkForUpdates;
    }

    @Override
    public InputStream get(URL url) throws IOException {
        File localFile = getLocalFile(url);

        if (!localFile.exists())
        {
            // the file isn't already in our cache, return null
            return null;
        }

        if (checkForUpdates)
        {
            if (isUpdateAvailable(url, localFile))
            {
                // there is an update available, so don't return cached version
                return null;
            }
        }
        return new FileInputStream(localFile);
    }

    @Override
    public void put(URL url, InputStream data) throws IOException {
        File localFile = getLocalFile(url);
        localFile.getParentFile().mkdirs();
        FileOutputStream out = new FileOutputStream(localFile);
        try {
            copy(data, out);
        } finally {
            out.close();
        }
    }

    /**
     * Returns the local File corresponding to the given remote URI.
     * @param remoteUri the remote URI
     * @return the corresponding local file
     */
    public File getLocalFile(URL remoteUri)
    {
        StringBuilder sb = new StringBuilder();

        String host = remoteUri.getHost();
        String query = remoteUri.getQuery();
        String path = remoteUri.getPath();

        if (host != null)
        {
            sb.append(host);
        }
        if (path != null)
        {
            sb.append(path);
        }
        if (query != null)
        {
            sb.append('?');
            sb.append(query);
        }

        String name;

        final int maxLen = 250;

        if (sb.length() < maxLen)
        {
            name = sb.toString();
        }
        else
        {
            name = sb.substring(0, maxLen);
        }

        name = name.replace('?', '$');
        name = name.replace('*', '$');
        name = name.replace(':', '$');
        name = name.replace('<', '$');
        name = name.replace('>', '$');
        name = name.replace('"', '$');

        File f = new File(cacheDir, name);

        return f;
    }

    /**
     * @param remoteUri the remote URI
     * @param localFile the corresponding local file
     * @return true if the resource at the given remote URI is newer than the resource cached locally.
     */
    private static boolean isUpdateAvailable(URL remoteUri, File localFile)
    {
        URLConnection conn;
        try
        {
            conn = remoteUri.openConnection();
        }
        catch (MalformedURLException ex)
        {
            log.error("An exception occurred", ex);
            return false;
        }
        catch (IOException ex)
        {
            log.error("An exception occurred", ex);
            return false;
        }
        if (!(conn instanceof HttpURLConnection))
        {
            // don't bother with non-http connections
            return false;
        }

        long localLastMod = localFile.lastModified();
        long remoteLastMod = 0L;
        HttpURLConnection httpconn = (HttpURLConnection) conn;
        // disable caching so we don't get in feedback loop with ResponseCache
        httpconn.setUseCaches(false);
        try
        {
            httpconn.connect();
            remoteLastMod = httpconn.getLastModified();
        }
        catch (IOException ex)
        {
            // log.error("An exception occurred", ex);();
            return false;
        }
        finally
        {
            httpconn.disconnect();
        }

        return (remoteLastMod > localLastMod);
    }

    // use Java7 functionality when upgrading
    private static long copy(InputStream source, OutputStream sink) throws IOException
    {
        long nread = 0L;
        byte[] buf = new byte[8192];
        int n;
        while ((n = source.read(buf)) > 0) {
            sink.write(buf, 0, n);
            nread += n;
        }
        return nread;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy