// BlogBridge -- RSS feed reader, manager, and web based service
// Copyright (C) 2002-2006 by R. Pito Salas
//
// This program 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 2 of the License, or (at your option) any later version.
//
// This program 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 this program;
// if not, write to the Free Software Foundation, Inc., 59 Temple Place,
// Suite 330, Boston, MA 02111-1307 USA
//
// Contact: R. Pito Salas
// mailto:pitosalas@users.sourceforge.net
// More information: about BlogBridge
// http://www.blogbridge.com
// http://sourceforge.net/projects/blogbridge
//
// $Id: ImageFetcher.java,v 1.16 2008/04/07 18:26:04 spyromus Exp $
//
package com.salas.bb.utils.uif.images;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Image fetcher is an utility framework entry point. This framework is aimed on
* non-blocking loading of images while keeping the internal media pipeline free.
* It solves the problem when the application requires several pictures (big or
* from slow servers) and requires some local resource. As both of these types
* of images walk through the same pipeline the first slow group may block the
* trafic and application will freeze. With this small framework we separate the
* slow group from global media pipeline in their own processing threads.
*
* <p>Framework has several thread and a queue of tasks. The loading of images is
* similar to the usual <code>Toolkit.getDefaultToolkit().getImage(...)</code>
* calls and can simply replace them.</p>
*
* <p>In addition, it uses modern <code>URLInputStream</code> implementation which
* knows how to control bandwidth, do seamless resuming and pause/unpause. When
* the actual fetching starts (the moment when image consumers request for data)
* the framework registers activity in <code>NetManager</code> and continue with
* data loading.</p>
*/
public final class ImageFetcher
{
private static final Logger LOG = Logger.getLogger(ImageFetcher.class.getName());
private static Cache cache;
private static Map<String, Image> downloadedImages;
static
{
downloadedImages = new HashMap<String, Image>();
}
/**
* Sets the cache to use.
*
* @param aCache cache.
*/
public static void setCache(Cache aCache)
{
cache = aCache;
}
/**
* Clears the images loading queue.
*/
public static void clearQueue()
{
// Removes everything from the queue
SavingImageSource.clearQueues();
downloadedImages.clear();
cache.verifyLimits();
}
/**
* Loads image from the source URL.
*
* @param source source URL.
*
* @return image.
*/
public static synchronized Image load(URL source)
{
Image img;
// See if we have an image in cache
img = cache.get(source);
if (img == null)
{
// There's no cached image, see if we are downloading something
String cacheFN = cache.urlToFilename(source);
img = getDownloadedImage(cacheFN);
if (img == null)
{
// Image is not being downloaded, create a temp file and start downloading
File cacheFile = cache.getCachedFile(source);
try
{
File tempFile = new File(cacheFile.getAbsolutePath() + ".tmp");
tempFile.createNewFile();
tempFile.deleteOnExit();
img = loadImage(source, tempFile, cacheFile);
// Register the download
registerDownloadedImage(cacheFN, img);
} catch (IOException e)
{
LOG.log(Level.WARNING, "Error loading image", e);
}
}
}
return img;
}
/**
* Creates a producer for source and returns an image.
*
* @param source source URL.
* @param temp file to hold temporary information.
* @param dest final destination file to hold cached image data.
*
* @return image.
*/
public static Image loadImage(URL source, File temp, File dest)
{
// Create an image producer
SavingImageSource producer = null;
try
{
producer = new SavingImageSource(source, temp, dest);
} catch (IOException e)
{
LOG.log(Level.WARNING, "Error creating image producer", e);
}
// Start loading the image
return producer == null ? null : Toolkit.getDefaultToolkit().createImage(producer);
}
/**
* Creates a producer for source and returns an image.
*
* @param file file to load an image from.
*
* @return image.
*/
public static Image loadImage(File file)
{
// Create an image producer
SavingImageSource producer = null;
try
{
producer = new SavingImageSource(file);
} catch (IOException e)
{
LOG.log(Level.WARNING, "Error creating image producer", e);
}
// Start loading the image
return producer == null ? null : Toolkit.getDefaultToolkit().createImage(producer);
}
/**
* Invoked when loading of an image starts to avoid duplicate loadings.
*
* @param fn cached image file name.
* @param img image.
*/
public static void registerDownloadedImage(String fn, Image img)
{
downloadedImages.put(fn, img);
}
/**
* Returns an image that is currently downloaded by its cached name.
*
* @param fn cached image file name.
*
* @return image or <code>NULL</code> if the image isn't currently downloaded.
*/
public static Image getDownloadedImage(String fn)
{
return downloadedImages.get(fn);
}
/**
* Invoked when the image is completely downloaded and available to the cache.
*
* @param fn cached image filename.
*/
public static void unregisterDownloadedImage(String fn)
{
synchronized (ImageFetcher.class)
{
downloadedImages.remove(fn);
}
cache.verifyLimits();
}
}