/* * This file is part of Airsonic. * * Airsonic is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Airsonic is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Airsonic. If not, see . * * Copyright 2014 (C) Sindre Mehus */ package org.airsonic.player.service; import de.umass.lastfm.cache.Cache; import de.umass.lastfm.cache.FileSystemCache; import org.airsonic.player.util.FileUtil; import org.apache.commons.io.IOUtils; import java.io.*; import java.util.Properties; /** * Based on {@link FileSystemCache}, but properly closes files and enforces * time-to-live (by ignoring HTTP header directives). * * @author Sindre Mehus * @version $Id$ */ public class LastFmCache extends Cache { private final File cacheDir; private final long ttl; public LastFmCache(File cacheDir, final long ttl) { this.cacheDir = cacheDir; this.ttl = ttl; setExpirationPolicy((method, params) -> ttl); } @Override public boolean contains(String cacheEntryName) { return getXmlFile(cacheEntryName).exists(); } @Override public InputStream load(String cacheEntryName) { try (FileInputStream in = new FileInputStream(getXmlFile(cacheEntryName))) { return new ByteArrayInputStream(IOUtils.toByteArray(in)); } catch (Exception e) { return null; } } @Override public void remove(String cacheEntryName) { getXmlFile(cacheEntryName).delete(); getMetaFile(cacheEntryName).delete(); } @Override public void store(String cacheEntryName, InputStream inputStream, long expirationDate) { createCache(); OutputStream xmlOut = null; OutputStream metaOut = null; try { File xmlFile = getXmlFile(cacheEntryName); xmlOut = new FileOutputStream(xmlFile); IOUtils.copy(inputStream, xmlOut); File metaFile = getMetaFile(cacheEntryName); Properties properties = new Properties(); // Note: Ignore the given expirationDate, since Last.fm sets it to just one day ahead. properties.setProperty("expiration-date", Long.toString(getExpirationDate())); metaOut = new FileOutputStream(metaFile); properties.store(metaOut, null); } catch (Exception e) { // we ignore the exception. if something went wrong we just don't cache it. } finally { FileUtil.closeQuietly(xmlOut); FileUtil.closeQuietly(metaOut); } } private long getExpirationDate() { return System.currentTimeMillis() + ttl; } private void createCache() { if (!cacheDir.exists()) { cacheDir.mkdirs(); } } @Override public boolean isExpired(String cacheEntryName) { File f = getMetaFile(cacheEntryName); if (!f.exists()) { return false; } InputStream in = null; try { Properties p = new Properties(); in = new FileInputStream(f); p.load(in); long expirationDate = Long.valueOf(p.getProperty("expiration-date")); return expirationDate < System.currentTimeMillis(); } catch (Exception e) { return false; } finally { FileUtil.closeQuietly(in); } } @Override public void clear() { for (File file : cacheDir.listFiles()) { if (file.isFile()) { file.delete(); } } } private File getXmlFile(String cacheEntryName) { return new File(cacheDir, cacheEntryName + ".xml"); } private File getMetaFile(String cacheEntryName) { return new File(cacheDir, cacheEntryName + ".meta"); } }