package com.idega.idegaweb;
/**
* Title: idegaclasses
* Description:
* Copyright: Copyright (c) 2001
* Company: idega
* @author <a href="tryggvi@idega.is">Tryggvi Larusson</a>
* @version 1.0
*/
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.logging.Logger;
import com.idega.data.CacheableEntity;
import com.idega.data.GenericEntity;
import com.idega.data.IDOEntity;
import com.idega.data.IDOHome;
import com.idega.data.IDOLegacyEntity;
import com.idega.repository.data.RefactorClassRegistry;
import com.idega.data.IDOLookup;
import com.idega.repository.data.Singleton;
import com.idega.util.FileUtil;
import com.idega.util.StringHandler;
import com.idega.util.caching.Cache;
import com.idega.util.text.TextSoap;
public class IWCacheManager implements Singleton {
private static final String IW_CACHEMANAGER_KEY = "iw_cachemanager";
public static final String IW_ROOT_CACHE_DIRECTORY = "iw_cache";
private Logger log = Logger.getLogger(IWCacheManager.class.getName());
//private static IWCacheManager instance;
private Map objectsMap;
private Map timesMap;
private Map intervalsMap;
private Map entityMaps;
private Map entityMapsKeys;
private Map _keysMap;
private static final long CACHE_NEVER_EXPIRES = -1;
private IWCacheManager() {
}
public static synchronized IWCacheManager getInstance(IWMainApplication iwma){
IWCacheManager iwcm = (IWCacheManager)iwma.getAttribute(IW_CACHEMANAGER_KEY);
if(iwcm==null){
iwcm = new IWCacheManager();
iwma.setAttribute(IW_CACHEMANAGER_KEY,iwcm);
}
return iwcm;
}
/*public static IWCacheManager getInstance(){
if(instance==null){
instance = new IWCacheManager();
}
return instance;
}*/
public boolean isCacheValid(String key){
if(isNull(key)){
//System.out.println(" CacheKey is null ");
return false;
}
else{
long currentTime = System.currentTimeMillis();
long invalidation = getTimeOfInvalidation(key);
//System.out.println("Current : "+currentTime);
//System.out.println("Invalidation: "+invalidation);
if ( invalidation == CACHE_NEVER_EXPIRES ) {
//System.out.println(" cache never expires ");
return true;
}
else if (currentTime > invalidation) {
//System.out.println(" currentTime > invalidation ");
return false;
}
else{
//System.out.println(" currentTime <= invalidation ");
return true;
}
}
}
private boolean isNull(String key){
return !getObjectsMap().containsKey(key);
}
public void invalidateCache(String key){
removeCache(key);
}
private Map getKeysMap(){
if(this._keysMap==null){
this._keysMap=new HashMap();
}
return this._keysMap;
}
public synchronized void registerDerivedKey(String key,String derivedKey){
List derived = (List) getKeysMap().get(key);
if(derived==null){
derived=new Vector();
getKeysMap().put(key,derived);
}
derived.add(derivedKey);
}
public synchronized void setObject(String key,String derivedKey, Object object,long cacheInterval){
registerDerivedKey(key,derivedKey);
setObject(derivedKey,object,cacheInterval);
}
private synchronized void setObject(String key, Object object,long cacheInterval){
getObjectsMap().put(key,object);
getTimesMap().put(key,getCurrentTime());
if (cacheInterval < 1) {
cacheInterval = CACHE_NEVER_EXPIRES;
}
getIntervalsMap().put(key,new Long(cacheInterval));
}
public Object getObject(String key){
return getObjectsMap().get(key);
}
private Long getCurrentTime(){
return new Long(System.currentTimeMillis());
}
private long getTimeOfInvalidation(String key){
long interval = getCacheingInterval(key);
if (interval == CACHE_NEVER_EXPIRES) {
return interval;
}
else {
return getTimeOfCacheing(key)+interval;
}
}
private long getTimeOfCacheing(String key){
Long time = (Long)getTimesMap().get(key);
if(time!=null){
return time.longValue();
}
else{
return 0;
}
}
private long getCacheingInterval(String key){
Long time = (Long)getIntervalsMap().get(key);
if(time!=null){
return time.longValue();
}
else{
return 0;
}
}
private synchronized void removeCache(String key){
removeFromGlobalCache(key);
Map map = getKeysMap();
List derived = (List)map.get(key);
if(derived!=null){
Iterator iter = derived.iterator();
while (iter.hasNext()) {
String item = (String)iter.next();
removeFromGlobalCache(item);
}
}
}
private void removeFromGlobalCache(String key){
getObjectsMap().remove(key);
getTimesMap().remove(key);
getIntervalsMap().remove(key);
}
private Map getTimesMap(){
if(this.timesMap==null){
this.timesMap = new HashMap();
}
return this.timesMap;
}
private Map getObjectsMap(){
if(this.objectsMap==null){
this.objectsMap = new java.util.HashMap();
}
return this.objectsMap;
}
private Map getIntervalsMap(){
if(this.intervalsMap==null){
this.intervalsMap = new HashMap();
}
return this.intervalsMap;
}
//added by Eirikur Hrafnsson, eiki@idega.is
public Cache getCachedBlobObject( String entityClassString, int id, IWMainApplication iwma){
return getCachedBlobObject(entityClassString, id, iwma, null);
}
public Cache getCachedBlobObject( String entityClassString, int id, IWMainApplication iwma, String datasource){
//check if this blob has already been cached
Cache cache = (Cache) getObject(entityClassString+id+datasource);
if( cache == null || !isBlobCached(cache)) {//if null cache it for next time
cache = cacheBlob(entityClassString,id,iwma, datasource);
}
return cache;
}
/**
* Checks if the blob object is really cached on disk
* @param cache
* @return true if the cached file exists
*/
private boolean isBlobCached(Cache cache){
java.io.File f = new java.io.File(cache.getRealPathToFile());
return f.exists();
}
private Cache cacheBlob(String entityClassString, int id , IWMainApplication iwma, String datasource){
InputStream input = null;
Cache cacheObject = null;
try{
IDOHome home = IDOLookup.getHome(RefactorClassRegistry.forName(entityClassString));
if (datasource != null) {
home = IDOLookup.getHome(RefactorClassRegistry.forName(entityClassString), datasource);
}
GenericEntity ent = (GenericEntity) home.findByPrimaryKeyIDO(new Integer(id));
input = ent.getInputStreamColumnValue(ent.getLobColumnName());
String realPath = iwma.getApplicationRealPath()+FileUtil.getFileSeparator()+IW_ROOT_CACHE_DIRECTORY;
String appVPath = iwma.getApplicationContextURI();
String virtualPath;
if( appVPath.endsWith("/")) {
virtualPath = appVPath +IW_ROOT_CACHE_DIRECTORY;
}
else {
virtualPath = appVPath +"/"+IW_ROOT_CACHE_DIRECTORY;
}
String fileName = ent.getID()+"_"+ent.getName();
fileName = TextSoap.findAndCut(fileName," ");//remove spaces
if(input != null ){
FileUtil.streamToFile(input,realPath,fileName);
cacheObject = new Cache();
cacheObject.setEntity(ent);
cacheObject.setRealPathToFile(realPath+FileUtil.getFileSeparator()+fileName);
cacheObject.setVirtualPathToFile(virtualPath+"/"+URLEncoder.encode(fileName));//used to url encode here
setObject(entityClassString+id+datasource,cacheObject,0);
}
}
catch( Exception e ){
e.printStackTrace(System.err);
System.err.println("IWCacheManager : error getting stream from blob");
}
finally{
try{
if (input != null ) {
input.close();
}
}
catch(IOException e){
e.printStackTrace(System.err);
System.err.println("IWCacheManager : error closing stream");
}
}
return cacheObject;
}
public static void deleteCachedBlobs(IWMainApplication iwma){
String realPath = iwma.getApplicationRealPath();
FileUtil.deleteAllFilesInDirectory( realPath+IW_ROOT_CACHE_DIRECTORY );
}
/** caches a whole table. Must be of type CacheableEntity**/
public void cacheTable(CacheableEntity entity){
cacheTable(entity,entity.getCacheKey());
}
/** caches a single entity of type IDOEntity **/
public void cacheEntity(IDOEntity entity, String cacheKey){
if( this.entityMaps == null ){
this.entityMaps = new HashMap();
}
this.entityMaps.put(cacheKey, entity);
}
public IDOLegacyEntity getCachedEntity(String cacheKey){
if( this.entityMaps != null ){
return (IDOLegacyEntity) this.entityMaps.get(cacheKey);
}
else {
return null;
}
}
public void removeCachedEntity(String cacheKey){
if( this.entityMaps != null ){
this.entityMaps.remove(cacheKey);
}
}
/** caches a whole table and specifies which column to use for a key. Must be of type CacheableEntity**/
public void cacheTable(CacheableEntity entity, String columnNameForKey){
cacheTable(entity,columnNameForKey,null);
}
public void removeTableFromCache(Class entityClass){
if( this.entityMaps != null ){
this.entityMaps.remove(entityClass);
if( this.entityMapsKeys != null ) {
this.entityMapsKeys.remove(entityClass);
}
}
}
public Map getCachedTableMap(Class entityClass){
if( this.entityMaps!=null ){
return (Map) this.entityMaps.get(entityClass);
}
else {
return null;
}
}
public void cacheTable(CacheableEntity entity, String columnNameForKey ,String columnNameForSecondKey){
if( this.entityMaps == null ){
this.entityMaps = new HashMap();
this.entityMapsKeys = new HashMap();
}
if( this.entityMaps.get(getCorrectClassForEntity(entity)) == null ){
Map entityMap = new HashMap();
Vector keys = new Vector();
IDOLegacyEntity[] e;
try {
e = entity.findAll();
if( (e!= null) && (e.length>0) ){
boolean hasTwoKeys = false;
//store key names for update, insert and delete
keys.addElement(columnNameForKey);
if( columnNameForSecondKey != null ){
keys.addElement(columnNameForSecondKey);
hasTwoKeys = true;
}
this.entityMapsKeys.put(getCorrectClassForEntity(entity),keys);
//traverse through the table and make the entitymap and put it in the master map
for (int i = 0; i < e.length; i++) {
if(hasTwoKeys){
entityMap.put(StringHandler.concatAlphabetically(e[i].getStringColumnValue(columnNameForKey),e[i].getStringColumnValue(columnNameForSecondKey)),e[i]);
}
else{
entityMap.put(e[i].getStringColumnValue(columnNameForKey),e[i]);
}
}
this.entityMaps.put(getCorrectClassForEntity(entity),entityMap);
//done!
}
}
catch (Exception ex) {
ex.printStackTrace(System.err);
}
}
}
public IDOLegacyEntity getFromCachedTable(Class entityClass, String value ){
IDOLegacyEntity entity = null;
if( this.entityMaps != null ){
Map entityMap = getEntityMap(entityClass);
if( entityMap != null ){
entity = (IDOLegacyEntity) entityMap.get(value);
}
}
else {
System.out.println("IWCacheManager entityMaps is null!");
}
return entity;
}
public IDOLegacyEntity getFromCachedTable(Class entityClass, String value, String value2 ){
return getFromCachedTable(entityClass, StringHandler.concatAlphabetically(value,value2));
}
public Map getEntityMap(Class entityClass){
Map entityMap = null;
if( this.entityMaps != null ){
Class entityBeanClass = this.getCorrectClassForEntity(entityClass);
entityMap = (Map) this.entityMaps.get(entityBeanClass);
}//else System.out.println("IWCacheManager entityMaps is null!");
return entityMap;
}
public Vector getEntityKeyVector(Class entityClass){
Vector entityKeys = null;
if( this.entityMapsKeys != null ){
entityKeys = (Vector) this.entityMapsKeys.get(entityClass);
}
return entityKeys;
}
public void updateFromCachedTable(IDOLegacyEntity entity){
Vector keys = getEntityKeyVector(getCorrectClassForEntity(entity));
if( keys!=null ){
int length = keys.size();
if(length==2){
getEntityMap(getCorrectClassForEntity(entity)).put(StringHandler.concatAlphabetically(entity.getStringColumnValue((String) keys.elementAt(0)),entity.getStringColumnValue((String) keys.elementAt(1))),entity);
}
else{
getEntityMap(getCorrectClassForEntity(entity)).put(entity.getStringColumnValue((String) keys.elementAt(0)),entity);
}
}
}
public void deleteFromCachedTable(IDOLegacyEntity entity){
Vector keys = getEntityKeyVector(getCorrectClassForEntity(entity));
if( keys!=null ){
int length = keys.size();
if(length==2){
getEntityMap(getCorrectClassForEntity(entity)).remove(StringHandler.concatAlphabetically(entity.getStringColumnValue((String) keys.elementAt(0)),entity.getStringColumnValue((String) keys.elementAt(1))));
}
else{
getEntityMap(getCorrectClassForEntity(entity)).remove(entity.getStringColumnValue((String) keys.elementAt(0)));
}
}
}
public void insertIntoCachedTable(IDOLegacyEntity entity){
updateFromCachedTable(entity);
}
private Class getCorrectClassForEntity(IDOLegacyEntity entityInstance){
return getCorrectClassForEntity(entityInstance.getClass());
}
private Class getCorrectClassForEntity(Class entityBeanOrInterfaceClass){
return com.idega.data.IDOLookup.getInterfaceClassFor(entityBeanOrInterfaceClass);
}
/**
* Clears all caching in for all objects
*/
public void clearAllCaches(){
this.log.info("Clearing all IWCacheManager cache");
this._keysMap=null;
this.entityMaps=null;
this.entityMapsKeys=null;
this.intervalsMap=null;
this.objectsMap=null;
this.timesMap=null;
}
/**
* Unloads the instance from the application (typically called on shutdown)
*/
public void unload(IWMainApplication iwma){
iwma.removeAttribute(IW_CACHEMANAGER_KEY);
clearAllCaches();
}
}