/*
* This file is part of SpoutcraftPlugin.
*
* Copyright (c) 2011 SpoutcraftDev <http://spoutcraft.org//>
* SpoutcraftPlugin is licensed under the GNU Lesser General Public License.
*
* SpoutcraftPlugin is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SpoutcraftPlugin 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.getspout.spoutapi.io;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.ConcurrentHashMap;
import org.getspout.spoutapi.io.store.FlatFileStore;
public class CRCStore {
private static FlatFileStore<String> urlCRCStore;
private final static Object urlCRCStoreSync = new Object();
private final static ConcurrentHashMap<String,Long> lastCheck = new ConcurrentHashMap<String,Long>();
public static void setConfigFile(FlatFileStore<String> config) {
synchronized(urlCRCStoreSync) {
urlCRCStore = config;
urlCRCStore.load();
}
}
public static long getCRC(String urlString, byte[] buffer) {
if (urlString == null) {
return 0;
}
URL url;
try {
url = new URL(urlString);
} catch (MalformedURLException mue) {
return 0;
}
String key = url.toString();
String info;
long modified = 0;
long crc = 0;
synchronized(urlCRCStoreSync) {
if (urlCRCStore != null) {
info = urlCRCStore.get(key);
if (info != null) {
String[] split = info.split(":");
if (split.length == 2) {
try {
modified = Long.parseLong(split[0]);
crc = Long.parseLong(split[1]);
} catch (NumberFormatException nfe) {
}
}
}
}
}
URLConnection urlConn = null;
InputStream in = null;
try {
urlConn = url.openConnection();
} catch (IOException ioe) {
return 0;
}
try {
in = urlConn.getInputStream();
long currentTime = System.currentTimeMillis();
Long previous = lastCheck.get(urlString);
previous = previous == null ? 0 : previous;
boolean timeExpired = currentTime - previous > 600000; // Recheck every 10 mins
long urlLastModified = 0;
if (timeExpired) {
urlLastModified = urlConn.getLastModified();
lastCheck.put(urlString, currentTime);
}
boolean cacheHit = crc != 0;
boolean notUpdated = urlLastModified == modified && modified != 0;
if (cacheHit && (!timeExpired || notUpdated)) {
//System.out.println("Cached");
return crc;
} else {
crc = FileUtil.getCRC(in, buffer);
info = urlLastModified + ":" + crc;
if (urlCRCStore == null) {
System.out.println("[SpoutPlugin] Attempted to create CRC for URL " + urlString + " before urlCRCStore was initialized!");
return 0L;
}
synchronized(urlCRCStoreSync) {
urlCRCStore.set(key, info);
urlCRCStore.save();
}
return crc;
}
} catch (IOException ioe) {
crc = FileUtil.getCRC(in, buffer);
synchronized(urlCRCStoreSync) {
urlCRCStore.remove(key);
urlCRCStore.save();
}
return crc;
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
}
}
}
}
private static ConcurrentHashMap<String,Thread> CRCDownloads = new ConcurrentHashMap<String,Thread>();
public static class URLCheck extends Thread {
final String url;
final CRCStoreRunnable runnable;
final byte[] buffer;
public URLCheck(String url, byte[] buffer, CRCStoreRunnable runnable) {
this.url = url;
this.runnable = runnable;
this.buffer = buffer;
}
public void run() {
Thread downloadThread = CRCDownloads.get(url);
if (downloadThread == null) {
Thread old = CRCDownloads.putIfAbsent(url, this);
if (old != null) {
downloadThread = old;
} else {
downloadThread = this;
}
}
if (downloadThread != this) {
try {
downloadThread.join();
} catch (InterruptedException e) {
}
}
Long crc = null;
crc = CRCStore.getCRC(url, buffer);
if (crc == null) {
crc = 0L;
}
CRCDownloads.remove(url, this);
if (runnable != null) {
runnable.setCRC(crc);
runnable.run();
}
}
}
}