diff --git a/annotation/src/main/java/lcsb/mapviewer/annotation/cache/BigFileCache.java b/annotation/src/main/java/lcsb/mapviewer/annotation/cache/BigFileCache.java
index 3592481abe7510344f9d9779be234283b507e7eb..11c9daa14e79f986a40b9aa9ec44f94f08043090 100644
--- a/annotation/src/main/java/lcsb/mapviewer/annotation/cache/BigFileCache.java
+++ b/annotation/src/main/java/lcsb/mapviewer/annotation/cache/BigFileCache.java
@@ -48,848 +48,848 @@ import lcsb.mapviewer.persist.dao.cache.BigFileEntryDao;
  */
 public class BigFileCache {
 
-	/**
-	 * Buffer size used for downloading single chunk of a file.
-	 */
-	private static final int DOWNLOAD_BUFFER_SIZE	= 1024;
-
-	/**
-	 * Default class logger.
-	 */
-	private Logger					 logger								= Logger.getLogger(BigFileCache.class);
-
-	/**
-	 * Access class for database objects storing statuses of the files.
-	 */
-	@Autowired
-	private BigFileEntryDao	 bigFileEntryDao;
-
-	/**
-	 * Access class for database objects storing some configuration information.
-	 */
-	@Autowired
-	private ConfigurationDao configurationDao;
-
-	/**
-	 * Utils that help to manage the sessions in custom multithreaded
-	 * implementation.
-	 */
-	@Autowired
-	private DbUtils					 dbUtils;
-
-	/**
-	 * Service used for executing tasks in separate thread.
-	 */
-	private ExecutorService	 asyncExecutorService;
-
-	/**
-	 * Service used for executing tasks immediately.
-	 */
-	private ExecutorService	 syncExecutorService;
-
-	/**
-	 * Factory class used to create {@link FTPClient} objects.
-	 */
-	private FtpClientFactory ftpClientFactory			= new FtpClientFactory();
-
-	/**
-	 * Default constructor.
-	 */
-	public BigFileCache() {
-		// the executor is a daemon thread so that it will get killed automatically
-		// when the main program exits
-		asyncExecutorService = Executors.newScheduledThreadPool(10, new ThreadFactory() {
-			@Override
-			public Thread newThread(Runnable r) {
-				Thread t = new Thread(r);
-				t.setDaemon(true);
-				return t;
-			}
-		});
-		syncExecutorService = 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 initialized
-		// (additional managing thread was createed)
-		asyncExecutorService.submit(new Callable<Object>() {
-			@Override
-			public Object call() throws Exception {
-				return null;
-			}
-		});
-		syncExecutorService.submit(new Callable<Object>() {
-			@Override
-			public Object call() throws Exception {
-				return null;
-			}
-		});
-	}
-
-	/**
-	 * Returns a path for a file in local file system.
-	 * 
-	 * @param url
-	 *          ftp url to the file
-	 * @return a path for a file in local file systeml
-	 * @throws FileNotFoundException
-	 *           thrown when file should be in file system, but couldn't be found
-	 *           there (somebody manually removed it)
-	 */
-	public String getAbsolutePathForFile(String url) throws FileNotFoundException {
-		BigFileEntry entry = bigFileEntryDao.getByUrl(url);
-		if (entry == null) {
-			return null;
-		}
-		if (entry.getDownloadProgress() == null || entry.getDownloadProgress() < 100.0) {
-			throw new FileNotFoundException("File is not complete: " + entry.getLocalPath() + ". Downloaded from: " + url);
-		}
-		File f = new File(Configuration.getWebAppDir() + entry.getLocalPath());
-		if (!f.exists()) {
-			throw new FileNotFoundException("Missing big file: " + Configuration.getWebAppDir() + entry.getLocalPath() + ". Downloaded from: " + url);
-		}
-
-		return f.getAbsolutePath();
-	}
-
-	/**
-	 * Returns a path for a file in local file system for an ftp url.
-	 * 
-	 * @param url
-	 *          ftp url to the file
-	 * @return a path for a file in local file system for an ftp url
-	 * @throws FileNotFoundException
-	 *           thrown when file should be in file system, but couldn't be found
-	 *           there (somebody manually removed it)
-	 */
-	public String getLocalPathForFile(String url) throws FileNotFoundException {
-		BigFileEntry entry = bigFileEntryDao.getByUrl(url);
-		if (entry == null) {
-			return null;
-		}
-		if (entry.getDownloadProgress() == null || entry.getDownloadProgress() < 100.0) {
-			throw new FileNotFoundException("File is not complete: " + entry.getLocalPath() + ". Downloaded from: " + url);
-		}
-		File f = new File(Configuration.getWebAppDir() + entry.getLocalPath());
-		if (!f.exists()) {
-			throw new FileNotFoundException("Missing big file: " + Configuration.getWebAppDir() + entry.getLocalPath() + ". Downloaded from: " + url);
-		}
-
-		return entry.getLocalPath();
-	}
-
-	/**
-	 * Download big file from ftp server.
-	 * 
-	 * @param url
-	 *          url for file to download
-	 * @param async
-	 *          <code>true</code> if should the download be asynchronous
-	 * @param updater
-	 *          callback emthod that will be called with info updates about
-	 *          downloading process
-	 * @throws IOException
-	 *           thrown when there is a problem with downloading file
-	 * @throws URISyntaxException
-	 *           thrown when url is invalid
-	 */
-	public void downloadFile(String url, boolean async, IProgressUpdater updater) throws IOException, URISyntaxException {
-		Callable<Void> computations = null;
-		if (url.toLowerCase().startsWith("ftp:")) {
-			computations = new GetFtpFileTask(url, updater);
-		} else if (url.toLowerCase().startsWith("http:") || url.toLowerCase().startsWith("https:")) {
-			computations = new GetHttpFileTask(url, updater);
-		} else {
-			throw new URISyntaxException(url, "Unknown protocol for url");
-		}
-
-		if (async) {
-			asyncExecutorService.submit(computations);
-		} else {
-			Future<Void> task = syncExecutorService.submit(computations);
-			executeTask(task);
-		}
-	}
-
-	/**
-	 * Creates new {@link BigFileEntry} for given url.
-	 * 
-	 * @param url
-	 *          url for which entry will be created
-	 * @return new {@link BigFileEntry} for given url
-	 * @throws URISyntaxException
-	 *           thrown when url is invalid
-	 */
-	private BigFileEntry createEntryForBigFile(String url) throws URISyntaxException {
-		String localPath = configurationDao.getValueByType(ConfigurationElementType.BIG_FILE_STORAGE_DIR);
-		BigFileEntry entry = new BigFileEntry();
-		entry.setDownloadDate(Calendar.getInstance());
-		entry.setLocalPath(localPath);
-		entry.setUrl(url);
-		bigFileEntryDao.add(entry);
-
-		localPath = entry.getLocalPath() + "/" + entry.getId() + "/";
-		new File(Configuration.getWebAppDir() + localPath).mkdirs();
-		localPath += getFileName(url);
-
-		entry.setLocalPath(localPath);
-		bigFileEntryDao.update(entry);
-		bigFileEntryDao.flush();
-		return entry;
-	}
-
-	/**
-	 * Task that will be able to fetch file from ftp server.
-	 * 
-	 * @author Piotr Gawron
-	 *
-	 */
-	private final class GetFtpFileTask implements Callable<Void> {
-
-		/**
-		 * Url to the file that we want to download.
-		 * 
-		 */
-		private String					 url;
-
-		/**
-		 * Callback listener that will receive information about upload progress.
-		 * 
-		 */
-		private IProgressUpdater updater;
-
-		/**
-		 * Default constructor.
-		 * 
-		 * @param url
-		 *          {@link #url}
-		 * @param updater
-		 *          {@link #updater}
-		 */
-		private GetFtpFileTask(String url, IProgressUpdater updater) {
-			this.url = url;
-			if (updater != null) {
-				this.updater = updater;
-			} else {
-				this.updater = new IProgressUpdater() {
-					@Override
-					public void setProgress(double progress) {
-					}
-				};
-			}
-		}
-
-		@Override
-		public Void call() throws Exception {
-			dbUtils.createSessionForCurrentThread();
-			FTPClient ftp = ftpClientFactory.createFtpClient();
-			try {
-				try {
-					if (getAbsolutePathForFile(url) != null) {
-						logger.warn("File already downloaded. Skipping...");
-						return null;
-					}
-				} catch (FileNotFoundException e) {
-					removeFile(url);
-				}
-
-				BigFileEntry entry = createEntryForBigFile(url);
-				entry.setDownloadThreadId(Thread.currentThread().getId());
-				bigFileEntryDao.update(entry);
-
-				String server = getDomainName(url);
-				ftp.connect(server);
-				// After connection attempt, you should check the reply code to verify
-				// success.
-				int reply = ftp.getReplyCode();
-
-				if (!FTPReply.isPositiveCompletion(reply)) {
-					throw new IOException("FTP server refused connection.");
-				}
-				ftp.enterLocalPassiveMode();
-				ftp.login("anonymous", "");
-				ftp.setFileType(FTP.BINARY_FILE_TYPE);
-
-				long fileSize = -1;
-				String remotePath = getFilePath(url);
-				FTPFile[] files = ftp.listFiles(remotePath);
-				if (files.length == 1 && files[0].isFile()) {
-					fileSize = files[0].getSize();
-				}
-				final long size = fileSize;
-
-				OutputStream output = new FileOutputStream(Configuration.getWebAppDir() + entry.getLocalPath());
-				CountingOutputStream cos = new CountingOutputStream(output) {
-					private double lastProgress = -1;
-
-					protected void beforeWrite(int n) {
-						super.beforeWrite(n);
-						double newProgress = ((double) getCount()) / ((double) size) * IProgressUpdater.MAX_PROGRESS;
-						if (newProgress - lastProgress >= IProgressUpdater.PROGRESS_BAR_UPDATE_RESOLUTION) {
-							lastProgress = newProgress;
-							entry.setDownloadProgress(lastProgress);
-							bigFileEntryDao.update(entry);
-							bigFileEntryDao.commit();
-							updater.setProgress(lastProgress);
-						}
-					}
-				};
-				ftp.retrieveFile(remotePath, cos);
-
-				entry.setDownloadProgress(IProgressUpdater.MAX_PROGRESS);
-				bigFileEntryDao.update(entry);
-				bigFileEntryDao.commit();
-				updater.setProgress(IProgressUpdater.MAX_PROGRESS);
-
-				output.close();
-
-				ftp.logout();
-
-				return null;
-			} finally {
-				bigFileEntryDao.commit();
-				// close the transaction for this thread
-				dbUtils.closeSessionForCurrentThread();
-				if (ftp.isConnected()) {
-					ftp.disconnect();
-				}
-
-			}
-		}
-
-	}
-
-	/**
-	 * Class that describes task of downloading http file.
-	 * 
-	 * @author Piotr Gawron
-	 *
-	 */
-	private final class GetHttpFileTask implements Callable<Void> {
-
-		/**
-		 * Url to the file that we want to download.
-		 * 
-		 */
-		private String					 url;
-
-		/**
-		 * Callback listener that will receive information about upload progress.
-		 * 
-		 */
-		private IProgressUpdater updater;
-
-		/**
-		 * Default constructor.
-		 * 
-		 * @param url
-		 *          {@link #url}
-		 * @param updater
-		 *          {@link #updater}
-		 */
-		private GetHttpFileTask(String url, IProgressUpdater updater) {
-			this.url = url;
-			if (updater != null) {
-				this.updater = updater;
-			} else {
-				this.updater = new IProgressUpdater() {
-					@Override
-					public void setProgress(double progress) {
-					}
-				};
-			}
-		}
-
-		@Override
-		public Void call() throws Exception {
-			dbUtils.createSessionForCurrentThread();
-			BufferedInputStream in = null;
-			CountingOutputStream cos = null;
-			try {
-				try {
-					if (getAbsolutePathForFile(url) != null) {
-						logger.warn("File already downloaded. Skipping...");
-						return null;
-					}
-				} catch (FileNotFoundException e) {
-					removeFile(url);
-				}
-
-				BigFileEntry entry = createEntryForBigFile(url);
-				entry.setDownloadThreadId(Thread.currentThread().getId());
-				bigFileEntryDao.update(entry);
-
-				final long size = getRemoteHttpFileSize(url);
-
-				OutputStream output = new FileOutputStream(Configuration.getWebAppDir() + entry.getLocalPath());
-				cos = new CountingOutputStream(output) {
-					private double lastProgress = -1;
-
-					protected void beforeWrite(int n) {
-						super.beforeWrite(n);
-						double newProgress = ((double) getCount()) / ((double) size) * IProgressUpdater.MAX_PROGRESS;
-						if (newProgress - lastProgress >= IProgressUpdater.PROGRESS_BAR_UPDATE_RESOLUTION) {
-							lastProgress = newProgress;
-							entry.setDownloadProgress(lastProgress);
-							bigFileEntryDao.update(entry);
-							bigFileEntryDao.commit();
-							updater.setProgress(lastProgress);
-						}
-					}
-				};
-				URL website = new URL(url);
-				in = new BufferedInputStream(website.openStream());
-
-				final byte[] data = new byte[DOWNLOAD_BUFFER_SIZE];
-				int count;
-				while ((count = in.read(data, 0, DOWNLOAD_BUFFER_SIZE)) != -1) {
-					cos.write(data, 0, count);
-				}
-
-				entry.setDownloadProgress(IProgressUpdater.MAX_PROGRESS);
-				bigFileEntryDao.update(entry);
-				bigFileEntryDao.commit();
-				updater.setProgress(IProgressUpdater.MAX_PROGRESS);
-
-				output.close();
-
-				return null;
-			} finally {
-				bigFileEntryDao.commit();
-				// close the transaction for this thread
-				dbUtils.closeSessionForCurrentThread();
-				// close opened streams
-				if (in != null) {
-					in.close();
-				}
-				if (cos != null) {
-					cos.close();
-				}
-			}
-		}
-	}
-
-	/**
-	 * Checks if local file for given url is up to date. The check is based on
-	 * file size check (ftp doesn't provide checksums for files, so we cannot
-	 * compare it differently without downloading file).
-	 * 
-	 * @param url
-	 *          url to ftp file
-	 * @return <code>true</code> if file is up to date, <code>false</code> in
-	 *         other case
-	 * @throws URISyntaxException
-	 *           thrown when url is invalid
-	 * @throws IOException
-	 *           thrown when there is a problem with accessing local or remote
-	 *           file
-	 */
-	public boolean isLocalFileUpToDate(String url) throws URISyntaxException, IOException {
-		if (url.toLowerCase().startsWith("ftp")) {
-			return isLocalFtpFileUpToDate(url);
-		} else if (url.toLowerCase().startsWith("http")) {
-			return isLocalHttpFileUpToDate(url);
-		} else {
-			throw new URISyntaxException(url, "Unknown protocol");
-		}
-	}
-
-	/**
-	 * Checks if local file fetched from ftp is up to date.
-	 * 
-	 * @param url
-	 *          url to remote file
-	 * @return <code>true</code> if file is up to date, <code>false</code>
-	 *         otherwise
-	 * @throws FileNotFoundException
-	 *           thrown when local file cannot be found
-	 * @throws URISyntaxException
-	 *           thrown when url is invalid
-	 * @throws IOException
-	 *           thrown when there is a problem with connection to remote server
-	 */
-	public boolean isLocalFtpFileUpToDate(String url) throws FileNotFoundException, IOException, URISyntaxException {
-		boolean result = false;
-		BigFileEntry entry = bigFileEntryDao.getByUrl(url);
-		if (entry == null) {
-			throw new FileNotFoundException("File wasn't downloaded: " + url);
-		}
-		String path = Configuration.getWebAppDir() + entry.getLocalPath();
-		File f = new File(path);
-		if (!f.exists()) {
-			throw new FileNotFoundException("Missing file: " + path + ". Downloaded from: " + url);
-		}
-		long localSize = f.length();
-
-		FTPClient ftp = ftpClientFactory.createFtpClient();
-		try {
-			String server = getDomainName(url);
-			ftp.connect(server);
-			// After connection attempt, you should check the reply code to verify
-			// success.
-			int reply = ftp.getReplyCode();
-
-			if (!FTPReply.isPositiveCompletion(reply)) {
-				throw new IOException("FTP server refused connection.");
-			}
-			ftp.enterLocalPassiveMode();
-			ftp.login("anonymous", "");
-			ftp.setFileType(FTP.BINARY_FILE_TYPE);
-
-			long fileSize = -1;
-			String remotePath = getFilePath(url);
-			FTPFile[] files = ftp.listFiles(remotePath);
-			if (files.length == 1 && files[0].isFile()) {
-				fileSize = files[0].getSize();
-			}
-
-			result = (fileSize == localSize);
-			ftp.logout();
-		} finally {
-			if (ftp.isConnected()) {
-				ftp.disconnect();
-			}
-		}
-		return result;
-	}
-
-	/**
-	 * Checks if local file fetched from http is up to date.
-	 * 
-	 * @param url
-	 *          url to remote file
-	 * @return <code>true</code> if file is up to date, <code>false</code>
-	 *         otherwise
-	 * @throws IOException
-	 *           thrown when local file cannot be found or there is a problem with
-	 *           accesing remote file
-	 */
-	public boolean isLocalHttpFileUpToDate(String url) throws IOException {
-		boolean result = false;
-		BigFileEntry entry = bigFileEntryDao.getByUrl(url);
-		if (entry == null) {
-			throw new FileNotFoundException("File wasn't downloaded: " + url);
-		}
-		String path = Configuration.getWebAppDir() + entry.getLocalPath();
-		File f = new File(path);
-		if (!f.exists()) {
-			throw new FileNotFoundException("Missing file: " + path + ". Downloaded from: " + url);
-		}
-		long localSize = f.length();
-
-		long remoteSize = getRemoteHttpFileSize(url);
-
-		result = (localSize == remoteSize);
-		return result;
-	}
-
-	/**
-	 * Returns size of the remote file access via http url.
-	 * 
-	 * @param url
-	 *          url address to the file
-	 * @return size of the remote file access via http url
-	 * @throws IOException
-	 *           thrown when there is a problem with accessing remote file
-	 */
-	long getRemoteHttpFileSize(String url) throws IOException {
-		long remoteSize = -1;
-		HttpURLConnection conn = null;
-		try {
-			URL website = new URL(url);
-			conn = (HttpURLConnection) website.openConnection();
-			conn.setRequestMethod("HEAD");
-			conn.getInputStream();
-			remoteSize = conn.getContentLength();
-		} finally {
-			if (conn != null) {
-				conn.disconnect();
-			}
-		}
-		return remoteSize;
-	}
-
-	/**
-	 * Removes local file copy of a file given in a parameter.
-	 * 
-	 * @param url
-	 *          ftp url of a file
-	 * @throws IOException
-	 *           thrown when there is a problem with deleting file
-	 */
-	public void removeFile(String url) throws IOException {
-		BigFileEntry entry = bigFileEntryDao.getByUrl(url);
-		if (entry == null) {
-			throw new InvalidArgumentException("Cannot remove file. File wasn't downloaded: " + url);
-		}
-		String path = Configuration.getWebAppDir() + entry.getLocalPath();
-		File f = new File(path);
-		if (!f.exists()) {
-			logger.warn("Missing file: " + path + ". Downloaded from: " + url);
-		}
-		String dirPath = FilenameUtils.getFullPath(path);
-
-		FileUtils.deleteDirectory(new File(dirPath));
-
-		bigFileEntryDao.delete(entry);
-	}
-
-	/**
-	 * Task that describes updating file from ftp.
-	 * 
-	 * @author Piotr Gawron
-	 *
-	 */
-	private final class UpdateFtpFileTask implements Callable<Void> {
-
-		/**
-		 * Url to file.
-		 */
-		private String url;
-
-		/**
-		 * Default constructor.
-		 * 
-		 * @param url
-		 *          {@link #url}
-		 */
-		private UpdateFtpFileTask(String url) {
-			this.url = url;
-		}
-
-		@Override
-		public Void call() throws Exception {
-			dbUtils.createSessionForCurrentThread();
-			FTPClient ftp = ftpClientFactory.createFtpClient();
-			try {
-				BigFileEntry localEntryCopy = bigFileEntryDao.getByUrl(url);
-				localEntryCopy.setDownloadThreadId(Thread.currentThread().getId());
-				localEntryCopy.setDownloadProgress(0.0);
-				bigFileEntryDao.update(localEntryCopy);
-
-				// remove current version
-				new File(Configuration.getWebAppDir() + localEntryCopy.getLocalPath()).delete();
-
-				String server = getDomainName(url);
-				ftp.connect(server);
-				// After connection attempt, you should check the reply code to
-				// verify success.
-				int reply = ftp.getReplyCode();
-
-				if (!FTPReply.isPositiveCompletion(reply)) {
-					throw new IOException("FTP server refused connection.");
-				}
-				ftp.enterLocalPassiveMode();
-				ftp.login("anonymous", "");
-				ftp.setFileType(FTP.BINARY_FILE_TYPE);
-
-				long fileSize = -1;
-				String remotePath = getFilePath(url);
-				FTPFile[] files = ftp.listFiles(remotePath);
-				if (files.length == 1 && files[0].isFile()) {
-					fileSize = files[0].getSize();
-				}
-				final long size = fileSize;
-
-				OutputStream output = new FileOutputStream(localEntryCopy.getLocalPath());
-				CountingOutputStream cos = new CountingOutputStream(output) {
-					private double lastProgress = -1;
-
-					protected void beforeWrite(int n) {
-						super.beforeWrite(n);
-						double newProgress = ((double) getCount()) / ((double) size) * IProgressUpdater.MAX_PROGRESS;
-						if (newProgress - lastProgress >= IProgressUpdater.PROGRESS_BAR_UPDATE_RESOLUTION) {
-							lastProgress = newProgress;
-							localEntryCopy.setDownloadProgress(lastProgress);
-							bigFileEntryDao.update(localEntryCopy);
-						}
-					}
-				};
-				ftp.retrieveFile(remotePath, cos);
-
-				output.close();
-
-				ftp.logout();
-				return null;
-			} finally {
-				dbUtils.closeSessionForCurrentThread();
-				if (ftp.isConnected()) {
-					ftp.disconnect();
-				}
-			}
-		}
-
-	}
-
-	/**
-	 * Updates local copy of a file that can be downloaded from a url given in
-	 * parameter.
-	 * 
-	 * @param url
-	 *          url to an ftp file to be updated
-	 * @param async
-	 *          <code>true</code> if update should be done asynchronously,
-	 *          <code>false</code> otherwise
-	 * @throws IOException
-	 *           thrown when there is a problem with accessing remote file
-	 * @throws URISyntaxException
-	 *           thrown when url is invalid
-	 */
-	public void updateFile(String url, boolean async) throws URISyntaxException, IOException {
-		if (isLocalFileUpToDate(url)) {
-			logger.warn("File is up to date. Skipping...");
-			return;
-		}
-		UpdateFtpFileTask updateTask = new UpdateFtpFileTask(url);
-		if (async) {
-			asyncExecutorService.submit(updateTask);
-		} else {
-			Future<Void> task = syncExecutorService.submit(updateTask);
-			executeTask(task);
-		}
-	}
-
-	/**
-	 * Executes download/update task.
-	 * 
-	 * @param task
-	 *          task to be executed
-	 * @throws URISyntaxException
-	 *           thrown when task finsihed with {@link URISyntaxException}
-	 * @throws IOException
-	 *           thrown when task finsihed with {@link IOException}
-	 */
-	void executeTask(Future<?> task) throws URISyntaxException, IOException {
-		try {
-			task.get();
-		} catch (InterruptedException e) {
-			logger.error(e, e);
-		} catch (ExecutionException e) {
-			if (e.getCause() instanceof URISyntaxException) {
-				throw (URISyntaxException) e.getCause();
-			} else if (e.getCause() instanceof IOException) {
-				throw new IOException((IOException) e.getCause());
-			} else {
-				throw new InvalidStateException(e);
-			}
-		}
-	}
-
-	/**
-	 * Returns server domain name from url.
-	 * 
-	 * @param url
-	 *          url to be processed
-	 * @return server domain name from url
-	 * @throws URISyntaxException
-	 *           thrown when url is invalid
-	 */
-	String getDomainName(String url) throws URISyntaxException {
-		URI uri = new URI(url);
-		String domain = uri.getHost();
-		if (domain.startsWith("www.")) {
-			domain = domain.substring("www.".length());
-		}
-
-		return domain;
-	}
-
-	/**
-	 * Returns path to file on server without server domain name from url.
-	 * 
-	 * @param url
-	 *          url to be processed
-	 * @return path to file on server without server domain name from url
-	 * @throws URISyntaxException
-	 *           thrown when url is invalid
-	 */
-	public String getFilePath(String url) throws URISyntaxException {
-		URI uri = new URI(url);
-		return uri.getPath();
-	}
-
-	/**
-	 * Returns simple file name from url.
-	 * 
-	 * @param url
-	 *          url to be processed
-	 * @return simple file name from url
-	 * @throws URISyntaxException
-	 *           thrown when url is invalid
-	 */
-	public String getFileName(String url) throws URISyntaxException {
-		URI uri = new URI(url);
-		return FilenameUtils.getName(uri.getPath());
-	}
-
-	/**
-	 * Checks if the file identified by url is cached.
-	 * 
-	 * @param sourceUrl
-	 *          url that identifies file
-	 * @return <code>true</code> if the file is cached, <code>false</code>
-	 *         otherwise
-	 */
-	public boolean isCached(String sourceUrl) {
-		BigFileEntry entry = bigFileEntryDao.getByUrl(sourceUrl);
-		if (entry != null) {
-			File f = new File(Configuration.getWebAppDir() + entry.getLocalPath());
-			if (!f.exists()) {
-				logger.warn("File is supposed to be cached but it's not there... " + sourceUrl);
-				return false;
-			}
-		}
-		return entry != null;
-	}
-
-	/**
-	 * @param bigFileEntryDao
-	 *          the bigFileEntryDao to set
-	 * @see #bigFileEntryDao
-	 */
-	public void setBigFileEntryDao(BigFileEntryDao bigFileEntryDao) {
-		this.bigFileEntryDao = bigFileEntryDao;
-	}
-
-	/**
-	 * Return number of tasks that are executed or are waiting for execution.
-	 * 
-	 * @return number of tasks that are executed or are waiting for execution
-	 */
-	public int getDownloadThreadCount() {
-		return ((ScheduledThreadPoolExecutor) asyncExecutorService).getQueue().size() + ((ScheduledThreadPoolExecutor) asyncExecutorService).getActiveCount()
-				+ ((ScheduledThreadPoolExecutor) syncExecutorService).getQueue().size() + ((ScheduledThreadPoolExecutor) syncExecutorService).getActiveCount();
-	}
-
-	/**
-	 * @param ftpClientFactory
-	 *          the ftpClientFactory to set
-	 * @see #ftpClientFactory
-	 */
-	protected void setFtpClientFactory(FtpClientFactory ftpClientFactory) {
-		this.ftpClientFactory = ftpClientFactory;
-	}
-
-	/**
-	 * @return the configurationDao
-	 * @see #configurationDao
-	 */
-	protected ConfigurationDao getConfigurationDao() {
-		return configurationDao;
-	}
-
-	/**
-	 * @param configurationDao
-	 *          the configurationDao to set
-	 * @see #configurationDao
-	 */
-	protected void setConfigurationDao(ConfigurationDao configurationDao) {
-		this.configurationDao = configurationDao;
-	}
+  /**
+   * Buffer size used for downloading single chunk of a file.
+   */
+  private static final int DOWNLOAD_BUFFER_SIZE = 1024;
+
+  /**
+   * Default class logger.
+   */
+  private Logger logger = Logger.getLogger(BigFileCache.class);
+
+  /**
+   * Access class for database objects storing statuses of the files.
+   */
+  @Autowired
+  private BigFileEntryDao bigFileEntryDao;
+
+  /**
+   * Access class for database objects storing some configuration information.
+   */
+  @Autowired
+  private ConfigurationDao configurationDao;
+
+  /**
+   * Utils that help to manage the sessions in custom multithreaded
+   * implementation.
+   */
+  @Autowired
+  private DbUtils dbUtils;
+
+  /**
+   * Service used for executing tasks in separate thread.
+   */
+  private ExecutorService asyncExecutorService;
+
+  /**
+   * Service used for executing tasks immediately.
+   */
+  private ExecutorService syncExecutorService;
+
+  /**
+   * Factory class used to create {@link FTPClient} objects.
+   */
+  private FtpClientFactory ftpClientFactory = new FtpClientFactory();
+
+  /**
+   * Default constructor.
+   */
+  public BigFileCache() {
+    // the executor is a daemon thread so that it will get killed automatically
+    // when the main program exits
+    asyncExecutorService = Executors.newScheduledThreadPool(10, new ThreadFactory() {
+      @Override
+      public Thread newThread(Runnable r) {
+        Thread t = new Thread(r);
+        t.setDaemon(true);
+        return t;
+      }
+    });
+    syncExecutorService = 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 initialized
+    // (additional managing thread was createed)
+    asyncExecutorService.submit(new Callable<Object>() {
+      @Override
+      public Object call() throws Exception {
+        return null;
+      }
+    });
+    syncExecutorService.submit(new Callable<Object>() {
+      @Override
+      public Object call() throws Exception {
+        return null;
+      }
+    });
+  }
+
+  /**
+   * Returns a path for a file in local file system.
+   * 
+   * @param url
+   *          url to the file
+   * @return a path for a file in local file system
+   * @throws FileNotFoundException
+   *           thrown when file should be in file system, but couldn't be found
+   *           there (somebody manually removed it)
+   */
+  public String getAbsolutePathForFile(String url) throws FileNotFoundException {
+    BigFileEntry entry = bigFileEntryDao.getByUrl(url);
+    if (entry == null) {
+      return null;
+    }
+    if (entry.getDownloadProgress() == null || entry.getDownloadProgress() < 100.0) {
+      throw new FileNotFoundException("File is not complete: " + entry.getLocalPath() + ". Downloaded from: " + url);
+    }
+    File f = new File(Configuration.getWebAppDir() + entry.getLocalPath());
+    if (!f.exists()) {
+      throw new FileNotFoundException(
+          "Missing big file: " + Configuration.getWebAppDir() + entry.getLocalPath() + ". Downloaded from: " + url);
+    }
+
+    return f.getAbsolutePath();
+  }
+
+  /**
+   * Returns a path for a file in local file system for an ftp url.
+   * 
+   * @param url
+   *          ftp url to the file
+   * @return a path for a file in local file system for an ftp url
+   * @throws FileNotFoundException
+   *           thrown when file should be in file system, but couldn't be found
+   *           there (somebody manually removed it)
+   */
+  public String getLocalPathForFile(String url) throws FileNotFoundException {
+    BigFileEntry entry = bigFileEntryDao.getByUrl(url);
+    if (entry == null) {
+      return null;
+    }
+    if (entry.getDownloadProgress() == null || entry.getDownloadProgress() < 100.0) {
+      throw new FileNotFoundException("File is not complete: " + entry.getLocalPath() + ". Downloaded from: " + url);
+    }
+    File f = new File(Configuration.getWebAppDir() + entry.getLocalPath());
+    if (!f.exists()) {
+      throw new FileNotFoundException(
+          "Missing big file: " + Configuration.getWebAppDir() + entry.getLocalPath() + ". Downloaded from: " + url);
+    }
+
+    return entry.getLocalPath();
+  }
+
+  /**
+   * Download big file from ftp server.
+   * 
+   * @param url
+   *          url for file to download
+   * @param async
+   *          <code>true</code> if should the download be asynchronous
+   * @param updater
+   *          callback method that will be called with info updates about
+   *          downloading process
+   * @throws IOException
+   *           thrown when there is a problem with downloading file
+   * @throws URISyntaxException
+   *           thrown when url is invalid
+   */
+  public void downloadFile(String url, boolean async, IProgressUpdater updater) throws IOException, URISyntaxException {
+    Callable<Void> computations = null;
+    if (url.toLowerCase().startsWith("ftp:")) {
+      computations = new GetFtpFileTask(url, updater);
+    } else if (url.toLowerCase().startsWith("http:") || url.toLowerCase().startsWith("https:")) {
+      computations = new GetHttpFileTask(url, updater);
+    } else {
+      throw new URISyntaxException(url, "Unknown protocol for url");
+    }
+
+    if (async) {
+      asyncExecutorService.submit(computations);
+    } else {
+      Future<Void> task = syncExecutorService.submit(computations);
+      executeTask(task);
+    }
+  }
+
+  /**
+   * Creates new {@link BigFileEntry} for given url.
+   * 
+   * @param url
+   *          url for which entry will be created
+   * @return new {@link BigFileEntry} for given url
+   * @throws URISyntaxException
+   *           thrown when url is invalid
+   */
+  private BigFileEntry createEntryForBigFile(String url) throws URISyntaxException {
+    String localPath = configurationDao.getValueByType(ConfigurationElementType.BIG_FILE_STORAGE_DIR);
+    BigFileEntry entry = new BigFileEntry();
+    entry.setDownloadDate(Calendar.getInstance());
+    entry.setLocalPath(localPath);
+    entry.setUrl(url);
+    bigFileEntryDao.add(entry);
+
+    localPath = entry.getLocalPath() + "/" + entry.getId() + "/";
+    new File(Configuration.getWebAppDir() + localPath).mkdirs();
+    localPath += getFileName(url);
+
+    entry.setLocalPath(localPath);
+    bigFileEntryDao.update(entry);
+    bigFileEntryDao.flush();
+    return entry;
+  }
+
+  /**
+   * Task that will be able to fetch file from ftp server.
+   * 
+   * @author Piotr Gawron
+   *
+   */
+  private final class GetFtpFileTask implements Callable<Void> {
+
+    /**
+     * Url to the file that we want to download.
+     * 
+     */
+    private String url;
+
+    /**
+     * Callback listener that will receive information about upload progress.
+     * 
+     */
+    private IProgressUpdater updater;
+
+    /**
+     * Default constructor.
+     * 
+     * @param url
+     *          {@link #url}
+     * @param updater
+     *          {@link #updater}
+     */
+    private GetFtpFileTask(String url, IProgressUpdater updater) {
+      this.url = url;
+      if (updater != null) {
+        this.updater = updater;
+      } else {
+        this.updater = new IProgressUpdater() {
+          @Override
+          public void setProgress(double progress) {
+          }
+        };
+      }
+    }
+
+    @Override
+    public Void call() throws Exception {
+      dbUtils.createSessionForCurrentThread();
+      FTPClient ftp = ftpClientFactory.createFtpClient();
+      try {
+        try {
+          if (getAbsolutePathForFile(url) != null) {
+            logger.warn("File already downloaded. Skipping...");
+            return null;
+          }
+        } catch (FileNotFoundException e) {
+          removeFile(url);
+        }
+
+        BigFileEntry entry = createEntryForBigFile(url);
+        entry.setDownloadThreadId(Thread.currentThread().getId());
+        bigFileEntryDao.update(entry);
+
+        String server = getDomainName(url);
+        ftp.connect(server);
+        // After connection attempt, you should check the reply code to verify
+        // success.
+        int reply = ftp.getReplyCode();
+
+        if (!FTPReply.isPositiveCompletion(reply)) {
+          throw new IOException("FTP server refused connection.");
+        }
+        ftp.enterLocalPassiveMode();
+        ftp.login("anonymous", "");
+        ftp.setFileType(FTP.BINARY_FILE_TYPE);
+
+        long fileSize = -1;
+        String remotePath = getFilePath(url);
+        FTPFile[] files = ftp.listFiles(remotePath);
+        if (files.length == 1 && files[0].isFile()) {
+          fileSize = files[0].getSize();
+        }
+        final long size = fileSize;
+
+        OutputStream output = new FileOutputStream(Configuration.getWebAppDir() + entry.getLocalPath());
+        CountingOutputStream cos = new CountingOutputStream(output) {
+          private double lastProgress = -1;
+
+          protected void beforeWrite(int n) {
+            super.beforeWrite(n);
+            double newProgress = ((double) getCount()) / ((double) size) * IProgressUpdater.MAX_PROGRESS;
+            if (newProgress - lastProgress >= IProgressUpdater.PROGRESS_BAR_UPDATE_RESOLUTION) {
+              lastProgress = newProgress;
+              entry.setDownloadProgress(lastProgress);
+              bigFileEntryDao.update(entry);
+              bigFileEntryDao.commit();
+              updater.setProgress(lastProgress);
+            }
+          }
+        };
+        ftp.retrieveFile(remotePath, cos);
+
+        entry.setDownloadProgress(IProgressUpdater.MAX_PROGRESS);
+        bigFileEntryDao.update(entry);
+        bigFileEntryDao.commit();
+        updater.setProgress(IProgressUpdater.MAX_PROGRESS);
+
+        output.close();
+
+        ftp.logout();
+
+        return null;
+      } finally {
+        bigFileEntryDao.commit();
+        // close the transaction for this thread
+        dbUtils.closeSessionForCurrentThread();
+        if (ftp.isConnected()) {
+          ftp.disconnect();
+        }
+
+      }
+    }
+
+  }
+
+  /**
+   * Class that describes task of downloading http file.
+   * 
+   * @author Piotr Gawron
+   *
+   */
+  private final class GetHttpFileTask implements Callable<Void> {
+
+    /**
+     * Url to the file that we want to download.
+     * 
+     */
+    private String url;
+
+    /**
+     * Callback listener that will receive information about upload progress.
+     * 
+     */
+    private IProgressUpdater updater;
+
+    /**
+     * Default constructor.
+     * 
+     * @param url
+     *          {@link #url}
+     * @param updater
+     *          {@link #updater}
+     */
+    private GetHttpFileTask(String url, IProgressUpdater updater) {
+      this.url = url;
+      if (updater != null) {
+        this.updater = updater;
+      } else {
+        this.updater = new IProgressUpdater() {
+          @Override
+          public void setProgress(double progress) {
+          }
+        };
+      }
+    }
+
+    @Override
+    public Void call() throws Exception {
+      dbUtils.createSessionForCurrentThread();
+      BufferedInputStream in = null;
+      CountingOutputStream cos = null;
+      try {
+        try {
+          if (getAbsolutePathForFile(url) != null) {
+            logger.warn("File already downloaded. Skipping...");
+            return null;
+          }
+        } catch (FileNotFoundException e) {
+          removeFile(url);
+        }
+        BigFileEntry entry = createEntryForBigFile(url);
+        entry.setDownloadThreadId(Thread.currentThread().getId());
+        bigFileEntryDao.update(entry);
+
+        final long size = getRemoteHttpFileSize(url);
+
+        OutputStream output = new FileOutputStream(Configuration.getWebAppDir() + entry.getLocalPath());
+        cos = new CountingOutputStream(output) {
+          private double lastProgress = -1;
+
+          protected void beforeWrite(int n) {
+            super.beforeWrite(n);
+            double newProgress = ((double) getCount()) / ((double) size) * IProgressUpdater.MAX_PROGRESS;
+            if (newProgress - lastProgress >= IProgressUpdater.PROGRESS_BAR_UPDATE_RESOLUTION) {
+              lastProgress = newProgress;
+              entry.setDownloadProgress(lastProgress);
+              bigFileEntryDao.update(entry);
+              bigFileEntryDao.commit();
+              updater.setProgress(lastProgress);
+            }
+          }
+        };
+        URL website = new URL(url);
+        in = new BufferedInputStream(website.openStream());
+
+        final byte[] data = new byte[DOWNLOAD_BUFFER_SIZE];
+        int count;
+        while ((count = in.read(data, 0, DOWNLOAD_BUFFER_SIZE)) != -1) {
+          cos.write(data, 0, count);
+        }
+
+        entry.setDownloadProgress(IProgressUpdater.MAX_PROGRESS);
+        bigFileEntryDao.update(entry);
+        bigFileEntryDao.commit();
+        updater.setProgress(IProgressUpdater.MAX_PROGRESS);
+
+        output.close();
+
+        return null;
+      } finally {
+        bigFileEntryDao.commit();
+        // close the transaction for this thread
+        dbUtils.closeSessionForCurrentThread();
+        // close opened streams
+        if (in != null) {
+          in.close();
+        }
+        if (cos != null) {
+          cos.close();
+        }
+      }
+    }
+  }
+
+  /**
+   * Checks if local file for given url is up to date. The check is based on file
+   * size check (ftp doesn't provide checksums for files, so we cannot compare it
+   * differently without downloading file).
+   * 
+   * @param url
+   *          url to ftp file
+   * @return <code>true</code> if file is up to date, <code>false</code> in other
+   *         case
+   * @throws URISyntaxException
+   *           thrown when url is invalid
+   * @throws IOException
+   *           thrown when there is a problem with accessing local or remote file
+   */
+  public boolean isLocalFileUpToDate(String url) throws URISyntaxException, IOException {
+    if (url.toLowerCase().startsWith("ftp")) {
+      return isLocalFtpFileUpToDate(url);
+    } else if (url.toLowerCase().startsWith("http")) {
+      return isLocalHttpFileUpToDate(url);
+    } else {
+      throw new URISyntaxException(url, "Unknown protocol");
+    }
+  }
+
+  /**
+   * Checks if local file fetched from ftp is up to date.
+   * 
+   * @param url
+   *          url to remote file
+   * @return <code>true</code> if file is up to date, <code>false</code> otherwise
+   * @throws FileNotFoundException
+   *           thrown when local file cannot be found
+   * @throws URISyntaxException
+   *           thrown when url is invalid
+   * @throws IOException
+   *           thrown when there is a problem with connection to remote server
+   */
+  public boolean isLocalFtpFileUpToDate(String url) throws FileNotFoundException, IOException, URISyntaxException {
+    boolean result = false;
+    BigFileEntry entry = bigFileEntryDao.getByUrl(url);
+    if (entry == null) {
+      throw new FileNotFoundException("File wasn't downloaded: " + url);
+    }
+    String path = Configuration.getWebAppDir() + entry.getLocalPath();
+    File f = new File(path);
+    if (!f.exists()) {
+      throw new FileNotFoundException("Missing file: " + path + ". Downloaded from: " + url);
+    }
+    long localSize = f.length();
+
+    FTPClient ftp = ftpClientFactory.createFtpClient();
+    try {
+      String server = getDomainName(url);
+      ftp.connect(server);
+      // After connection attempt, you should check the reply code to verify
+      // success.
+      int reply = ftp.getReplyCode();
+
+      if (!FTPReply.isPositiveCompletion(reply)) {
+        throw new IOException("FTP server refused connection.");
+      }
+      ftp.enterLocalPassiveMode();
+      ftp.login("anonymous", "");
+      ftp.setFileType(FTP.BINARY_FILE_TYPE);
+
+      long fileSize = -1;
+      String remotePath = getFilePath(url);
+      FTPFile[] files = ftp.listFiles(remotePath);
+      if (files.length == 1 && files[0].isFile()) {
+        fileSize = files[0].getSize();
+      }
+
+      result = (fileSize == localSize);
+      ftp.logout();
+    } finally {
+      if (ftp.isConnected()) {
+        ftp.disconnect();
+      }
+    }
+    return result;
+  }
+
+  /**
+   * Checks if local file fetched from http is up to date.
+   * 
+   * @param url
+   *          url to remote file
+   * @return <code>true</code> if file is up to date, <code>false</code> otherwise
+   * @throws IOException
+   *           thrown when local file cannot be found or there is a problem with
+   *           accessing remote file
+   */
+  public boolean isLocalHttpFileUpToDate(String url) throws IOException {
+    boolean result = false;
+    BigFileEntry entry = bigFileEntryDao.getByUrl(url);
+    if (entry == null) {
+      throw new FileNotFoundException("File wasn't downloaded: " + url);
+    }
+    String path = Configuration.getWebAppDir() + entry.getLocalPath();
+    File f = new File(path);
+    if (!f.exists()) {
+      throw new FileNotFoundException("Missing file: " + path + ". Downloaded from: " + url);
+    }
+    long localSize = f.length();
+
+    long remoteSize = getRemoteHttpFileSize(url);
+
+    result = (localSize == remoteSize);
+    return result;
+  }
+
+  /**
+   * Returns size of the remote file access via http url.
+   * 
+   * @param url
+   *          url address to the file
+   * @return size of the remote file access via http url
+   * @throws IOException
+   *           thrown when there is a problem with accessing remote file
+   */
+  long getRemoteHttpFileSize(String url) throws IOException {
+    long remoteSize = -1;
+    HttpURLConnection conn = null;
+    try {
+      URL website = new URL(url);
+      conn = (HttpURLConnection) website.openConnection();
+      conn.setRequestMethod("HEAD");
+      conn.getInputStream();
+      remoteSize = conn.getContentLength();
+    } finally {
+      if (conn != null) {
+        conn.disconnect();
+      }
+    }
+    return remoteSize;
+  }
+
+  /**
+   * Removes local file copy of a file given in a parameter.
+   * 
+   * @param url
+   *          ftp url of a file
+   * @throws IOException
+   *           thrown when there is a problem with deleting file
+   */
+  public void removeFile(String url) throws IOException {
+    BigFileEntry entry = bigFileEntryDao.getByUrl(url);
+    if (entry == null) {
+      throw new InvalidArgumentException("Cannot remove file. File wasn't downloaded: " + url);
+    }
+    String path = Configuration.getWebAppDir() + entry.getLocalPath();
+    File f = new File(path);
+    if (!f.exists()) {
+      logger.warn("Missing file: " + path + ". Downloaded from: " + url);
+    }
+    String dirPath = FilenameUtils.getFullPath(path);
+
+    FileUtils.deleteDirectory(new File(dirPath));
+
+    bigFileEntryDao.delete(entry);
+  }
+
+  /**
+   * Task that describes updating file from ftp.
+   * 
+   * @author Piotr Gawron
+   *
+   */
+  private final class UpdateFtpFileTask implements Callable<Void> {
+
+    /**
+     * Url to file.
+     */
+    private String url;
+
+    /**
+     * Default constructor.
+     * 
+     * @param url
+     *          {@link #url}
+     */
+    private UpdateFtpFileTask(String url) {
+      this.url = url;
+    }
+
+    @Override
+    public Void call() throws Exception {
+      dbUtils.createSessionForCurrentThread();
+      FTPClient ftp = ftpClientFactory.createFtpClient();
+      try {
+        BigFileEntry localEntryCopy = bigFileEntryDao.getByUrl(url);
+        localEntryCopy.setDownloadThreadId(Thread.currentThread().getId());
+        localEntryCopy.setDownloadProgress(0.0);
+        bigFileEntryDao.update(localEntryCopy);
+
+        // remove current version
+        new File(Configuration.getWebAppDir() + localEntryCopy.getLocalPath()).delete();
+
+        String server = getDomainName(url);
+        ftp.connect(server);
+        // After connection attempt, you should check the reply code to
+        // verify success.
+        int reply = ftp.getReplyCode();
+
+        if (!FTPReply.isPositiveCompletion(reply)) {
+          throw new IOException("FTP server refused connection.");
+        }
+        ftp.enterLocalPassiveMode();
+        ftp.login("anonymous", "");
+        ftp.setFileType(FTP.BINARY_FILE_TYPE);
+
+        long fileSize = -1;
+        String remotePath = getFilePath(url);
+        FTPFile[] files = ftp.listFiles(remotePath);
+        if (files.length == 1 && files[0].isFile()) {
+          fileSize = files[0].getSize();
+        }
+        final long size = fileSize;
+
+        OutputStream output = new FileOutputStream(localEntryCopy.getLocalPath());
+        CountingOutputStream cos = new CountingOutputStream(output) {
+          private double lastProgress = -1;
+
+          protected void beforeWrite(int n) {
+            super.beforeWrite(n);
+            double newProgress = ((double) getCount()) / ((double) size) * IProgressUpdater.MAX_PROGRESS;
+            if (newProgress - lastProgress >= IProgressUpdater.PROGRESS_BAR_UPDATE_RESOLUTION) {
+              lastProgress = newProgress;
+              localEntryCopy.setDownloadProgress(lastProgress);
+              bigFileEntryDao.update(localEntryCopy);
+            }
+          }
+        };
+        ftp.retrieveFile(remotePath, cos);
+
+        output.close();
+
+        ftp.logout();
+        return null;
+      } finally {
+        dbUtils.closeSessionForCurrentThread();
+        if (ftp.isConnected()) {
+          ftp.disconnect();
+        }
+      }
+    }
+
+  }
+
+  /**
+   * Updates local copy of a file that can be downloaded from a url given in
+   * parameter.
+   * 
+   * @param url
+   *          url to an ftp file to be updated
+   * @param async
+   *          <code>true</code> if update should be done asynchronously,
+   *          <code>false</code> otherwise
+   * @throws IOException
+   *           thrown when there is a problem with accessing remote file
+   * @throws URISyntaxException
+   *           thrown when url is invalid
+   */
+  public void updateFile(String url, boolean async) throws URISyntaxException, IOException {
+    if (isLocalFileUpToDate(url)) {
+      logger.warn("File is up to date. Skipping...");
+      return;
+    }
+    UpdateFtpFileTask updateTask = new UpdateFtpFileTask(url);
+    if (async) {
+      asyncExecutorService.submit(updateTask);
+    } else {
+      Future<Void> task = syncExecutorService.submit(updateTask);
+      executeTask(task);
+    }
+  }
+
+  /**
+   * Executes download/update task.
+   * 
+   * @param task
+   *          task to be executed
+   * @throws URISyntaxException
+   *           thrown when task finished with {@link URISyntaxException}
+   * @throws IOException
+   *           thrown when task finished with {@link IOException}
+   */
+  void executeTask(Future<?> task) throws URISyntaxException, IOException {
+    try {
+      task.get();
+    } catch (InterruptedException e) {
+      logger.error(e, e);
+    } catch (ExecutionException e) {
+      if (e.getCause() instanceof URISyntaxException) {
+        throw (URISyntaxException) e.getCause();
+      } else if (e.getCause() instanceof IOException) {
+        throw new IOException((IOException) e.getCause());
+      } else {
+        throw new InvalidStateException(e);
+      }
+    }
+  }
+
+  /**
+   * Returns server domain name from url.
+   * 
+   * @param url
+   *          url to be processed
+   * @return server domain name from url
+   * @throws URISyntaxException
+   *           thrown when url is invalid
+   */
+  String getDomainName(String url) throws URISyntaxException {
+    URI uri = new URI(url);
+    String domain = uri.getHost();
+    if (domain.startsWith("www.")) {
+      domain = domain.substring("www.".length());
+    }
+
+    return domain;
+  }
+
+  /**
+   * Returns path to file on server without server domain name from url.
+   * 
+   * @param url
+   *          url to be processed
+   * @return path to file on server without server domain name from url
+   * @throws URISyntaxException
+   *           thrown when url is invalid
+   */
+  public String getFilePath(String url) throws URISyntaxException {
+    URI uri = new URI(url);
+    return uri.getPath();
+  }
+
+  /**
+   * Returns simple file name from url.
+   * 
+   * @param url
+   *          url to be processed
+   * @return simple file name from url
+   * @throws URISyntaxException
+   *           thrown when url is invalid
+   */
+  public String getFileName(String url) throws URISyntaxException {
+    URI uri = new URI(url);
+    return FilenameUtils.getName(uri.getPath());
+  }
+
+  /**
+   * Checks if the file identified by url is cached.
+   * 
+   * @param sourceUrl
+   *          url that identifies file
+   * @return <code>true</code> if the file is cached, <code>false</code> otherwise
+   */
+  public boolean isCached(String sourceUrl) {
+    BigFileEntry entry = bigFileEntryDao.getByUrl(sourceUrl);
+    if (entry != null) {
+      File f = new File(Configuration.getWebAppDir() + entry.getLocalPath());
+      if (!f.exists()) {
+        logger.warn("File is supposed to be cached but it's not there... " + sourceUrl);
+        bigFileEntryDao.delete(entry);
+        return false;
+      }
+    }
+    return entry != null;
+  }
+
+  /**
+   * @param bigFileEntryDao
+   *          the bigFileEntryDao to set
+   * @see #bigFileEntryDao
+   */
+  public void setBigFileEntryDao(BigFileEntryDao bigFileEntryDao) {
+    this.bigFileEntryDao = bigFileEntryDao;
+  }
+
+  /**
+   * Return number of tasks that are executed or are waiting for execution.
+   * 
+   * @return number of tasks that are executed or are waiting for execution
+   */
+  public int getDownloadThreadCount() {
+    return ((ScheduledThreadPoolExecutor) asyncExecutorService).getQueue().size()
+        + ((ScheduledThreadPoolExecutor) asyncExecutorService).getActiveCount()
+        + ((ScheduledThreadPoolExecutor) syncExecutorService).getQueue().size()
+        + ((ScheduledThreadPoolExecutor) syncExecutorService).getActiveCount();
+  }
+
+  /**
+   * @param ftpClientFactory
+   *          the ftpClientFactory to set
+   * @see #ftpClientFactory
+   */
+  protected void setFtpClientFactory(FtpClientFactory ftpClientFactory) {
+    this.ftpClientFactory = ftpClientFactory;
+  }
+
+  /**
+   * @return the configurationDao
+   * @see #configurationDao
+   */
+  protected ConfigurationDao getConfigurationDao() {
+    return configurationDao;
+  }
+
+  /**
+   * @param configurationDao
+   *          the configurationDao to set
+   * @see #configurationDao
+   */
+  protected void setConfigurationDao(ConfigurationDao configurationDao) {
+    this.configurationDao = configurationDao;
+  }
 
 }
\ No newline at end of file
diff --git a/annotation/src/test/java/lcsb/mapviewer/annotation/cache/BigFileCacheTest.java b/annotation/src/test/java/lcsb/mapviewer/annotation/cache/BigFileCacheTest.java
index 87ca09b4d0e98ad99823475f6e9f9fa28dd17f07..fef9e3780344364b4741803c8e97a8f7691894e0 100644
--- a/annotation/src/test/java/lcsb/mapviewer/annotation/cache/BigFileCacheTest.java
+++ b/annotation/src/test/java/lcsb/mapviewer/annotation/cache/BigFileCacheTest.java
@@ -41,544 +41,544 @@ import lcsb.mapviewer.persist.dao.cache.BigFileEntryDao;
 
 public class BigFileCacheTest extends AnnotationTestFunctions {
 
-	Logger			 logger	 = Logger.getLogger(BigFileCacheTest.class);
-
-	String			 ftpUrl	 = "ftp://ftp.informatik.rwth-aachen.de/pub/Linux/debian-cd/current/i386/bt-cd/MD5SUMS";
-
-	String			 httpUrl = "http://minerva.uni.lu/humans.txt";
-
-	@Autowired
-	BigFileCache bigFileCache;
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testDownloadFile() throws Exception {
-		try {
-			bigFileCache.downloadFile(ftpUrl, false, null);
-			String localFile = bigFileCache.getAbsolutePathForFile(ftpUrl);
-			assertTrue(bigFileCache.isCached(ftpUrl));
-			assertTrue(bigFileCache.isLocalFileUpToDate(ftpUrl));
-			File f = new File(localFile);
-			assertTrue(f.exists());
-			String content = super.readFile(localFile);
-			assertTrue(content.contains("iso"));
-
-			// when we try to download file that is already downloaded there should be
-			// a warning
-			bigFileCache.downloadFile(ftpUrl, false, null);
-			assertEquals(1, getWarnings().size());
-
-			// however when due to some reason the file will be removed from file
-			// system
-			f.delete();
-			// the file should be downloaded again
-			bigFileCache.downloadFile(ftpUrl, false, null);
-			// additional warning about it
-			assertEquals(2, getWarnings().size());
-
-			localFile = bigFileCache.getAbsolutePathForFile(ftpUrl);
-			f = new File(localFile);
-			assertTrue(f.exists());
-
-			// when we are trying to update file that is up to date then we will have
-			// a warning about it (but file shouldn't be changed)
-			bigFileCache.updateFile(ftpUrl, false);
-			assertEquals(3, getWarnings().size());
-
-			bigFileCache.removeFile(ftpUrl);
-
-			assertNull(bigFileCache.getAbsolutePathForFile(ftpUrl));
-
-			assertFalse(f.exists());
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testDownloadFileWithUnknownProtocol() throws Exception {
-		try {
-			bigFileCache.downloadFile("wtf://file.com", false, null);
-
-		} catch (URISyntaxException e) {
-			assertTrue(e.getMessage().contains("Unknown protocol for url"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testDownloadAsyncFileFromHttp() throws Exception {
-		try {
-			bigFileCache.downloadFile(httpUrl, true, null);
-			waitForDownload();
-			String localFile = bigFileCache.getAbsolutePathForFile(httpUrl);
-			assertTrue(bigFileCache.isLocalFileUpToDate(httpUrl));
-			File f = new File(localFile);
-			assertTrue(f.exists());
-			String content = super.readFile(localFile);
-			assertTrue(content.contains("Contact"));
-			bigFileCache.removeFile(httpUrl);
-
-			assertNull(bigFileCache.getAbsolutePathForFile(httpUrl));
-
-			assertFalse(f.exists());
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	private void waitForDownload() throws InterruptedException {
-		while (bigFileCache.getDownloadThreadCount() > 0) {
-			logger.debug("Waiting for download to finish");
-			Thread.sleep(100);
-		}
-	}
-
-	@Test
-	public void testIsLocalHttpFileUpToDateWhenMissing() throws Exception {
-		try {
-			bigFileCache.isLocalFileUpToDate(httpUrl);
-			fail("Exception expected");
-		} catch (FileNotFoundException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testIsLocalHttpFileUpToDateWhenFileRemovedManually() throws Exception {
-		try {
-			bigFileCache.downloadFile(httpUrl, false, new IProgressUpdater() {
-				@Override
-				public void setProgress(double progress) {
-				}
-			});
-			new File(bigFileCache.getAbsolutePathForFile(httpUrl)).delete();
-			try {
-				bigFileCache.isLocalFileUpToDate(httpUrl);
-				fail("Exception expected");
-			} catch (FileNotFoundException e) {
-			}
-			bigFileCache.removeFile(httpUrl);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testIsLocalFtpFileUpToDateWhenMissing() throws Exception {
-		try {
-			bigFileCache.isLocalFileUpToDate(ftpUrl);
-			fail("Exception expected");
-		} catch (FileNotFoundException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testRefreshCacheQueryWhenFtpConnectionFails() throws Exception {
-
-		try {
-			bigFileCache.downloadFile(ftpUrl, false, new IProgressUpdater() {
-				@Override
-				public void setProgress(double progress) {
-				}
-			});
-			assertTrue(bigFileCache.isLocalFileUpToDate(ftpUrl));
-
-			FTPClient mockClient = Mockito.mock(FTPClient.class);
-			Mockito.doAnswer(new Answer<Integer>() {
-
-				@Override
-				public Integer answer(InvocationOnMock invocation) throws Throwable {
-					return FTPReply.REQUEST_DENIED;
-				}
-			}).when(mockClient).getReplyCode();
-
-			FtpClientFactory factory = Mockito.mock(FtpClientFactory.class);
-			when(factory.createFtpClient()).thenReturn(mockClient);
-
-			bigFileCache.setFtpClientFactory(factory);
-
-			bigFileCache.isLocalFileUpToDate(ftpUrl);
-			fail("Exception expected");
-		} catch (IOException e) {
-			assertTrue(e.getMessage().contains("FTP server refused connection"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		} finally {
-			bigFileCache.setFtpClientFactory(new FtpClientFactory());
-			bigFileCache.removeFile(ftpUrl);
-		}
-	}
-
-	@Test
-	public void testDownloadWhenFtpConnectionFails() throws Exception {
-		try {
-			FTPClient mockClient = Mockito.mock(FTPClient.class);
-			Mockito.doAnswer(new Answer<Integer>() {
-				@Override
-				public Integer answer(InvocationOnMock invocation) throws Throwable {
-					return FTPReply.REQUEST_DENIED;
-				}
-			}).when(mockClient).getReplyCode();
-
-			FtpClientFactory factory = Mockito.mock(FtpClientFactory.class);
-			when(factory.createFtpClient()).thenReturn(mockClient);
-
-			bigFileCache.setFtpClientFactory(factory);
-			bigFileCache.downloadFile(ftpUrl, false, null);
-
-			fail("Exception expected");
-		} catch (IOException e) {
-			assertTrue(e.getMessage().contains("FTP server refused connection"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		} finally {
-			bigFileCache.setFtpClientFactory(new FtpClientFactory());
-			bigFileCache.removeFile(ftpUrl);
-		}
-	}
-
-	@Test
-	public void testDownloadHttpWhenDownloadFails() throws Exception {
-		ConfigurationDao configurationDao = bigFileCache.getConfigurationDao();
-		
-		try {
-
-			ConfigurationDao mockDao = Mockito.mock(ConfigurationDao.class);
-			when(mockDao.getValueByType(any())).thenThrow(new RuntimeException());
-			bigFileCache.setConfigurationDao(mockDao);
-			bigFileCache.downloadFile(httpUrl, false, null);
-
-			fail("Exception expected");
-		} catch (InvalidStateException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		} finally {
-			bigFileCache.setConfigurationDao(configurationDao);
-		}
-	}
-
-	@Test
-	public void testDownloadedFileRemovedException() throws Exception {
-		try {
-			String url = ftpUrl;
-			bigFileCache.downloadFile(url, false, new IProgressUpdater() {
-				@Override
-				public void setProgress(double progress) {
-				}
-			});
-			String localFile = bigFileCache.getAbsolutePathForFile(url);
-			File f = new File(localFile);
-			assertTrue(f.exists());
-			f.delete();
-
-			try {
-				bigFileCache.getAbsolutePathForFile(url);
-				fail("Exception expected");
-			} catch (FileNotFoundException e) {
-
-			}
-			try {
-				bigFileCache.isLocalFileUpToDate(url);
-				fail("Exception expected");
-			} catch (FileNotFoundException e) {
-
-			}
-
-			bigFileCache.removeFile(url);
-
-			assertNull(bigFileCache.getAbsolutePathForFile(url));
-
-			assertFalse(f.exists());
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetPathForFileBeingDownloaded() throws Exception {
-		try {
-			String url = ftpUrl;
-			BigFileCache bigFileCacheUnderTest = new BigFileCache();
-			BigFileEntryDao mockDao = Mockito.mock(BigFileEntryDao.class);
-			BigFileEntry entry = new BigFileEntry();
-			when(mockDao.getByUrl(anyString())).thenReturn(entry);
-
-			bigFileCacheUnderTest.setBigFileEntryDao(mockDao);
-			try {
-				bigFileCacheUnderTest.getAbsolutePathForFile(url);
-				fail("Exception expected");
-			} catch (FileNotFoundException e) {
-				assertTrue(e.getMessage().contains("File is not complete"));
-			}
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testUpdateFile() throws Exception {
-		try {
-			bigFileCache.downloadFile(ftpUrl, false, new IProgressUpdater() {
-				@Override
-				public void setProgress(double progress) {
-				}
-			});
-			String localFile = bigFileCache.getAbsolutePathForFile(ftpUrl);
-			File f = new File(localFile);
-			f.delete();
-			PrintWriter out = new PrintWriter(localFile);
-			out.println("tesxt");
-			out.close();
-
-			String content = super.readFile(localFile);
-			assertFalse(content.contains("iso"));
-
-			assertFalse(bigFileCache.isLocalFileUpToDate(ftpUrl));
-			bigFileCache.updateFile(ftpUrl, false);
-
-			localFile = bigFileCache.getAbsolutePathForFile(ftpUrl);
-
-			content = super.readFile(localFile);
-			assertTrue(content.contains("iso"));
-
-			// now try update asynchronously
-			f = new File(localFile);
-			f.delete();
-			out = new PrintWriter(localFile);
-			out.println("tesxt");
-			out.close();
-
-			assertFalse(bigFileCache.isLocalFileUpToDate(ftpUrl));
-			bigFileCache.updateFile(ftpUrl, true);
-
-			waitForDownload();
-
-			assertTrue(bigFileCache.isLocalFileUpToDate(ftpUrl));
-
-			// check when connection fails
-			f = new File(localFile);
-			f.delete();
-			out = new PrintWriter(localFile);
-			out.println("tesxt");
-			out.close();
-
-			FTPClient mockClient = Mockito.mock(FTPClient.class);
-			Mockito.doAnswer(new Answer<Integer>() {
-
-				//first answer (for checking if the file should be updated)
-				@Override
-				public Integer answer(InvocationOnMock invocation) throws Throwable {
-					return FTPReply.COMMAND_OK;
-				}
-			}).doAnswer(new Answer<Integer>() {
-				//second answer (for downloading)
-				@Override
-				public Integer answer(InvocationOnMock invocation) throws Throwable {
-					return FTPReply.REQUEST_DENIED;
-				}
-			}).when(mockClient).getReplyCode();
-			
-			Mockito.doAnswer(new Answer<FTPFile[]>() {
-
-				@Override
-				public FTPFile[] answer(InvocationOnMock invocation) throws Throwable {
-					return new FTPFile[]{};
-				}
-			}).when(mockClient).listFiles(anyString());
-
-			FtpClientFactory factory = Mockito.mock(FtpClientFactory.class);
-			when(factory.createFtpClient()).thenReturn(mockClient);
-
-			bigFileCache.setFtpClientFactory(factory);
-			try {
-				bigFileCache.updateFile(ftpUrl, false);
-				fail("Exception expected");
-			} catch (IOException e) {
-				assertTrue(e.getMessage().contains("FTP server refused connection"));
-			} catch (Exception e) {
-				e.printStackTrace();
-				throw e;
-			} finally {
-				bigFileCache.setFtpClientFactory(new FtpClientFactory());
-			}
-
-			bigFileCache.removeFile(ftpUrl);
-
-			assertNull(bigFileCache.getAbsolutePathForFile(ftpUrl));
-
-			assertFalse(f.exists());
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetRemoteHttpFileSizeForInvalidUrl() throws Exception {
-		try {
-			bigFileCache.getRemoteHttpFileSize("invalidurl");
-			fail("Exception expected");
-		} catch (IOException e) {
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testRemoveFileThatDoesntExist() throws Exception {
-		try {
-			bigFileCache.removeFile("unexisting file");
-			fail("Exception expected");
-		} catch (InvalidArgumentException e) {
-			assertTrue(e.getMessage().contains("Cannot remove file. File wasn't downloaded"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testIsLocalFileUpToDateForInvalidURI() throws Exception {
-		try {
-			bigFileCache.isLocalFileUpToDate("unexistingFileProtocol://bla");
-			fail("Exception expected");
-		} catch (URISyntaxException e) {
-			assertTrue(e.getMessage().contains("Unknown protocol"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetDomainName() throws Exception {
-		try {
-			String domain = bigFileCache.getDomainName("http://www.eskago.pl/radio/eska-rock");
-			assertEquals("eskago.pl", domain);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testExecuteProblematicTask() throws Exception {
-		try {
-			Future<?> task = Executors.newScheduledThreadPool(10, new ThreadFactory() {
-				@Override
-				public Thread newThread(Runnable r) {
-					Thread t = new Thread(r);
-					t.setDaemon(true);
-					return t;
-				}
-			}).submit(new Callable<Void>() {
-				@Override
-				public Void call() throws Exception {
-					throw new Exception();
-				}
-			});
-			bigFileCache.executeTask(task);
-			fail("Exception expected");
-		} catch (InvalidStateException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testExecuteProblematicTask2() throws Exception {
-		try {
-			Future<?> task = Executors.newScheduledThreadPool(10, new ThreadFactory() {
-				@Override
-				public Thread newThread(Runnable r) {
-					Thread t = new Thread(r);
-					t.setDaemon(true);
-					return t;
-				}
-			}).submit(new Callable<Void>() {
-				@Override
-				public Void call() throws Exception {
-					throw new URISyntaxException("","");
-				}
-			});
-			bigFileCache.executeTask(task);
-			fail("Exception expected");
-		} catch (URISyntaxException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testExecuteInterruptedTask() throws Exception {
-		try {
-			Future<?> task = Executors.newScheduledThreadPool(10, new ThreadFactory() {
-				@Override
-				public Thread newThread(Runnable r) {
-					Thread t = new Thread(r);
-					t.setDaemon(true);
-					return t;
-				}
-			}).submit(new Callable<Void>() {
-				@Override
-				public Void call() throws Exception {
-					Thread.sleep(100);
-					return null;
-				}
-			});
-			Thread t = new Thread(new Runnable() {
-				@Override
-				public void run() {
-					try {
-						bigFileCache.executeTask(task);
-					} catch (Exception e) {
-						logger.fatal(e,e);
-					}
-				}
-			});
-
-			t.start();
-			// interrupt thread
-			t.interrupt();
-			t.join();
-
-			assertEquals(1, getErrors().size());
-			assertEquals(0, getFatals().size());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
+  Logger logger = Logger.getLogger(BigFileCacheTest.class);
+
+  String ftpUrl = "ftp://ftp.informatik.rwth-aachen.de/pub/Linux/debian-cd/current/i386/bt-cd/MD5SUMS";
+
+  String httpUrl = "https://www.google.pl/humans.txt";
+
+  @Autowired
+  BigFileCache bigFileCache;
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testDownloadFile() throws Exception {
+    try {
+      bigFileCache.downloadFile(ftpUrl, false, null);
+      String localFile = bigFileCache.getAbsolutePathForFile(ftpUrl);
+      assertTrue(bigFileCache.isCached(ftpUrl));
+      assertTrue(bigFileCache.isLocalFileUpToDate(ftpUrl));
+      File f = new File(localFile);
+      assertTrue(f.exists());
+      String content = super.readFile(localFile);
+      assertTrue(content.contains("iso"));
+
+      // when we try to download file that is already downloaded there should be
+      // a warning
+      bigFileCache.downloadFile(ftpUrl, false, null);
+      assertEquals(1, getWarnings().size());
+
+      // however when due to some reason the file will be removed from file
+      // system
+      f.delete();
+      // the file should be downloaded again
+      bigFileCache.downloadFile(ftpUrl, false, null);
+      // additional warning about it
+      assertEquals(2, getWarnings().size());
+
+      localFile = bigFileCache.getAbsolutePathForFile(ftpUrl);
+      f = new File(localFile);
+      assertTrue(f.exists());
+
+      // when we are trying to update file that is up to date then we will have
+      // a warning about it (but file shouldn't be changed)
+      bigFileCache.updateFile(ftpUrl, false);
+      assertEquals(3, getWarnings().size());
+
+      bigFileCache.removeFile(ftpUrl);
+
+      assertNull(bigFileCache.getAbsolutePathForFile(ftpUrl));
+
+      assertFalse(f.exists());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testDownloadFileWithUnknownProtocol() throws Exception {
+    try {
+      bigFileCache.downloadFile("wtf://file.com", false, null);
+
+    } catch (URISyntaxException e) {
+      assertTrue(e.getMessage().contains("Unknown protocol for url"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testDownloadAsyncFileFromHttp() throws Exception {
+    try {
+      bigFileCache.downloadFile(httpUrl, true, null);
+      waitForDownload();
+      String localFile = bigFileCache.getAbsolutePathForFile(httpUrl);
+      assertTrue(bigFileCache.isLocalFileUpToDate(httpUrl));
+      File f = new File(localFile);
+      assertTrue(f.exists());
+      String content = super.readFile(localFile);
+      assertTrue(content.contains("Google"));
+      bigFileCache.removeFile(httpUrl);
+
+      assertNull(bigFileCache.getAbsolutePathForFile(httpUrl));
+
+      assertFalse(f.exists());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  private void waitForDownload() throws InterruptedException {
+    while (bigFileCache.getDownloadThreadCount() > 0) {
+      logger.debug("Waiting for download to finish");
+      Thread.sleep(100);
+    }
+  }
+
+  @Test
+  public void testIsLocalHttpFileUpToDateWhenMissing() throws Exception {
+    try {
+      bigFileCache.isLocalFileUpToDate(httpUrl + "?some_get_param");
+      fail("Exception expected");
+    } catch (FileNotFoundException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testIsLocalHttpFileUpToDateWhenFileRemovedManually() throws Exception {
+    try {
+      bigFileCache.downloadFile(httpUrl, false, new IProgressUpdater() {
+        @Override
+        public void setProgress(double progress) {
+        }
+      });
+      new File(bigFileCache.getAbsolutePathForFile(httpUrl)).delete();
+      try {
+        bigFileCache.isLocalFileUpToDate(httpUrl);
+        fail("Exception expected");
+      } catch (FileNotFoundException e) {
+      }
+      bigFileCache.removeFile(httpUrl);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testIsLocalFtpFileUpToDateWhenMissing() throws Exception {
+    try {
+      bigFileCache.isLocalFileUpToDate(ftpUrl);
+      fail("Exception expected");
+    } catch (FileNotFoundException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testRefreshCacheQueryWhenFtpConnectionFails() throws Exception {
+
+    try {
+      bigFileCache.downloadFile(ftpUrl, false, new IProgressUpdater() {
+        @Override
+        public void setProgress(double progress) {
+        }
+      });
+      assertTrue(bigFileCache.isLocalFileUpToDate(ftpUrl));
+
+      FTPClient mockClient = Mockito.mock(FTPClient.class);
+      Mockito.doAnswer(new Answer<Integer>() {
+
+        @Override
+        public Integer answer(InvocationOnMock invocation) throws Throwable {
+          return FTPReply.REQUEST_DENIED;
+        }
+      }).when(mockClient).getReplyCode();
+
+      FtpClientFactory factory = Mockito.mock(FtpClientFactory.class);
+      when(factory.createFtpClient()).thenReturn(mockClient);
+
+      bigFileCache.setFtpClientFactory(factory);
+
+      bigFileCache.isLocalFileUpToDate(ftpUrl);
+      fail("Exception expected");
+    } catch (IOException e) {
+      assertTrue(e.getMessage().contains("FTP server refused connection"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    } finally {
+      bigFileCache.setFtpClientFactory(new FtpClientFactory());
+      bigFileCache.removeFile(ftpUrl);
+    }
+  }
+
+  @Test
+  public void testDownloadWhenFtpConnectionFails() throws Exception {
+    try {
+      FTPClient mockClient = Mockito.mock(FTPClient.class);
+      Mockito.doAnswer(new Answer<Integer>() {
+        @Override
+        public Integer answer(InvocationOnMock invocation) throws Throwable {
+          return FTPReply.REQUEST_DENIED;
+        }
+      }).when(mockClient).getReplyCode();
+
+      FtpClientFactory factory = Mockito.mock(FtpClientFactory.class);
+      when(factory.createFtpClient()).thenReturn(mockClient);
+
+      bigFileCache.setFtpClientFactory(factory);
+      bigFileCache.downloadFile(ftpUrl, false, null);
+
+      fail("Exception expected");
+    } catch (IOException e) {
+      assertTrue(e.getMessage().contains("FTP server refused connection"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    } finally {
+      bigFileCache.setFtpClientFactory(new FtpClientFactory());
+      bigFileCache.removeFile(ftpUrl);
+    }
+  }
+
+  @Test
+  public void testDownloadHttpWhenDownloadFails() throws Exception {
+    ConfigurationDao configurationDao = bigFileCache.getConfigurationDao();
+
+    try {
+
+      ConfigurationDao mockDao = Mockito.mock(ConfigurationDao.class);
+      when(mockDao.getValueByType(any())).thenThrow(new RuntimeException());
+      bigFileCache.setConfigurationDao(mockDao);
+      bigFileCache.downloadFile(httpUrl, false, null);
+
+      fail("Exception expected");
+    } catch (InvalidStateException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    } finally {
+      bigFileCache.setConfigurationDao(configurationDao);
+    }
+  }
+
+  @Test
+  public void testDownloadedFileRemovedException() throws Exception {
+    try {
+      String url = ftpUrl;
+      bigFileCache.downloadFile(url, false, new IProgressUpdater() {
+        @Override
+        public void setProgress(double progress) {
+        }
+      });
+      String localFile = bigFileCache.getAbsolutePathForFile(url);
+      File f = new File(localFile);
+      assertTrue(f.exists());
+      f.delete();
+
+      try {
+        bigFileCache.getAbsolutePathForFile(url);
+        fail("Exception expected");
+      } catch (FileNotFoundException e) {
+
+      }
+      try {
+        bigFileCache.isLocalFileUpToDate(url);
+        fail("Exception expected");
+      } catch (FileNotFoundException e) {
+
+      }
+
+      bigFileCache.removeFile(url);
+
+      assertNull(bigFileCache.getAbsolutePathForFile(url));
+
+      assertFalse(f.exists());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetPathForFileBeingDownloaded() throws Exception {
+    try {
+      String url = ftpUrl;
+      BigFileCache bigFileCacheUnderTest = new BigFileCache();
+      BigFileEntryDao mockDao = Mockito.mock(BigFileEntryDao.class);
+      BigFileEntry entry = new BigFileEntry();
+      when(mockDao.getByUrl(anyString())).thenReturn(entry);
+
+      bigFileCacheUnderTest.setBigFileEntryDao(mockDao);
+      try {
+        bigFileCacheUnderTest.getAbsolutePathForFile(url);
+        fail("Exception expected");
+      } catch (FileNotFoundException e) {
+        assertTrue(e.getMessage().contains("File is not complete"));
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testUpdateFile() throws Exception {
+    try {
+      bigFileCache.downloadFile(ftpUrl, false, new IProgressUpdater() {
+        @Override
+        public void setProgress(double progress) {
+        }
+      });
+      String localFile = bigFileCache.getAbsolutePathForFile(ftpUrl);
+      File f = new File(localFile);
+      f.delete();
+      PrintWriter out = new PrintWriter(localFile);
+      out.println("tesxt");
+      out.close();
+
+      String content = super.readFile(localFile);
+      assertFalse(content.contains("iso"));
+
+      assertFalse(bigFileCache.isLocalFileUpToDate(ftpUrl));
+      bigFileCache.updateFile(ftpUrl, false);
+
+      localFile = bigFileCache.getAbsolutePathForFile(ftpUrl);
+
+      content = super.readFile(localFile);
+      assertTrue(content.contains("iso"));
+
+      // now try update asynchronously
+      f = new File(localFile);
+      f.delete();
+      out = new PrintWriter(localFile);
+      out.println("tesxt");
+      out.close();
+
+      assertFalse(bigFileCache.isLocalFileUpToDate(ftpUrl));
+      bigFileCache.updateFile(ftpUrl, true);
+
+      waitForDownload();
+
+      assertTrue(bigFileCache.isLocalFileUpToDate(ftpUrl));
+
+      // check when connection fails
+      f = new File(localFile);
+      f.delete();
+      out = new PrintWriter(localFile);
+      out.println("tesxt");
+      out.close();
+
+      FTPClient mockClient = Mockito.mock(FTPClient.class);
+      Mockito.doAnswer(new Answer<Integer>() {
+
+        // first answer (for checking if the file should be updated)
+        @Override
+        public Integer answer(InvocationOnMock invocation) throws Throwable {
+          return FTPReply.COMMAND_OK;
+        }
+      }).doAnswer(new Answer<Integer>() {
+        // second answer (for downloading)
+        @Override
+        public Integer answer(InvocationOnMock invocation) throws Throwable {
+          return FTPReply.REQUEST_DENIED;
+        }
+      }).when(mockClient).getReplyCode();
+
+      Mockito.doAnswer(new Answer<FTPFile[]>() {
+
+        @Override
+        public FTPFile[] answer(InvocationOnMock invocation) throws Throwable {
+          return new FTPFile[] {};
+        }
+      }).when(mockClient).listFiles(anyString());
+
+      FtpClientFactory factory = Mockito.mock(FtpClientFactory.class);
+      when(factory.createFtpClient()).thenReturn(mockClient);
+
+      bigFileCache.setFtpClientFactory(factory);
+      try {
+        bigFileCache.updateFile(ftpUrl, false);
+        fail("Exception expected");
+      } catch (IOException e) {
+        assertTrue(e.getMessage().contains("FTP server refused connection"));
+      } catch (Exception e) {
+        e.printStackTrace();
+        throw e;
+      } finally {
+        bigFileCache.setFtpClientFactory(new FtpClientFactory());
+      }
+
+      bigFileCache.removeFile(ftpUrl);
+
+      assertNull(bigFileCache.getAbsolutePathForFile(ftpUrl));
+
+      assertFalse(f.exists());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetRemoteHttpFileSizeForInvalidUrl() throws Exception {
+    try {
+      bigFileCache.getRemoteHttpFileSize("invalidurl");
+      fail("Exception expected");
+    } catch (IOException e) {
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testRemoveFileThatDoesntExist() throws Exception {
+    try {
+      bigFileCache.removeFile("unexisting file");
+      fail("Exception expected");
+    } catch (InvalidArgumentException e) {
+      assertTrue(e.getMessage().contains("Cannot remove file. File wasn't downloaded"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testIsLocalFileUpToDateForInvalidURI() throws Exception {
+    try {
+      bigFileCache.isLocalFileUpToDate("unexistingFileProtocol://bla");
+      fail("Exception expected");
+    } catch (URISyntaxException e) {
+      assertTrue(e.getMessage().contains("Unknown protocol"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetDomainName() throws Exception {
+    try {
+      String domain = bigFileCache.getDomainName("http://www.eskago.pl/radio/eska-rock");
+      assertEquals("eskago.pl", domain);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testExecuteProblematicTask() throws Exception {
+    try {
+      Future<?> task = Executors.newScheduledThreadPool(10, new ThreadFactory() {
+        @Override
+        public Thread newThread(Runnable r) {
+          Thread t = new Thread(r);
+          t.setDaemon(true);
+          return t;
+        }
+      }).submit(new Callable<Void>() {
+        @Override
+        public Void call() throws Exception {
+          throw new Exception();
+        }
+      });
+      bigFileCache.executeTask(task);
+      fail("Exception expected");
+    } catch (InvalidStateException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testExecuteProblematicTask2() throws Exception {
+    try {
+      Future<?> task = Executors.newScheduledThreadPool(10, new ThreadFactory() {
+        @Override
+        public Thread newThread(Runnable r) {
+          Thread t = new Thread(r);
+          t.setDaemon(true);
+          return t;
+        }
+      }).submit(new Callable<Void>() {
+        @Override
+        public Void call() throws Exception {
+          throw new URISyntaxException("", "");
+        }
+      });
+      bigFileCache.executeTask(task);
+      fail("Exception expected");
+    } catch (URISyntaxException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testExecuteInterruptedTask() throws Exception {
+    try {
+      Future<?> task = Executors.newScheduledThreadPool(10, new ThreadFactory() {
+        @Override
+        public Thread newThread(Runnable r) {
+          Thread t = new Thread(r);
+          t.setDaemon(true);
+          return t;
+        }
+      }).submit(new Callable<Void>() {
+        @Override
+        public Void call() throws Exception {
+          Thread.sleep(100);
+          return null;
+        }
+      });
+      Thread t = new Thread(new Runnable() {
+        @Override
+        public void run() {
+          try {
+            bigFileCache.executeTask(task);
+          } catch (Exception e) {
+            logger.fatal(e, e);
+          }
+        }
+      });
+
+      t.start();
+      // interrupt thread
+      t.interrupt();
+      t.join();
+
+      assertEquals(1, getErrors().size());
+      assertEquals(0, getFatals().size());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
 
 }