package moviescraper.doctord.model;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import moviescraper.doctord.controller.FileDownloaderUtilities;
public class ImageCache {
private static final int initialCapacity = 200;
private static Map<URL, Image> cache = Collections.synchronizedMap(new HashMap<URL, Image>(initialCapacity));
private static Map<URL, Image> modifiedImageCache = Collections.synchronizedMap(new HashMap<URL, Image>(initialCapacity));
public static Image getImageFromCache(URL url, boolean isImageModified, URL referrerURL) throws IOException
{
Map<URL, Image> cacheToUse = isImageModified ? modifiedImageCache : cache;
//Cache already contains the item, so just return it
if(cacheToUse.containsKey(url))
{
return cacheToUse.get(url);
}
//we didn't find it, so read the Image into the cache and also return it
else
{
try{
if(url != null)
{
Image imageFromUrl = FileDownloaderUtilities.getImageFromUrl(url, referrerURL);
if(imageFromUrl != null)
{
cacheToUse.put(url, imageFromUrl);
return imageFromUrl;
}
}
//we couldn't read in the image from the URL so just return a blank image
Image blankImage = createBlankImage();
cacheToUse.put(url, blankImage);
return blankImage;
}
catch (OutOfMemoryError e) {
System.out.println("We ran out of memory..clearing the cache. It was size " + cache.size()
+ " before the clear");
cacheToUse.clear();
System.gc();
return FileDownloaderUtilities.getImageFromUrl(url);
}
catch(IOException e)
{
e.printStackTrace();
Image blankImage = createBlankImage();
cacheToUse.put(url, blankImage);
return blankImage;
}
}
}
public static void putImageInCache(URL url, Image image, boolean isImageModified)
{
Map<URL, Image> cacheToUse = isImageModified ? modifiedImageCache : cache;
//300 is arbitrary for now, but at some point we gotta boot stuff from cache or we will run out memory
//Ideally, I would boot out old items first, but I would need a new data structure to do this, probably
//by using a library already written that handles all the cache stuff rather than just using a map like I'm doing
//in this class
//TODO: purge old items instead of the whole world. get a real cache library from a 3rd party
if(cacheToUse.size() > 300)
{
System.out.println("Clearing cache - cache had " + cacheToUse.size() + " items before clearing.");
cacheToUse.clear();
}
cacheToUse.put(url, image);
}
private static Image createBlankImage()
{
return new BufferedImage(1,1, BufferedImage.TYPE_INT_ARGB);
}
public static void removeImageFromCache(URL url, boolean isImageModified)
{
Map<URL, Image> cacheToUse = isImageModified ? modifiedImageCache : cache;
cacheToUse.remove(url);
}
public static boolean isImageCached(URL url, boolean isImageModified)
{
Map<URL, Image> cacheToUse = isImageModified ? modifiedImageCache : cache;
return cacheToUse.containsKey(url);
}
}