CacheContainer.java 4.99 KB
package it.softecspa.fileproxy.cache;

import it.softecspa.fileproxy.DatabaseBalancer.Balancer;
import it.softecspa.fileproxy.services.ServerCacheFactory.CacheKey;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.SortedMap;

import org.apache.log4j.Logger;

public class CacheContainer {
	
	// Singleton instance
	private static CacheContainer instance;
		
	private Logger log = Logger.getLogger(getClass());
	
	// Mappe degli elementi
	private HashMap<String, CacheElement<?,?>>[] cache = null;
	private HashMap<String, List<CacheElement<?,?>>>[] cachedTables = null;
	
	
	private CacheContainer() {
		super();
		synchronized (CacheContainer.class) {
			if (instance == null) {
				instance = this;
				
				log.info(CacheContainer.class.getSimpleName()+" instance is starting!");
				instance.flushAll();
			}
		}
	}

	
	public static CacheContainer getInstance() {
		synchronized (CacheContainer.class) {
			if (instance == null) new CacheContainer();			
		}
		return instance;
	}
	
	
	
	protected synchronized void flushAll() {
		flush(Balancer.MASTER);
		flush(Balancer.STAGE);
	}
	
	
	@SuppressWarnings("unchecked")
	protected synchronized void flush(Balancer balancer) {
		// CACHE
		if (cache==null) cache = new HashMap[2];
		if (cache[balancer.index()]==null) cache[balancer.index()] = new HashMap<String, CacheElement<?,?>>();
		// Elenco tabelle coinvolte per singola cache
		if (cachedTables==null) cachedTables = new HashMap[2];
		if (cachedTables[balancer.index()]==null) cachedTables[balancer.index()] = new HashMap<String, List<CacheElement<?,?>>>();
		
		// ....pulizia
		Collection<CacheElement<?,?>> collection =  cache[balancer.index()].values();
		for (Iterator<CacheElement<?,?>> i = collection.iterator(); i.hasNext(); ) {
			CacheElement<?,?> element = i.next();
			if (element!=null) element.flush();	
		}
	}

	

	public void createContainer(CacheElement<?,?> element) throws CacheException {
		createContainer(element.getUniqueName(), element, true);
	}
	
	public void createContainer(CacheKey uniqueNane, CacheElement<?,?> element, boolean autoflush) throws CacheException {
		if (element==null) return;
		
		if (uniqueNane==null) throw new CacheException("CacheElement with null name");
		String name = uniqueNane.toString();
		if (log.isDebugEnabled()) log.debug("Create empty container with name '"+name+"'");
		int index = element.getBalancer().index();
		
		CacheElement<?, ?> found = cache[index].get(name);
		if (found!=null) {
			if (found.getClass()!=element.getClass()) {
				throw new CacheException("CacheElement ClassCastException: element named '"+name+"' class is "+found.getClass().getSimpleName()+"!");
			}
				
			if (autoflush) {
				// Se esiste già un container con quel nome lo pulisco;
				cache[index].get(name).flush();
				return;
			} else {
				throw new CacheException("CacheElement with name '"+name+"' just exist!");
			}
		} else {
			addTables(name, element, index);
		}
		
		// Aggiungo l'elemento alla cache
		cache[element.getBalancer().index()].put(name, element);		
	}


	private void addTables(String name, CacheElement<?,?> element, int index) {
		for (String table : element.getTables()) {			
			List<CacheElement<?,?>> lista = cachedTables[index].get(table);
			if (lista==null) {
				lista = new ArrayList<CacheElement<?,?>>();
				cachedTables[index].put(table, lista);
			}
			if (!lista.contains(name)) {
				lista.add(element);
			}
		}
		
		
	}


	@SuppressWarnings("unchecked")
	public <K,V> CacheElement<K,V> getCacheElement(CacheKey uniqueName, Balancer balancer) throws CacheException {
		int index = balancer.index();
		String name = uniqueName.toString();
		
		// Estraggo il container
		CacheElement<K,V> container = null;		
		try {					
			container = (CacheElement<K,V>) cache[index].get(name);
			
			// FIXME aggiungere log dell'errore su DB e invio email
		
			return container;
			
		} catch (ClassCastException e) {
			throw new CacheException("ClassCastException estracting element with name '"+name+"'", e);
		} catch (Exception e) {
			throw new CacheException("Unhandled exception estracting element with name '"+name+"'");
		}
	}
	
	/**
	 * Restituisce il container dati legato alla chiave
	 * @param uniqueName
	 * @param balancer
	 * @return
	 * @throws CacheException
	 */
	public <K,V> SortedMap<K,V> getContainer(CacheKey uniqueName, Balancer balancer) throws CacheException {
		// Estraggo il container
		CacheElement<K,V> cacheElement = getCacheElement(uniqueName, balancer);		
		
		// Controllo se i dati sono validi, altrimenti faccio un load
		if (cacheElement.isExpired()) {
			cacheElement.load();
		}
		
		return cacheElement.getContainer();		
	}

	/**
	 * Restituisce la lista completa delle tabelle in cache
	 * @return
	 */
	public HashMap<String, List<CacheElement<?, ?>>>[] getCachedTables() {
		return cachedTables;
	}
	
}