diff --git a/annotation/src/main/java/lcsb/mapviewer/annotation/cache/ApplicationLevelCache.java b/annotation/src/main/java/lcsb/mapviewer/annotation/cache/ApplicationLevelCache.java
index 5da894ab325c73ca1008ebb6310021f37b4b074d..9bd95528fa871d3099cf8cfb5e00ee2925db065e 100644
--- a/annotation/src/main/java/lcsb/mapviewer/annotation/cache/ApplicationLevelCache.java
+++ b/annotation/src/main/java/lcsb/mapviewer/annotation/cache/ApplicationLevelCache.java
@@ -21,123 +21,129 @@ import lcsb.mapviewer.model.cache.CacheType;
  */
 public final class ApplicationLevelCache extends XmlParser implements QueryCacheInterface {
 
-	/**
-	 * How many values should be stored in cache before we even try to consider
-	 * releasing object due to huge memory usage.
-	 */
-	static final int										 MIN_CACHED_VALUES_BEFORE_CLEAN	= 100;
-
-	/**
-	 * Default class logger.
-	 */
-	private static Logger								 logger													= Logger.getLogger(ApplicationLevelCache.class);
-
-	/**
-	 * Cached nodes stored locally and identified by string.
-	 */
-	private static Map<String, Node>		 cachedQueryNodes								= new HashMap<String, Node>();
-
-	/**
-	 * Cached strings stored locally and identified by string.
-	 */
-	private static Map<String, String>	 cachedQueryString							= new HashMap<String, String>();
-
-	/**
-	 * Global instance of cache.
-	 */
-	private static ApplicationLevelCache cache													= null;
-
-	/**
-	 * Returns single instance of global application cache (singleton pattern).
-	 * 
-	 * @return single instance of global application cache
-	 */
-	public static ApplicationLevelCache getInstance() {
-		if (Configuration.isApplicationCacheOn()) {
-			if (cache == null) {
-				cache = new ApplicationLevelCache();
-			}
-			return cache;
-		} else {
-			return null;
-		}
-	}
-
-	/**
-	 * Default constructor. Prevents instatiation.
-	 */
-	private ApplicationLevelCache() {
-
-	}
-
-	@Override
-	public synchronized Node getXmlNodeByQuery(String query, CacheType type) {
-		Node result = null;
-		result = cachedQueryNodes.get(type.getId() + "\n" + query);
-		return result;
-	}
-
-	@Override
-	public synchronized String getStringByQuery(String query, CacheType type) {
-		String result = null;
-		result = cachedQueryString.get(type.getId() + "\n" + query);
-		return result;
-	}
-
-	@Override
-	public synchronized void setCachedQuery(String query, CacheType type, Object object) {
-		performMemoryBalance();
-
-		if (object instanceof String) {
-			cachedQueryString.put(type.getId() + "\n" + query, (String) object);
-		} else if (object instanceof Node) {
-			cachedQueryNodes.put(type.getId() + "\n" + query, (Node) object);
-		} else if (object == null) {
-			cachedQueryString.put(type.getId() + "\n" + query, (String) object);
-		} else {
-			throw new CacheException("Unknown object type: " + object.getClass());
-		}
-	}
-
-	/**
-	 * Method that clean cache if memory usage is too high.
-	 */
-	synchronized void performMemoryBalance() {
-		long cacheCount = 0;
-		cacheCount += cachedQueryString.size();
-		cacheCount += cachedQueryNodes.size();
-		// check memory usage only if we have some data to clear
-		if (cacheCount > MIN_CACHED_VALUES_BEFORE_CLEAN) {
-			Runtime runtime = Runtime.getRuntime();
-			long maxMem = runtime.maxMemory();
-			long useMem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
-			// if free memory is less than 10% then we clear cache
-			if (useMem > maxMem * Configuration.getMemorySaturationRatioTriggerClean()) {
-				logger.info("Cache will be cleared");
-				logger.info("Memory usage: " + useMem + " out of " + maxMem + " is used. Exceeded: " + maxMem * Configuration.getMemorySaturationRatioTriggerClean());
-				logger.info("Elements in cache: " + cacheCount);
-				clearCache();
-				System.gc();
-			}
-		}
-	}
-
-	@Override
-	public synchronized void removeByQuery(String query, CacheType type) {
-		cachedQueryString.remove(type.getId() + "\n" + query);
-		cachedQueryNodes.remove(type.getId() + "\n" + query);
-	}
-
-	@Override
-	public synchronized void clearCache() {
-		logger.info("Clearing application cache");
-		cachedQueryNodes.clear();
-		cachedQueryString.clear();
-	}
-
-	@Override
-	public void invalidateByQuery(String query, CacheType type) {
-		removeByQuery(query, type);
-	}
+  /**
+   * How many values should be stored in cache before we even try to consider
+   * releasing object due to huge memory usage.
+   */
+  static final int MIN_CACHED_VALUES_BEFORE_CLEAN = 100;
+
+  /**
+   * Default class logger.
+   */
+  private static Logger logger = Logger.getLogger(ApplicationLevelCache.class);
+
+  /**
+   * Cached nodes stored locally and identified by string.
+   */
+  private static Map<String, Node> cachedQueryNodes = new HashMap<String, Node>();
+
+  /**
+   * Cached strings stored locally and identified by string.
+   */
+  private static Map<String, String> cachedQueryString = new HashMap<String, String>();
+
+  /**
+   * Global instance of cache.
+   */
+  private static ApplicationLevelCache cache = null;
+
+  /**
+   * Returns single instance of global application cache (singleton pattern).
+   * 
+   * @return single instance of global application cache
+   */
+  public static ApplicationLevelCache getInstance() {
+    if (Configuration.isApplicationCacheOn()) {
+      if (cache == null) {
+        cache = new ApplicationLevelCache();
+      }
+      return cache;
+    } else {
+      return null;
+    }
+  }
+
+  /**
+   * Default constructor. Prevents instantiation.
+   */
+  private ApplicationLevelCache() {
+
+  }
+
+  @Override
+  public synchronized Node getXmlNodeByQuery(String query, CacheType type) {
+    Node result = null;
+    result = cachedQueryNodes.get(type.getId() + "\n" + query);
+    return result;
+  }
+
+  @Override
+  public synchronized String getStringByQuery(String query, CacheType type) {
+    String result = null;
+    result = cachedQueryString.get(type.getId() + "\n" + query);
+    return result;
+  }
+
+  @Override
+  public synchronized void setCachedQuery(String query, CacheType type, Object object) {
+    setCachedQuery(query, type, object, 0);
+  }
+  
+  @Override
+  public synchronized void setCachedQuery(String query, CacheType type, Object object, int validDays) {
+    performMemoryBalance();
+
+    if (object instanceof String) {
+      cachedQueryString.put(type.getId() + "\n" + query, (String) object);
+    } else if (object instanceof Node) {
+      cachedQueryNodes.put(type.getId() + "\n" + query, (Node) object);
+    } else if (object == null) {
+      cachedQueryString.put(type.getId() + "\n" + query, (String) object);
+    } else {
+      throw new CacheException("Unknown object type: " + object.getClass());
+    }
+  }
+
+  /**
+   * Method that clean cache if memory usage is too high.
+   */
+  synchronized void performMemoryBalance() {
+    long cacheCount = 0;
+    cacheCount += cachedQueryString.size();
+    cacheCount += cachedQueryNodes.size();
+    // check memory usage only if we have some data to clear
+    if (cacheCount > MIN_CACHED_VALUES_BEFORE_CLEAN) {
+      Runtime runtime = Runtime.getRuntime();
+      long maxMem = runtime.maxMemory();
+      long useMem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
+      // if free memory is less than 10% then we clear cache
+      if (useMem > maxMem * Configuration.getMemorySaturationRatioTriggerClean()) {
+        logger.info("Cache will be cleared");
+        logger.info("Memory usage: " + useMem + " out of " + maxMem + " is used. Exceeded: "
+            + maxMem * Configuration.getMemorySaturationRatioTriggerClean());
+        logger.info("Elements in cache: " + cacheCount);
+        clearCache();
+        System.gc();
+      }
+    }
+  }
+
+  @Override
+  public synchronized void removeByQuery(String query, CacheType type) {
+    cachedQueryString.remove(type.getId() + "\n" + query);
+    cachedQueryNodes.remove(type.getId() + "\n" + query);
+  }
+
+  @Override
+  public synchronized void clearCache() {
+    logger.info("Clearing application cache");
+    cachedQueryNodes.clear();
+    cachedQueryString.clear();
+  }
+
+  @Override
+  public void invalidateByQuery(String query, CacheType type) {
+    removeByQuery(query, type);
+  }
 
 }
diff --git a/annotation/src/main/java/lcsb/mapviewer/annotation/cache/CachableInterface.java b/annotation/src/main/java/lcsb/mapviewer/annotation/cache/CachableInterface.java
index cd61b3f287c9eae4b90fd64a5b4f6bc1af1737c2..953f91175e74305457b446a2fa270241d38f1224 100644
--- a/annotation/src/main/java/lcsb/mapviewer/annotation/cache/CachableInterface.java
+++ b/annotation/src/main/java/lcsb/mapviewer/annotation/cache/CachableInterface.java
@@ -108,6 +108,12 @@ public abstract class CachableInterface extends XmlParser {
     }
   }
 
+  protected final void setCacheValue(String key, String result, int validDays) {
+    if (cache != null) {
+      cache.setCachedQuery(key, getCacheType(), result, validDays);
+    }
+  }
+
   /**
    * Retrieves string from cache.
    * 
@@ -181,11 +187,11 @@ public abstract class CachableInterface extends XmlParser {
   }
 
   /**
-   * Returns a content of the webpage for a given url using GET request.
+   * Returns a content of the web page for a given url using GET request.
    * 
    * @param accessUrl
-   *          webpage url address
-   * @return content of the webpage
+   *          web page url address
+   * @return content of the web page
    * @throws IOException
    *           thrown when there are problems with connection to ChEMBL database
    */
@@ -194,16 +200,16 @@ public abstract class CachableInterface extends XmlParser {
   }
 
   /**
-   * Returns a content of the webpage for a given url. If postData is not null,
+   * Returns a content of the web page for a given url. If postData is not null,
    * the page will be accessed using POST request. Otherwise GET will be used.
    * 
    * @param accessUrl
-   *          webpage url address
+   *          web page url address
    * @param httpRequestMethod
    *          type of HTTP request (GET, POST, PUT, PATCH, DELETE, ...)
    * @param postData
    *          string to be sent in the body of the request
-   * @return content of the webpage
+   * @return content of the web page
    * @throws IOException
    *           thrown when there are problems with connection to ChEMBL database
    */
@@ -235,7 +241,7 @@ public abstract class CachableInterface extends XmlParser {
   public String cleanHtml(String text) {
     int startIndex;
     int endIndex;
-    // and now clean the descripton from html tags (should be somehow
+    // and now clean the description from html tags (should be somehow
     // improved...)
 
     StringBuilder result = new StringBuilder();
diff --git a/annotation/src/main/java/lcsb/mapviewer/annotation/cache/GeneralCache.java b/annotation/src/main/java/lcsb/mapviewer/annotation/cache/GeneralCache.java
index 2f3addc126a9e9d787df6a2fab2752b99ed179f3..6c98ed1aa4018bc2be7493e1d40a6c91aafc09ac 100644
--- a/annotation/src/main/java/lcsb/mapviewer/annotation/cache/GeneralCache.java
+++ b/annotation/src/main/java/lcsb/mapviewer/annotation/cache/GeneralCache.java
@@ -1,17 +1,17 @@
 package lcsb.mapviewer.annotation.cache;
 
-import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.model.cache.CacheType;
-
 import org.apache.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 import org.w3c.dom.Node;
 
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
+import lcsb.mapviewer.model.cache.CacheType;
+
 /**
  * Cache used by the application. It contains two sub-classes responsible for
  * application level cache (for single run of the application) and database
- * level cache (for information that were gathere since the beginning).
+ * level cache (for information that were gathered since the beginning).
  * 
  * @author Piotr Gawron
  * 
@@ -19,127 +19,135 @@ import org.w3c.dom.Node;
 @Transactional(value = "txManager")
 public class GeneralCache implements GeneralCacheInterface {
 
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private static Logger				logger = Logger.getLogger(GeneralCache.class);
-
-	/**
-	 * Application level cache. More information can be found
-	 * {@link ApplicationLevelCache here}.
-	 */
-	private QueryCacheInterface	cache1 = ApplicationLevelCache.getInstance();
-
-	/**
-	 * Database level cache. More information can be found
-	 * {@link PermanentDatabaseLevelCache here}.
-	 */
-	@Autowired
-	private QueryCacheInterface	cache2;
-
-	@Override
-	public void clearCache() {
-		if (cache1 != null) {
-			cache1.clearCache();
-		}
-		if (cache2 != null) {
-			cache2.clearCache();
-		}
-	}
-
-	@Override
-	public Node getXmlNodeByQuery(String query, CacheType type) {
-		if (type == null) {
-			throw new InvalidArgumentException("Cache type cannot be null");
-		}
-
-		Node result = null;
-		if (cache1 != null) {
-			result = cache1.getXmlNodeByQuery(query, type);
-		}
-		if (result == null && cache2 != null) {
-			result = cache2.getXmlNodeByQuery(query, type);
-			if (result != null && cache1 != null) {
-				cache1.setCachedQuery(query, type, result);
-			}
-		}
-		return result;
-	}
-
-	@Override
-	public String getStringByQuery(String query, CacheType type) {
-		if (type == null) {
-			throw new InvalidArgumentException("Cache type cannot be null");
-		}
-		String result = null;
-		if (cache1 != null) {
-			result = cache1.getStringByQuery(query, type);
-		}
-		if (result == null && cache2 != null) {
-			result = cache2.getStringByQuery(query, type);
-			if (result != null && cache1 != null) {
-				cache1.setCachedQuery(query, type, result);
-			}
-		}
-		return result;
-	}
-
-	@Override
-	public void setCachedQuery(String query, CacheType type, Object object) {
-		if (type == null) {
-			throw new InvalidArgumentException("Cache type cannot be null");
-		}
-		if (cache1 != null) {
-			cache1.setCachedQuery(query, type, object);
-		}
-		if (cache2 != null) {
-			cache2.setCachedQuery(query, type, object);
-		}
-	}
-
-	@Override
-	public void removeByQuery(String query, CacheType type) {
-		if (type == null) {
-			throw new InvalidArgumentException("Cache type cannot be null");
-		}
-		if (cache1 != null) {
-			cache1.removeByQuery(query, type);
-		}
-		if (cache2 != null) {
-			cache2.removeByQuery(query, type);
-		}
-	}
-
-	@Override
-	public void invalidateByQuery(String query, CacheType type) {
-		if (type == null) {
-			throw new InvalidArgumentException("Cache type cannot be null");
-		}
-		if (cache1 != null) {
-			cache1.invalidateByQuery(query, type);
-		}
-		if (cache2 != null) {
-			cache2.invalidateByQuery(query, type);
-		}
-
-	}
-
-	/**
-	 * @return the cache2
-	 * @see #cache2
-	 */
-	public QueryCacheInterface getCache2() {
-		return cache2;
-	}
-
-	/**
-	 * @param cache2
-	 *          the cache2 to set
-	 * @see #cache2
-	 */
-	public void setCache2(QueryCacheInterface cache2) {
-		this.cache2 = cache2;
-	}
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private static Logger logger = Logger.getLogger(GeneralCache.class);
+
+  /**
+   * Application level cache. More information can be found
+   * {@link ApplicationLevelCache here}.
+   */
+  private QueryCacheInterface cache1 = ApplicationLevelCache.getInstance();
+
+  /**
+   * Database level cache. More information can be found
+   * {@link PermanentDatabaseLevelCache here}.
+   */
+  @Autowired
+  private QueryCacheInterface cache2;
+
+  @Override
+  public void clearCache() {
+    if (cache1 != null) {
+      cache1.clearCache();
+    }
+    if (cache2 != null) {
+      cache2.clearCache();
+    }
+  }
+
+  @Override
+  public Node getXmlNodeByQuery(String query, CacheType type) {
+    if (type == null) {
+      throw new InvalidArgumentException("Cache type cannot be null");
+    }
+
+    Node result = null;
+    if (cache1 != null) {
+      result = cache1.getXmlNodeByQuery(query, type);
+    }
+    if (result == null && cache2 != null) {
+      result = cache2.getXmlNodeByQuery(query, type);
+      if (result != null && cache1 != null) {
+        cache1.setCachedQuery(query, type, result);
+      }
+    }
+    return result;
+  }
+
+  @Override
+  public String getStringByQuery(String query, CacheType type) {
+    if (type == null) {
+      throw new InvalidArgumentException("Cache type cannot be null");
+    }
+    String result = null;
+    if (cache1 != null) {
+      result = cache1.getStringByQuery(query, type);
+    }
+    if (result == null && cache2 != null) {
+      result = cache2.getStringByQuery(query, type);
+      if (result != null && cache1 != null) {
+        cache1.setCachedQuery(query, type, result);
+      }
+    }
+    return result;
+  }
+
+  @Override
+  public void setCachedQuery(String query, CacheType type, Object object) {
+    if (type == null) {
+      throw new InvalidArgumentException("Cache type cannot be null");
+    }
+    setCachedQuery(query, type, object, type.getValidity());
+  }
+
+  @Override
+  public void setCachedQuery(String query, CacheType type, Object object, int validDays) {
+    if (type == null) {
+      throw new InvalidArgumentException("Cache type cannot be null");
+    }
+    if (cache1 != null) {
+      cache1.setCachedQuery(query, type, object, validDays);
+    }
+    if (cache2 != null) {
+      cache2.setCachedQuery(query, type, object, validDays);
+    }
+  }
+
+  @Override
+  public void removeByQuery(String query, CacheType type) {
+    if (type == null) {
+      throw new InvalidArgumentException("Cache type cannot be null");
+    }
+    if (cache1 != null) {
+      cache1.removeByQuery(query, type);
+    }
+    if (cache2 != null) {
+      cache2.removeByQuery(query, type);
+    }
+  }
+
+  @Override
+  public void invalidateByQuery(String query, CacheType type) {
+    if (type == null) {
+      throw new InvalidArgumentException("Cache type cannot be null");
+    }
+    if (cache1 != null) {
+      cache1.invalidateByQuery(query, type);
+    }
+    if (cache2 != null) {
+      cache2.invalidateByQuery(query, type);
+    }
+
+  }
+
+  /**
+   * @return the cache2
+   * @see #cache2
+   */
+  public QueryCacheInterface getCache2() {
+    return cache2;
+  }
+
+  /**
+   * @param cache2
+   *          the cache2 to set
+   * @see #cache2
+   */
+  public void setCache2(QueryCacheInterface cache2) {
+    this.cache2 = cache2;
+  }
 
 }
diff --git a/annotation/src/main/java/lcsb/mapviewer/annotation/cache/GeneralCacheWithExclusion.java b/annotation/src/main/java/lcsb/mapviewer/annotation/cache/GeneralCacheWithExclusion.java
index 8bf1c1add7ac038254a46c525d3109e74fe3a67c..412043bd981b868c8faddd94614658161c822d57 100644
--- a/annotation/src/main/java/lcsb/mapviewer/annotation/cache/GeneralCacheWithExclusion.java
+++ b/annotation/src/main/java/lcsb/mapviewer/annotation/cache/GeneralCacheWithExclusion.java
@@ -7,7 +7,7 @@ import lcsb.mapviewer.common.exception.InvalidArgumentException;
 import lcsb.mapviewer.model.cache.CacheType;
 
 /**
- * This implementation of cache works as a nomral cache except of the fact that
+ * This implementation of cache works as a normal cache except of the fact that
  * first few query requests are ignored (return null). It's used when refreshing
  * data from cache. Object of this class is injected into a
  * {@link CachableInterface} and after that normal call is performed. First
@@ -18,76 +18,81 @@ import lcsb.mapviewer.model.cache.CacheType;
  *
  */
 public class GeneralCacheWithExclusion implements GeneralCacheInterface {
-	
-	/**
-	 * Default class logger.
-	 */
-	private Logger								logger	= Logger.getLogger(GeneralCacheWithExclusion.class);
 
-	/**
-	 * How many queries should be ignored.
-	 */
-	private int										counter	= 0;
+  /**
+   * Default class logger.
+   */
+  private Logger logger = Logger.getLogger(GeneralCacheWithExclusion.class);
 
-	/**
-	 * Original cache object.
-	 */
-	private GeneralCacheInterface	cache;
+  /**
+   * How many queries should be ignored.
+   */
+  private int counter = 0;
 
-	/**
-	 * Constructor that creates cache.
-	 * 
-	 * @param originalCache
-	 *          {@link #cache}
-	 * @param exclusionCount
-	 *          {@link #counter}
-	 */
-	public GeneralCacheWithExclusion(GeneralCacheInterface originalCache, int exclusionCount) {
-		if (originalCache == null) {
-			throw new InvalidArgumentException("Cache passed as argument cannot be null");
-		}
-		this.counter = exclusionCount;
-		this.cache = originalCache;
-	}
+  /**
+   * Original cache object.
+   */
+  private GeneralCacheInterface cache;
 
-	@Override
-	public Node getXmlNodeByQuery(String identifier, CacheType type) {
-		if (counter > 0) {
-			counter--;
-			logger.debug("Ignoring cache query due to cache refresh: " + identifier + ", " + type);
-			return null;
-		}
-		return cache.getXmlNodeByQuery(identifier, type);
-	}
+  /**
+   * Constructor that creates cache.
+   * 
+   * @param originalCache
+   *          {@link #cache}
+   * @param exclusionCount
+   *          {@link #counter}
+   */
+  public GeneralCacheWithExclusion(GeneralCacheInterface originalCache, int exclusionCount) {
+    if (originalCache == null) {
+      throw new InvalidArgumentException("Cache passed as argument cannot be null");
+    }
+    this.counter = exclusionCount;
+    this.cache = originalCache;
+  }
 
-	@Override
-	public String getStringByQuery(String identifier, CacheType type) {
-		if (counter > 0) {
-			counter--;
-			logger.debug("Ignoring cache query due to cache refresh: " + identifier + ", " + type);
-			return null;
-		}
-		return cache.getStringByQuery(identifier, type);
-	}
+  @Override
+  public Node getXmlNodeByQuery(String identifier, CacheType type) {
+    if (counter > 0) {
+      counter--;
+      logger.debug("Ignoring cache query due to cache refresh: " + identifier + ", " + type);
+      return null;
+    }
+    return cache.getXmlNodeByQuery(identifier, type);
+  }
 
-	@Override
-	public void setCachedQuery(String identifier, CacheType type, Object value) {
-		cache.setCachedQuery(identifier, type, value);
-	}
+  @Override
+  public String getStringByQuery(String identifier, CacheType type) {
+    if (counter > 0) {
+      counter--;
+      logger.debug("Ignoring cache query due to cache refresh: " + identifier + ", " + type);
+      return null;
+    }
+    return cache.getStringByQuery(identifier, type);
+  }
 
-	@Override
-	public void clearCache() {
-		cache.clearCache();
+  @Override
+  public void setCachedQuery(String identifier, CacheType type, Object value) {
+    cache.setCachedQuery(identifier, type, value);
+  }
+  
+  @Override
+  public void setCachedQuery(String identifier, CacheType type, Object value, int validDays) {
+    cache.setCachedQuery(identifier, type, value, validDays);
+  }
 
-	}
+  @Override
+  public void clearCache() {
+    cache.clearCache();
 
-	@Override
-	public void removeByQuery(String identifier, CacheType type) {
-		cache.removeByQuery(identifier, type);
-	}
+  }
 
-	@Override
-	public void invalidateByQuery(String identifier, CacheType type) {
-		cache.invalidateByQuery(identifier, type);
-	}
+  @Override
+  public void removeByQuery(String identifier, CacheType type) {
+    cache.removeByQuery(identifier, type);
+  }
+
+  @Override
+  public void invalidateByQuery(String identifier, CacheType type) {
+    cache.invalidateByQuery(identifier, type);
+  }
 }
diff --git a/annotation/src/main/java/lcsb/mapviewer/annotation/cache/PermanentDatabaseLevelCache.java b/annotation/src/main/java/lcsb/mapviewer/annotation/cache/PermanentDatabaseLevelCache.java
index 607a26f3ba2166176d90aa00fa55c754a1d6c97f..08c0fabbfe8fa51f82996ee01cbe73c63facd78b 100644
--- a/annotation/src/main/java/lcsb/mapviewer/annotation/cache/PermanentDatabaseLevelCache.java
+++ b/annotation/src/main/java/lcsb/mapviewer/annotation/cache/PermanentDatabaseLevelCache.java
@@ -40,525 +40,539 @@ import lcsb.mapviewer.persist.dao.cache.CacheQueryDao;
  * 
  */
 @Transactional(value = "txManager")
-public class PermanentDatabaseLevelCache extends XmlParser implements PermanentDatabaseLevelCacheInterface, ApplicationContextAware {
-
-	/**
-	 * This class represents new thread task for quering database.
-	 * 
-	 * @author Piotr Gawron
-	 * 
-	 */
-	private final class QueryTask implements Callable<CacheQuery> {
-
-		/**
-		 * Identifier of cached entry.
-		 * 
-		 * @see CacheQuery#query
-		 */
-		private String		query;
-
-		/**
-		 * Type of cached entry.
-		 * 
-		 * @see CacheQuery#type
-		 */
-		private CacheType	type;
-
-		/**
-		 * Default constructor.
-		 * 
-		 * @param query
-		 *          {@link #query}
-		 * @param type
-		 *          {@link #type}
-		 */
-		private QueryTask(String query, CacheType type) {
-			logger.debug("Query task start");
-			this.query = query;
-			this.type = type;
-		}
-
-		@Override
-		public CacheQuery call() throws Exception {
-			logger.debug("Query task call");
-			dbUtils.createSessionForCurrentThread();
-			logger.debug("Query task session started");
-			CacheQuery entry = getCacheQueryDao().getByQuery((String) query, type);
-			logger.debug("Query task data retrieved");
-			dbUtils.closeSessionForCurrentThread();
-			logger.debug("Query task return");
-			return entry;
-		}
-
-	}
-
-	/**
-	 * This class represents new thread task for refreshing element in db.
-	 * 
-	 * @author Piotr Gawron
-	 * 
-	 */
-	private final class RefreshTask implements Callable<CacheQuery> {
-
-		/**
-		 * Identifier of cached entry.
-		 * 
-		 * @see CacheQuery#query
-		 */
-		private String		query;
-
-		/**
-		 * Type of cached entry.
-		 * 
-		 * @see CacheQuery#type
-		 */
-		private CacheType	type;
-
-		/**
-		 * Default constructor.
-		 * 
-		 * @param query
-		 *          {@link #query}
-		 * @param type
-		 *          {@link #type}
-		 */
-		private RefreshTask(String query, CacheType type) {
-			logger.debug("Refresh task start (query: " + query + ")");
-			this.query = query;
-			this.type = type;
-		}
-
-		@Override
-		public CacheQuery call() throws Exception {
-			logger.debug("Refresh task call");
-			CachableInterface cachableInterface = null;
-			try {
-				Constructor<?> ctor;
-				Class<?> clazz = Class.forName(type.getClassName());
-				ctor = clazz.getConstructor();
-				Object object = ctor.newInstance();
-				if (object instanceof CachableInterface) {
-					cachableInterface = (CachableInterface) object;
-				} else {
-					logger.fatal("Invalid class type: " + object.getClass() + ". Class cannot be cast into " + CachableInterface.class);
-				}
-				applicationContext.getAutowireCapableBeanFactory().autowireBean(object);
-
-			} catch (Exception e) {
-				logger.fatal("Problem with creating cache query updater", e);
-			}
-			if (cachableInterface != null) {
-				cachableInterface.setCache(new GeneralCacheWithExclusion(cachableInterface.getCache(), 1));
-				dbUtils.createSessionForCurrentThread();
-				logger.debug("Refresh task session started");
-				try {
-					Object result = cachableInterface.refreshCacheQuery(query);
-					if (result == null) {
-						removeByQuery(query, type);
-					} else {
-						setCachedQuery(query, type, result);
-
-					}
-				} catch (SourceNotAvailable e) {
-					logger.error("Cannot refresh cache", e);
-				} catch (InvalidArgumentException e) {
-					removeByQuery(query, type);
-					logger.error("Problem with refreshing. Invalid data to refresh", e);
-				} catch (Exception e) {
-					logger.error("Severe problem in cache", e);
-				} finally {
-					// close the transaction for this thread
-					dbUtils.closeSessionForCurrentThread();
-					logger.debug("Refresh task session closed");
-				}
-			}
-			logger.debug("Refresh task finish");
-			final Future<CacheQuery> task = service.submit(new QueryTask(query, type));
-			return task.get();
-		}
-
-	}
-
-	/**
-	 * This class represents new thread task for adding entry to database.
-	 * 
-	 * @author Piotr Gawron
-	 * 
-	 */
-	private final class AddTask implements Callable<CacheQuery> {
-
-		/**
-		 * Identifier of cached entry.
-		 * 
-		 * @see CacheQuery#query
-		 */
-		private String		query;
-
-		/**
-		 * Type of cached entry.
-		 * 
-		 * @see CacheQuery#type
-		 */
-		private CacheType	type;
-
-		/**
-		 * Value to cache.
-		 * 
-		 * @see CacheQuery#value
-		 */
-		private String		value;
-
-		/**
-		 * Default constructor.
-		 * 
-		 * @param query
-		 *          {@link #query}
-		 * @param type
-		 *          {@link #type}
-		 * @param value
-		 *          {@link #value}
-		 */
-		private AddTask(String query, CacheType type, String value) {
-			logger.debug("Add task start");
-			this.query = query;
-			this.type = type;
-			this.value = value;
-		}
-
-		@Override
-		public CacheQuery call() throws Exception {
-			logger.debug("Add task call");
-			dbUtils.createSessionForCurrentThread();
-			CacheQuery entry = getCacheQueryDao().getByQuery((String) query, type);
-
-			if (entry == null) {
-				entry = new CacheQuery();
-				entry.setQuery((String) query);
-				entry.setAccessed(Calendar.getInstance());
-			} else {
-				entry.setAccessed(Calendar.getInstance());
-			}
-			entry.setValue(value);
-			entry.setType(type);
-			Calendar expires = Calendar.getInstance();
-			expires.add(Calendar.DAY_OF_MONTH, type.getValidity());
-			entry.setExpires(expires);
-
-			getCacheQueryDao().add(entry);
-			dbUtils.closeSessionForCurrentThread();
-			return entry;
-		}
-
-	}
-
-	/**
-	 * This class represents new thread task for removing entry from database.
-	 * 
-	 * @author Piotr Gawron
-	 * 
-	 */
-	private final class RemoveTask implements Callable<CacheQuery> {
-
-		/**
-		 * Identifier of cached entry.
-		 * 
-		 * @see CacheQuery#query
-		 */
-		private String		query;
-
-		/**
-		 * Type of cached entry.
-		 * 
-		 * @see CacheQuery#type
-		 */
-		private CacheType	type;
-
-		/**
-		 * Default constructor.
-		 * 
-		 * @param query
-		 *          {@link #query}
-		 * @param type
-		 *          {@link #type}
-		 */
-		private RemoveTask(String query, CacheType type) {
-			logger.debug("Remove task start");
-			this.query = query;
-			this.type = type;
-		}
-
-		@Override
-		public CacheQuery call() throws Exception {
-			logger.debug("Remove task call");
-			dbUtils.createSessionForCurrentThread();
-			CacheQuery entry = getCacheQueryDao().getByQuery((String) query, type);
-			if (entry != null) {
-				getCacheQueryDao().delete(entry);
-			}
-			dbUtils.closeSessionForCurrentThread();
-			return entry;
-		}
-
-	}
-
-	/**
-	 * This class represents new thread task for invalidating entry in database.
-	 * 
-	 * @author Piotr Gawron
-	 * 
-	 */
-	private final class InvalidateTask implements Callable<CacheQuery> {
-
-		/**
-		 * Identifier of cached entry.
-		 */
-		private String		query;
-
-		/**
-		 * Type of cached entry.
-		 */
-		private CacheType	type;
-
-		/**
-		 * Default constructor.
-		 * 
-		 * @param query
-		 *          {@link #query}
-		 * @param type
-		 *          {@link #type}
-		 */
-		private InvalidateTask(String query, CacheType type) {
-			logger.debug("Invalidate task start");
-			this.query = query;
-			this.type = type;
-		}
-
-		@Override
-		public CacheQuery call() throws Exception {
-			logger.debug("Invalidate task call");
-			dbUtils.createSessionForCurrentThread();
-			try {
-				Calendar date = Calendar.getInstance();
-
-				date.add(Calendar.DATE, -1);
-
-				CacheQuery entry = getCacheQueryDao().getByQuery(query, type);
-				if (entry != null) {
-					entry.setExpires(date);
-					getCacheQueryDao().update(entry);
-					cacheRefreshService.submit(new RefreshTask(query, type));
-				}
-				return entry;
-			} finally {
-				// close session even when we had a problem
-				dbUtils.closeSessionForCurrentThread();
-			}
-		}
-
-	}
-
-	/**
-	 * Spring application context.
-	 */
-	private static ApplicationContext	applicationContext;
-
-	/**
-	 * Default class logger.
-	 */
-	private static Logger							logger = Logger.getLogger(PermanentDatabaseLevelCache.class);
-
-	/**
-	 * Data access object for query entries accessed by string key.
-	 */
-	@Autowired
-	private CacheQueryDao							cacheQueryDao;
-
-	/**
-	 * Utils that help to manage the sessions in custom multithreaded
-	 * implementation.
-	 */
-	@Autowired
-	private DbUtils										dbUtils;
-
-	/**
-	 * Service used for executing database tasks in separate thread.
-	 */
-	private ExecutorService						service;
-
-	/**
-	 * This service is used for execution and queue of the refresh entries in the
-	 * database.
-	 */
-	private ExecutorService						cacheRefreshService;
-
-	/**
-	 * Post init spring method used for initialization of {@link #service} used
-	 * for execution of db tasks.
-	 */
-	@PostConstruct
-	public void init() {
-		// the executor is a daemon thread so that it will get killed automatically
-		// when the main program exits
-		service = Executors.newScheduledThreadPool(1, new ThreadFactory() {
-			@Override
-			public Thread newThread(Runnable r) {
-				Thread t = new Thread(r);
-				t.setDaemon(true);
-				return t;
-			}
-		});
-		cacheRefreshService = Executors.newScheduledThreadPool(1, new ThreadFactory() {
-			@Override
-			public Thread newThread(Runnable r) {
-				Thread t = new Thread(r);
-				t.setDaemon(true);
-				return t;
-			}
-		});
-
-		// put in the queue empty task to make sure that everything was initializedd
-		// (additional managing thread was createed)
-		service.submit(new Callable<Object>() {
-			@Override
-			public Object call() throws Exception {
-				return null;
-			}
-		});
-		cacheRefreshService.submit(new Callable<Object>() {
-			@Override
-			public Object call() throws Exception {
-				return null;
-			}
-		});
-	}
-
-	@Override
-	public void clearCache() {
-		cacheQueryDao.clearTable();
-	}
-
-	@Override
-	public Node getXmlNodeByQuery(String query, CacheType type) {
-		final Future<CacheQuery> task = service.submit(new QueryTask(query, type));
-		CacheQuery entry = executeTask(task);
-
-		if (entry == null) {
-			return null;
-		}
-		try {
-			Document document = getXmlDocumentFromString(entry.getValue());
-			Calendar currentDate = Calendar.getInstance();
-			if (currentDate.after(entry.getExpires())) {
-				cacheRefreshService.submit(new RefreshTask(query, type));
-			}
-			Node result = null;
-			if (document != null) {
-				result = document.getFirstChild();
-			}
-			return result;
-		} catch (InvalidXmlSchemaException e) {
-			logger.warn("Invalid xml for query: " + query);
-			logger.warn("xml: " + entry.getValue());
-			removeByQuery(query, type);
-			return null;
-		}
-	}
-
-	@Override
-	public String getStringByQuery(String query, CacheType type) {
-		Calendar currentDate = Calendar.getInstance();
-		final Future<CacheQuery> task = service.submit(new QueryTask(query, type));
-		CacheQuery entry = executeTask(task);
-		if (entry == null) {
-			return null;
-		}
-		if (currentDate.before(entry.getExpires())) {
-			return entry.getValue();
-		} else {
-			cacheRefreshService.submit(new RefreshTask(query, type));
-			return entry.getValue();
-		}
-	}
-
-	@Override
-	public void setCachedQuery(String query, CacheType type, Object object) {
-		String value = null;
-		if (object instanceof String) {
-			value = (String) object;
-		} else if (object instanceof Node) {
-			value = nodeToString((Node) object, true);
-		} else if (object == null) {
-			value = null;
-		} else {
-			throw new CacheException("Unknown object type: " + object.getClass());
-		}
-		if (value == null) {
-			removeByQuery(query, type);
-		} else {
-			final Future<CacheQuery> task = service.submit(new AddTask(query, type, value));
-			executeTask(task);
-		}
-	}
-
-	@Override
-	public void removeByQuery(String query, CacheType type) {
-		final Future<CacheQuery> task = service.submit(new RemoveTask(query, type));
-		executeTask(task);
-	}
-
-	@Override
-	public void invalidateByQuery(String query, CacheType type) {
-		final Future<CacheQuery> task = service.submit(new InvalidateTask(query, type));
-		executeTask(task);
-	}
-
-	/**
-	 * Executes and returns result of the task provided in the parameter. This
-	 * method is blocking (it's waiting for the results).
-	 * 
-	 * @param task
-	 *          task to be executed
-	 * @return value returned by the task
-	 */
-	private CacheQuery executeTask(final Future<CacheQuery> task) {
-		try {
-			return task.get();
-		} catch (InterruptedException e1) {
-			logger.error(e1, e1);
-		} catch (ExecutionException e1) {
-			logger.error(e1, e1);
-		}
-		return null;
-	}
-
-	@Override
-	public void setApplicationContext(ApplicationContext arg0) {
-		applicationContext = arg0;
-	}
-
-	@Override
-	public int getRefreshPendingQueueSize() {
-		return ((ScheduledThreadPoolExecutor) cacheRefreshService).getQueue().size();
-	}
-
-	@Override
-	public boolean refreshIsBusy() {
-		return getRefreshPendingQueueSize() != 0 || getRefreshExecutingTasksSize() != 0;
-	}
-
-	@Override
-	public int getRefreshExecutingTasksSize() {
-		return ((ScheduledThreadPoolExecutor) cacheRefreshService).getActiveCount();
-	}
-
-	@Override
-	public CacheQueryDao getCacheQueryDao() {
-		return cacheQueryDao;
-	}
-
-	@Override
-	public void setCacheQueryDao(CacheQueryDao cacheQueryDao) {
-		this.cacheQueryDao = cacheQueryDao;
-	}
+public class PermanentDatabaseLevelCache extends XmlParser
+    implements PermanentDatabaseLevelCacheInterface, ApplicationContextAware {
+
+  /**
+   * This class represents new thread task for quering database.
+   * 
+   * @author Piotr Gawron
+   * 
+   */
+  private final class QueryTask implements Callable<CacheQuery> {
+
+    /**
+     * Identifier of cached entry.
+     * 
+     * @see CacheQuery#query
+     */
+    private String query;
+
+    /**
+     * Type of cached entry.
+     * 
+     * @see CacheQuery#type
+     */
+    private CacheType type;
+
+    /**
+     * Default constructor.
+     * 
+     * @param query
+     *          {@link #query}
+     * @param type
+     *          {@link #type}
+     */
+    private QueryTask(String query, CacheType type) {
+      logger.debug("Query task start");
+      this.query = query;
+      this.type = type;
+    }
+
+    @Override
+    public CacheQuery call() throws Exception {
+      logger.debug("Query task call");
+      dbUtils.createSessionForCurrentThread();
+      logger.debug("Query task session started");
+      CacheQuery entry = getCacheQueryDao().getByQuery((String) query, type);
+      logger.debug("Query task data retrieved");
+      dbUtils.closeSessionForCurrentThread();
+      logger.debug("Query task return");
+      return entry;
+    }
+
+  }
+
+  /**
+   * This class represents new thread task for refreshing element in db.
+   * 
+   * @author Piotr Gawron
+   * 
+   */
+  private final class RefreshTask implements Callable<CacheQuery> {
+
+    /**
+     * Identifier of cached entry.
+     * 
+     * @see CacheQuery#query
+     */
+    private String query;
+
+    /**
+     * Type of cached entry.
+     * 
+     * @see CacheQuery#type
+     */
+    private CacheType type;
+
+    /**
+     * Default constructor.
+     * 
+     * @param query
+     *          {@link #query}
+     * @param type
+     *          {@link #type}
+     */
+    private RefreshTask(String query, CacheType type) {
+      logger.debug("Refresh task start (query: " + query + ")");
+      this.query = query;
+      this.type = type;
+    }
+
+    @Override
+    public CacheQuery call() throws Exception {
+      logger.debug("Refresh task call");
+      CachableInterface cachableInterface = null;
+      try {
+        Constructor<?> ctor;
+        Class<?> clazz = Class.forName(type.getClassName());
+        ctor = clazz.getConstructor();
+        Object object = ctor.newInstance();
+        if (object instanceof CachableInterface) {
+          cachableInterface = (CachableInterface) object;
+        } else {
+          logger.fatal(
+              "Invalid class type: " + object.getClass() + ". Class cannot be cast into " + CachableInterface.class);
+        }
+        applicationContext.getAutowireCapableBeanFactory().autowireBean(object);
+
+      } catch (Exception e) {
+        logger.fatal("Problem with creating cache query updater", e);
+      }
+      if (cachableInterface != null) {
+        cachableInterface.setCache(new GeneralCacheWithExclusion(cachableInterface.getCache(), 1));
+        dbUtils.createSessionForCurrentThread();
+        logger.debug("Refresh task session started");
+        try {
+          Object result = cachableInterface.refreshCacheQuery(query);
+          if (result == null) {
+            removeByQuery(query, type);
+          } else {
+            setCachedQuery(query, type, result);
+
+          }
+        } catch (SourceNotAvailable e) {
+          logger.error("Cannot refresh cache", e);
+        } catch (InvalidArgumentException e) {
+          removeByQuery(query, type);
+          logger.error("Problem with refreshing. Invalid data to refresh", e);
+        } catch (Exception e) {
+          logger.error("Severe problem in cache", e);
+        } finally {
+          // close the transaction for this thread
+          dbUtils.closeSessionForCurrentThread();
+          logger.debug("Refresh task session closed");
+        }
+      }
+      logger.debug("Refresh task finish");
+      final Future<CacheQuery> task = service.submit(new QueryTask(query, type));
+      return task.get();
+    }
+
+  }
+
+  /**
+   * This class represents new thread task for adding entry to database.
+   * 
+   * @author Piotr Gawron
+   * 
+   */
+  private final class AddTask implements Callable<CacheQuery> {
+
+    /**
+     * Identifier of cached entry.
+     * 
+     * @see CacheQuery#query
+     */
+    private String query;
+
+    /**
+     * Type of cached entry.
+     * 
+     * @see CacheQuery#type
+     */
+    private CacheType type;
+
+    /**
+     * Value to cache.
+     * 
+     * @see CacheQuery#value
+     */
+    private String value;
+
+    /**
+     * How long should the entry be valid in days.
+     * 
+     */
+    private int validDays;
+
+    /**
+     * Default constructor.
+     * 
+     * @param query
+     *          {@link #query}
+     * @param type
+     *          {@link #type}
+     * @param value
+     *          {@link #value}
+     */
+    private AddTask(String query, CacheType type, String value, int validDays) {
+      logger.debug("Add task start");
+      this.query = query;
+      this.type = type;
+      this.value = value;
+      this.validDays = validDays;
+    }
+
+    @Override
+    public CacheQuery call() throws Exception {
+      logger.debug("Add task call");
+      dbUtils.createSessionForCurrentThread();
+      CacheQuery entry = getCacheQueryDao().getByQuery((String) query, type);
+
+      if (entry == null) {
+        entry = new CacheQuery();
+        entry.setQuery((String) query);
+        entry.setAccessed(Calendar.getInstance());
+      } else {
+        entry.setAccessed(Calendar.getInstance());
+      }
+      entry.setValue(value);
+      entry.setType(type);
+      Calendar expires = Calendar.getInstance();
+      expires.add(Calendar.DAY_OF_MONTH, validDays);
+      entry.setExpires(expires);
+
+      getCacheQueryDao().add(entry);
+      dbUtils.closeSessionForCurrentThread();
+      return entry;
+    }
+
+  }
+
+  /**
+   * This class represents new thread task for removing entry from database.
+   * 
+   * @author Piotr Gawron
+   * 
+   */
+  private final class RemoveTask implements Callable<CacheQuery> {
+
+    /**
+     * Identifier of cached entry.
+     * 
+     * @see CacheQuery#query
+     */
+    private String query;
+
+    /**
+     * Type of cached entry.
+     * 
+     * @see CacheQuery#type
+     */
+    private CacheType type;
+
+    /**
+     * Default constructor.
+     * 
+     * @param query
+     *          {@link #query}
+     * @param type
+     *          {@link #type}
+     */
+    private RemoveTask(String query, CacheType type) {
+      logger.debug("Remove task start");
+      this.query = query;
+      this.type = type;
+    }
+
+    @Override
+    public CacheQuery call() throws Exception {
+      logger.debug("Remove task call");
+      dbUtils.createSessionForCurrentThread();
+      CacheQuery entry = getCacheQueryDao().getByQuery((String) query, type);
+      if (entry != null) {
+        getCacheQueryDao().delete(entry);
+      }
+      dbUtils.closeSessionForCurrentThread();
+      return entry;
+    }
+
+  }
+
+  /**
+   * This class represents new thread task for invalidating entry in database.
+   * 
+   * @author Piotr Gawron
+   * 
+   */
+  private final class InvalidateTask implements Callable<CacheQuery> {
+
+    /**
+     * Identifier of cached entry.
+     */
+    private String query;
+
+    /**
+     * Type of cached entry.
+     */
+    private CacheType type;
+
+    /**
+     * Default constructor.
+     * 
+     * @param query
+     *          {@link #query}
+     * @param type
+     *          {@link #type}
+     */
+    private InvalidateTask(String query, CacheType type) {
+      logger.debug("Invalidate task start");
+      this.query = query;
+      this.type = type;
+    }
+
+    @Override
+    public CacheQuery call() throws Exception {
+      logger.debug("Invalidate task call");
+      dbUtils.createSessionForCurrentThread();
+      try {
+        Calendar date = Calendar.getInstance();
+
+        date.add(Calendar.DATE, -1);
+
+        CacheQuery entry = getCacheQueryDao().getByQuery(query, type);
+        if (entry != null) {
+          entry.setExpires(date);
+          getCacheQueryDao().update(entry);
+          cacheRefreshService.submit(new RefreshTask(query, type));
+        }
+        return entry;
+      } finally {
+        // close session even when we had a problem
+        dbUtils.closeSessionForCurrentThread();
+      }
+    }
+
+  }
+
+  /**
+   * Spring application context.
+   */
+  private static ApplicationContext applicationContext;
+
+  /**
+   * Default class logger.
+   */
+  private static Logger logger = Logger.getLogger(PermanentDatabaseLevelCache.class);
+
+  /**
+   * Data access object for query entries accessed by string key.
+   */
+  @Autowired
+  private CacheQueryDao cacheQueryDao;
+
+  /**
+   * Utility that help to manage the sessions in custom multithreaded
+   * implementation.
+   */
+  @Autowired
+  private DbUtils dbUtils;
+
+  /**
+   * Service used for executing database tasks in separate thread.
+   */
+  private ExecutorService service;
+
+  /**
+   * This service is used for execution and queue of the refresh entries in the
+   * database.
+   */
+  private ExecutorService cacheRefreshService;
+
+  /**
+   * Post init spring method used for initialization of {@link #service} used for
+   * execution of db tasks.
+   */
+  @PostConstruct
+  public void init() {
+    // the executor is a daemon thread so that it will get killed automatically
+    // when the main program exits
+    service = Executors.newScheduledThreadPool(1, new ThreadFactory() {
+      @Override
+      public Thread newThread(Runnable r) {
+        Thread t = new Thread(r);
+        t.setDaemon(true);
+        return t;
+      }
+    });
+    cacheRefreshService = Executors.newScheduledThreadPool(1, new ThreadFactory() {
+      @Override
+      public Thread newThread(Runnable r) {
+        Thread t = new Thread(r);
+        t.setDaemon(true);
+        return t;
+      }
+    });
+
+    // put in the queue empty task to make sure that everything was initializedd
+    // (additional managing thread was createed)
+    service.submit(new Callable<Object>() {
+      @Override
+      public Object call() throws Exception {
+        return null;
+      }
+    });
+    cacheRefreshService.submit(new Callable<Object>() {
+      @Override
+      public Object call() throws Exception {
+        return null;
+      }
+    });
+  }
+
+  @Override
+  public void clearCache() {
+    cacheQueryDao.clearTable();
+  }
+
+  @Override
+  public Node getXmlNodeByQuery(String query, CacheType type) {
+    final Future<CacheQuery> task = service.submit(new QueryTask(query, type));
+    CacheQuery entry = executeTask(task);
+
+    if (entry == null) {
+      return null;
+    }
+    try {
+      Document document = getXmlDocumentFromString(entry.getValue());
+      Calendar currentDate = Calendar.getInstance();
+      if (currentDate.after(entry.getExpires())) {
+        cacheRefreshService.submit(new RefreshTask(query, type));
+      }
+      Node result = null;
+      if (document != null) {
+        result = document.getFirstChild();
+      }
+      return result;
+    } catch (InvalidXmlSchemaException e) {
+      logger.warn("Invalid xml for query: " + query);
+      logger.warn("xml: " + entry.getValue());
+      removeByQuery(query, type);
+      return null;
+    }
+  }
+
+  @Override
+  public String getStringByQuery(String query, CacheType type) {
+    Calendar currentDate = Calendar.getInstance();
+    final Future<CacheQuery> task = service.submit(new QueryTask(query, type));
+    CacheQuery entry = executeTask(task);
+    if (entry == null) {
+      return null;
+    }
+    if (currentDate.before(entry.getExpires())) {
+      return entry.getValue();
+    } else {
+      cacheRefreshService.submit(new RefreshTask(query, type));
+      return entry.getValue();
+    }
+  }
+
+  @Override
+  public void setCachedQuery(String query, CacheType type, Object object) {
+    setCachedQuery(query, type, object, type.getValidity());
+  }
+
+  @Override
+  public void setCachedQuery(String query, CacheType type, Object object, int validDays) {
+    String value = null;
+    if (object instanceof String) {
+      value = (String) object;
+    } else if (object instanceof Node) {
+      value = nodeToString((Node) object, true);
+    } else if (object == null) {
+      value = null;
+    } else {
+      throw new CacheException("Unknown object type: " + object.getClass());
+    }
+    if (value == null) {
+      removeByQuery(query, type);
+    } else {
+      final Future<CacheQuery> task = service.submit(new AddTask(query, type, value, validDays));
+      executeTask(task);
+    }
+  }
+
+  @Override
+  public void removeByQuery(String query, CacheType type) {
+    final Future<CacheQuery> task = service.submit(new RemoveTask(query, type));
+    executeTask(task);
+  }
+
+  @Override
+  public void invalidateByQuery(String query, CacheType type) {
+    final Future<CacheQuery> task = service.submit(new InvalidateTask(query, type));
+    executeTask(task);
+  }
+
+  /**
+   * Executes and returns result of the task provided in the parameter. This
+   * method is blocking (it's waiting for the results).
+   * 
+   * @param task
+   *          task to be executed
+   * @return value returned by the task
+   */
+  private CacheQuery executeTask(final Future<CacheQuery> task) {
+    try {
+      return task.get();
+    } catch (InterruptedException e1) {
+      logger.error(e1, e1);
+    } catch (ExecutionException e1) {
+      logger.error(e1, e1);
+    }
+    return null;
+  }
+
+  @Override
+  public void setApplicationContext(ApplicationContext arg0) {
+    applicationContext = arg0;
+  }
+
+  @Override
+  public int getRefreshPendingQueueSize() {
+    return ((ScheduledThreadPoolExecutor) cacheRefreshService).getQueue().size();
+  }
+
+  @Override
+  public boolean refreshIsBusy() {
+    return getRefreshPendingQueueSize() != 0 || getRefreshExecutingTasksSize() != 0;
+  }
+
+  @Override
+  public int getRefreshExecutingTasksSize() {
+    return ((ScheduledThreadPoolExecutor) cacheRefreshService).getActiveCount();
+  }
+
+  @Override
+  public CacheQueryDao getCacheQueryDao() {
+    return cacheQueryDao;
+  }
+
+  @Override
+  public void setCacheQueryDao(CacheQueryDao cacheQueryDao) {
+    this.cacheQueryDao = cacheQueryDao;
+  }
 
 }
\ No newline at end of file
diff --git a/annotation/src/main/java/lcsb/mapviewer/annotation/cache/PermanentDatabaseLevelCacheInterface.java b/annotation/src/main/java/lcsb/mapviewer/annotation/cache/PermanentDatabaseLevelCacheInterface.java
index 8a33101cbf9c43e253dc78940bdd403b4d96dfd7..438685d1fe2a6c3af43e3740cae225725f7e2ff1 100644
--- a/annotation/src/main/java/lcsb/mapviewer/annotation/cache/PermanentDatabaseLevelCacheInterface.java
+++ b/annotation/src/main/java/lcsb/mapviewer/annotation/cache/PermanentDatabaseLevelCacheInterface.java
@@ -27,9 +27,9 @@ public interface PermanentDatabaseLevelCacheInterface extends QueryCacheInterfac
 	boolean refreshIsBusy();
 
 	/**
-	 * Returns aproximate number of refresh tasks that are currently executed.
+	 * Returns approximate number of refresh tasks that are currently executed.
 	 * 
-	 * @return aproximate number of refresh tasks that are currently executed.
+	 * @return approximate number of refresh tasks that are currently executed.
 	 */
 	int getRefreshExecutingTasksSize();
 
diff --git a/annotation/src/main/java/lcsb/mapviewer/annotation/cache/QueryCacheInterface.java b/annotation/src/main/java/lcsb/mapviewer/annotation/cache/QueryCacheInterface.java
index 5609ec00c8587249735285c1bacc4637dbd364d0..bb18339908e72d97c2d058a4564b1ed54b6bb89f 100644
--- a/annotation/src/main/java/lcsb/mapviewer/annotation/cache/QueryCacheInterface.java
+++ b/annotation/src/main/java/lcsb/mapviewer/annotation/cache/QueryCacheInterface.java
@@ -12,67 +12,69 @@ import org.w3c.dom.Node;
  */
 public interface QueryCacheInterface {
 
-	/**
-	 * Returns xml node from the cache. The entry (xml node in this case) is
-	 * identified by string and type associated with the entry.
-	 * 
-	 * @param identifier
-	 *          string identifing node in the database
-	 * @param type
-	 *          type of the entry
-	 * @return node from cache for given identifier and type
-	 */
-	Node getXmlNodeByQuery(String identifier, CacheType type);
+  /**
+   * Returns xml node from the cache. The entry (xml node in this case) is
+   * identified by string and type associated with the entry.
+   * 
+   * @param identifier
+   *          string identifying node in the database
+   * @param type
+   *          type of the entry
+   * @return node from cache for given identifier and type
+   */
+  Node getXmlNodeByQuery(String identifier, CacheType type);
 
-	/**
-	 * Returns string from the cache. The entry (string in this case) is
-	 * identified by string and type associated with the entry.
-	 * 
-	 * @param identifier
-	 *          string identifing node in the database
-	 * @param type
-	 *          type of the entry
-	 * @return node from cache for given string identifier and type
-	 */
-	String getStringByQuery(String identifier, CacheType type);
+  /**
+   * Returns string from the cache. The entry (string in this case) is identified
+   * by string and type associated with the entry.
+   * 
+   * @param identifier
+   *          string identifying node in the database
+   * @param type
+   *          type of the entry
+   * @return node from cache for given string identifier and type
+   */
+  String getStringByQuery(String identifier, CacheType type);
 
-	/**
-	 * Puts new value into cache. The entry is identified with type and identfier.
-	 * 
-	 * @param identifier
-	 *          string identifing entry in the database
-	 * @param type
-	 *          type of the entry
-	 * @param value
-	 *          value to be stored in the cache
-	 */
-	void setCachedQuery(String identifier, CacheType type, Object value);
+  /**
+   * Puts new value into cache. The entry is identified with type and identifier.
+   * 
+   * @param identifier
+   *          string identifying entry in the database
+   * @param type
+   *          type of the entry
+   * @param value
+   *          value to be stored in the cache
+   */
+  void setCachedQuery(String identifier, CacheType type, Object value);
+  
+  void setCachedQuery(String identifier, CacheType type, Object value, int validDays);
 
-	/**
-	 * Clears permanently whole cache.
-	 */
-	void clearCache();
+  /**
+   * Clears permanently whole cache.
+   */
+  void clearCache();
 
-	/**
-	 * Removes element from the database.
-	 * 
-	 * @param identifier
-	 *          string identifing entry in the database
-	 * @param type
-	 *          type of the entry
-	 */
-	void removeByQuery(String identifier, CacheType type);
+  /**
+   * Removes element from the database.
+   * 
+   * @param identifier
+   *          string identifying entry in the database
+   * @param type
+   *          type of the entry
+   */
+  void removeByQuery(String identifier, CacheType type);
 
-	/**
-	 * This method invalidate result, but doesn't remove it (data should be
-	 * available until resource will be updated from original source). Moreover,
-	 * value reload method is called.
-	 * 
-	 * @param identifier
-	 *          string identifing entry in the database
-	 * @param type
-	 *          type of the entry
-	 */
-	void invalidateByQuery(String identifier, CacheType type);
+  /**
+   * This method invalidate result, but doesn't remove it (data should be
+   * available until resource will be updated from original source). Moreover,
+   * value reload method is called.
+   * 
+   * @param identifier
+   *          string identifying entry in the database
+   * @param type
+   *          type of the entry
+   */
+  void invalidateByQuery(String identifier, CacheType type);
 
 }
diff --git a/annotation/src/main/java/lcsb/mapviewer/annotation/services/MiriamConnector.java b/annotation/src/main/java/lcsb/mapviewer/annotation/services/MiriamConnector.java
index 6cf4f1819003508f194c5b31dd5d6d2311df6c78..e12b3fea8767325fabcdc51bb2c2554a97f51c94 100644
--- a/annotation/src/main/java/lcsb/mapviewer/annotation/services/MiriamConnector.java
+++ b/annotation/src/main/java/lcsb/mapviewer/annotation/services/MiriamConnector.java
@@ -1,19 +1,20 @@
 package lcsb.mapviewer.annotation.services;
 
 import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 import org.apache.log4j.Logger;
 import org.hibernate.AnnotationException;
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
+
+import com.google.gson.Gson;
 
 import lcsb.mapviewer.annotation.cache.CachableInterface;
 import lcsb.mapviewer.annotation.cache.GeneralCacheInterface;
 import lcsb.mapviewer.annotation.cache.SourceNotAvailable;
 import lcsb.mapviewer.annotation.cache.WebPageDownloader;
 import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.common.exception.InvalidXmlSchemaException;
 import lcsb.mapviewer.model.map.MiriamData;
 import lcsb.mapviewer.model.map.MiriamRelationType;
 import lcsb.mapviewer.model.map.MiriamType;
@@ -101,7 +102,8 @@ public final class MiriamConnector extends CachableInterface implements IExterna
       return result;
     } else {
       logger.warn("Cannot find url for miriam: " + miriamData);
-      setCacheValue(query, INVALID_LINK);
+      // if url cannot be found then mark miriam data as invalid for one day
+      setCacheValue(query, INVALID_LINK, 1);
       return null;
     }
   }
@@ -218,26 +220,20 @@ public final class MiriamConnector extends CachableInterface implements IExterna
   protected String getUrlString2(MiriamData md) throws AnnotationException {
     try {
       String result = null;
-      String uri = md.getDataType().getUris().get(0) + ":" + md.getResource();
-      String query = "https://www.ebi.ac.uk/miriamws/main/rest/resolve/" + uri;
-      String page;
-      page = getWebPageContent(query);
-      Document document = getXmlDocumentFromString(page);
-      Node uris = document.getFirstChild();
-      NodeList nodes = uris.getChildNodes();
-      for (int i = 0; i < nodes.getLength(); i++) {
-        Node node = nodes.item(i);
-        if (Node.ELEMENT_NODE == node.getNodeType()) {
-          if (getNodeAttr("deprecated", node).equals("")) {
-            result = node.getTextContent();
-          }
-        }
-      }
+      String queryUri = md.getDataType().getUris().get(0) + ":" + md.getResource();
+      String query = "https://www.ebi.ac.uk/miriamws/main/rest/resolve/" + queryUri;
+      String page = getWebPageContent(query);
+      Gson gson = new Gson();
+
+      Map<?, ?> gsonObject = new HashMap<String, Object>();
+      gsonObject = (Map<?, ?>) gson.fromJson(page, gsonObject.getClass());
+      Object uris = gsonObject.get("uri");
+      Map<?, ?> entry = (Map<?, ?>) ((List<?>) uris).get(0);
+      result = (String) entry.get("$");
+
       return result;
-    } catch (IOException e) {
+    } catch (Exception e) {
       throw new AnnotationException("Problem with accessing miriam REST API", e);
-    } catch (InvalidXmlSchemaException e) {
-      throw new AnnotationException("Problem with parsing miriam REST API response", e);
     }
   }
 
diff --git a/annotation/src/test/java/lcsb/mapviewer/annotation/cache/CacheMock.java b/annotation/src/test/java/lcsb/mapviewer/annotation/cache/CacheMock.java
deleted file mode 100644
index ec075bc30c7f706e76e702dcf780e79f44bed65b..0000000000000000000000000000000000000000
--- a/annotation/src/test/java/lcsb/mapviewer/annotation/cache/CacheMock.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package lcsb.mapviewer.annotation.cache;
-
-import lcsb.mapviewer.model.cache.CacheType;
-
-import org.w3c.dom.Node;
-
-public class CacheMock implements GeneralCacheInterface {
-
-	@Override
-	public Node getXmlNodeByQuery(String query, CacheType type) {
-		// TODO Auto-generated method stub
-		return null;
-	}
-
-	@Override
-	public String getStringByQuery(String query, CacheType source) {
-		// TODO Auto-generated method stub
-		return null;
-	}
-
-	@Override
-	public void setCachedQuery(String query, CacheType type, Object node) {
-		// TODO Auto-generated method stub
-		
-	}
-
-	@Override
-	public void clearCache() {
-		// TODO Auto-generated method stub
-		
-	}
-
-	@Override
-	public void removeByQuery(String query, CacheType type) {
-		// TODO Auto-generated method stub
-		
-	}
-
-	@Override
-	public void invalidateByQuery(String query, CacheType type) {
-		// TODO Auto-generated method stub
-		
-	}
-
-}
diff --git a/annotation/src/test/java/lcsb/mapviewer/annotation/services/ChemicalParserTest.java b/annotation/src/test/java/lcsb/mapviewer/annotation/services/ChemicalParserTest.java
index 2d3691370ea8957217e4949272371ba17546db4e..99899cb5e7b95b28c259dc3f49bcf16dc72d0ead 100644
--- a/annotation/src/test/java/lcsb/mapviewer/annotation/services/ChemicalParserTest.java
+++ b/annotation/src/test/java/lcsb/mapviewer/annotation/services/ChemicalParserTest.java
@@ -574,6 +574,7 @@ public class ChemicalParserTest extends AnnotationTestFunctions {
   public void testGetEmptySuggestedQueryList() throws Exception {
     try {
       Project project = new Project();
+      project.setId(-1);
 
       List<String> result = chemicalParser.getSuggestedQueryList(project, parkinsonDiseaseId);
 
diff --git a/annotation/src/test/java/lcsb/mapviewer/annotation/services/MiriamConnectorTest.java b/annotation/src/test/java/lcsb/mapviewer/annotation/services/MiriamConnectorTest.java
index a8b145d6cf2e48606c049f7fb7842f0f469ae1be..85d4105e01be05a67a1a7dc2fb85f3f9498856ac 100644
--- a/annotation/src/test/java/lcsb/mapviewer/annotation/services/MiriamConnectorTest.java
+++ b/annotation/src/test/java/lcsb/mapviewer/annotation/services/MiriamConnectorTest.java
@@ -219,16 +219,16 @@ public class MiriamConnectorTest extends AnnotationTestFunctions {
     }
   }
 
-	@Test
-	public void testGetUrl2WithInvalidApiResponse() throws Exception {
-		WebPageDownloader downloader = miriamConnector.getWebPageDownloader();
-		GeneralCacheInterface cache = miriamConnector.getCache();
-		try {
-			// exclude first cached value
-			miriamConnector.setCache(new GeneralCacheWithExclusion(cache, 1));
-			WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class);
-			when(mockDownloader.getFromNetwork(anyString(), anyString(), anyString())).thenThrow(new IOException());
-			miriamConnector.setWebPageDownloader(mockDownloader);
+  @Test
+  public void testGetUrl2WithInvalidApiResponse() throws Exception {
+    WebPageDownloader downloader = miriamConnector.getWebPageDownloader();
+    GeneralCacheInterface cache = miriamConnector.getCache();
+    try {
+      // exclude first cached value
+      miriamConnector.setCache(new GeneralCacheWithExclusion(cache, 1));
+      WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class);
+      when(mockDownloader.getFromNetwork(anyString(), anyString(), anyString())).thenThrow(new IOException());
+      miriamConnector.setWebPageDownloader(mockDownloader);
 
       miriamConnector.getUrlString2(TaxonomyBackend.HUMAN_TAXONOMY);
 
@@ -243,49 +243,24 @@ public class MiriamConnectorTest extends AnnotationTestFunctions {
     }
   }
 
-	@Test
-	public void testGetUrl2WithInvalidApiResponse2() throws Exception {
-		WebPageDownloader downloader = miriamConnector.getWebPageDownloader();
-		GeneralCacheInterface cache = miriamConnector.getCache();
-		try {
-			// exclude first cached value
-			miriamConnector.setCache(new GeneralCacheWithExclusion(cache, 1));
-			WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class);
-			when(mockDownloader.getFromNetwork(anyString(), anyString(), anyString())).thenReturn("");
-			miriamConnector.setWebPageDownloader(mockDownloader);
-
-      miriamConnector.getUrlString2(TaxonomyBackend.HUMAN_TAXONOMY);
-
-    } catch (AnnotationException e) {
-      assertTrue(e.getMessage().contains("Problem with parsing miriam REST API response"));
+  @Test
+  public void testRefreshCacheQueryNotAvailable() throws Exception {
+    WebPageDownloader downloader = miriamConnector.getWebPageDownloader();
+    try {
+      WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class);
+      when(mockDownloader.getFromNetwork(anyString(), anyString(), anyString())).thenThrow(new IOException());
+      miriamConnector.setWebPageDownloader(mockDownloader);
+      miriamConnector.refreshCacheQuery("http://google.pl/");
+      fail("Exception expected");
+    } catch (SourceNotAvailable e) {
     } catch (Exception e) {
       e.printStackTrace();
       throw e;
     } finally {
       miriamConnector.setWebPageDownloader(downloader);
-      miriamConnector.setCache(cache);
     }
   }
 
-
-	@Test
-	public void testRefreshCacheQueryNotAvailable() throws Exception {
-		WebPageDownloader downloader = miriamConnector.getWebPageDownloader();
-		try {
-			WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class);
-			when(mockDownloader.getFromNetwork(anyString(), anyString(), anyString())).thenThrow(new IOException());
-			miriamConnector.setWebPageDownloader(mockDownloader);
-			miriamConnector.refreshCacheQuery("http://google.pl/");
-			fail("Exception expected");
-		} catch (SourceNotAvailable e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		} finally {
-			miriamConnector.setWebPageDownloader(downloader);
-		}
-	}
-
   @Test
   public void testRefreshInvalidCacheQuery() throws Exception {
     try {
diff --git a/persist/src/db/11.1.0/fix_db_20170713.sql b/persist/src/db/12.0.0/fix_db_20170713.sql
similarity index 100%
rename from persist/src/db/11.1.0/fix_db_20170713.sql
rename to persist/src/db/12.0.0/fix_db_20170713.sql
diff --git a/persist/src/db/11.1.0/fix_db_20170720.sql b/persist/src/db/12.0.0/fix_db_20170720.sql
similarity index 100%
rename from persist/src/db/11.1.0/fix_db_20170720.sql
rename to persist/src/db/12.0.0/fix_db_20170720.sql
diff --git a/persist/src/db/11.1.0/fix_db_20170808.sql b/persist/src/db/12.0.0/fix_db_20170808.sql
similarity index 100%
rename from persist/src/db/11.1.0/fix_db_20170808.sql
rename to persist/src/db/12.0.0/fix_db_20170808.sql
diff --git a/persist/src/db/11.1.0/fix_db_20170809.sql b/persist/src/db/12.0.0/fix_db_20170809.sql
similarity index 100%
rename from persist/src/db/11.1.0/fix_db_20170809.sql
rename to persist/src/db/12.0.0/fix_db_20170809.sql
diff --git a/persist/src/db/11.1.0/fix_db_20170814.sql b/persist/src/db/12.0.0/fix_db_20170814.sql
similarity index 100%
rename from persist/src/db/11.1.0/fix_db_20170814.sql
rename to persist/src/db/12.0.0/fix_db_20170814.sql
diff --git a/persist/src/db/11.1.0/fix_db_20170822.sql b/persist/src/db/12.0.0/fix_db_20170822.sql
similarity index 100%
rename from persist/src/db/11.1.0/fix_db_20170822.sql
rename to persist/src/db/12.0.0/fix_db_20170822.sql
diff --git a/persist/src/db/11.1.0/fix_db_20170829.sql b/persist/src/db/12.0.0/fix_db_20170829.sql
similarity index 100%
rename from persist/src/db/11.1.0/fix_db_20170829.sql
rename to persist/src/db/12.0.0/fix_db_20170829.sql
diff --git a/persist/src/db/11.1.0/fix_db_20171004.sql b/persist/src/db/12.0.0/fix_db_20171004.sql
similarity index 100%
rename from persist/src/db/11.1.0/fix_db_20171004.sql
rename to persist/src/db/12.0.0/fix_db_20171004.sql
diff --git a/persist/src/db/12.0.0/fix_db_20171115.sql b/persist/src/db/12.0.0/fix_db_20171115.sql
new file mode 100644
index 0000000000000000000000000000000000000000..62d0d3dd86c590d372c335a5eea3c97321e7edc2
--- /dev/null
+++ b/persist/src/db/12.0.0/fix_db_20171115.sql
@@ -0,0 +1,2 @@
+-- clear invalid urls from miriam connector
+delete from cachequery where type = (select iddb from cache_type where classname='lcsb.mapviewer.annotation.services.MiriamConnector') and value = 'INVALID';