package jadex.commons;
import jadex.commons.collection.SCollection;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.URL;
import java.util.Map;
/**
* A cache for CachedObjects that reflect files.
* A cached object is loaded per filename
* (not the filename of the held object in the cache).
*/
public class ObjectCache implements Serializable
{
//-------- attributes --------
/** The persist strategy (always or only on demand by manually calling persist). */
protected boolean persist_always;
/** The flag indicating if cached objects are stored on disk themselves. */
protected boolean persist_single;
/** The filename of the cache. */
protected String filename;
/** The expression caches for filename. */
// todo: are not cleaned up currently, only when outdated
protected Map cache;
//-------- constructors --------
/**
* Create a new cache.
*/
public ObjectCache(String filename)
{
this(filename, false, false);
}
/**
* Create a new cache.
*/
public ObjectCache(String filename, boolean persist_always, boolean persist_single)
{
this(filename, persist_always, persist_single, 25);
}
/**
* Create a new cache.
*/
public ObjectCache(String filename, boolean persist_always, boolean persist_single, int max)
{
if(!persist_single && filename==null)
throw new IllegalArgumentException("Filename must not null when saving to single file.");
this.persist_always = persist_always;
this.persist_single = persist_single;
this.filename = filename;
//this.cache = SCollection.createHashMap();
this.cache = SCollection.createLRU(max);
}
//-------- methods --------
/**
* Load the cached file.
* @param filename The filename of the cached object.
* @param lastmodified The last modified date important for the up-to-date check.
* -1 for do not check.
*/
public synchronized CachedObject loadCachedObject(String filename, long lastmodified)
{
assert filename!=null;
// Try to retrieve from caches for cache ;-)
CachedObject ret = (CachedObject)cache.get(filename);
// Otherwise try to load file/url.
if(ret==null && persist_single)
{
InputStream fis = null;
ObjectInputStream ois = null;
try
{
if(filename.startsWith("jar:") || filename.startsWith("http:") || filename.startsWith("ftp:"))
fis = new URL(filename).openStream();
else
fis = new FileInputStream(filename);
ois = new ObjectInputStream(fis);
ret = (CachedObject)ois.readObject();
cache.put(filename, ret);
}
catch(Exception e)
{
//e.printStackTrace();
//System.out.println("Could not load expression cache: "+filename);
}
try{if(fis!=null)fis.close();}catch(IOException e){e.printStackTrace();}
try{if(ois!=null)ois.close();}catch(IOException e){e.printStackTrace();}
}
// Check consistency of expression cache.
if(ret!=null)
{
// Check cached date.
if(lastmodified!=-1 && lastmodified!=ret.getLastModified()
// For jar entries use zip format precision of 2 seconds.
&& !(filename.startsWith("jar:") && (Math.abs(lastmodified-ret.getLastModified())<2000)))
{
// System.out.println("Cache outdated: "+filename);
ret = null;
cache.remove(filename);
}
}
return ret;
}
/**
* Add a cached object.
* @param co The new object.
*/
public synchronized void add(CachedObject co)
{
// Do nothing if object is already contained in cache.
if(cache.containsKey(co.getFilename()))
return; //throw new RuntimeException("Cache already contains object: "+co.getFilename());
cache.put(co.getFilename(), co);
if(persist_always)
{
if(!persist_single)
{
try
{
persist();
}
catch(IOException e)
{
throw new RuntimeException("Could not persist object cache: "+filename);
}
}
// Only for performance here only the new object is saved.
else
{
try
{
co.persist();
}
catch(IOException e)
{
throw new RuntimeException("Could not persist cached object: "+filename);
}
}
}
}
/**
* Add a cached object.
* @param co The new object.
* /
public void remove(CachedObject co)
{
cache.remove(co.getFilename());
}*/
/**
* Add a cached object.
* @param filename The filename.
*/
public synchronized void remove(String filename)
{
cache.remove(filename);
}
/**
* Presist the cached object.
*/
public synchronized void persist() throws IOException
{
if(!persist_single)
{
if(!filename.startsWith("jar:"))
{
try
{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filename));
oos.writeObject(this);
oos.close();
//System.out.println("Wrote cache to disk: "+filename);
}
catch(FileNotFoundException e)
{
//e.printStackTrace();
throw new IOException("Could not write cache to disk: "+filename);
}
}
}
else
{
CachedObject[] cos = (CachedObject[])cache.values().toArray(new CachedObject[cache.size()]);
for(int i=0; i<cos.length; i++)
{
cos[i].persist();
}
}
}
/**
* Clear the cache.
*/
public synchronized void clear()
{
cache.clear();
}
//-------- static methods --------
/**
* Load the model cache.
* @param filename The filename.
* @return The object cache.
*/
public static synchronized ObjectCache loadObjectCache(String filename)
{
ObjectCache ret = null;
InputStream fis = null;
ObjectInputStream ois = null;
try
{
if(filename.startsWith("jar:") || filename.startsWith("http:") || filename.startsWith("ftp:"))
fis = new URL(filename).openStream();
else
fis = new FileInputStream(filename);
ois = new ObjectInputStream(fis);
ret = (ObjectCache)ois.readObject();
}
catch(Exception e)
{
//e.printStackTrace();
System.out.println("Could not load models cache: "+filename);
}
try{if(fis!=null)fis.close();}catch(IOException e){e.printStackTrace();}
try{if(ois!=null)ois.close();}catch(IOException e){e.printStackTrace();}
return ret;
}
}